5#include <boost/python.hpp>
6#include <boost/python/def.hpp>
7#include <boost/python/numpy.hpp>
8namespace bp = boost::python;
9namespace np = boost::python::numpy;
26 IntegrationType::GAUSS;
50 BoundaryEle::UserDataOperator;
91template <
int SPACE_DIM, IntegrationType I,
typename OpBase>
98#include <ElasticSpring.hpp>
99#include <FluidLevel.hpp>
100#include <CalculateTraction.hpp>
101#include <NaturalDomainBC.hpp>
102#include <NaturalBoundaryBC.hpp>
103#include <HookeOps.hpp>
110 const std::string block_name,
int dim);
143 Vec objective_function_gradient,
144 Vec adjoint_vector, Vec dJ_du);
155 boost::shared_ptr<ObjectiveFunctionData>
164 char objective_function_file_name[255] =
"objective_function.py";
166 PETSC_NULLPTR, PETSC_NULLPTR,
"-objective_function",
167 objective_function_file_name, 255, PETSC_NULLPTR);
170 auto file_exists = [](std::string myfile) {
171 std::ifstream file(myfile.c_str());
177 if (!file_exists(objective_function_file_name)) {
178 MOFEM_LOG(
"WORLD", Sev::error) <<
"Objective function file NOT found: "
179 << objective_function_file_name;
186 char sensitivity_method_name[32] =
"adjoint";
188 "-sensitivity_method", sensitivity_method_name,
189 sizeof(sensitivity_method_name), PETSC_NULLPTR);
190 std::string sensitivity_method = sensitivity_method_name;
191 std::transform(sensitivity_method.begin(), sensitivity_method.end(),
192 sensitivity_method.begin(),
193 [](
unsigned char c) { return std::tolower(c); });
194 if (sensitivity_method ==
"direct") {
196 }
else if (sensitivity_method ==
"adjoint") {
200 "Unknown -sensitivity_method. Use 'direct' or 'adjoint'.");
203 <<
"Sensitivity method: " << sensitivity_method;
227 MOFEM_LOG(
"WORLD", Sev::inform) <<
"Objective function value: " <<
f;
234 INSERT_VALUES, SCATTER_FORWARD);
242 MOFEM_LOG(
"WORLD", Sev::inform) <<
"Topology optimization completed";
295 enum bases { AINSWORTH, DEMKOWICZ, LASBASETOPT };
296 const char *list_bases[LASBASETOPT] = {
"ainsworth",
"demkowicz"};
297 PetscInt choice_base_value = AINSWORTH;
299 LASBASETOPT, &choice_base_value, PETSC_NULLPTR);
301 switch (choice_base_value) {
305 <<
"Set AINSWORTH_LEGENDRE_BASE for displacements";
310 <<
"Set DEMKOWICZ_JACOBI_BASE for displacements";
344 auto project_ho_geometry = [&]() {
348 CHKERR project_ho_geometry();
364 auto create_adjoint_dm = [&]() {
367 constexpr int adjoint_field_order = 1;
369 auto add_field = [&]() {
374 for (
auto tt = MBEDGE;
375 tt <= moab::CN::TypeDimensionMap[
SPACE_DIM - 1].second; ++tt)
377 "ADJOINT_FIELD", adjoint_field_order);
384 auto add_adjoint_fe_impl = [&]() {
418 simple->getBitRefLevelMask());
423 auto set_adjoint_dm_imp = [&]() {
427 simple->getBitRefLevelMask());
429 CHKERR DMSetFromOptions(adjoint_dm);
436 CHKERR DMSetUp(adjoint_dm);
461 CHKERR bc_mng->removeBlockDOFsOnEntities(
simple->getProblemName(),
"REMOVE_X",
463 CHKERR bc_mng->removeBlockDOFsOnEntities(
simple->getProblemName(),
"REMOVE_Y",
465 CHKERR bc_mng->removeBlockDOFsOnEntities(
simple->getProblemName(),
"REMOVE_Z",
467 CHKERR bc_mng->removeBlockDOFsOnEntities(
simple->getProblemName(),
468 "REMOVE_ALL",
"U", 0, 3);
470 simple->getProblemName(),
"U");
472 CHKERR bc_mng->removeBlockDOFsOnEntities(
"ADJOINT",
"REMOVE_X",
473 "ADJOINT_FIELD", 0, 0);
474 CHKERR bc_mng->removeBlockDOFsOnEntities(
"ADJOINT",
"REMOVE_Y",
475 "ADJOINT_FIELD", 1, 1);
476 CHKERR bc_mng->removeBlockDOFsOnEntities(
"ADJOINT",
"REMOVE_Z",
477 "ADJOINT_FIELD", 2, 2);
478 CHKERR bc_mng->removeBlockDOFsOnEntities(
"ADJOINT",
"REMOVE_ALL",
479 "ADJOINT_FIELD", 0, 3);
480 CHKERR bc_mng->removeBlockDOFsOnEntities(
"ADJOINT",
"FIX_X",
"ADJOINT_FIELD",
482 CHKERR bc_mng->removeBlockDOFsOnEntities(
"ADJOINT",
"FIX_Y",
"ADJOINT_FIELD",
484 CHKERR bc_mng->removeBlockDOFsOnEntities(
"ADJOINT",
"FIX_Z",
"ADJOINT_FIELD",
486 CHKERR bc_mng->removeBlockDOFsOnEntities(
"ADJOINT",
"FIX_ALL",
487 "ADJOINT_FIELD", 0, 3);
509 CHKERR pip->setBoundaryRhsIntegrationRule(integration_rule_bc);
510 CHKERR pip->setBoundaryLhsIntegrationRule(integration_rule_bc);
514 pip->getOpDomainLhsPipeline(), {H1},
"GEOMETRY");
516 pip->getOpDomainRhsPipeline(), {H1},
"GEOMETRY");
518 pip->getOpBoundaryRhsPipeline(), {NOSPACE},
"GEOMETRY");
520 pip->getOpBoundaryLhsPipeline(), {NOSPACE},
"GEOMETRY");
524 CHKERR HookeOps::opFactoryDomainLhs<SPACE_DIM, A, I, DomainEleOp>(
525 mField, pip->getOpDomainLhsPipeline(),
"U",
"MAT_ELASTIC", Sev::noisy);
529 CHKERR HookeOps::opFactoryDomainRhs<SPACE_DIM, A, I, DomainEleOp>(
530 mField, pip->getOpDomainRhsPipeline(),
"U",
"MAT_ELASTIC", Sev::noisy);
534 pip->getOpDomainRhsPipeline(),
mField,
"U", Sev::inform);
540 pip->getOpBoundaryRhsPipeline(),
mField,
"U", -1, Sev::inform);
543 pip->getOpBoundaryLhsPipeline(),
mField,
"U", Sev::noisy);
559 auto set_essential_bc = [&]() {
564 auto pre_proc_rhs = boost::make_shared<FEMethod>();
565 auto post_proc_rhs = boost::make_shared<FEMethod>();
566 auto post_proc_lhs = boost::make_shared<FEMethod>();
568 auto get_pre_proc_hook = [&]() {
572 pre_proc_rhs->preProcessHook = get_pre_proc_hook();
574 auto get_post_proc_hook_rhs = [
this, post_proc_rhs]() {
578 post_proc_rhs, 1.)();
582 auto get_post_proc_hook_lhs = [
this, post_proc_lhs]() {
586 post_proc_lhs, 1.)();
590 post_proc_rhs->postProcessHook = get_post_proc_hook_rhs;
591 post_proc_lhs->postProcessHook = get_post_proc_hook_lhs;
593 ksp_ctx_ptr->getPreProcComputeRhs().push_front(pre_proc_rhs);
594 ksp_ctx_ptr->getPostProcComputeRhs().push_back(post_proc_rhs);
595 ksp_ctx_ptr->getPostProcSetOperators().push_back(post_proc_lhs);
599 auto setup_and_solve = [&](
auto solver) {
601 BOOST_LOG_SCOPED_THREAD_ATTR(
"Timeline", attrs::timer());
602 MOFEM_LOG(
"TIMER", Sev::noisy) <<
"KSPSetUp";
604 MOFEM_LOG(
"TIMER", Sev::noisy) <<
"KSPSetUp <= Done";
605 MOFEM_LOG(
"TIMER", Sev::noisy) <<
"KSPSolve";
607 MOFEM_LOG(
"TIMER", Sev::noisy) <<
"KSPSolve <= Done";
614 CHKERR set_essential_bc();
617 CHKERR VecGhostUpdateBegin(d, INSERT_VALUES, SCATTER_FORWARD);
618 CHKERR VecGhostUpdateEnd(d, INSERT_VALUES, SCATTER_FORWARD);
621 auto evaluate_field_at_the_point = [&]() {
625 std::array<double, 3> field_eval_coords{0.0, 0.0, 0.0};
628 field_eval_coords.data(), &coords_dim,
634 auto field_eval_data =
638 ->buildTree<SPACE_DIM>(field_eval_data,
simple->getDomainFEName());
640 field_eval_data->setEvalPoints(field_eval_coords.data(), 1);
641 auto no_rule = [](
int,
int,
int) {
return -1; };
642 auto field_eval_fe_ptr = field_eval_data->feMethodPtr;
643 field_eval_fe_ptr->getRuleHook = no_rule;
645 field_eval_fe_ptr->getOpPtrVector().push_back(
649 ->evalFEAtThePoint<SPACE_DIM>(
650 field_eval_coords.data(), 1e-12,
simple->getProblemName(),
651 simple->getDomainFEName(), field_eval_data,
659 <<
"U_X: " << t_disp(0) <<
" U_Y: " << t_disp(1);
662 <<
"U_X: " << t_disp(0) <<
" U_Y: " << t_disp(1)
663 <<
" U_Z: " << t_disp(2);
671 CHKERR evaluate_field_at_the_point();
684 std::vector<std::pair<std::string, SmartPetscObj<Vec>>> additional_vecs;
685 if (gradient_vector) {
686 additional_vecs.emplace_back(
"GRADIENT", gradient_vector);
688 if (adjoint_vector) {
689 additional_vecs.emplace_back(
"ADJOINT", adjoint_vector);
692 additional_vecs.emplace_back(
"dJ_dU", dJ_du);
697 "out_elastic_" + std::to_string(iter) +
".h5m", additional_vecs,
715 t_diff(
i,
j,
k,
l) = 0;
716 t_diff(0, 0, 0, 0) = 1;
717 t_diff(1, 1, 1, 1) = 1;
719 t_diff(1, 0, 1, 0) = 0.5;
720 t_diff(1, 0, 0, 1) = 0.5;
722 t_diff(0, 1, 0, 1) = 0.5;
723 t_diff(0, 1, 1, 0) = 0.5;
725 if constexpr (DIM == 3) {
726 t_diff(2, 2, 2, 2) = 1;
728 t_diff(2, 0, 2, 0) = 0.5;
729 t_diff(2, 0, 0, 2) = 0.5;
730 t_diff(0, 2, 0, 2) = 0.5;
731 t_diff(0, 2, 2, 0) = 0.5;
733 t_diff(2, 1, 2, 1) = 0.5;
734 t_diff(2, 1, 1, 2) = 0.5;
735 t_diff(1, 2, 1, 2) = 0.5;
736 t_diff(1, 2, 2, 1) = 0.5;
745 boost::shared_ptr<ObjectiveFunctionData> python_ptr,
746 boost::shared_ptr<HookeOps::CommonData> comm_ptr,
747 boost::shared_ptr<MatrixDouble> u_ptr)
759 auto nb_gauss_pts = getGaussPts().size2();
761 auto objective_dstress =
762 boost::make_shared<MatrixDouble>(nb_gauss_pts, symm_size);
763 auto objective_dstrain =
764 boost::make_shared<MatrixDouble>(nb_gauss_pts, symm_size);
766 boost::make_shared<MatrixDouble>(nb_gauss_pts,
SPACE_DIM);
768 auto evaluate_python = [&]() {
770 auto &coords = OP::getCoordsAtGaussPts();
781 auto vol = OP::getMeasure();
782 auto t_w = OP::getFTensor0IntegrationWeight();
785 getFTensor4DdgFromMat<SPACE_DIM, SPACE_DIM, 0>(*(
commPtr->matDPtr));
790 getFTensor2SymmetricFromMat<SPACE_DIM>(*objective_dstress);
792 getFTensor2SymmetricFromMat<SPACE_DIM>(*objective_dstrain);
793 auto t_obj_du = getFTensor1FromMat<SPACE_DIM>(*objective_du);
795 for (
int gg = 0; gg != nb_gauss_pts; ++gg) {
796 const double alpha = t_w * vol;
798 t_adjoint_stress(
i,
j) =
799 t_D(
i,
j,
k,
l) * t_obj_dstress(
k,
l) + t_obj_dstrain(
i,
j);
801 auto t_nf = OP::template getNf<SPACE_DIM>();
803 for (; rr != OP::nbRows /
SPACE_DIM; rr++) {
804 t_nf(
j) += alpha * t_row_grad(
i) * t_adjoint_stress(
i,
j);
805 t_nf(
j) += alpha * t_row_base * t_obj_du(
j);
812 for (; rr < OP::nbRowBaseFunctions; ++rr) {
828 boost::shared_ptr<ObjectiveFunctionData>
pythonPtr;
829 boost::shared_ptr<HookeOps::CommonData>
commPtr;
830 boost::shared_ptr<MatrixDouble>
uPtr;
836 boost::shared_ptr<HookeOps::CommonData> comm_ptr,
837 boost::shared_ptr<MatrixDouble> jac_ptr,
838 boost::shared_ptr<MatrixDouble> u_ptr,
839 boost::shared_ptr<double> glob_objective_ptr)
854 getGaussPts().size2();
856 auto objective_ptr = boost::make_shared<MatrixDouble>(
859 auto evaluate_python = [&]() {
861 auto &coords = OP::getCoordsAtGaussPts();
868 auto vol = OP::getMeasure();
869 auto t_w = getFTensor0IntegrationWeight();
870 for (
auto gg = 0; gg != nb_gauss_pts; ++gg) {
872 auto alpha = t_w * vol;
873 (*globObjectivePtr) += alpha * t_obj;
889 boost::shared_ptr<HookeOps::CommonData>
commPtr;
891 boost::shared_ptr<MatrixDouble>
uPtr;
899 boost::shared_ptr<HookeOps::CommonData> comm_ptr,
900 boost::shared_ptr<MatrixDouble> jac_ptr,
901 boost::shared_ptr<MatrixDouble> u_ptr,
902 boost::shared_ptr<MatrixDouble> grad_lambda_u_ptr,
903 boost::shared_ptr<double> glob_objective_ptr)
904 :
OP(
"ADJOINT_FIELD",
"ADJOINT_FIELD",
OP::OPROW),
pythonPtr(python_ptr),
918 const auto nb_gauss_pts =
919 getGaussPts().size2();
920 const auto nb_dofs = data.
getIndices().size();
939 auto objective_ptr = boost::make_shared<MatrixDouble>(
941 auto objective_dstress = boost::make_shared<MatrixDouble>(
944 auto objective_dstrain = boost::make_shared<MatrixDouble>(
949 auto evaluate_python = [&]() {
951 auto &coords = OP::getCoordsAtGaussPts();
963 getFTensor2FromMat<SPACE_DIM, SPACE_DIM>(*(
commPtr->matGradPtr));
965 getFTensor4DdgFromMat<SPACE_DIM, SPACE_DIM, 0>(*(
commPtr->matDPtr));
966 auto t_jac = getFTensor2FromMat<SPACE_DIM, SPACE_DIM>(*(
jacPtr));
967 auto t_grad_lambda_u =
972 getFTensor2SymmetricFromMat<SPACE_DIM>(*objective_dstress);
974 getFTensor2SymmetricFromMat<SPACE_DIM>(*objective_dstrain);
976 auto vol = OP::getMeasure();
977 auto t_w = getFTensor0IntegrationWeight();
979 for (
auto gg = 0; gg != nb_gauss_pts; ++gg) {
980 auto alpha = t_w * vol;
981 (*globObjectivePtr) += alpha * t_obj;
989 t_diff_inv_jac(
i,
j,
I,
J) =
990 -t_inv_jac(
i,
I) * t_inv_jac(
J,
j);
993 t_diff_grad(
i,
j,
I,
J) = t_grad_u(
i,
k) * t_diff_inv_jac(
k,
j,
I,
J);
996 t_d_strain(
i,
j,
I,
J) =
997 t_diff_symm(
i,
j,
k,
l) * t_diff_grad(
k,
l,
I,
J);
999 auto t_local_grad_vector = OP::template getNf<SPACE_DIM>();
1001 for (; bb != nb_dofs/
SPACE_DIM; bb++) {
1004 t_coef(
I) = (t_inv_jac(
J,
I) * t_base_diff(
J)) * t_det;
1006 t_local_grad_vector(
I) +=
1009 ((t_obj_dstress(
k,
l) * t_D(
k,
l,
i,
j)) +
1010 t_obj_dstrain(
i,
j)) *
1011 (t_d_strain(
i,
j,
I,
J) * t_base_diff(
J))
1019 t_local_grad_vector(
I) -=
1020 alpha * (t_grad_lambda_u(
i,
j) * t_D(
i,
j,
k,
l)) *
1021 (t_d_strain(
k,
l,
I,
J) * t_base_diff(
J));
1023 ++t_local_grad_vector;
1026 for (; bb < nb_base_funcs; ++bb) {
1043 CHKERR evaluate_python();
1049 boost::shared_ptr<ObjectiveFunctionData>
pythonPtr;
1050 boost::shared_ptr<HookeOps::CommonData>
commPtr;
1051 boost::shared_ptr<MatrixDouble>
jacPtr;
1052 boost::shared_ptr<MatrixDouble>
uPtr;
1059 Vec objective_function_gradient,
1066 auto get_essential_fe = [
this]() {
1067 auto post_proc_rhs = boost::make_shared<FEMethod>();
1068 auto get_post_proc_hook_rhs = [
this, post_proc_rhs]() {
1071 post_proc_rhs, 0)();
1074 post_proc_rhs->postProcessHook = get_post_proc_hook_rhs;
1075 return post_proc_rhs;
1078 auto get_objective_fe = [&](
auto lambda_vec,
auto glob_objective_ptr,
1080 auto fe_obj = boost::make_shared<DomainEle>(
mField);
1081 fe_obj->getRuleHook = fe_rule;
1082 auto &pip = fe_obj->getOpPtrVector();
1085 auto jac_ptr = boost::make_shared<MatrixDouble>();
1086 auto u_ptr = boost::make_shared<MatrixDouble>();
1087 auto grad_lambda_ptr = boost::make_shared<MatrixDouble>();
1090 "GEOMETRY", jac_ptr));
1094 "U", grad_lambda_ptr, lambda_smart_vec));
1096 auto common_ptr = HookeOps::commonDataFactory<SPACE_DIM, I, DomainEleOp>(
1097 mField, pip,
"U",
"MAT_ELASTIC", Sev::noisy);
1100 glob_objective_ptr));
1104 auto evaluate_objective_terms =
1105 [&](
auto objective_fe,
auto objective_ptr) {
1107 *objective_ptr = 0.0;
1108 CHKERR VecZeroEntries(objective_function_gradient);
1109 CHKERR VecGhostUpdateBegin(
lambda, INSERT_VALUES, SCATTER_FORWARD);
1110 CHKERR VecGhostUpdateEnd(
lambda, INSERT_VALUES, SCATTER_FORWARD);
1111 objective_fe->f = objective_function_gradient;
1114 MPI_Allreduce(MPI_IN_PLACE, objective_ptr.get(), 1, MPI_DOUBLE, MPI_SUM,
1116 CHKERR VecAssemblyBegin(objective_function_gradient);
1117 CHKERR VecAssemblyEnd(objective_function_gradient);
1118 CHKERR VecGhostUpdateBegin(objective_function_gradient, ADD_VALUES,
1120 CHKERR VecGhostUpdateEnd(objective_function_gradient, ADD_VALUES,
1125 auto calculate_variance_of_objective_function_dJ_du = [&]() {
1127 auto fe = boost::make_shared<DomainEle>(
mField);
1128 fe->getRuleHook = [](int, int,
int p_data) {
1129 return 2 * p_data + p_data - 1;
1131 auto &pip = fe->getOpPtrVector();
1133 auto u_ptr = boost::make_shared<MatrixDouble>();
1135 auto common_ptr = HookeOps::commonDataFactory<SPACE_DIM, I, DomainEleOp>(
1136 mField, pip,
"U",
"MAT_ELASTIC", Sev::noisy);
1138 CHKERR VecZeroEntries(dJ_du);
1141 CHKERR VecAssemblyBegin(dJ_du);
1142 CHKERR VecAssemblyEnd(dJ_du);
1143 auto post_proc_rhs = get_essential_fe();
1144 post_proc_rhs->f = dJ_du;
1146 post_proc_rhs.get());
1150 auto calculate_adjoint_lambda = [&]() {
1153 MOFEM_LOG(
"WORLD", Sev::inform) <<
"Solving for adjoint variable lambda";
1156 CHKERR VecGhostUpdateBegin(
lambda, INSERT_VALUES, SCATTER_FORWARD);
1157 CHKERR VecGhostUpdateEnd(
lambda, INSERT_VALUES, SCATTER_FORWARD);
1161 auto fe_rule = [](int, int,
int p_data) {
return 2 * p_data + p_data - 1; };
1162 auto objective_ptr_value = boost::make_shared<double>(0.0);
1163 auto objective_fe = get_objective_fe(
lambda, objective_ptr_value, fe_rule);
1165 auto adjoint = [&]() {
1168 CHKERR calculate_variance_of_objective_function_dJ_du();
1169 CHKERR calculate_adjoint_lambda();
1170 CHKERR evaluate_objective_terms(objective_fe, objective_ptr_value);
1171 *objective_function_value = *objective_ptr_value;
1174 <<
"Objective function: " << *objective_function_value;
1176 CHKERR VecAssemblyBegin(objective_function_gradient);
1177 CHKERR VecAssemblyEnd(objective_function_gradient);
1178 CHKERR VecGhostUpdateBegin(
lambda, INSERT_VALUES, SCATTER_FORWARD);
1179 CHKERR VecGhostUpdateEnd(
lambda, INSERT_VALUES, SCATTER_FORWARD);
1187 MOFEM_LOG(
"WORLD", Sev::inform) <<
"Running Adjoint Sensitivity...";
1193 "Wrong sensitivity type selected");
1196 CHKERR VecAssemblyBegin(objective_function_gradient);
1197 CHKERR VecAssemblyEnd(objective_function_gradient);
1207 PetscBool gradient_fd_check = PETSC_FALSE;
1209 &gradient_fd_check, PETSC_NULLPTR);
1210 if (gradient_fd_check) {
1212 PetscInt nb_modes = 5;
1214 "-gradient_nb_modes", &nb_modes, PETSC_NULLPTR);
1220 auto fe_rule = [](int, int,
int p_data) {
return 2 * p_data + p_data - 1; };
1221 auto get_objective_fe = [&](
auto glob_objective_ptr,
auto fe_rule) {
1222 auto fe_obj_fe = boost::make_shared<DomainEle>(
mField);
1223 fe_obj_fe->getRuleHook = fe_rule;
1224 auto &pip = fe_obj_fe->getOpPtrVector();
1226 auto jac_ptr = boost::make_shared<MatrixDouble>();
1227 auto u_ptr = boost::make_shared<MatrixDouble>();
1229 "GEOMETRY", jac_ptr));
1231 auto common_ptr = HookeOps::commonDataFactory<SPACE_DIM, I, DomainEleOp>(
1232 mField, pip,
"U",
"MAT_ELASTIC", Sev::noisy);
1234 glob_objective_ptr));
1238 auto f = boost::make_shared<double>(0.);
1239 auto fe_obj = get_objective_fe(
f, fe_rule);
1244 auto evaluate_objective_terms = [&](
auto objective_fe,
auto objective_ptr,
1245 double &objective_value) {
1247 *objective_ptr = 0.0;
1250 MPI_Allreduce(MPI_IN_PLACE, objective_ptr.get(), 1, MPI_DOUBLE, MPI_SUM,
1252 objective_value = *objective_ptr;
1257 for (PetscInt mode = 0; mode < nb_modes; ++mode) {
1259 MOFEM_LOG(
"WORLD", Sev::verbose) <<
"Processing mode: " << mode;
1265 auto a_dof = adj_dofs.find(mode);
1266 if (a_dof != adj_dofs.end()) {
1267 auto ent = (*a_dof)->getEnt();
1268 auto dof_idx = (*a_dof)->getEntDofIdx();
1272 auto dof = dofs.find(uid);
1273 if (dof != dofs.end()) {
1274 auto org_geom_val = (*dof)->getFieldData();
1275 constexpr double eps = 1e-6;
1277 (*dof)->getFieldData() = org_geom_val +
eps;
1281 CHKERR evaluate_objective_terms(fe_obj,
f, f_plus);
1283 (*dof)->getFieldData() = org_geom_val -
eps;
1287 CHKERR evaluate_objective_terms(fe_obj,
f, f_minus);
1290 CHKERR VecGetArray(gradient_vector, &g_array);
1291 if ((*a_dof)->getHasLocalIndex()) {
1292 auto adjoint_grad = g_array[(*a_dof)->getPetscLocalDofIdx()];
1293 auto finite_diff_grad = (f_plus - f_minus) / (2 *
eps);
1294 auto err = std::abs(adjoint_grad - finite_diff_grad) /
1295 std::max(std::abs(adjoint_grad),
1296 std::abs(finite_diff_grad));
1298 <<
"Mode: " << mode <<
", Adjoint gradient: " << adjoint_grad
1299 <<
", Finite difference gradient: " << finite_diff_grad
1300 <<
", Relative error: "
1301 << std::abs(adjoint_grad - finite_diff_grad) /
1302 std::max(std::abs(adjoint_grad),
1303 std::abs(finite_diff_grad));
1304 constexpr double tol = 1e-4;
1307 "Gradient check failed for mode %d: relative error %e is "
1308 "greater than tolerance %e",
1313 CHKERR VecRestoreArray(gradient_vector, &g_array);
1315 constexpr bool restore_solution =
false;
1316 if constexpr (restore_solution) {
1317 (*dof)->getFieldData() = org_geom_val;
1339 const char param_file[] =
"param_file.petsc";
1342 auto core_log = logging::core::get();
1354 DMType dm_name =
"DMMOFEM";
1356 DMType dm_name_mg =
"DMMOFEM_MG";
1361 moab::Core mb_instance;
1362 moab::Interface &moab = mb_instance;
1380 if (Py_FinalizeEx() < 0) {
1386 const std::string block_name,
int dim) {
1392 std::regex((boost::format(
"%s(.*)") % block_name).str())
1396 for (
auto bc : bcs) {
1400 "get meshset ents");
1404 for (
auto dd = dim - 1; dd >= 0; --dd) {
1408 moab::Interface::UNION),
1428 CHKERR moab.add_entities(*out_meshset, r);
1429 CHKERR moab.write_file(name.c_str(),
"VTK",
"", out_meshset->get_ptr(), 1);
#define MOFEM_LOG_SYNCHRONISE(comm)
Synchronise "SYNC" channel.
Interface for Python-based objective function evaluation in topology optimization.
#define FTENSOR_INDEX(DIM, I)
void simple(double P1[], double P2[], double P3[], double c[], const int N)
SensitivityMethod derivative_type
ElementsAndOps< SPACE_DIM >::DomainEle DomainEle
ElementsAndOps< SPACE_DIM >::BoundaryEle BoundaryEle
#define CATCH_ERRORS
Catch errors.
FieldApproximationBase
approximation base
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base .
#define CHK_THROW_MESSAGE(err, msg)
Check and throw MoFEM exception.
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
#define CHK_MOAB_THROW(err, msg)
Check error code of MoAB function and throw MoFEM exception.
@ MOFEM_ATOM_TEST_INVALID
@ MOFEM_DATA_INCONSISTENCY
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
#define MoFEMFunctionBeginHot
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
PostProcEleByDim< SPACE_DIM >::PostProcEleDomain PostProcEleDomain
PostProcEleByDim< SPACE_DIM >::PostProcEleBdy PostProcEleBdy
auto diff_symmetrize(FTensor::Number< DIM >)
static char help[]
[Finite difference check]
PetscBool is_plane_strain
PipelineManager::ElementsAndOpsByDim< SPACE_DIM >::DomainEle DomainEle
Domain finite elements.
constexpr int SPACE_DIM
[Define dimension]
SensitivityMethod derivative_type
constexpr double poisson_ratio
Poisson's ratio ν
constexpr int BASE_DIM
[Constants and material properties]
constexpr double shear_modulus_G
Shear modulus G = E/(2(1+ν))
constexpr IntegrationType I
Use Gauss quadrature for integration.
constexpr double bulk_modulus_K
Bulk modulus K = E/(3(1-2ν))
FormsIntegrators< DomainEleOp >::Assembly< A >::OpBase DomainBaseOp
[Postprocess results]
constexpr AssemblyType A
[Define dimension]
PipelineManager::ElementsAndOpsByDim< SPACE_DIM >::BoundaryEle BoundaryEle
Boundary finite elements.
Range get_range_from_block(MoFEM::Interface &m_field, const std::string block_name, int dim)
constexpr double young_modulus
[Material properties for linear elasticity]
PetscErrorCode DMMoFEMSetIsPartitioned(DM dm, PetscBool is_partitioned)
PetscErrorCode DMMoFEMAddElement(DM dm, std::string fe_name)
add element to dm
PetscErrorCode DMMoFEMSetSquareProblem(DM dm, PetscBool square_problem)
set squared problem
PetscErrorCode DMMoFEMCreateMoFEM(DM dm, MoFEM::Interface *m_field_ptr, const char problem_name[], const MoFEM::BitRefLevel bit_level, const MoFEM::BitRefLevel bit_mask=MoFEM::BitRefLevel().set())
Must be called by user to set MoFEM data structures.
PetscErrorCode DMoFEMPostProcessFiniteElements(DM dm, MoFEM::FEMethod *method)
execute finite element method for each element in dm (problem)
PetscErrorCode DMoFEMMeshToLocalVector(DM dm, Vec l, InsertMode mode, ScatterMode scatter_mode, RowColData rc=RowColData::COL)
set local (or ghosted) vector values on mesh for partition only
PetscErrorCode DMRegister_MoFEM(const char sname[])
Register MoFEM problem.
MoFEMErrorCode DMRegister_MGViaApproxOrders(const char sname[])
Register DM for Multi-Grid via approximation orders.
PetscErrorCode DMoFEMLoopFiniteElements(DM dm, const char fe_name[], MoFEM::FEMethod *method, CacheTupleWeakPtr cache_ptr=CacheTupleSharedPtr())
Executes FEMethod for finite elements in DM.
auto createDMVector(DM dm, RowColData rc=RowColData::COL)
Get smart vector from DM.
virtual const DofEntity_multiIndex * get_dofs() const =0
Get the dofs object.
virtual MoFEMErrorCode add_ents_to_finite_element_by_dim(const EntityHandle entities, const int dim, const std::string name, const bool recursive=true)=0
add entities to finite element
virtual MoFEMErrorCode add_finite_element(const std::string &fe_name, enum MoFEMTypes bh=MF_EXCL, int verb=DEFAULT_VERBOSITY)=0
add finite element
virtual MoFEMErrorCode build_finite_elements(int verb=DEFAULT_VERBOSITY)=0
Build finite elements.
virtual MoFEMErrorCode modify_finite_element_add_field_col(const std::string &fe_name, const std::string name_row)=0
set field col which finite element use
virtual MoFEMErrorCode modify_finite_element_add_field_row(const std::string &fe_name, const std::string name_row)=0
set field row which finite element use
virtual MoFEMErrorCode modify_finite_element_add_field_data(const std::string &fe_name, const std::string name_field)=0
set finite element field data
virtual MoFEMErrorCode build_fields(int verb=DEFAULT_VERBOSITY)=0
virtual MoFEMErrorCode add_ents_to_field_by_dim(const Range &ents, const int dim, const std::string &name, int verb=DEFAULT_VERBOSITY)=0
Add entities to field meshset.
virtual MoFEMErrorCode set_field_order(const EntityHandle meshset, const EntityType type, const std::string &name, const ApproximationOrder order, int verb=DEFAULT_VERBOSITY)=0
Set order approximation of the entities in the field.
static LoggerType & setLog(const std::string channel)
Set ans resset chanel logger.
#define MOFEM_LOG(channel, severity)
Log.
#define MOFEM_LOG_TAG(channel, tag)
Tag channel.
#define MOFEM_LOG_CHANNEL(channel)
Set and reset channel.
virtual MoFEMErrorCode loop_dofs(const Problem *problem_ptr, const std::string &field_name, RowColData rc, DofMethod &method, int lower_rank, int upper_rank, int verb=DEFAULT_VERBOSITY)=0
Make a loop over dofs.
MoFEMErrorCode getCubitMeshsetPtr(const int ms_id, const CubitBCType cubit_bc_type, const CubitMeshSets **cubit_meshset_ptr) const
get cubit meshset
FTensor::Index< 'i', SPACE_DIM > i
const double c
speed of light (cm/ns)
FTensor::Index< 'J', DIM1 > J
FTensor::Index< 'l', 3 > l
FTensor::Index< 'j', 3 > j
FTensor::Index< 'k', 3 > k
MoFEMErrorCode postProcessElasticResults(MoFEM::Interface &mField, SmartPetscObj< DM > dm, const std::string &domain_fe_name, const std::string &out_file_name, std::vector< std::pair< std::string, SmartPetscObj< Vec > > > extra_vectors={}, const std::vector< std::string > &tags_to_transfer={}, const Sev hooke_ops_sev=Sev::verbose)
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
implementation of Data Operators for Forces and Sources
PetscErrorCode DMMoFEMSetDestroyProblem(DM dm, PetscBool destroy_problem)
PetscErrorCode PetscOptionsGetInt(PetscOptions *, const char pre[], const char name[], PetscInt *ivalue, PetscBool *set)
PetscErrorCode PetscOptionsGetBool(PetscOptions *, const char pre[], const char name[], PetscBool *bval, PetscBool *set)
SmartPetscObj< Vec > vectorDuplicate(Vec vec)
Create duplicate vector of smart vector.
PetscErrorCode PetscOptionsGetRealArray(PetscOptions *, const char pre[], const char name[], PetscReal dval[], PetscInt *nmax, PetscBool *set)
auto getDMKspCtx(DM dm)
Get KSP context data structure used by DM.
static MoFEMErrorCode invertTensor(FTensor::Tensor2< T1, DIM, DIM > &t, T2 &det, FTensor::Tensor2< T3, DIM, DIM > &inv_t)
static auto determinantTensor(FTensor::Tensor2< T, DIM, DIM > &t)
Calculate the determinant of a tensor of rank DIM.
PetscErrorCode PetscOptionsGetEList(PetscOptions *, const char pre[], const char name[], const char *const *list, PetscInt next, PetscInt *value, PetscBool *set)
PetscErrorCode PetscOptionsGetString(PetscOptions *, const char pre[], const char name[], char str[], size_t size, PetscBool *set)
auto getFTensor0FromMat(M &data)
Get tensor rank 0 (scalar) form data vector.
auto get_temp_meshset_ptr(moab::Interface &moab)
Create smart pointer to temporary meshset.
auto createDM(MPI_Comm comm, const std::string dm_type_name)
Creates smart DM object.
boost::shared_ptr< CacheTuple > CacheTupleSharedPtr
auto getProblemPtr(DM dm)
get problem pointer from DM
boost::shared_ptr< ObjectiveFunctionData > create_python_objective_function(std::string)
constexpr auto field_name
static constexpr int approx_order
PetscBool is_plane_strain
Boundary conditions marker.
MoFEMErrorCode boundaryCondition()
MoFEMErrorCode assembleSystem()
MoFEMErrorCode readMesh()
boost::shared_ptr< ObjectiveFunctionData > pythonPtr
Interface to Python objective function.
SmartPetscObj< DM > adjointDM
Data manager for adjoint problem.
FieldApproximationBase base
Choice of finite element basis functions.
SmartPetscObj< KSP > kspElastic
Linear solver for elastic problem.
MoFEMErrorCode testGradient(Vec gradient_vector)
[calculateGradient]
int fieldOrder
Polynomial order for approximation.
Example(MoFEM::Interface &m_field)
MoFEMErrorCode runProblem()
Main driver function for the optimization process.
MoFEMErrorCode calculateGradient(PetscReal *objective_function_value, Vec objective_function_gradient, Vec adjoint_vector)
Calculate objective function gradient using adjoint method.
MoFEMErrorCode setupAdJoint()
MoFEM::Interface & mField
Reference to MoFEM interface.
MoFEMErrorCode setupProblem()
MoFEMErrorCode postprocessElastic(int iter, SmartPetscObj< Vec > adjoint_vector=nullptr)
Post-process and output results.
MoFEMErrorCode solveElastic()
Solve forward elastic problem.
boost::shared_ptr< MatrixDouble > vectorFieldPtr
Field values at evaluation points.
Add operators pushing bases from local to physical configuration.
Boundary condition manager for finite element problem setup.
MoFEMErrorCode synchroniseEntities(Range &ent, std::map< int, Range > *received_ents, int verb=DEFAULT_VERBOSITY)
synchronize entity range on processors (collective)
virtual FieldBitNumber get_field_bit_number(const std::string name) const =0
get field bit number
virtual moab::Interface & get_moab()=0
virtual MoFEMErrorCode cache_problem_entities(const std::string prb_name, CacheTupleWeakPtr cache_ptr)=0
Cache variables.
virtual MoFEMErrorCode build_adjacencies(const Range &ents, int verb=DEFAULT_VERBOSITY)=0
build adjacencies
virtual MoFEMErrorCode add_field(const std::string name, const FieldSpace space, const FieldApproximationBase base, const FieldCoefficientsNumber nb_of_coefficients, const TagType tag_type=MB_TAG_SPARSE, const enum MoFEMTypes bh=MF_EXCL, int verb=DEFAULT_VERBOSITY)=0
Add field.
virtual MPI_Comm & get_comm() const =0
virtual int get_comm_rank() const =0
static MoFEMErrorCode Initialize(int *argc, char ***args, const char file[], const char help[])
Initializes the MoFEM database PETSc, MOAB and MPI.
static MoFEMErrorCode Finalize()
Checks for options to be called at the conclusion of the program.
Deprecated interface functions.
Definition of the displacement bc data structure.
static UId getUniqueIdCalculate(const DofIdx dof, UId ent_uid)
Data on single entity (This is passed as argument to DataOperator::doWork)
FTensor::Tensor0< FTensor::PackPtr< double *, 1 > > getFTensor0N(const FieldApproximationBase base)
Get base function as Tensor0.
auto getFTensor1DiffN(const FieldApproximationBase base)
Get derivatives of base functions.
MatrixDouble & getN(const FieldApproximationBase base)
get base functions this return matrix (nb. of rows is equal to nb. of Gauss pts, nb....
const VectorInt & getIndices() const
Get global indices of degrees of freedom on entity.
Class (Function) to enforce essential constrains on the left hand side diagonal.
Class (Function) to enforce essential constrains on the right hand side diagonal.
Class (Function) to enforce essential constrains.
UId getLocalUniqueIdCalculate()
Get the Local Unique Id Calculate object.
Field evaluator interface.
static boost::shared_ptr< SinkType > createSink(boost::shared_ptr< std::ostream > stream_ptr, std::string comm_filter)
Create a sink object.
static boost::shared_ptr< std::ostream > getStrmWorld()
Get the strm world object.
static boost::shared_ptr< std::ostream > getStrmSync()
Get the strm sync object.
Interface for managing meshsets containing materials and boundary conditions.
Get field gradients at integration pts for scalar field rank 0, i.e. vector field.
Specialization for MatrixDouble vector field values calculation.
Template struct for dimension-specific finite element types.
PipelineManager interface.
MoFEMErrorCode setDomainRhsIntegrationRule(RuleHookFun rule)
Set integration rule for domain right-hand side finite element.
Problem manager is used to build and partition problems.
Projection of edge entities with one mid-node on hierarchical basis.
Simple interface for fast problem set-up.
MoFEMErrorCode getOptions()
get options
MoFEMErrorCode getDM(DM *dm)
Get DM.
const std::string getDomainFEName() const
Get the Domain FE Name.
intrusive_ptr for managing petsc objects
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.
Vector manager is used to create vectors \mofem_vectors.
boost::shared_ptr< HookeOps::CommonData > commPtr
ForcesAndSourcesCore::UserDataOperator OP
boost::shared_ptr< double > globObjectivePtr
OpAdJointObjective(boost::shared_ptr< ObjectiveFunctionData > python_ptr, boost::shared_ptr< HookeOps::CommonData > comm_ptr, boost::shared_ptr< MatrixDouble > jac_ptr, boost::shared_ptr< MatrixDouble > u_ptr, boost::shared_ptr< MatrixDouble > grad_lambda_u_ptr, boost::shared_ptr< double > glob_objective_ptr)
boost::shared_ptr< ObjectiveFunctionData > pythonPtr
boost::shared_ptr< MatrixDouble > gradLambdaUPtr
boost::shared_ptr< MatrixDouble > uPtr
MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &data)
Compute objective function contributions at element level.
boost::shared_ptr< MatrixDouble > jacPtr
boost::shared_ptr< double > globObjectivePtr
ForcesAndSourcesCore::UserDataOperator OP
boost::shared_ptr< MatrixDouble > jacPtr
OpObjective(boost::shared_ptr< ObjectiveFunctionData > python_ptr, boost::shared_ptr< HookeOps::CommonData > comm_ptr, boost::shared_ptr< MatrixDouble > jac_ptr, boost::shared_ptr< MatrixDouble > u_ptr, boost::shared_ptr< double > glob_objective_ptr)
boost::shared_ptr< MatrixDouble > uPtr
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Compute objective function contributions at element level.
boost::shared_ptr< HookeOps::CommonData > commPtr
boost::shared_ptr< ObjectiveFunctionData > pythonPtr
boost::shared_ptr< HookeOps::CommonData > commPtr
OpStateSensitivity(const std::string field_name, boost::shared_ptr< ObjectiveFunctionData > python_ptr, boost::shared_ptr< HookeOps::CommonData > comm_ptr, boost::shared_ptr< MatrixDouble > u_ptr)
MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &data)
boost::shared_ptr< MatrixDouble > uPtr
boost::shared_ptr< ObjectiveFunctionData > pythonPtr
PipelineManager::ElementsAndOpsByDim< 2 >::FaceSideEle SideEle
PipelineManager::ElementsAndOpsByDim< 3 >::FaceSideEle SideEle
#define EXECUTABLE_DIMENSION
PetscBool do_eval_field
Evaluate field.
ElementsAndOps< SPACE_DIM >::SideEle SideEle
PipelineManager::ElementsAndOpsByDim< SPACE_DIM >::BoundaryEle BoundaryEle
PostProcEleByDim< SPACE_DIM >::SideEle SideEle
PipelineManager::ElementsAndOpsByDim< SPACE_DIM >::DomainEle DomainEle