13 #ifndef EXECUTABLE_DIMENSION
14 #define EXECUTABLE_DIMENSION 3
17 #ifndef SCHUR_ASSEMBLE
18 #define SCHUR_ASSEMBLE 0
25 #include <boost/python.hpp>
26 #include <boost/python/def.hpp>
27 #include <boost/python/numpy.hpp>
28 namespace bp = boost::python;
29 namespace np = boost::python::numpy;
32 using namespace MoFEM;
73 IT>::OpBaseTimesVector<1, SPACE_DIM, 1>;
106 #ifdef WITH_MODULE_MFRONT_INTERFACE
107 #include <MFrontMoFEMInterface.hpp>
146 boost::shared_ptr<SDFPython> sdfPythonPtr;
161 CHKERR createCommonData();
187 enum bases { AINSWORTH, DEMKOWICZ, LASBASETOPT };
188 const char *list_bases[LASBASETOPT] = {
"ainsworth",
"demkowicz"};
189 PetscInt choice_base_value = AINSWORTH;
191 LASBASETOPT, &choice_base_value, PETSC_NULL);
194 switch (choice_base_value) {
198 <<
"Set AINSWORTH_LEGENDRE_BASE for displacements";
203 <<
"Set DEMKOWICZ_JACOBI_BASE for displacements";
223 auto get_skin = [&]() {
225 CHKERR mField.get_moab().get_entities_by_dimension(0,
SPACE_DIM, body_ents);
226 Skinner skin(&mField.get_moab());
228 CHKERR skin.find_skin(0, body_ents,
false, skin_ents);
232 auto filter_blocks = [&](
auto skin) {
233 bool is_contact_block =
false;
238 (boost::format(
"%s(.*)") %
"CONTACT").str()
247 <<
"Find contact block set: " <<
m->getName();
248 auto meshset =
m->getMeshset();
249 Range contact_meshset_range;
250 CHKERR mField.get_moab().get_entities_by_dimension(
251 meshset,
SPACE_DIM - 1, contact_meshset_range,
true);
254 contact_meshset_range);
255 contact_range.merge(contact_meshset_range);
257 if (is_contact_block) {
259 <<
"Nb entities in contact surface: " << contact_range.size();
261 skin = intersect(skin, contact_range);
266 auto filter_true_skin = [&](
auto skin) {
268 ParallelComm *pcomm =
270 CHKERR pcomm->filter_pstatus(skin, PSTATUS_SHARED | PSTATUS_MULTISHARED,
271 PSTATUS_NOT, -1, &boundary_ents);
272 return boundary_ents;
275 auto boundary_ents = filter_true_skin(filter_blocks(get_skin()));
278 CHKERR simple->setFieldOrder(
"SIGMA", sigma_order, &boundary_ents);
283 CHKERR mField.get_moab().get_adjacencies(boundary_ents, 1,
false, ho_ents,
284 moab::Interface::UNION);
286 ho_ents = boundary_ents;
295 auto project_ho_geometry = [&]() {
297 return mField.loop_dofs(
"GEOMETRY", ent_method);
300 PetscBool project_geometry = PETSC_TRUE;
302 &project_geometry, PETSC_NULL);
303 if (project_geometry) {
304 CHKERR project_ho_geometry();
314 PetscBool use_mfront = PETSC_FALSE;
336 if (!mfrontInterface) {
340 MOFEM_LOG(
"CONTACT", Sev::inform) <<
"Using MFront for material model";
351 PetscBool use_scale = PETSC_FALSE;
366 char sdf_file_name[255];
368 sdf_file_name, 255, PETSC_NULL);
370 sdfPythonPtr = boost::make_shared<SDFPython>();
371 CHKERR sdfPythonPtr->sdfInit(sdf_file_name);
372 sdfPythonWeakPtr = sdfPythonPtr;
378 "Use executable contact_2d with axisymmetric model");
382 "Axisymmetric model is only available with MFront (set "
385 MOFEM_LOG(
"CONTACT", Sev::inform) <<
"Using axisymmetric model";
390 MOFEM_LOG(
"CONTACT", Sev::inform) <<
"Using plane strain model";
395 #ifndef WITH_MODULE_MFRONT_INTERFACE
398 "MFrontInterface module was not found while use_mfront was set to 1");
402 boost::make_shared<MFrontMoFEMInterface<TRIDIMENSIONAL>>(
407 boost::make_shared<MFrontMoFEMInterface<AXISYMMETRICAL>>(
410 mfrontInterface = boost::make_shared<MFrontMoFEMInterface<PLANESTRAIN>>(
415 CHKERR mfrontInterface->getCommandLineParameters();
419 auto dm =
simple->getDM();
424 mfrontInterface->setMonitorPtr(monitorPtr);
434 auto bc_mng = mField.getInterface<
BcManager>();
437 for (
auto f : {
"U",
"SIGMA"}) {
438 CHKERR bc_mng->removeBlockDOFsOnEntities(
simple->getProblemName(),
439 "REMOVE_X",
f, 0, 0);
440 CHKERR bc_mng->removeBlockDOFsOnEntities(
simple->getProblemName(),
441 "REMOVE_Y",
f, 1, 1);
442 CHKERR bc_mng->removeBlockDOFsOnEntities(
simple->getProblemName(),
443 "REMOVE_Z",
f, 2, 2);
444 CHKERR bc_mng->removeBlockDOFsOnEntities(
simple->getProblemName(),
445 "REMOVE_ALL",
f, 0, 3);
448 CHKERR bc_mng->removeBlockDOFsOnEntities(
simple->getProblemName(),
"FIX_X",
449 "SIGMA", 0, 0,
false,
true);
450 CHKERR bc_mng->removeBlockDOFsOnEntities(
simple->getProblemName(),
"FIX_Y",
451 "SIGMA", 1, 1,
false,
true);
452 CHKERR bc_mng->removeBlockDOFsOnEntities(
simple->getProblemName(),
"FIX_Z",
453 "SIGMA", 2, 2,
false,
true);
454 CHKERR bc_mng->removeBlockDOFsOnEntities(
simple->getProblemName(),
"FIX_ALL",
455 "SIGMA", 0, 3,
false,
true);
456 CHKERR bc_mng->removeBlockDOFsOnEntities(
457 simple->getProblemName(),
"NO_CONTACT",
"SIGMA", 0, 3,
false,
true);
462 simple->getProblemName(),
"U");
474 auto time_scale = boost::make_shared<ScaledTimeScale>();
475 auto body_force_time_scale =
476 boost::make_shared<ScaledTimeScale>(
"body_force_hist.txt");
485 auto add_domain_base_ops = [&](
auto &pip) {
492 auto henky_common_data_ptr = boost::make_shared<HenckyOps::CommonData>();
493 henky_common_data_ptr->matDPtr = boost::make_shared<MatrixDouble>();
494 henky_common_data_ptr->matGradPtr = boost::make_shared<MatrixDouble>();
496 auto add_domain_ops_lhs = [&](
auto &pip) {
506 auto fe_domain_lhs = pip_mng->getDomainLhsFE();
508 auto get_inertia_and_mass_damping =
510 return (
rho *
scale) * fe_domain_lhs->ts_aa +
513 pip.push_back(
new OpMass(
"U",
"U", get_inertia_and_mass_damping));
517 auto fe_domain_lhs = pip_mng->getDomainLhsFE();
519 auto get_inertia_and_mass_damping =
523 pip.push_back(
new OpMass(
"U",
"U", get_inertia_and_mass_damping));
526 if (!mfrontInterface) {
527 CHKERR HenckyOps::opFactoryDomainLhs<SPACE_DIM, AT, IT, DomainEleOp>(
528 mField, pip,
"U",
"MAT_ELASTIC", Sev::verbose,
scale);
530 CHKERR mfrontInterface->opFactoryDomainLhs(pip);
536 auto add_domain_ops_rhs = [&](
auto &pip) {
540 pip, mField,
"U", {body_force_time_scale}, Sev::inform);
544 AT>::LinearForm<IT>::OpBaseTimesVector<1,
SPACE_DIM, 1>;
549 auto mat_acceleration = boost::make_shared<MatrixDouble>();
551 "U", mat_acceleration));
553 new OpInertiaForce(
"U", mat_acceleration, [](
double,
double,
double) {
560 auto mat_velocity = boost::make_shared<MatrixDouble>();
564 new OpInertiaForce(
"U", mat_velocity, [](
double,
double,
double) {
569 if (!mfrontInterface) {
570 CHKERR HenckyOps::opFactoryDomainRhs<SPACE_DIM, AT, IT, DomainEleOp>(
571 mField, pip,
"U",
"MAT_ELASTIC", Sev::inform,
scale);
573 CHKERR mfrontInterface->opFactoryDomainRhs(pip);
576 CHKERR ContactOps::opFactoryDomainRhs<SPACE_DIM, AT, IT, DomainEleOp>(
582 auto add_boundary_base_ops = [&](
auto &pip) {
592 auto add_boundary_ops_lhs = [&](
auto &pip) {
602 pip, mField,
"U", Sev::inform);
607 auto fe_boundary_lhs = pip_mng->getBoundaryLhsFE();
612 [
this, fe_boundary_lhs](
double,
double,
double) {
621 ContactOps::opFactoryBoundaryLhs<SPACE_DIM, AT, GAUSS, BoundaryEleOp>(
625 mField, pip,
simple->getDomainFEName(),
"SIGMA",
"U",
"GEOMETRY",
631 auto add_boundary_ops_rhs = [&](
auto &pip) {
636 AT>::LinearForm<IT>::OpBaseTimesVector<1,
SPACE_DIM, 1>;
641 pip, mField,
"U", {time_scale}, Sev::inform);
644 auto u_disp = boost::make_shared<MatrixDouble>();
645 auto dot_u_disp = boost::make_shared<MatrixDouble>();
650 new OpSpringRhs(
"U", u_disp, [
this](
double,
double,
double) {
654 new OpSpringRhs(
"U", dot_u_disp, [
this](
double,
double,
double) {
660 ContactOps::opFactoryBoundaryRhs<SPACE_DIM, AT, GAUSS, BoundaryEleOp>(
666 CHKERR add_domain_base_ops(pip_mng->getOpDomainLhsPipeline());
667 CHKERR add_domain_base_ops(pip_mng->getOpDomainRhsPipeline());
668 CHKERR add_domain_ops_lhs(pip_mng->getOpDomainLhsPipeline());
669 CHKERR add_domain_ops_rhs(pip_mng->getOpDomainRhsPipeline());
671 CHKERR add_boundary_base_ops(pip_mng->getOpBoundaryLhsPipeline());
672 CHKERR add_boundary_base_ops(pip_mng->getOpBoundaryRhsPipeline());
673 CHKERR add_boundary_ops_lhs(pip_mng->getOpBoundaryLhsPipeline());
674 CHKERR add_boundary_ops_rhs(pip_mng->getOpBoundaryRhsPipeline());
676 if (mfrontInterface) {
677 CHKERR mfrontInterface->setUpdateElementVariablesOperators();
680 CHKERR pip_mng->setDomainRhsIntegrationRule(integration_rule_vol);
681 CHKERR pip_mng->setDomainLhsIntegrationRule(integration_rule_vol);
682 CHKERR pip_mng->setBoundaryRhsIntegrationRule(integration_rule_boundary);
683 CHKERR pip_mng->setBoundaryLhsIntegrationRule(integration_rule_boundary);
691 static boost::shared_ptr<SetUpSchur>
706 auto set_section_monitor = [&](
auto solver) {
709 CHKERR TSGetSNES(solver, &snes);
710 PetscViewerAndFormat *vf;
711 CHKERR PetscViewerAndFormatCreate(PETSC_VIEWER_STDOUT_WORLD,
712 PETSC_VIEWER_DEFAULT, &vf);
715 (
MoFEMErrorCode(*)(SNES, PetscInt, PetscReal,
void *))SNESMonitorFields,
720 auto scatter_create = [&](
auto D,
auto coeff) {
722 CHKERR is_manager->isCreateProblemFieldAndRank(
simple->getProblemName(),
723 ROW,
"U", coeff, coeff, is);
725 CHKERR ISGetLocalSize(is, &loc_size);
727 CHKERR VecCreateMPI(mField.get_comm(), loc_size, PETSC_DETERMINE, &
v);
729 CHKERR VecScatterCreate(
D, is,
v, PETSC_NULL, &scatter);
734 auto set_time_monitor = [&](
auto dm,
auto solver) {
736 monitorPtr->setScatterVectors(uXScatter, uYScatter, uZScatter);
737 boost::shared_ptr<ForcesAndSourcesCore>
null;
739 monitorPtr,
null,
null);
743 auto set_essential_bc = [&]() {
747 auto pre_proc_ptr = boost::make_shared<FEMethod>();
748 auto post_proc_rhs_ptr = boost::make_shared<FEMethod>();
749 auto post_proc_lhs_ptr = boost::make_shared<FEMethod>();
752 auto time_scale = boost::make_shared<TimeScale>();
754 auto get_bc_hook_rhs = [&]() {
756 {time_scale},
false);
759 pre_proc_ptr->preProcessHook = get_bc_hook_rhs();
761 auto get_post_proc_hook_rhs = [&]() {
763 mField, post_proc_rhs_ptr, 1.);
765 auto get_post_proc_hook_lhs = [&]() {
767 mField, post_proc_lhs_ptr, 1.);
769 post_proc_rhs_ptr->postProcessHook = get_post_proc_hook_rhs();
771 ts_ctx_ptr->getPreProcessIFunction().push_front(pre_proc_ptr);
772 ts_ctx_ptr->getPreProcessIJacobian().push_front(pre_proc_ptr);
773 ts_ctx_ptr->getPostProcessIFunction().push_back(post_proc_rhs_ptr);
774 post_proc_lhs_ptr->postProcessHook = get_post_proc_hook_lhs();
775 ts_ctx_ptr->getPostProcessIJacobian().push_back(post_proc_lhs_ptr);
780 auto set_schur_pc = [&](
auto solver) {
781 boost::shared_ptr<SetUpSchur> schur_ptr;
790 auto dm =
simple->getDM();
795 uXScatter = scatter_create(
D, 0);
796 uYScatter = scatter_create(
D, 1);
798 uZScatter = scatter_create(
D, 2);
802 CHKERR set_essential_bc();
805 auto solver = pip_mng->createTSIM();
806 CHKERR TSSetFromOptions(solver);
807 auto schur_pc_ptr = set_schur_pc(solver);
810 CHKERR set_section_monitor(solver);
811 CHKERR set_time_monitor(dm, solver);
812 CHKERR TSSetSolution(solver,
D);
814 CHKERR TSSolve(solver, NULL);
816 auto solver = pip_mng->createTSIM2();
817 CHKERR TSSetFromOptions(solver);
818 auto schur_pc_ptr = set_schur_pc(solver);
820 auto dm =
simple->getDM();
824 CHKERR set_section_monitor(solver);
825 CHKERR set_time_monitor(dm, solver);
826 CHKERR TS2SetSolution(solver,
D, DD);
828 CHKERR TSSolve(solver, NULL);
838 if (
atom_test && !mField.get_comm_rank()) {
845 double tol_norm = 7.5;
849 fem_force = t_ptr[1];
853 fem_force = t_ptr[1];
854 norm = monitorPtr->getErrorNorm(1);
858 fem_force = t_ptr[2];
862 hertz_force = 15.873;
863 fem_force = t_ptr[1];
864 norm = monitorPtr->getErrorNorm(1);
868 fem_force = t_ptr[1];
871 hertz_force = 0.5289;
872 fem_force = t_ptr[2];
876 "atom test %d does not exist",
atom_test);
878 if (fabs(fem_force - hertz_force) / hertz_force >
tol) {
880 "atom test %d diverged! %3.4e != %3.4e",
atom_test, fem_force,
883 if (norm > tol_norm) {
885 "atom test %d diverged! %3.4e > %3.4e",
atom_test, norm,
897 static char help[] =
"...\n\n";
899 int main(
int argc,
char *argv[]) {
907 const char param_file[] =
"param_file.petsc";
911 auto core_log = logging::core::get();
920 DMType dm_name =
"DMMOFEM";
950 if (Py_FinalizeEx() < 0) {
985 CHKERR TSGetSNES(solver, &snes);
987 CHKERR SNESGetKSP(snes, &ksp);
988 CHKERR KSPSetFromOptions(ksp);
991 CHKERR KSPGetPC(ksp, &pc);
993 PetscBool is_pcfs = PETSC_FALSE;
994 PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &is_pcfs);
997 MOFEM_LOG(
"CONTACT", Sev::inform) <<
"Setup Schur pc";
1002 "It is expected that Schur matrix is not allocated. This is "
1003 "possible only if PC is set up twice");
1015 CHKERR TSGetDM(solver, &solver_dm);
1016 CHKERR DMSetMatType(solver_dm, MATSHELL);
1023 auto swap_assemble = [](TS ts, PetscReal
t,
Vec u,
Vec u_t, PetscReal
a,
1024 Mat
A, Mat B,
void *ctx) {
1027 CHKERR TSSetIJacobian(solver,
A,
P, swap_assemble, ts_ctx_ptr.get());
1029 auto swap_assemble = [](TS ts, PetscReal
t,
Vec u,
Vec u_t,
Vec utt,
1030 PetscReal
a, PetscReal aa, Mat
A, Mat B,
1034 CHKERR TSSetI2Jacobian(solver,
A,
P, swap_assemble, ts_ctx_ptr.get());
1042 CHKERR setDiagonalPC(pc);
1045 MOFEM_LOG(
"CONTACT", Sev::inform) <<
"No Schur PC";
1047 pip->getOpBoundaryLhsPipeline().push_back(
1050 pip->getOpDomainLhsPipeline().push_back(
1060 auto create_dm = [&](
const char *name,
const char *
field_name) {
1061 auto dm =
createDM(mField.get_comm(),
"DMMOFEM");
1062 auto create_dm_imp = [&]() {
1074 "Error in creating schurDM. It is possible that schurDM is "
1082 schurDM = create_dm(
"SCHUR",
"U");
1083 blockDM = create_dm(
"BLOCK",
"SIGMA");
1087 auto get_nested_mat_data = [&](
auto schur_dm,
auto block_dm) {
1093 simple->getDomainFEName(),
1097 {
"U",
"U"}, {
"SIGMA",
"U"}, {
"U",
"SIGMA"}, {
"SIGMA",
"SIGMA"}
1105 {schurDM, blockDM}, block_mat_data,
1107 {
"SIGMA"}, {
nullptr}, true
1112 auto nested_mat_data = get_nested_mat_data(schurDM, blockDM);
1117 "Only BLOCK_SCHUR is implemented");
1126 double eps_stab = 1e-4;
1132 using OpMassStab = B::OpMass<3, SPACE_DIM * SPACE_DIM>;
1138 boost::shared_ptr<BlockStructure> block_data;
1146 pip->getOpBoundaryLhsPipeline().push_back(
1147 new OpMassStab(
"SIGMA",
"SIGMA",
1148 [eps_stab](
double,
double,
double) {
return eps_stab; }));
1149 pip->getOpBoundaryLhsPipeline().push_back(
1158 pip->getOpDomainLhsPipeline().push_back(
1165 auto pre_proc_schur_lhs_ptr = boost::make_shared<FEMethod>();
1166 auto post_proc_schur_lhs_ptr = boost::make_shared<FEMethod>();
1168 pre_proc_schur_lhs_ptr->preProcessHook = [
this]() {
1170 CHKERR MatZeroEntries(S);
1171 MOFEM_LOG(
"CONTACT", Sev::verbose) <<
"Lhs Assemble Begin";
1175 post_proc_schur_lhs_ptr->postProcessHook = [
this, ao_up,
1176 post_proc_schur_lhs_ptr]() {
1178 MOFEM_LOG(
"CONTACT", Sev::verbose) <<
"Lhs Assemble End";
1179 auto print_mat_norm = [
this](
auto a, std::string prefix) {
1182 CHKERR MatNorm(
a, NORM_FROBENIUS, &nrm);
1183 MOFEM_LOG(
"CONTACT", Sev::noisy) << prefix <<
" norm = " << nrm;
1186 CHKERR MatAssemblyBegin(S, MAT_FINAL_ASSEMBLY);
1187 CHKERR MatAssemblyEnd(S, MAT_FINAL_ASSEMBLY);
1189 mField, post_proc_schur_lhs_ptr, 1, S, ao_up)();
1191 CHKERR print_mat_norm(S,
"S");
1193 MOFEM_LOG(
"CONTACT", Sev::verbose) <<
"Lhs Assemble Finish";
1198 ts_ctx_ptr->getPreProcessIJacobian().push_front(pre_proc_schur_lhs_ptr);
1199 ts_ctx_ptr->getPostProcessIJacobian().push_back(post_proc_schur_lhs_ptr);
1207 auto block_is =
getDMSubData(blockDM)->getSmartRowIs();
1208 CHKERR PCFieldSplitSetIS(pc, NULL, block_is);
1209 CHKERR PCFieldSplitSetSchurPre(pc, PC_FIELDSPLIT_SCHUR_PRE_USER, S);
1216 CHKERR PCFieldSplitSchurGetSubKSP(pc, PETSC_NULL, &subksp);
1217 auto get_pc = [](
auto ksp) {
1219 CHKERR KSPGetPC(ksp, &pc_raw);
1223 CHKERR PetscFree(subksp);
1227 boost::shared_ptr<SetUpSchur>
1229 return boost::shared_ptr<SetUpSchur>(
new SetUpSchurImpl(m_field));