205 auto &ep = *ctx_impl_ptr->
ep_ptr;
206 auto &m_field = ep.
mField;
211 boost::make_shared<VolumeElementForcesAndSourcesCore>(m_field);
212 auto fe_interior_adjoint =
213 boost::make_shared<VolumeElementForcesAndSourcesCore>(m_field);
214 auto fe_natural_adjoint =
215 boost::make_shared<FaceElementForcesAndSourcesCore>(m_field);
217 boost::shared_ptr<double> J_ptr(
220 CHKERR VecZeroEntries(dJ_dX_vec);
221 CHKERR VecGhostUpdateBegin(dJ_dX_vec, INSERT_VALUES, SCATTER_FORWARD);
222 CHKERR VecGhostUpdateEnd(dJ_dX_vec, INSERT_VALUES, SCATTER_FORWARD);
225 boundary_integration_hook, J_ptr,
226 dJ_dX_vec, eval_energy_model);
229 auto alpha = ep.alphaW;
230 auto rho = ep.alphaRho;
231 auto alpha_viscous_omega = ep.alphaViscousOmega;
233 ep, fe_interior_adjoint, interior_integration_hook,
235 alpha,
rho, alpha_viscous_omega,
nullptr);
237 ep, fe_natural_adjoint, interior_integration_hook,
244 fe_interior_adjoint);
248 CHKERR VecAssemblyBegin(dJ_dX_vec);
249 CHKERR VecAssemblyEnd(dJ_dX_vec);
250 CHKERR VecGhostUpdateBegin(dJ_dX_vec, ADD_VALUES, SCATTER_REVERSE);
251 CHKERR VecGhostUpdateEnd(dJ_dX_vec, ADD_VALUES, SCATTER_REVERSE);
252 CHKERR VecGhostUpdateBegin(dJ_dX_vec, INSERT_VALUES, SCATTER_FORWARD);
253 CHKERR VecGhostUpdateEnd(dJ_dX_vec, INSERT_VALUES, SCATTER_FORWARD);
318 Vec sol,
double *f, Vec
g,
324 <<
"Starting finite difference dJ_dX gradient test with epsilon = "
327 auto &ep = *ctx_impl_ptr->
ep_ptr;
334 Range body_skin_verts;
335 CHKERR ep.mField.get_moab().get_connectivity(body_skin, body_skin_verts,
338 auto direction_vec = opt->setRandomFields(
339 ep.dmMaterial, {{ep.materialH1Positions, {-1, 1.}}},
343 CHKERR VecCopy(direction_vec, delta_vec);
344 CHKERR VecScale(delta_vec, epsilon);
347 CHKERR VecCopy(sol, a_vec);
348 CHKERR VecAXPY(a_vec, 1., delta_vec);
350 CHKERR VecCopy(sol, b_vec);
351 CHKERR VecAXPY(b_vec, -1., delta_vec);
358 <<
"Objective at a_vec: J_plus = " << std::setprecision(12) << J_plus;
366 <<
"Objective at b_vec: J_minus = " << std::setprecision(12) << J_minus;
367 double dJ_da = (J_plus - J_minus) / (2 * epsilon);
370 CHKERR VecDot(
g, direction_vec, &exact_dJ);
371 double error = dJ_da - exact_dJ;
374 <<
"J = " << *f <<
", dJ/dX = " << dJ_da <<
", exact dJ/dX = " << exact_dJ
375 <<
", error = " << error <<
", fraction " << dJ_da / exact_dJ;
382 CHKERR VecZeroEntries(g_duplicate_vec);
385 CHKERR ep.mField.getInterface<
ISManager>()->isCreateProblemFieldAndRank(
386 adj_problem_ptr->getName(),
RowColData::ROW, ep.materialH1Positions, 0, 3,
387 is, &body_skin_verts);
389 CHKERR ISAllGather(is, &is_raw);
392 CHKERR ISGetSize(is, &nb_dofs);
393 const PetscInt *is_ptr;
394 CHKERR ISGetIndices(is, &is_ptr);
396 constexpr double procent = 0;
397 const int nb_dofs_comp = ceil(procent * nb_dofs / 100.);
399 auto get_vec_value = [&](Vec vec, PetscInt idx) {
401 CHKERR VecGetArray(vec, &array);
402 double &value = array[idx];
403 CHKERR VecRestoreArray(vec, &array);
407 auto set_vec_value = [&](Vec vec, PetscInt idx,
double value) {
410 CHKERR VecGetArray(vec, &array);
412 CHKERR VecRestoreArray(vec, &array);
416 for (
auto i = 0,
j = 0;
i != nb_dofs; ++
i) {
418 <<
"Testing DOF " <<
i <<
" out of " << nb_dofs;
419 auto dof_it = adj_dofs.find(is_ptr[
i]);
420 if (dof_it != adj_dofs.end()) {
421 auto idx = (*dof_it)->getPetscLocalDofIdx();
422 auto exact_dJ = get_vec_value(
g, idx);
423 constexpr double epsilon = 1e-8;
424 if (std::abs(exact_dJ) < epsilon) {
426 <<
"Skipping DOF index " << idx
427 <<
" due to small gradient value: " << exact_dJ;
430 if (
j >= nb_dofs_comp) {
432 <<
"Stopping finite difference test after " << nb_dofs_comp
433 <<
" DOFs, out of total " << nb_dofs;
438 CHKERR VecCopy(sol, direction_vec);
439 CHKERR set_vec_value(direction_vec, idx,
440 get_vec_value(direction_vec, idx) + epsilon);
446 CHKERR VecCopy(sol, direction_vec);
447 CHKERR set_vec_value(direction_vec, idx,
448 get_vec_value(direction_vec, idx) - epsilon);
454 double dJ_da = (J_plus - J_minus) / (2 * epsilon);
455 CHKERR set_vec_value(g_duplicate_vec, idx, dJ_da);
457 double error = dJ_da - exact_dJ;
459 <<
"DOF index: " << idx <<
", J = " << *
f <<
", dJ/dX = " << dJ_da
460 <<
", exact dJ/dX = " << exact_dJ <<
", error = " << error
461 <<
", fraction " << dJ_da / exact_dJ;
466 CHKERR ISRestoreIndices(is, &is_ptr);
469 double *g_array, *g_duplicate_array;
470 CHKERR VecGetArray(
g, &g_array);
471 CHKERR VecGetArray(g_duplicate_vec, &g_duplicate_array);
472 auto &moab = ep.mField.get_moab();
474 double def_val[] = {0, 0, 0};
475 CHKERR moab.tag_get_handle(
"G", 3, MB_TYPE_DOUBLE, th_g,
476 MB_TAG_CREAT | MB_TAG_SPARSE, &def_val);
477 CHKERR moab.tag_get_handle(
"G_fd", 3, MB_TYPE_DOUBLE, th_fd_g,
478 MB_TAG_CREAT | MB_TAG_SPARSE, &def_val);
479 for (
auto &dof : adj_dofs) {
480 if (!dof->getHasLocalIndex())
482 auto idx = dof->getPetscLocalDofIdx();
483 auto ent = dof->getEnt();
484 auto coeff = dof->getDofCoeffIdx();
486 CHKERR moab.tag_set_data(th_g, &ent, 1, &g_array[idx]);
487 CHKERR moab.tag_set_data(th_fd_g, &ent, 1, &g_duplicate_array[idx]);
490 CHKERR VecRestoreArray(
g, &g_array);
491 CHKERR VecRestoreArray(g_duplicate_vec, &g_duplicate_array);
493 EntityHandle root_mesh = 0;
494 std::vector<Tag> tags_list{th_g, th_fd_g};
495 CHKERR moab.write_file(
"gradient_comparison.h5m",
"MOAB",
496 "PARALLEL=WRITE_PART", &root_mesh, 1,
497 &*tags_list.begin(), tags_list.size());
499 CHKERR moab.tag_delete(th_g);
500 CHKERR moab.tag_delete(th_fd_g);
520 <<
"Starting finite difference dJ_dx gradient test with epsilon = "
523 auto &ep = *ctx_impl_ptr->
ep_ptr;
528 CHKERR VecGhostUpdateBegin(sol, INSERT_VALUES, SCATTER_FORWARD);
529 CHKERR VecGhostUpdateEnd(sol, INSERT_VALUES, SCATTER_FORWARD);
531 const std::array<double, 2> piola_range{{-1, 1}};
532 const std::array<double, 2> bubble_range{{-1, 1}};
533 const std::array<double, 2> spatial_l2_disp_range{{-1, 1}};
534 const std::array<double, 2> rot_axis_range{{-1, 1}};
535 const std::array<double, 2> stretch_tensor_range{{-1, 1}};
536 const std::array<double, 2> hybrid_spatial_disp_range{{-1, 1}};
538 std::vector<OperatorsTester::RandomFieldData> random_fields{
539 {ep.piolaStress, piola_range},
540 {ep.bubbleField, bubble_range},
541 {ep.spatialL2Disp, spatial_l2_disp_range},
542 {ep.rotAxis, rot_axis_range},
543 {ep.stretchTensor, stretch_tensor_range},
544 {ep.hybridSpatialDisp, hybrid_spatial_disp_range}};
551 CHKERR VecCopy(direction_vec, delta_vec);
552 CHKERR VecScale(delta_vec, epsilon);
555 CHKERR VecCopy(sol, a_vec);
556 CHKERR VecAXPY(a_vec, 1, delta_vec);
558 CHKERR VecCopy(sol, b_vec);
559 CHKERR VecAXPY(b_vec, -1, delta_vec);
565 <<
"Objective at a_vec: J_plus = " << std::setprecision(12) << J_plus;
572 <<
"Objective at b_vec: J_minus = " << std::setprecision(12) << J_minus;
573 double dJ_da = (J_plus - J_minus) / (2 * epsilon);
576 CHKERR VecNorm(sol, NORM_2, &nrm_sol);
581 boost::make_shared<VolumeElementForcesAndSourcesCore>(ep.mField);
587 boundary_integration_hook, eval_energy_model);
588 CHKERR VecZeroEntries(dJ_dx_vec);
589 CHKERR VecGhostUpdateBegin(dJ_dx_vec, INSERT_VALUES, SCATTER_FORWARD);
590 CHKERR VecGhostUpdateEnd(dJ_dx_vec, INSERT_VALUES, SCATTER_FORWARD);
594 CHKERR VecAssemblyBegin(dJ_dx_vec);
595 CHKERR VecAssemblyEnd(dJ_dx_vec);
596 CHKERR VecGhostUpdateBegin(dJ_dx_vec, ADD_VALUES, SCATTER_REVERSE);
597 CHKERR VecGhostUpdateEnd(dJ_dx_vec, ADD_VALUES, SCATTER_REVERSE);
598 CHKERR VecGhostUpdateBegin(dJ_dx_vec, INSERT_VALUES, SCATTER_FORWARD);
599 CHKERR VecGhostUpdateEnd(dJ_dx_vec, INSERT_VALUES, SCATTER_FORWARD);
602 CHKERR VecDot(dJ_dx_vec, direction_vec, &exact_dJ);
603 double error = dJ_da - exact_dJ;
606 <<
"dJ/dx = " << dJ_da <<
", exact dJ/dx = " << exact_dJ
607 <<
", error = " << error <<
", fraction " << dJ_da / exact_dJ
608 <<
" x norm: " << nrm_sol;
620 auto &ep = *ctx_impl_ptr->
ep_ptr;
628 CHKERR VecGhostUpdateBegin(row_sol, INSERT_VALUES, SCATTER_FORWARD);
629 CHKERR VecGhostUpdateEnd(row_sol, INSERT_VALUES, SCATTER_FORWARD);
635 CHKERR VecGhostUpdateBegin(col_sol, INSERT_VALUES, SCATTER_FORWARD);
636 CHKERR VecGhostUpdateEnd(col_sol, INSERT_VALUES, SCATTER_FORWARD);
638 MOFEM_LOG(
"EP", Sev::inform) <<
"Starting finite difference dJ_dX "
639 "gradient test with epsilon = "
644 opt->
setRandomFields(ep.dmMaterial, {{ep.materialH1Positions, {-1., 1.}}},
646 CHKERR VecGhostUpdateBegin(direction_vec, INSERT_VALUES, SCATTER_FORWARD);
647 CHKERR VecGhostUpdateEnd(direction_vec, INSERT_VALUES, SCATTER_FORWARD);
649 const std::array<double, 2> piola_range{{-1, 1}};
650 const std::array<double, 2> bubble_range{{-1, 1}};
651 const std::array<double, 2> spatial_l2_disp_range{{-1, 1}};
652 const std::array<double, 2> rot_axis_range{{-1, 1}};
653 const std::array<double, 2> stretch_tensor_range{{-1, 1}};
654 const std::array<double, 2> hybrid_spatial_disp_range{{-1, 1}};
656 std::vector<OperatorsTester::RandomFieldData> adjoint_random_fields{
657 {ep.piolaStress, piola_range},
658 {ep.bubbleField, bubble_range},
659 {ep.spatialL2Disp, spatial_l2_disp_range},
660 {ep.rotAxis, rot_axis_range},
661 {ep.stretchTensor, stretch_tensor_range},
662 {ep.hybridSpatialDisp, hybrid_spatial_disp_range}};
664 auto adjoint_vec = opt->setRandomFields(ep.dmMaterial, adjoint_random_fields,
666 CHKERR VecGhostUpdateBegin(adjoint_vec, INSERT_VALUES, SCATTER_FORWARD);
667 CHKERR VecGhostUpdateEnd(adjoint_vec, INSERT_VALUES, SCATTER_FORWARD);
669 const std::array<double, 2> state_piola_range{{-1, 1}};
670 const std::array<double, 2> state_bubble_range{{-1, 1}};
671 const std::array<double, 2> state_spatial_l2_disp_range{{-1, 1}};
672 const std::array<double, 2> state_rot_axis_range{{-1, 1}};
673 const std::array<double, 2> state_stretch_tensor_range{{-1, 1}};
674 const std::array<double, 2> state_hybrid_spatial_disp_range{{-1, 1}};
676 std::vector<OperatorsTester::RandomFieldData> state_random_fields{
677 {ep.piolaStress, state_piola_range},
678 {ep.bubbleField, state_bubble_range},
679 {ep.spatialL2Disp, state_spatial_l2_disp_range},
680 {ep.rotAxis, state_rot_axis_range},
681 {ep.stretchTensor, state_stretch_tensor_range},
682 {ep.hybridSpatialDisp, state_hybrid_spatial_disp_range}};
684 auto state_vec = opt->setRandomFields(ep.dmElastic, state_random_fields,
686 CHKERR VecGhostUpdateBegin(state_vec, INSERT_VALUES, SCATTER_FORWARD);
687 CHKERR VecGhostUpdateEnd(state_vec, INSERT_VALUES, SCATTER_FORWARD);
691 boost::shared_ptr<double> J_ptr(0);
693 CHKERR VecZeroEntries(dJ_dX_vec);
696 boost::make_shared<VolumeElementForcesAndSourcesCore>(ep.mField);
698 boundary_integration_hook, J_ptr,
699 dJ_dX_vec, eval_energy_model);
703 CHKERR VecAssemblyBegin(dJ_dX_vec);
704 CHKERR VecAssemblyEnd(dJ_dX_vec);
705 CHKERR VecGhostUpdateBegin(dJ_dX_vec, ADD_VALUES, SCATTER_REVERSE);
706 CHKERR VecGhostUpdateEnd(dJ_dX_vec, ADD_VALUES, SCATTER_REVERSE);
707 CHKERR VecGhostUpdateBegin(dJ_dX_vec, INSERT_VALUES, SCATTER_FORWARD);
708 CHKERR VecGhostUpdateEnd(dJ_dX_vec, INSERT_VALUES, SCATTER_FORWARD);
711 CHKERR VecCopy(direction_vec, delta_vec);
712 CHKERR VecScale(delta_vec, epsilon);
715 CHKERR VecCopy(row_sol, a_vec);
716 CHKERR VecAXPY(a_vec, 1, delta_vec);
718 CHKERR VecCopy(row_sol, b_vec);
719 CHKERR VecAXPY(b_vec, -1, delta_vec);
721 auto fe_material_plus =
722 boost::make_shared<VolumeElementForcesAndSourcesCore>(ep.mField);
723 auto J_plus = boost::make_shared<double>(0);
725 interior_integration_hook,
726 boundary_integration_hook, J_plus,
nullptr,
728 auto fe_material_minus =
729 boost::make_shared<VolumeElementForcesAndSourcesCore>(ep.mField);
730 auto J_minus = boost::make_shared<double>(0);
732 ep, fe_material_minus, interior_integration_hook,
733 boundary_integration_hook, J_minus,
nullptr, eval_energy_model);
741 <<
"Objective at a_vec: J_plus = " << std::setprecision(12) << *J_plus;
749 <<
"Objective at b_vec: J_minus = " << std::setprecision(12) << *J_minus;
751 double dJ_da = (*J_plus - *J_minus) / (2 * epsilon);
754 CHKERR VecDot(dJ_dX_vec, direction_vec, &exact_dJ);
755 double fd_error = dJ_da - exact_dJ;
758 <<
"Fd dJ/dX = " << dJ_da <<
", exact dJ/dX = " << exact_dJ
759 <<
", error = " << fd_error;
771 auto &ep = *ctx_impl_ptr->
ep_ptr;
777 CHKERR VecGhostUpdateBegin(row_sol, INSERT_VALUES, SCATTER_FORWARD);
778 CHKERR VecGhostUpdateEnd(row_sol, INSERT_VALUES, SCATTER_FORWARD);
784 CHKERR VecGhostUpdateBegin(col_sol, INSERT_VALUES, SCATTER_FORWARD);
785 CHKERR VecGhostUpdateEnd(col_sol, INSERT_VALUES, SCATTER_FORWARD);
787 MOFEM_LOG(
"EP", Sev::inform) <<
"Starting finite difference dJ_adjoint_dX "
788 "gradient test with epsilon = "
793 opt->
setRandomFields(ep.dmMaterial, {{ep.materialH1Positions, {-1., 1.}}},
795 CHKERR VecGhostUpdateBegin(direction_vec, INSERT_VALUES, SCATTER_FORWARD);
796 CHKERR VecGhostUpdateEnd(direction_vec, INSERT_VALUES, SCATTER_FORWARD);
798 const std::array<double, 2> piola_range{{-1, 1}};
799 const std::array<double, 2> bubble_range{{-1, 1}};
800 const std::array<double, 2> spatial_l2_disp_range{{-1, 1}};
801 const std::array<double, 2> rot_axis_range{{-1, 1}};
802 const std::array<double, 2> stretch_tensor_range{{-1, 1}};
803 const std::array<double, 2> hybrid_spatial_disp_range{{-1, 1}};
805 std::vector<OperatorsTester::RandomFieldData> adjoint_random_fields{
806 {ep.piolaStress, piola_range},
807 {ep.bubbleField, bubble_range},
808 {ep.spatialL2Disp, spatial_l2_disp_range},
809 {ep.rotAxis, rot_axis_range},
810 {ep.stretchTensor, stretch_tensor_range},
811 {ep.hybridSpatialDisp, hybrid_spatial_disp_range}};
813 auto adjoint_vec = opt->setRandomFields(ep.dmMaterial, adjoint_random_fields,
815 CHKERR VecGhostUpdateBegin(adjoint_vec, INSERT_VALUES, SCATTER_FORWARD);
816 CHKERR VecGhostUpdateEnd(adjoint_vec, INSERT_VALUES, SCATTER_FORWARD);
818 const std::array<double, 2> state_piola_range{{-1, 1}};
819 const std::array<double, 2> state_bubble_range{{-1, 1}};
820 const std::array<double, 2> state_spatial_l2_disp_range{{-1, 1}};
821 const std::array<double, 2> state_rot_axis_range{{-1, 1}};
822 const std::array<double, 2> state_stretch_tensor_range{{-1, 1}};
823 const std::array<double, 2> state_hybrid_spatial_disp_range{{-1, 1}};
825 std::vector<OperatorsTester::RandomFieldData> state_random_fields{
826 {ep.piolaStress, state_piola_range},
827 {ep.bubbleField, state_bubble_range},
828 {ep.spatialL2Disp, state_spatial_l2_disp_range},
829 {ep.rotAxis, state_rot_axis_range},
830 {ep.stretchTensor, state_stretch_tensor_range},
831 {ep.hybridSpatialDisp, state_hybrid_spatial_disp_range}};
833 auto state_vec = opt->setRandomFields(ep.dmElastic, state_random_fields,
835 CHKERR VecGhostUpdateBegin(state_vec, INSERT_VALUES, SCATTER_FORWARD);
836 CHKERR VecGhostUpdateEnd(state_vec, INSERT_VALUES, SCATTER_FORWARD);
840 boost::shared_ptr<double> J_ptr;
842 CHKERR VecZeroEntries(dJ_dX_vec);
844 CHKERR VecZeroEntries(x_t_vec);
846 auto get_f_rhs_vec = [&]() {
848 auto fe_interior_rhs = ep.elasticFeRhs;
849 auto fe_boundary_rhs = ep.elasticBcRhs;
850 fe_interior_rhs->f = f_rhs_vec;
851 fe_interior_rhs->x_t = x_t_vec;
852 fe_interior_rhs->data_ctx |=
854 CHKERR TSGetTime(ctx_impl_ptr->timeSolver, &fe_interior_rhs->ts_t);
855 CHKERR TSGetTimeStep(ctx_impl_ptr->timeSolver, &fe_interior_rhs->ts_dt);
856 CHKERR TSGetStepNumber(ctx_impl_ptr->timeSolver, &fe_interior_rhs->ts_step);
857 fe_boundary_rhs->f = f_rhs_vec;
858 fe_boundary_rhs->x_t = x_t_vec;
859 fe_boundary_rhs->data_ctx |=
861 CHKERR TSGetTime(ctx_impl_ptr->timeSolver, &fe_boundary_rhs->ts_t);
862 CHKERR TSGetTimeStep(ctx_impl_ptr->timeSolver, &fe_boundary_rhs->ts_dt);
863 CHKERR TSGetStepNumber(ctx_impl_ptr->timeSolver, &fe_boundary_rhs->ts_step);
864 CHKERR VecZeroEntries(f_rhs_vec);
869 CHKERR VecAssemblyBegin(f_rhs_vec);
870 CHKERR VecAssemblyEnd(f_rhs_vec);
871 CHKERR VecGhostUpdateBegin(f_rhs_vec, ADD_VALUES, SCATTER_REVERSE);
872 CHKERR VecGhostUpdateEnd(f_rhs_vec, ADD_VALUES, SCATTER_REVERSE);
876 auto alpha = ep.alphaW;
877 auto rho = ep.alphaRho;
878 auto alpha_viscous_omega = ep.alphaViscousOmega;
880 auto interior_integration_hook = ctx_impl_ptr->integrationAtInterior;
881 auto boundary_integration_hook = ctx_impl_ptr->integrationAtFace;
883 boost::make_shared<VolumeElementForcesAndSourcesCore>(ep.mField);
884 auto fe_adjoint_boundary =
885 boost::make_shared<FaceElementForcesAndSourcesCore>(ep.mField);
887 ep, fe_adjoint, interior_integration_hook, boundary_integration_hook,
888 adjoint_vec, dJ_dX_vec, alpha,
rho, alpha_viscous_omega,
891 ep, fe_adjoint_boundary, interior_integration_hook,
892 boundary_integration_hook, adjoint_vec, dJ_dX_vec, J_ptr);
897 fe_adjoint_boundary);
898 CHKERR VecAssemblyBegin(dJ_dX_vec);
899 CHKERR VecAssemblyEnd(dJ_dX_vec);
900 CHKERR VecGhostUpdateBegin(dJ_dX_vec, ADD_VALUES, SCATTER_REVERSE);
901 CHKERR VecGhostUpdateEnd(dJ_dX_vec, ADD_VALUES, SCATTER_REVERSE);
902 CHKERR VecGhostUpdateBegin(dJ_dX_vec, INSERT_VALUES, SCATTER_FORWARD);
903 CHKERR VecGhostUpdateEnd(dJ_dX_vec, INSERT_VALUES, SCATTER_FORWARD);
906 CHKERR VecCopy(direction_vec, delta_vec);
907 CHKERR VecScale(delta_vec, epsilon);
910 CHKERR VecCopy(row_sol, a_vec);
911 CHKERR VecAXPY(a_vec, 1, delta_vec);
913 CHKERR VecCopy(row_sol, b_vec);
914 CHKERR VecAXPY(b_vec, -1, delta_vec);
916 auto fe_adjoint_fd_plus =
917 boost::make_shared<VolumeElementForcesAndSourcesCore>(ep.mField);
918 auto fe_adjoint_fd_minus =
919 boost::make_shared<VolumeElementForcesAndSourcesCore>(ep.mField);
920 auto fe_adjoint_fd_plus_boundary =
921 boost::make_shared<FaceElementForcesAndSourcesCore>(ep.mField);
922 auto fe_adjoint_fd_minus_boundary =
923 boost::make_shared<FaceElementForcesAndSourcesCore>(ep.mField);
925 auto J_plus = boost::make_shared<double>(0);
927 ep, fe_adjoint_fd_plus, interior_integration_hook,
928 boundary_integration_hook, adjoint_vec,
931 ep, fe_adjoint_fd_plus_boundary, interior_integration_hook,
934 auto J_minus = boost::make_shared<double>(0);
936 ep, fe_adjoint_fd_minus, interior_integration_hook,
937 boundary_integration_hook, adjoint_vec,
940 ep, fe_adjoint_fd_minus_boundary, interior_integration_hook,
948 fe_adjoint_fd_plus_boundary);
949 auto f_rhs_plus_vec = get_f_rhs_vec();
950 double nrm_f_rhs_plus;
951 CHKERR VecNorm(f_rhs_plus_vec, NORM_2, &nrm_f_rhs_plus);
954 <<
"Objective at a_vec: J_plus = " << std::setprecision(12) << *J_plus
955 <<
", Norm of f_rhs_plus_vec = " << nrm_f_rhs_plus;
959 fe_adjoint_fd_minus);
961 fe_adjoint_fd_minus_boundary);
962 auto f_rhs_minus_vec = get_f_rhs_vec();
963 double nrm_f_rhs_minus;
964 CHKERR VecNorm(f_rhs_minus_vec, NORM_2, &nrm_f_rhs_minus);
967 <<
"Objective at b_vec: J_minus = " << std::setprecision(12) << *J_minus
968 <<
", Norm of f_rhs_minus_vec = " << nrm_f_rhs_minus;
970 double dJ_da = (*J_plus - *J_minus) / (2 * epsilon);
971 CHKERR VecAXPY(f_rhs_plus_vec, -1, f_rhs_minus_vec);
972 CHKERR VecScale(f_rhs_plus_vec, 1. / (2 * epsilon));
974 CHKERR VecDot(f_rhs_plus_vec, adjoint_vec, &lambda_dJ_dX);
977 CHKERR VecDot(dJ_dX_vec, direction_vec, &exact_dJ);
978 double fd_error = dJ_da - exact_dJ;
979 double fd_dJ_dX_error = lambda_dJ_dX - exact_dJ;
982 <<
"Fd dJ_adjoint/dX = " << dJ_da <<
", exact dJ/dX = " << exact_dJ
983 <<
", error = " << fd_error;
985 <<
"Fd lambda * dJ/dX = " << lambda_dJ_dX
986 <<
", exact dJ/dX = " << exact_dJ <<
", error = " << fd_dJ_dX_error;