203 auto &ep = *ctx_impl_ptr->
ep_ptr;
204 auto &m_field = ep.
mField;
209 boost::make_shared<VolumeElementForcesAndSourcesCore>(m_field);
210 auto fe_interior_adjoint =
211 boost::make_shared<VolumeElementForcesAndSourcesCore>(m_field);
212 auto fe_natural_adjoint =
213 boost::make_shared<FaceElementForcesAndSourcesCore>(m_field);
215 boost::shared_ptr<double> J_ptr(
218 CHKERR VecZeroEntries(dJ_dX_vec);
219 CHKERR VecGhostUpdateBegin(dJ_dX_vec, INSERT_VALUES, SCATTER_FORWARD);
220 CHKERR VecGhostUpdateEnd(dJ_dX_vec, INSERT_VALUES, SCATTER_FORWARD);
223 boundary_integration_hook, J_ptr,
224 dJ_dX_vec, eval_energy_model);
227 auto alpha = ep.alphaW;
228 auto rho = ep.alphaRho;
229 auto alpha_omega = ep.alphaOmega;
231 ep, fe_interior_adjoint, interior_integration_hook,
233 alpha,
rho, alpha_omega,
nullptr);
235 ep, fe_natural_adjoint, interior_integration_hook,
242 fe_interior_adjoint);
246 CHKERR VecAssemblyBegin(dJ_dX_vec);
247 CHKERR VecAssemblyEnd(dJ_dX_vec);
248 CHKERR VecGhostUpdateBegin(dJ_dX_vec, ADD_VALUES, SCATTER_REVERSE);
249 CHKERR VecGhostUpdateEnd(dJ_dX_vec, ADD_VALUES, SCATTER_REVERSE);
250 CHKERR VecGhostUpdateBegin(dJ_dX_vec, INSERT_VALUES, SCATTER_FORWARD);
251 CHKERR VecGhostUpdateEnd(dJ_dX_vec, INSERT_VALUES, SCATTER_FORWARD);
316 Vec sol,
double *f, Vec
g,
322 <<
"Starting finite difference dJ_dX gradient test with epsilon = "
325 auto &ep = *ctx_impl_ptr->
ep_ptr;
332 Range body_skin_verts;
333 CHKERR ep.mField.get_moab().get_connectivity(body_skin, body_skin_verts,
336 auto direction_vec = opt->setRandomFields(
337 ep.dmMaterial, {{ep.materialH1Positions, {-1, 1.}}},
341 CHKERR VecCopy(direction_vec, delta_vec);
342 CHKERR VecScale(delta_vec, epsilon);
345 CHKERR VecCopy(sol, a_vec);
346 CHKERR VecAXPY(a_vec, 1., delta_vec);
348 CHKERR VecCopy(sol, b_vec);
349 CHKERR VecAXPY(b_vec, -1., delta_vec);
356 <<
"Objective at a_vec: J_plus = " << std::setprecision(12) << J_plus;
364 <<
"Objective at b_vec: J_minus = " << std::setprecision(12) << J_minus;
365 double dJ_da = (J_plus - J_minus) / (2 * epsilon);
368 CHKERR VecDot(
g, direction_vec, &exact_dJ);
369 double error = dJ_da - exact_dJ;
372 <<
"J = " << *f <<
", dJ/dX = " << dJ_da <<
", exact dJ/dX = " << exact_dJ
373 <<
", error = " << error <<
", fraction " << dJ_da / exact_dJ;
380 CHKERR VecZeroEntries(g_duplicate_vec);
383 CHKERR ep.mField.getInterface<
ISManager>()->isCreateProblemFieldAndRank(
384 adj_problem_ptr->getName(),
RowColData::ROW, ep.materialH1Positions, 0, 3,
385 is, &body_skin_verts);
387 CHKERR ISAllGather(is, &is_raw);
390 CHKERR ISGetSize(is, &nb_dofs);
391 const PetscInt *is_ptr;
392 CHKERR ISGetIndices(is, &is_ptr);
394 constexpr double procent = 0;
395 const int nb_dofs_comp = ceil(procent * nb_dofs / 100.);
397 auto get_vec_value = [&](Vec vec, PetscInt idx) {
399 CHKERR VecGetArray(vec, &array);
400 double &value = array[idx];
401 CHKERR VecRestoreArray(vec, &array);
405 auto set_vec_value = [&](Vec vec, PetscInt idx,
double value) {
408 CHKERR VecGetArray(vec, &array);
410 CHKERR VecRestoreArray(vec, &array);
414 for (
auto i = 0,
j = 0;
i != nb_dofs; ++
i) {
416 <<
"Testing DOF " <<
i <<
" out of " << nb_dofs;
417 auto dof_it = adj_dofs.find(is_ptr[
i]);
418 if (dof_it != adj_dofs.end()) {
419 auto idx = (*dof_it)->getPetscLocalDofIdx();
420 auto exact_dJ = get_vec_value(
g, idx);
421 constexpr double epsilon = 1e-8;
422 if (std::abs(exact_dJ) < epsilon) {
424 <<
"Skipping DOF index " << idx
425 <<
" due to small gradient value: " << exact_dJ;
428 if (
j >= nb_dofs_comp) {
430 <<
"Stopping finite difference test after " << nb_dofs_comp
431 <<
" DOFs, out of total " << nb_dofs;
436 CHKERR VecCopy(sol, direction_vec);
437 CHKERR set_vec_value(direction_vec, idx,
438 get_vec_value(direction_vec, idx) + epsilon);
444 CHKERR VecCopy(sol, direction_vec);
445 CHKERR set_vec_value(direction_vec, idx,
446 get_vec_value(direction_vec, idx) - epsilon);
452 double dJ_da = (J_plus - J_minus) / (2 * epsilon);
453 CHKERR set_vec_value(g_duplicate_vec, idx, dJ_da);
455 double error = dJ_da - exact_dJ;
457 <<
"DOF index: " << idx <<
", J = " << *
f <<
", dJ/dX = " << dJ_da
458 <<
", exact dJ/dX = " << exact_dJ <<
", error = " << error
459 <<
", fraction " << dJ_da / exact_dJ;
464 CHKERR ISRestoreIndices(is, &is_ptr);
467 double *g_array, *g_duplicate_array;
468 CHKERR VecGetArray(
g, &g_array);
469 CHKERR VecGetArray(g_duplicate_vec, &g_duplicate_array);
470 auto &moab = ep.mField.get_moab();
472 double def_val[] = {0, 0, 0};
473 CHKERR moab.tag_get_handle(
"G", 3, MB_TYPE_DOUBLE, th_g,
474 MB_TAG_CREAT | MB_TAG_SPARSE, &def_val);
475 CHKERR moab.tag_get_handle(
"G_fd", 3, MB_TYPE_DOUBLE, th_fd_g,
476 MB_TAG_CREAT | MB_TAG_SPARSE, &def_val);
477 for (
auto &dof : adj_dofs) {
478 if (!dof->getHasLocalIndex())
480 auto idx = dof->getPetscLocalDofIdx();
481 auto ent = dof->getEnt();
482 auto coeff = dof->getDofCoeffIdx();
484 CHKERR moab.tag_set_data(th_g, &ent, 1, &g_array[idx]);
485 CHKERR moab.tag_set_data(th_fd_g, &ent, 1, &g_duplicate_array[idx]);
488 CHKERR VecRestoreArray(
g, &g_array);
489 CHKERR VecRestoreArray(g_duplicate_vec, &g_duplicate_array);
492 std::vector<Tag> tags_list{th_g, th_fd_g};
493 CHKERR moab.write_file(
"gradient_comparison.h5m",
"MOAB",
494 "PARALLEL=WRITE_PART", &root_mesh, 1,
495 &*tags_list.begin(), tags_list.size());
497 CHKERR moab.tag_delete(th_g);
498 CHKERR moab.tag_delete(th_fd_g);
518 <<
"Starting finite difference dJ_dx gradient test with epsilon = "
521 auto &ep = *ctx_impl_ptr->
ep_ptr;
526 CHKERR VecGhostUpdateBegin(sol, INSERT_VALUES, SCATTER_FORWARD);
527 CHKERR VecGhostUpdateEnd(sol, INSERT_VALUES, SCATTER_FORWARD);
529 const std::array<double, 2> piola_range{{-1, 1}};
530 const std::array<double, 2> bubble_range{{-1, 1}};
531 const std::array<double, 2> spatial_l2_disp_range{{-1, 1}};
532 const std::array<double, 2> rot_axis_range{{-1, 1}};
533 const std::array<double, 2> stretch_tensor_range{{-1, 1}};
534 const std::array<double, 2> hybrid_spatial_disp_range{{-1, 1}};
536 std::vector<OperatorsTester::RandomFieldData> random_fields{
537 {ep.piolaStress, piola_range},
538 {ep.bubbleField, bubble_range},
539 {ep.spatialL2Disp, spatial_l2_disp_range},
540 {ep.rotAxis, rot_axis_range},
541 {ep.stretchTensor, stretch_tensor_range},
542 {ep.hybridSpatialDisp, hybrid_spatial_disp_range}};
549 CHKERR VecCopy(direction_vec, delta_vec);
550 CHKERR VecScale(delta_vec, epsilon);
553 CHKERR VecCopy(sol, a_vec);
554 CHKERR VecAXPY(a_vec, 1, delta_vec);
556 CHKERR VecCopy(sol, b_vec);
557 CHKERR VecAXPY(b_vec, -1, delta_vec);
563 <<
"Objective at a_vec: J_plus = " << std::setprecision(12) << J_plus;
570 <<
"Objective at b_vec: J_minus = " << std::setprecision(12) << J_minus;
571 double dJ_da = (J_plus - J_minus) / (2 * epsilon);
574 CHKERR VecNorm(sol, NORM_2, &nrm_sol);
579 boost::make_shared<VolumeElementForcesAndSourcesCore>(ep.mField);
585 boundary_integration_hook, eval_energy_model);
586 CHKERR VecZeroEntries(dJ_dx_vec);
587 CHKERR VecGhostUpdateBegin(dJ_dx_vec, INSERT_VALUES, SCATTER_FORWARD);
588 CHKERR VecGhostUpdateEnd(dJ_dx_vec, INSERT_VALUES, SCATTER_FORWARD);
592 CHKERR VecAssemblyBegin(dJ_dx_vec);
593 CHKERR VecAssemblyEnd(dJ_dx_vec);
594 CHKERR VecGhostUpdateBegin(dJ_dx_vec, ADD_VALUES, SCATTER_REVERSE);
595 CHKERR VecGhostUpdateEnd(dJ_dx_vec, ADD_VALUES, SCATTER_REVERSE);
596 CHKERR VecGhostUpdateBegin(dJ_dx_vec, INSERT_VALUES, SCATTER_FORWARD);
597 CHKERR VecGhostUpdateEnd(dJ_dx_vec, INSERT_VALUES, SCATTER_FORWARD);
600 CHKERR VecDot(dJ_dx_vec, direction_vec, &exact_dJ);
601 double error = dJ_da - exact_dJ;
604 <<
"dJ/dx = " << dJ_da <<
", exact dJ/dx = " << exact_dJ
605 <<
", error = " << error <<
", fraction " << dJ_da / exact_dJ
606 <<
" x norm: " << nrm_sol;
618 auto &ep = *ctx_impl_ptr->
ep_ptr;
626 CHKERR VecGhostUpdateBegin(row_sol, INSERT_VALUES, SCATTER_FORWARD);
627 CHKERR VecGhostUpdateEnd(row_sol, INSERT_VALUES, SCATTER_FORWARD);
633 CHKERR VecGhostUpdateBegin(col_sol, INSERT_VALUES, SCATTER_FORWARD);
634 CHKERR VecGhostUpdateEnd(col_sol, INSERT_VALUES, SCATTER_FORWARD);
636 MOFEM_LOG(
"EP", Sev::inform) <<
"Starting finite difference dJ_dX "
637 "gradient test with epsilon = "
642 opt->
setRandomFields(ep.dmMaterial, {{ep.materialH1Positions, {-1., 1.}}},
644 CHKERR VecGhostUpdateBegin(direction_vec, INSERT_VALUES, SCATTER_FORWARD);
645 CHKERR VecGhostUpdateEnd(direction_vec, INSERT_VALUES, SCATTER_FORWARD);
647 const std::array<double, 2> piola_range{{-1, 1}};
648 const std::array<double, 2> bubble_range{{-1, 1}};
649 const std::array<double, 2> spatial_l2_disp_range{{-1, 1}};
650 const std::array<double, 2> rot_axis_range{{-1, 1}};
651 const std::array<double, 2> stretch_tensor_range{{-1, 1}};
652 const std::array<double, 2> hybrid_spatial_disp_range{{-1, 1}};
654 std::vector<OperatorsTester::RandomFieldData> adjoint_random_fields{
655 {ep.piolaStress, piola_range},
656 {ep.bubbleField, bubble_range},
657 {ep.spatialL2Disp, spatial_l2_disp_range},
658 {ep.rotAxis, rot_axis_range},
659 {ep.stretchTensor, stretch_tensor_range},
660 {ep.hybridSpatialDisp, hybrid_spatial_disp_range}};
662 auto adjoint_vec = opt->setRandomFields(ep.dmMaterial, adjoint_random_fields,
664 CHKERR VecGhostUpdateBegin(adjoint_vec, INSERT_VALUES, SCATTER_FORWARD);
665 CHKERR VecGhostUpdateEnd(adjoint_vec, INSERT_VALUES, SCATTER_FORWARD);
667 const std::array<double, 2> state_piola_range{{-1, 1}};
668 const std::array<double, 2> state_bubble_range{{-1, 1}};
669 const std::array<double, 2> state_spatial_l2_disp_range{{-1, 1}};
670 const std::array<double, 2> state_rot_axis_range{{-1, 1}};
671 const std::array<double, 2> state_stretch_tensor_range{{-1, 1}};
672 const std::array<double, 2> state_hybrid_spatial_disp_range{{-1, 1}};
674 std::vector<OperatorsTester::RandomFieldData> state_random_fields{
675 {ep.piolaStress, state_piola_range},
676 {ep.bubbleField, state_bubble_range},
677 {ep.spatialL2Disp, state_spatial_l2_disp_range},
678 {ep.rotAxis, state_rot_axis_range},
679 {ep.stretchTensor, state_stretch_tensor_range},
680 {ep.hybridSpatialDisp, state_hybrid_spatial_disp_range}};
682 auto state_vec = opt->setRandomFields(ep.dmElastic, state_random_fields,
684 CHKERR VecGhostUpdateBegin(state_vec, INSERT_VALUES, SCATTER_FORWARD);
685 CHKERR VecGhostUpdateEnd(state_vec, INSERT_VALUES, SCATTER_FORWARD);
689 boost::shared_ptr<double> J_ptr(0);
691 CHKERR VecZeroEntries(dJ_dX_vec);
694 boost::make_shared<VolumeElementForcesAndSourcesCore>(ep.mField);
696 boundary_integration_hook, J_ptr,
697 dJ_dX_vec, eval_energy_model);
701 CHKERR VecAssemblyBegin(dJ_dX_vec);
702 CHKERR VecAssemblyEnd(dJ_dX_vec);
703 CHKERR VecGhostUpdateBegin(dJ_dX_vec, ADD_VALUES, SCATTER_REVERSE);
704 CHKERR VecGhostUpdateEnd(dJ_dX_vec, ADD_VALUES, SCATTER_REVERSE);
705 CHKERR VecGhostUpdateBegin(dJ_dX_vec, INSERT_VALUES, SCATTER_FORWARD);
706 CHKERR VecGhostUpdateEnd(dJ_dX_vec, INSERT_VALUES, SCATTER_FORWARD);
709 CHKERR VecCopy(direction_vec, delta_vec);
710 CHKERR VecScale(delta_vec, epsilon);
713 CHKERR VecCopy(row_sol, a_vec);
714 CHKERR VecAXPY(a_vec, 1, delta_vec);
716 CHKERR VecCopy(row_sol, b_vec);
717 CHKERR VecAXPY(b_vec, -1, delta_vec);
719 auto fe_material_plus =
720 boost::make_shared<VolumeElementForcesAndSourcesCore>(ep.mField);
721 auto J_plus = boost::make_shared<double>(0);
723 interior_integration_hook,
724 boundary_integration_hook, J_plus,
nullptr,
726 auto fe_material_minus =
727 boost::make_shared<VolumeElementForcesAndSourcesCore>(ep.mField);
728 auto J_minus = boost::make_shared<double>(0);
730 ep, fe_material_minus, interior_integration_hook,
731 boundary_integration_hook, J_minus,
nullptr, eval_energy_model);
739 <<
"Objective at a_vec: J_plus = " << std::setprecision(12) << *J_plus;
747 <<
"Objective at b_vec: J_minus = " << std::setprecision(12) << *J_minus;
749 double dJ_da = (*J_plus - *J_minus) / (2 * epsilon);
752 CHKERR VecDot(dJ_dX_vec, direction_vec, &exact_dJ);
753 double fd_error = dJ_da - exact_dJ;
756 <<
"Fd dJ/dX = " << dJ_da <<
", exact dJ/dX = " << exact_dJ
757 <<
", error = " << fd_error;
769 auto &ep = *ctx_impl_ptr->
ep_ptr;
775 CHKERR VecGhostUpdateBegin(row_sol, INSERT_VALUES, SCATTER_FORWARD);
776 CHKERR VecGhostUpdateEnd(row_sol, INSERT_VALUES, SCATTER_FORWARD);
782 CHKERR VecGhostUpdateBegin(col_sol, INSERT_VALUES, SCATTER_FORWARD);
783 CHKERR VecGhostUpdateEnd(col_sol, INSERT_VALUES, SCATTER_FORWARD);
785 MOFEM_LOG(
"EP", Sev::inform) <<
"Starting finite difference dJ_adjoint_dX "
786 "gradient test with epsilon = "
791 opt->
setRandomFields(ep.dmMaterial, {{ep.materialH1Positions, {-1., 1.}}},
793 CHKERR VecGhostUpdateBegin(direction_vec, INSERT_VALUES, SCATTER_FORWARD);
794 CHKERR VecGhostUpdateEnd(direction_vec, INSERT_VALUES, SCATTER_FORWARD);
796 const std::array<double, 2> piola_range{{-1, 1}};
797 const std::array<double, 2> bubble_range{{-1, 1}};
798 const std::array<double, 2> spatial_l2_disp_range{{-1, 1}};
799 const std::array<double, 2> rot_axis_range{{-1, 1}};
800 const std::array<double, 2> stretch_tensor_range{{-1, 1}};
801 const std::array<double, 2> hybrid_spatial_disp_range{{-1, 1}};
803 std::vector<OperatorsTester::RandomFieldData> adjoint_random_fields{
804 {ep.piolaStress, piola_range},
805 {ep.bubbleField, bubble_range},
806 {ep.spatialL2Disp, spatial_l2_disp_range},
807 {ep.rotAxis, rot_axis_range},
808 {ep.stretchTensor, stretch_tensor_range},
809 {ep.hybridSpatialDisp, hybrid_spatial_disp_range}};
811 auto adjoint_vec = opt->setRandomFields(ep.dmMaterial, adjoint_random_fields,
813 CHKERR VecGhostUpdateBegin(adjoint_vec, INSERT_VALUES, SCATTER_FORWARD);
814 CHKERR VecGhostUpdateEnd(adjoint_vec, INSERT_VALUES, SCATTER_FORWARD);
816 const std::array<double, 2> state_piola_range{{-1, 1}};
817 const std::array<double, 2> state_bubble_range{{-1, 1}};
818 const std::array<double, 2> state_spatial_l2_disp_range{{-1, 1}};
819 const std::array<double, 2> state_rot_axis_range{{-1, 1}};
820 const std::array<double, 2> state_stretch_tensor_range{{-1, 1}};
821 const std::array<double, 2> state_hybrid_spatial_disp_range{{-1, 1}};
823 std::vector<OperatorsTester::RandomFieldData> state_random_fields{
824 {ep.piolaStress, state_piola_range},
825 {ep.bubbleField, state_bubble_range},
826 {ep.spatialL2Disp, state_spatial_l2_disp_range},
827 {ep.rotAxis, state_rot_axis_range},
828 {ep.stretchTensor, state_stretch_tensor_range},
829 {ep.hybridSpatialDisp, state_hybrid_spatial_disp_range}};
831 auto state_vec = opt->setRandomFields(ep.dmElastic, state_random_fields,
833 CHKERR VecGhostUpdateBegin(state_vec, INSERT_VALUES, SCATTER_FORWARD);
834 CHKERR VecGhostUpdateEnd(state_vec, INSERT_VALUES, SCATTER_FORWARD);
838 boost::shared_ptr<double> J_ptr;
840 CHKERR VecZeroEntries(dJ_dX_vec);
842 CHKERR VecZeroEntries(x_t_vec);
844 auto get_f_rhs_vec = [&]() {
846 auto fe_interior_rhs = ep.elasticFeRhs;
847 auto fe_boundary_rhs = ep.elasticBcRhs;
848 fe_interior_rhs->f = f_rhs_vec;
849 fe_interior_rhs->x_t = x_t_vec;
850 fe_interior_rhs->data_ctx |=
852 CHKERR TSGetTime(ctx_impl_ptr->timeSolver, &fe_interior_rhs->ts_t);
853 CHKERR TSGetTimeStep(ctx_impl_ptr->timeSolver, &fe_interior_rhs->ts_dt);
854 CHKERR TSGetStepNumber(ctx_impl_ptr->timeSolver, &fe_interior_rhs->ts_step);
855 fe_boundary_rhs->f = f_rhs_vec;
856 fe_boundary_rhs->x_t = x_t_vec;
857 fe_boundary_rhs->data_ctx |=
859 CHKERR TSGetTime(ctx_impl_ptr->timeSolver, &fe_boundary_rhs->ts_t);
860 CHKERR TSGetTimeStep(ctx_impl_ptr->timeSolver, &fe_boundary_rhs->ts_dt);
861 CHKERR TSGetStepNumber(ctx_impl_ptr->timeSolver, &fe_boundary_rhs->ts_step);
862 CHKERR VecZeroEntries(f_rhs_vec);
867 CHKERR VecAssemblyBegin(f_rhs_vec);
868 CHKERR VecAssemblyEnd(f_rhs_vec);
869 CHKERR VecGhostUpdateBegin(f_rhs_vec, ADD_VALUES, SCATTER_REVERSE);
870 CHKERR VecGhostUpdateEnd(f_rhs_vec, ADD_VALUES, SCATTER_REVERSE);
874 auto alpha = ep.alphaW;
875 auto rho = ep.alphaRho;
876 auto alpha_omega = ep.alphaOmega;
878 auto interior_integration_hook = ctx_impl_ptr->integrationAtInterior;
879 auto boundary_integration_hook = ctx_impl_ptr->integrationAtFace;
881 boost::make_shared<VolumeElementForcesAndSourcesCore>(ep.mField);
882 auto fe_adjoint_boundary =
883 boost::make_shared<FaceElementForcesAndSourcesCore>(ep.mField);
885 ep, fe_adjoint, interior_integration_hook, boundary_integration_hook,
886 adjoint_vec, dJ_dX_vec, alpha,
rho, alpha_omega,
889 ep, fe_adjoint_boundary, interior_integration_hook,
890 boundary_integration_hook, adjoint_vec, dJ_dX_vec, J_ptr);
895 fe_adjoint_boundary);
896 CHKERR VecAssemblyBegin(dJ_dX_vec);
897 CHKERR VecAssemblyEnd(dJ_dX_vec);
898 CHKERR VecGhostUpdateBegin(dJ_dX_vec, ADD_VALUES, SCATTER_REVERSE);
899 CHKERR VecGhostUpdateEnd(dJ_dX_vec, ADD_VALUES, SCATTER_REVERSE);
900 CHKERR VecGhostUpdateBegin(dJ_dX_vec, INSERT_VALUES, SCATTER_FORWARD);
901 CHKERR VecGhostUpdateEnd(dJ_dX_vec, INSERT_VALUES, SCATTER_FORWARD);
904 CHKERR VecCopy(direction_vec, delta_vec);
905 CHKERR VecScale(delta_vec, epsilon);
908 CHKERR VecCopy(row_sol, a_vec);
909 CHKERR VecAXPY(a_vec, 1, delta_vec);
911 CHKERR VecCopy(row_sol, b_vec);
912 CHKERR VecAXPY(b_vec, -1, delta_vec);
914 auto fe_adjoint_fd_plus =
915 boost::make_shared<VolumeElementForcesAndSourcesCore>(ep.mField);
916 auto fe_adjoint_fd_minus =
917 boost::make_shared<VolumeElementForcesAndSourcesCore>(ep.mField);
918 auto fe_adjoint_fd_plus_boundary =
919 boost::make_shared<FaceElementForcesAndSourcesCore>(ep.mField);
920 auto fe_adjoint_fd_minus_boundary =
921 boost::make_shared<FaceElementForcesAndSourcesCore>(ep.mField);
923 auto J_plus = boost::make_shared<double>(0);
925 ep, fe_adjoint_fd_plus, interior_integration_hook,
926 boundary_integration_hook, adjoint_vec,
929 ep, fe_adjoint_fd_plus_boundary, interior_integration_hook,
932 auto J_minus = boost::make_shared<double>(0);
934 ep, fe_adjoint_fd_minus, interior_integration_hook,
935 boundary_integration_hook, adjoint_vec,
938 ep, fe_adjoint_fd_minus_boundary, interior_integration_hook,
946 fe_adjoint_fd_plus_boundary);
947 auto f_rhs_plus_vec = get_f_rhs_vec();
948 double nrm_f_rhs_plus;
949 CHKERR VecNorm(f_rhs_plus_vec, NORM_2, &nrm_f_rhs_plus);
952 <<
"Objective at a_vec: J_plus = " << std::setprecision(12) << *J_plus
953 <<
", Norm of f_rhs_plus_vec = " << nrm_f_rhs_plus;
957 fe_adjoint_fd_minus);
959 fe_adjoint_fd_minus_boundary);
960 auto f_rhs_minus_vec = get_f_rhs_vec();
961 double nrm_f_rhs_minus;
962 CHKERR VecNorm(f_rhs_minus_vec, NORM_2, &nrm_f_rhs_minus);
965 <<
"Objective at b_vec: J_minus = " << std::setprecision(12) << *J_minus
966 <<
", Norm of f_rhs_minus_vec = " << nrm_f_rhs_minus;
968 double dJ_da = (*J_plus - *J_minus) / (2 * epsilon);
969 CHKERR VecAXPY(f_rhs_plus_vec, -1, f_rhs_minus_vec);
970 CHKERR VecScale(f_rhs_plus_vec, 1. / (2 * epsilon));
972 CHKERR VecDot(f_rhs_plus_vec, adjoint_vec, &lambda_dJ_dX);
975 CHKERR VecDot(dJ_dX_vec, direction_vec, &exact_dJ);
976 double fd_error = dJ_da - exact_dJ;
977 double fd_dJ_dX_error = lambda_dJ_dX - exact_dJ;
980 <<
"Fd dJ_adjoint/dX = " << dJ_da <<
", exact dJ/dX = " << exact_dJ
981 <<
", error = " << fd_error;
983 <<
"Fd lambda * dJ/dX = " << lambda_dJ_dX
984 <<
", exact dJ/dX = " << exact_dJ <<
", error = " << fd_dJ_dX_error;