v0.16.3
Loading...
Searching...
No Matches
NonlinearElasticExample.hpp
Go to the documentation of this file.
1/**
2 * @file NonlinearElasticExample.hpp
3 * @example mofem/tutorials/vec-2_nonlinear_elasticity/src/NonlinearElasticExample.hpp
4 * @date 2025-10-5
5 *
6 * @copyright Anonymous authors (c) 2025 under the MIT license (see LICENSE for
7 * details)
8 */
9
10#ifdef WITH_ADOL_C
11 #include <MatOps.hpp>
12 #include <MatElastic.hpp>
13 #include <MatHuHu.hpp>
14 #include <MatUmat.hpp>
15 #include <MatGenericElastic.hpp>
17 #ifdef WITH_ADOL_C_SIMPLE_DAMAGE
19 #endif
20#endif
21
23
25
26 MoFEMErrorCode runProblem();
27
28protected:
30 boost::shared_ptr<DomainEle> updateFe;
31 boost::shared_ptr<PostProcEleDomain> postProcDomainFe;
32 boost::shared_ptr<PostProcEleBdy> postProcBdyFe;
33#ifdef AXISYMMETRIC
34 static constexpr int MAT_DIM = 3;
35 PetscBool useAdolcMaterial = PETSC_TRUE;
36#else
37 static constexpr int MAT_DIM = SPACE_DIM;
38 PetscBool useAdolcMaterial = PETSC_FALSE;
39#endif
41
42 MoFEMErrorCode readMesh();
43 MoFEMErrorCode setupProblem();
44 MoFEMErrorCode boundaryCondition();
45 MoFEMErrorCode assembleSystemHencky();
46 MoFEMErrorCode assembleSystemAdolc();
47 MoFEMErrorCode opTest();
48 MoFEMErrorCode TsSolve();
49 MoFEMErrorCode gettingNorms();
50 MoFEMErrorCode outputResults();
51 MoFEMErrorCode checkResults();
52
54
55 static MoFEMErrorCode
57 elasticExamplePtr = example_ptr;
58 return 0;
59 }
60 static MoFEMErrorCode postStepDestroy() {
61 elasticExamplePtr = nullptr;
62 return 0;
63 }
64 static MoFEMErrorCode preStepFun(TS ts) { return 0; }
65 static MoFEMErrorCode postStepFun(TS ts) {
67 (void)ts;
69 auto dm = simple->getDM();
71 CHKERR DMoFEMLoopFiniteElements(dm, simple->getDomainFEName(),
73 }
75 }
76
77 private:
79 };
80
81 std::vector<Tag>
82 listTagsToTransfer; ///< list of tags to transfer to postprocessor
83
84#ifdef WITH_ADOL_C
85 #ifdef AXISYMMETRIC
86 static inline constexpr int modelType = MatOps::MODEL_AXISYMMETRIC;
87 #else
88 static inline constexpr int modelType =
89 (SPACE_DIM == 3) ? MatOps::MODEL_3D : MatOps::MODEL_2D_PLANE_STRAIN;
90 #endif
91 boost::shared_ptr<MatOps::PhysicalEquations> physicalEquationsPtr;
92 boost::shared_ptr<MatOps::PhysicalEquations> physicalHuHuPtr;
93#endif
94
95 static auto get_skin(MoFEM::Interface &m_field, Range body_ents) {
96 Skinner skin(&m_field.get_moab());
97 Range skin_ents;
98 CHK_MOAB_THROW(skin.find_skin(0, body_ents, false, skin_ents), "find_skin");
99 return skin_ents;
100 };
101
102 static auto filter_true_skin(MoFEM::Interface &m_field, Range &&skin) {
103 Range boundary_ents;
104 ParallelComm *pcomm =
105 ParallelComm::get_pcomm(&m_field.get_moab(), MYPCOMM_INDEX);
106 CHK_MOAB_THROW(pcomm->filter_pstatus(skin,
107 PSTATUS_SHARED | PSTATUS_MULTISHARED,
108 PSTATUS_NOT, -1, &boundary_ents),
109 "filter_pstatus");
110 return boundary_ents;
111 };
112};
113
114//! [Run problem]
120
121 PetscBool test_op = PETSC_FALSE;
122 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-test_op", &test_op,
123 PETSC_NULLPTR);
124
125 if (useAdolcMaterial == PETSC_TRUE) {
127 } else {
129 }
130
131 if (test_op == PETSC_TRUE) {
132 CHKERR opTest();
133 }
134 CHKERR TsSolve();
139}
140//! [Run problem]
141
142//! [Read mesh]
145 auto simple = mField.getInterface<Simple>();
146 CHKERR simple->getOptions();
147 CHKERR simple->loadFile();
148 CHKERR mField.getInterface<MeshsetsManager>()->setMeshsetFromFile();
150}
151//! [Read mesh]
152
153//! [Set up problem]
156 Simple *simple = mField.getInterface<Simple>();
157
158 enum bases { AINSWORTH, DEMKOWICZ, LASBASETOPT };
159 const char *list_bases[LASBASETOPT] = {"ainsworth", "demkowicz"};
160 PetscInt choice_base_value = AINSWORTH;
161 CHKERR PetscOptionsGetEList(PETSC_NULLPTR, NULL, "-base", list_bases,
162 LASBASETOPT, &choice_base_value, PETSC_NULLPTR);
163
164 switch (choice_base_value) {
165 case AINSWORTH:
167 MOFEM_LOG("WORLD", Sev::inform)
168 << "Set AINSWORTH_LEGENDRE_BASE for displacements";
169 break;
170 case DEMKOWICZ:
172 MOFEM_LOG("WORLD", Sev::inform)
173 << "Set DEMKOWICZ_JACOBI_BASE for displacements";
174 break;
175 default:
177 break;
178 }
179
180 // Add field
181 CHKERR simple->addDomainField("U", H1, approximationBase, SPACE_DIM);
182 CHKERR simple->addBoundaryField("U", H1, approximationBase, SPACE_DIM);
183 CHKERR simple->addDataField("GEOMETRY", H1, approximationBase, SPACE_DIM);
184 int order = 2;
185 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-order", &order, PETSC_NULLPTR);
186 CHKERR simple->setFieldOrder("U", order);
187 CHKERR simple->setFieldOrder("GEOMETRY", 2);
188 CHKERR simple->setUp();
189
190 auto project_ho_geometry = [&]() {
191 Projection10NodeCoordsOnField ent_method(mField, "GEOMETRY");
192 return mField.loop_dofs("GEOMETRY", ent_method);
193 };
194 CHKERR project_ho_geometry();
195
196 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-use_adolc_material",
197 &useAdolcMaterial, PETSC_NULLPTR);
198#ifndef WITH_ADOL_C
199 if (useAdolcMaterial == PETSC_TRUE) {
200 SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
201 "ADOL-C support is not enabled. Please reconfigure with "
202 "-DWITH_ADOL_C=ON and recompile to use AdolC material model.");
203 }
204#endif
205 if (useAdolcMaterial == PETSC_TRUE) {
206 MOFEM_LOG("WORLD", Sev::inform) << "Use ADOL-C material model";
207 } else {
208 MOFEM_LOG("WORLD", Sev::inform) << "Use Hencky material model";
209 }
210
211 auto tag_meshest = [&]() {
213
214 auto set_block = [&](auto name, int dim) {
215 std::map<int, Range> map;
216 auto set_tag_impl = [&](auto name) {
218 auto mesh_mng = mField.getInterface<MeshsetsManager>();
219 auto bcs = mesh_mng->getCubitMeshsetPtr(
220
221 std::regex((boost::format("%s(.*)") % name).str())
222
223 );
224 std::map<int, int> ids_map;
225 int bit_id = 1;
226 for (auto bc : bcs) {
227 int id = bc->getMeshsetId();
228 ids_map[id] = bit_id;
229 bit_id <<= 1;
230 }
231 for (auto bc : bcs) {
232 Range r;
233 CHKERR bc->getMeshsetIdEntitiesByDimension(mField.get_moab(), dim, r,
234 true);
235 map[ids_map[bc->getMeshsetId()]] = r;
236 MOFEM_LOG("EXAMPLE", Sev::inform)
237 << "Block " << name << " id " << bc->getMeshsetId() << " : "
238 << ids_map[bc->getMeshsetId()] << " has " << r.size()
239 << " entities";
240 }
242 };
243
244 CHKERR set_tag_impl(name);
245
246 return std::make_pair(name, map);
247 };
248
249 auto set_skin = [&](auto &&map) {
250 for (auto &m : map.second) {
251 auto s = filter_true_skin(mField, get_skin(mField, m.second));
252 m.second.swap(s);
253 MOFEM_LOG("EXAMPLE", Sev::inform)
254 << "Skin for block " << map.first << " id " << m.first << " has "
255 << m.second.size() << " entities";
256 }
257 return map;
258 };
259
260 auto set_tag = [&](auto &&map) {
261 Tag th;
262 auto name = map.first;
263 int def_val[] = {-1};
264 CHK_MOAB_THROW(mField.get_moab().tag_get_handle(
265 name, 1, MB_TYPE_INTEGER, th,
266 MB_TAG_SPARSE | MB_TAG_CREAT, def_val),
267 "create tag");
268 for (auto &m : map.second) {
269 int id = m.first;
270 for (auto ent : m.second) {
271 int current_id;
273 mField.get_moab().tag_get_data(th, &ent, 1, &current_id),
274 "get tag data");
275 if (current_id != -1) {
276 id |= current_id;
277 }
278 CHK_MOAB_THROW(mField.get_moab().tag_set_data(th, &ent, 1, &id),
279 "set tag data");
280 }
281 }
282 return th;
283 };
284
285 if (SPACE_DIM == 3) {
286 listTagsToTransfer.push_back(set_tag(set_block("MAT_", 3)));
287 listTagsToTransfer.push_back(set_tag(set_skin(set_block("MAT_", 3))));
288 } else {
289 listTagsToTransfer.push_back(set_tag(set_block("MAT_", 2)));
290 }
291
293 };
294
295 CHKERR tag_meshest();
296
298}
299//! [Set up problem]
300
301//! [Boundary condition]
302
305 auto *pipeline_mng = mField.getInterface<PipelineManager>();
306 auto simple = mField.getInterface<Simple>();
307 auto bc_mng = mField.getInterface<BcManager>();
308 auto time_scale = boost::make_shared<ExampleTimeScale>();
309
311 pipeline_mng->getOpBoundaryRhsPipeline(), mField, "U", {time_scale},
312 "FORCE", "PRESSURE", Sev::inform);
313
314 //! [Define gravity vector]
316 pipeline_mng->getOpDomainRhsPipeline(), mField, "U", {time_scale},
317 "BODY_FORCE", Sev::inform);
318
319 // Essential BC
320 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "REMOVE_X",
321 "U", 0, 0);
322 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "REMOVE_Y",
323 "U", 1, 1);
324 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "REMOVE_Z",
325 "U", 2, 2);
326 CHKERR bc_mng->pushMarkDOFsOnEntities<DisplacementCubitBcData>(
327 simple->getProblemName(), "U");
328
330}
331//! [Boundary condition]
332
333//! [Push operators to pipeline]
336
337 auto *pipeline_mng = mField.getInterface<PipelineManager>();
338
339 auto integration_rule = [](int, int, int approx_order) {
340 return 2 * (approx_order - 1) + 1;
341 };
342
343 CHKERR pipeline_mng->setDomainRhsIntegrationRule(integration_rule);
344 CHKERR pipeline_mng->setDomainLhsIntegrationRule(integration_rule);
345 CHKERR pipeline_mng->setBoundaryRhsIntegrationRule(integration_rule);
346 CHKERR pipeline_mng->setEvaluationIntegrationRule(integration_rule);
347
348 auto add_domain_ops_lhs = [&](auto &pip) {
350 CHKERR AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(pip, {H1},
351 "GEOMETRY");
352 CHKERR
353 HenckyOps::opFactoryDomainLhs<SPACE_DIM, PETSC, GAUSS, DomainEleOp>(
354 mField, pip, "U", "MAT_ELASTIC", Sev::inform);
356 };
357
358 auto add_domain_ops_rhs = [&](auto &pip) {
360 CHKERR AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(pip, {H1},
361 "GEOMETRY");
362 CHKERR
363 HenckyOps::opFactoryDomainRhs<SPACE_DIM, PETSC, GAUSS, DomainEleOp>(
364 mField, pip, "U", "MAT_ELASTIC", Sev::inform);
366 };
367
368 CHKERR add_domain_ops_lhs(pipeline_mng->getOpDomainLhsPipeline());
369 CHKERR add_domain_ops_rhs(pipeline_mng->getOpDomainRhsPipeline());
370
371 // push operators to evaluation pipeline
372 CHKERR add_domain_ops_rhs(pipeline_mng->getOpEvaluationPipeline());
373 auto &domain_reaction_fe = pipeline_mng->getEvaluationFE();
374 domain_reaction_fe->postProcessHook =
375 EssentialPreProcReaction<DisplacementCubitBcData>(mField,
376 domain_reaction_fe);
377
378 PetscBool post_proc_vol;
379 PetscBool post_proc_skin;
380
381 if constexpr (SPACE_DIM == 2) {
382 post_proc_vol = PETSC_TRUE;
383 post_proc_skin = PETSC_FALSE;
384 } else {
385 post_proc_vol = PETSC_FALSE;
386 post_proc_skin = PETSC_TRUE;
387 }
388
389 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-post_proc_vol",
390 &post_proc_vol, PETSC_NULLPTR);
391 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-post_proc_skin",
392 &post_proc_skin, PETSC_NULLPTR);
393
394 // Setup postprocessing
395 auto create_post_proc_fe = [&]() {
396 auto post_proc_ele_domain = [this](auto &pip_domain) {
397 CHKERR AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(pip_domain, {H1},
398 "GEOMETRY");
399 auto common_ptr = commonDataFactory<SPACE_DIM, GAUSS, DomainEleOp>(
400 mField, pip_domain, "U", "MAT_ELASTIC", Sev::inform);
401 return common_ptr;
402 };
403
404 auto post_proc_map = [&](auto &pip, auto u_ptr, auto common_ptr) {
406
407 using OpPPMap = OpPostProcMapInMoab<SPACE_DIM, SPACE_DIM>;
408
409 pip->getOpPtrVector().push_back(
410
411 new OpPPMap(pip->getPostProcMesh(), pip->getMapGaussPts(), {},
412 {{"U", u_ptr}},
413 {{"GRAD", common_ptr->matGradPtr},
414 {"FIRST_PIOLA", common_ptr->getMatFirstPiolaStress()}},
415 {}));
417 };
418
419 auto push_post_proc_bdy = [&](auto &pip_bdy) {
420 if (post_proc_skin == PETSC_FALSE)
421 return boost::shared_ptr<PostProcEleBdy>();
422 auto simple = mField.getInterface<Simple>();
423 auto domain_fe_name = simple->getDomainFEName();
424 auto u_ptr = boost::make_shared<MatrixDouble>();
425 pip_bdy->getOpPtrVector().push_back(
426 new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_ptr));
427 auto op_loop_side =
428 new OpLoopSide<SideEle>(mField, domain_fe_name, SPACE_DIM);
429 auto common_ptr = post_proc_ele_domain(op_loop_side->getOpPtrVector());
430 pip_bdy->getOpPtrVector().push_back(op_loop_side);
431 CHKERR post_proc_map(pip_bdy, u_ptr, common_ptr);
432 return pip_bdy;
433 };
434
435 auto push_post_proc_domain = [&](auto &pip_domain) {
436 if (post_proc_vol == PETSC_FALSE)
437 return boost::shared_ptr<PostProcEleDomain>();
438
439 auto u_ptr = boost::make_shared<MatrixDouble>();
440 pip_domain->getOpPtrVector().push_back(
441 new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_ptr));
442 auto common_ptr = post_proc_ele_domain(pip_domain->getOpPtrVector());
443
444 CHKERR post_proc_map(pip_domain, u_ptr, common_ptr);
445
446 return pip_domain;
447 };
448
449 auto post_proc_fe_domain = boost::make_shared<PostProcEleDomain>(mField);
450 auto post_proc_fe_bdy = boost::make_shared<PostProcEleBdy>(mField);
451
452 return std::make_pair(push_post_proc_domain(post_proc_fe_domain),
453 push_post_proc_bdy(post_proc_fe_bdy));
454 };
455
456 auto post_proc_pair = create_post_proc_fe();
457 postProcDomainFe = post_proc_pair.first;
458 postProcBdyFe = post_proc_pair.second;
459
461}
462//! [Push operators to pipeline]
463
466
467 // get operators tester
468 auto simple = mField.getInterface<Simple>();
469 auto opt = mField.getInterface<OperatorsTester>(); // get interface to
470 // OperatorsTester
471 auto pip = mField.getInterface<PipelineManager>(); // get interface to
472 // pipeline manager
473
474 constexpr double eps = 1e-9;
475
476 auto x = opt->setRandomFields(simple->getDM(), {
477
478 {"U", {-1e-6, 1e-6}}
479
480 });
481
482 auto dot_x = opt->setRandomFields(simple->getDM(), {
483
484 {"U", {-1, 1}}
485
486 });
487
488 auto diff_x = opt->setRandomFields(simple->getDM(), {
489
490 {"U", {-1, 1}}
491
492 });
493
494 auto test_domain_ops = [&](auto fe_name, auto lhs_pipeline,
495 auto rhs_pipeline) {
497
498 auto diff_res = opt->checkCentralFiniteDifference(
499 simple->getDM(), fe_name, rhs_pipeline, lhs_pipeline, x, dot_x,
500 SmartPetscObj<Vec>(), diff_x, 0, 0.5, eps);
501
502 // Calculate norm of difference between directional derivative calculated
503 // from finite difference, and tangent matrix.
504 double fnorm;
505 CHKERR VecNorm(diff_res, NORM_2, &fnorm);
506 MOFEM_LOG_C("EXAMPLE", Sev::inform,
507 "Test consistency of tangent matrix %3.4e", fnorm);
508
509 CHKERR mField.getInterface<TestingInterface>()
510 ->checkError<TestType::DERIVATIVE>("domain tangent", fnorm, 0.,
511 {1e-5, 0.});
512
514 };
515
516 MOFEM_LOG("EXAMPLE", Sev::inform)
517 << "Test operators with finite difference of directional "
518 "derivative";
519 CHKERR test_domain_ops(simple->getDomainFEName(), pip->getDomainLhsFE(),
520 pip->getDomainRhsFE());
521
523}
524
527
528 auto *simple = mField.getInterface<Simple>();
529 auto *pipeline_mng = mField.getInterface<PipelineManager>();
530
531 auto integration_rule = [](int, int, int approx_order) {
532 return 2 * (approx_order - 1) + 1;
533 };
534
535 CHKERR pipeline_mng->setDomainRhsIntegrationRule(integration_rule);
536 CHKERR pipeline_mng->setDomainLhsIntegrationRule(integration_rule);
537 CHKERR pipeline_mng->setBoundaryRhsIntegrationRule(integration_rule);
538 CHKERR pipeline_mng->setEvaluationIntegrationRule(integration_rule);
539
540#ifdef WITH_ADOL_C
541 auto mat_ops_data_ptr = MatOps::createMatOpsDataPtr();
542
543 #ifdef WITH_ADOL_C_UMAT
544 {
545 constexpr int umat_model_type =
547 auto umat_physical_equations_ptr =
548 MatOps::createMatOpsPhysicalEquationsPtr<MatOps::UMAT, umat_model_type>(
549 mat_ops_data_ptr, MatOps::MatOpsTagsRegistry::setTagName("Umat"));
550
551 CHKERR umat_physical_equations_ptr->getOptions(&mField);
552 CHKERR umat_physical_equations_ptr->recordTape();
553
554 physicalEquationsPtr = umat_physical_equations_ptr;
555 }
556 #else
560 modelType>(
561 mat_ops_data_ptr,
562 MatOps::MatOpsTagsRegistry::setTagName("MetaPiolaResponse", 0));
563 }
564
565 #ifdef WITH_ADOL_C_GENERIC_ELASTIC
566 {
567 auto generic_physical_equations_ptr =
569 modelType>(
570 mat_ops_data_ptr,
572
574 // In example, lets do a simple linear elastic material, so we can verify the tangent matrix
575 generic_physical_equations_ptr->hookEvaluateVariable =
577 generic_physical_equations_ptr->hookEvaluateDerivatives =
579 generic_physical_equations_ptr->hookUpdateState =
581
582 CHKERR generic_physical_equations_ptr->getOptions(&mField);
583 CHKERR generic_physical_equations_ptr->recordTape();
584
585 auto &material_map = getMetaPiolaResponseMap(
586 boost::static_pointer_cast<MatOps::MatPiolaResponse>(
588 material_map[generic_physical_equations_ptr->tAg] =
589 boost::static_pointer_cast<MatOps::MatPiolaResponse>(
590 generic_physical_equations_ptr);
591 physicalEquationsPtr->tAg = generic_physical_equations_ptr->tAg;
592 }
593 #endif // WITH_ADOL_C_GENERIC_ELASTIC
594
595 #ifdef WITH_ADOL_C_SIMPLE_DAMAGE
596 {
597 auto generic_physical_equations_ptr =
599 modelType>(
601 "GenericElasticSimpleDamage"));
602
604 mField, boost::dynamic_pointer_cast<MatOps::GenericElastic>(
605 generic_physical_equations_ptr));
606
607 CHKERR generic_physical_equations_ptr->getOptions(&mField);
608 CHKERR generic_physical_equations_ptr->recordTape();
609
610 auto &material_map = getMetaPiolaResponseMap(
611 boost::static_pointer_cast<MatOps::MatPiolaResponse>(
613 material_map[generic_physical_equations_ptr->tAg] =
614 boost::static_pointer_cast<MatOps::MatPiolaResponse>(
615 generic_physical_equations_ptr);
616 physicalEquationsPtr->tAg = generic_physical_equations_ptr->tAg;
617 }
618 #endif // WITH_ADOL_C_SIMPLE_DAMAGE
619
621 CHKERR physicalEquationsPtr->getOptions(&mField);
622 CHKERR physicalEquationsPtr->recordTape();
623 }
624
625 if (!physicalHuHuPtr && !mField.getInterface<MeshsetsManager>()
626 ->getCubitMeshsetPtr(std::regex("MAT_HUHU(.*)"))
627 .empty()) {
628 const int tag_hu_hu = MatOps::MatOpsTagsRegistry::setTagName("HuHU");
630 MatOps::createMatOpsPhysicalEquationsPtr<MatOps::HUHU, modelType>(
631 MatOps::createMatOpsDataPtr(), tag_hu_hu);
632 CHKERR physicalHuHuPtr->getOptions(&mField);
633 CHKERR physicalHuHuPtr->recordTape();
634 }
635 #endif // WITH_ADOL_C_UMAT
636
637 auto add_domain_ops_lhs = [&](auto &pip) {
639 CHKERR AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(pip, {H1},
640 "GEOMETRY");
643 template opLhsFactory<PETSC, GAUSS, DomainEleOp>(
644 mField, pip, "U", physicalEquationsPtr);
645 }
646 if (physicalHuHuPtr) {
648 template opLhsFactory<PETSC, GAUSS, DomainEleOp>(
649 mField, pip, simple->getDomainFEName(), "U", physicalHuHuPtr);
650 }
652 };
653
654 auto add_domain_ops_rhs = [&](auto &pip) {
656 CHKERR AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(pip, {H1},
657 "GEOMETRY");
660 template opRhsFactory<PETSC, GAUSS, DomainEleOp>(
661 mField, pip, "U", physicalEquationsPtr);
662 }
663 if (physicalHuHuPtr) {
665 template opRhsFactory<PETSC, GAUSS, DomainEleOp>(
666 mField, pip, simple->getDomainFEName(), "U", physicalHuHuPtr);
667 }
669 };
670
671 auto add_domain_ops_update = [&](auto &pip) {
673 CHKERR AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(pip, {H1},
674 "GEOMETRY");
678 }
680 };
681
682 CHKERR add_domain_ops_lhs(pipeline_mng->getOpDomainLhsPipeline());
683 CHKERR add_domain_ops_rhs(pipeline_mng->getOpDomainRhsPipeline());
684
685 updateFe = boost::make_shared<DomainEle>(mField);
686 updateFe->getRuleHook = integration_rule;
687 CHKERR add_domain_ops_update(updateFe->getOpPtrVector());
688
689 CHKERR add_domain_ops_rhs(pipeline_mng->getOpEvaluationPipeline());
690 auto &domain_reaction_fe = pipeline_mng->getEvaluationFE();
691 domain_reaction_fe->postProcessHook =
692 EssentialPreProcReaction<DisplacementCubitBcData>(mField,
693 domain_reaction_fe);
694
695 PetscBool post_proc_vol;
696 PetscBool post_proc_skin;
697
698 if constexpr (SPACE_DIM == 2) {
699 post_proc_vol = PETSC_TRUE;
700 post_proc_skin = PETSC_FALSE;
701 } else {
702 post_proc_vol = PETSC_FALSE;
703 post_proc_skin = PETSC_TRUE;
704 }
705
706 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-post_proc_vol",
707 &post_proc_vol, PETSC_NULLPTR);
708 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-post_proc_skin",
709 &post_proc_skin, PETSC_NULLPTR);
710
711 // Setup postprocessing
712 auto create_post_proc_fe = [&]() {
713 using OpPPMap = OpPostProcMapInMoab<SPACE_DIM, SPACE_DIM>;
714
715 auto post_proc_ele_domain = [&](auto &pip_domain) {
717 CHKERR AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(pip_domain, {H1},
718 "GEOMETRY");
722 }
724 };
725
726 auto post_proc_map = [&](auto &pip, auto u_ptr) {
729 auto grad_ptr =
730 physicalEquationsPtr->matOpsDataPtr->getCommonDataPtr("grad");
731 auto first_piola_ptr =
732 physicalEquationsPtr->matOpsDataPtr->getCommonDataPtr("P");
733 pip->getOpPtrVector().push_back(new OpPPMap(pip->getPostProcMesh(),
734 pip->getMapGaussPts(), {},
735 {{"U", u_ptr}}, {}, {}));
736 pip->getOpPtrVector().push_back(
737 new OpPostProcMapInMoab<MAT_DIM, MAT_DIM>(
738 pip->getPostProcMesh(), pip->getMapGaussPts(), {}, {},
739 {{"GRAD", grad_ptr}, {"FIRST_PIOLA", first_piola_ptr}}, {}));
740 }
742 };
743
744 auto push_post_proc_bdy = [&](auto &pip_bdy) {
745 if (post_proc_skin == PETSC_FALSE)
746 return boost::shared_ptr<PostProcEleBdy>();
747 auto simple = mField.getInterface<Simple>();
748 auto domain_fe_name = simple->getDomainFEName();
749 auto u_ptr = boost::make_shared<MatrixDouble>();
750 pip_bdy->getOpPtrVector().push_back(
751 new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_ptr));
752 auto op_loop_side =
753 new OpLoopSide<SideEle>(mField, domain_fe_name, SPACE_DIM);
754 CHKERR post_proc_ele_domain(op_loop_side->getOpPtrVector());
755 pip_bdy->getOpPtrVector().push_back(op_loop_side);
756 CHKERR post_proc_map(pip_bdy, u_ptr);
757 return pip_bdy;
758 };
759
760 auto push_post_proc_domain = [&](auto &pip_domain) {
761 if (post_proc_vol == PETSC_FALSE)
762 return boost::shared_ptr<PostProcEleDomain>();
763 auto u_ptr = boost::make_shared<MatrixDouble>();
764 pip_domain->getOpPtrVector().push_back(
765 new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_ptr));
766 CHKERR post_proc_ele_domain(pip_domain->getOpPtrVector());
767
768 if (physicalEquationsPtr) {
769 auto state_tags = physicalEquationsPtr->matOpsDataPtr->getStateTags();
770 if (!state_tags.empty()) {
771 MatOps::StateTags selected_state_tags;
772 MatOps::StateTags statev_tags;
773 selected_state_tags.reserve(state_tags.size());
774 statev_tags.reserve(state_tags.size());
775
776 constexpr auto statev_prefix = "UMAT_STATEV_";
777 constexpr auto statev_prefix_len = sizeof("UMAT_STATEV_") - 1;
778 auto get_statev_index = [&](const std::string &name) {
779 return std::stoi(name.substr(statev_prefix_len));
780 };
781
782 for (const auto &state_tag : state_tags) {
783 const auto &name = state_tag.name;
784
785 if (name == "UMAT_DFGRD0" || name == "UMAT_STRESS") {
786 selected_state_tags.push_back(state_tag);
787 continue;
788 }
789
790 if (name.rfind(statev_prefix, 0) == 0) {
791 statev_tags.push_back(state_tag);
792 }
793 }
794
795 std::sort(statev_tags.begin(), statev_tags.end(),
796 [&](const auto &lhs, const auto &rhs) {
797 return get_statev_index(lhs.name) <
798 get_statev_index(rhs.name);
799 });
800 if (statev_tags.size() > 10)
801 statev_tags.resize(10);
802 selected_state_tags.insert(selected_state_tags.end(),
803 statev_tags.begin(), statev_tags.end());
804
805 if (selected_state_tags.empty())
806 return pip_domain;
807
808 auto simple = mField.getInterface<Simple>();
809 int state_order = 2;
810 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-order", &state_order,
811 PETSC_NULLPTR);
812 auto op_loop_this = new OpLoopThis<DomainEle>(
813 mField, simple->getDomainFEName(), Sev::noisy);
814 op_loop_this->getThisFEPtr()->getRuleHook = integration_rule;
815 pip_domain->getOpPtrVector().push_back(op_loop_this);
816 CHKERR addTagDGProjectionOps<SPACE_DIM, SPACE_DIM>(
817 mField.get_moab(), pip_domain->getOpPtrVector(),
818 op_loop_this->getThisFEPtr()->getOpPtrVector(),
819 pip_domain->getPostProcMesh(), pip_domain->getMapGaussPts(),
820 selected_state_tags, state_order, approximationBase);
821 }
822 }
823
824 CHKERR post_proc_map(pip_domain, u_ptr);
825
826 return pip_domain;
827 };
828
829 auto post_proc_fe_domain = boost::make_shared<PostProcEleDomain>(mField);
830 auto post_proc_fe_bdy = boost::make_shared<PostProcEleBdy>(mField);
831
832 return std::make_pair(push_post_proc_domain(post_proc_fe_domain),
833 push_post_proc_bdy(post_proc_fe_bdy));
834 };
835
836 auto post_proc_pair = create_post_proc_fe();
837 postProcDomainFe = post_proc_pair.first;
838 postProcBdyFe = post_proc_pair.second;
839
840#else
841 SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
842 "ADOL-C support is not enabled. Please reconfigure with "
843 "-DWITH_ADOL_C=ON and recompile to use AdolC material model.");
844
845#endif // WITH_ADOL
847}
848
849//! [TS Solve]
852 auto *simple = mField.getInterface<Simple>();
853 auto *pipeline_mng = mField.getInterface<PipelineManager>();
854
855 auto dm = simple->getDM();
856 auto ts = pipeline_mng->createTSIM();
857
858 auto add_extra_finite_elements_to_solver_pipelines = [&]() {
860
861 auto pre_proc_ptr = boost::make_shared<FEMethod>();
862 auto post_proc_rhs_ptr = boost::make_shared<FEMethod>();
863 auto post_proc_lhs_ptr = boost::make_shared<FEMethod>();
864
865 auto time_scale = boost::make_shared<ExampleTimeScale>();
866
867 auto get_bc_hook_rhs = [this, pre_proc_ptr, time_scale]() {
869 CHKERR EssentialPreProc<DisplacementCubitBcData>(mField, pre_proc_ptr,
870 {time_scale}, false)();
872 };
873
874 pre_proc_ptr->preProcessHook = get_bc_hook_rhs;
875
876 auto get_post_proc_hook_rhs = [this, post_proc_rhs_ptr]() {
878 CHKERR EssentialPreProcReaction<DisplacementCubitBcData>(
879 mField, post_proc_rhs_ptr, nullptr, Sev::verbose)();
880 CHKERR EssentialPostProcRhs<DisplacementCubitBcData>(
881 mField, post_proc_rhs_ptr, 1.)();
883 };
884 auto get_post_proc_hook_lhs = [this, post_proc_lhs_ptr]() {
886 CHKERR EssentialPostProcLhs<DisplacementCubitBcData>(
887 mField, post_proc_lhs_ptr, 1.)();
889 };
890 post_proc_rhs_ptr->postProcessHook = get_post_proc_hook_rhs;
891 post_proc_lhs_ptr->postProcessHook = get_post_proc_hook_lhs;
892
893 // This is low level pushing finite elements (pipelines) to solver
894 auto ts_ctx_ptr = getDMTsCtx(simple->getDM());
895 ts_ctx_ptr->getPreProcessIFunction().push_front(pre_proc_ptr);
896 ts_ctx_ptr->getPreProcessIJacobian().push_front(pre_proc_ptr);
897 ts_ctx_ptr->getPostProcessIFunction().push_back(post_proc_rhs_ptr);
898 ts_ctx_ptr->getPostProcessIJacobian().push_back(post_proc_lhs_ptr);
900 };
901
902 // Add extra finite elements to SNES solver pipelines to resolve essential
903 // boundary conditions
904 CHKERR add_extra_finite_elements_to_solver_pipelines();
905
906 auto create_monitor_fe = [dm](auto &&post_proc_fe) {
907 return boost::make_shared<Monitor>(dm.get(), post_proc_fe);
908 };
909
910 // Set monitor which postprocessing results and saves them to the hard drive
911 boost::shared_ptr<FEMethod> null_fe;
913 CHKERR postProcDomainFe->setTagsToTransfer(
914 std::vector<Tag>(listTagsToTransfer));
915 if (postProcBdyFe)
916 CHKERR postProcBdyFe->setTagsToTransfer(
917 std::vector<Tag>(listTagsToTransfer));
918 auto monitor_ptr =
919 create_monitor_fe(std::make_pair(postProcDomainFe, postProcBdyFe));
920 CHKERR DMMoFEMTSSetMonitor(dm, ts, simple->getDomainFEName(), null_fe,
921 null_fe, monitor_ptr);
922
923 // Set time solver
924 double ftime = 1;
925 CHKERR TSSetMaxTime(ts, ftime);
926 CHKERR TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP);
927
928 auto B = createDMMatrix(dm);
929 CHKERR TSSetI2Jacobian(ts, B, B, PETSC_NULLPTR, PETSC_NULLPTR);
930 auto D = createDMVector(simple->getDM());
931 CHKERR TSSetSolution(ts, D);
932 CHKERR TSSetFromOptions(ts);
933
934 PetscBool test_steps = PETSC_FALSE;
935 PetscBool test_piola_stress = PETSC_FALSE;
936 CHKERR PetscOptionsGetBool(nullptr, "", "-test_piola_stress",
937 &test_piola_stress, nullptr);
938 CHKERR PetscOptionsGetBool(nullptr, "", "-test_step_monitor", &test_steps,
939 nullptr);
940
941 const bool check_steps = test_steps || test_piola_stress;
942
943 auto check_piola_stress = [this](PetscReal time) {
945 auto simple = mField.getInterface<Simple>();
946
951
952 auto displacement_ptr = boost::make_shared<MatrixDouble>();
953
954 // These homogeneous cube fixtures prescribe Fzz = 1 - 0.1 * load time.
955 const double applied_F_zz = 1. - 0.1 * time;
956
957 t_P_expected(i, J) = 0.;
958 auto set_linear_elastic_piola = [&](const double strain_zz,
959 const double d_strain_d_F_zz) {
960 constexpr double E = 1.;
961 constexpr double nu = 0.3;
962 const double lambda = E * nu / ((1. + nu) * (1. - 2. * nu));
963 const double mu = E / (2. * (1. + nu));
964 for (int d = 0; d != SPACE_DIM - 1; ++d)
965 t_P_expected(d, d) = lambda * strain_zz;
966 t_P_expected(SPACE_DIM - 1, SPACE_DIM - 1) =
967 (lambda + 2. * mu) * strain_zz * d_strain_d_F_zz;
968 };
969
970#ifndef AXISYMMETRIC
971 auto set_neohookean_piola = [&](const double F_zz, const double J) {
972 constexpr double c10 = 1.;
973 constexpr double K = 1.;
974 double I1 = (SPACE_DIM - 1) + F_zz * F_zz;
975 if constexpr (SPACE_DIM == 2)
976 I1 += 1.; // Plane strain has F33 = 1.
977 const double J_to_minus_two_thirds = std::pow(J, -2. / 3.);
978 for (int d = 0; d != SPACE_DIM; ++d) {
979 const double F_dd = d == SPACE_DIM - 1 ? F_zz : 1.;
980 const double inv_F_dd = 1. / F_dd;
981 t_P_expected(d, d) =
982 2. * c10 * J_to_minus_two_thirds * (F_dd - (I1 / 3.) * inv_F_dd) +
983 K * J * (J - 1.) * inv_F_dd;
984 }
985 };
986
987#endif
988
989 auto eval_piola_at_point = [&](boost::shared_ptr<MatrixDouble> &mat_p,
990 std::array<double, 3> field_eval_coords) {
992 CHKERR mField.getInterface<TestingInterface>()
993 ->addFieldEvaluator<SPACE_DIM>(
994 simple->getProblemName(), simple->getDomainFEName(),
995 field_eval_coords, [&](auto &pipeline) {
997 CHKERR AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
998 pipeline, {H1}, "GEOMETRY");
999
1000 pipeline.push_back(new OpCalculateVectorFieldValues<SPACE_DIM>(
1001 "U", displacement_ptr));
1002
1003 if (useAdolcMaterial == PETSC_FALSE) {
1004 auto common_ptr =
1005 commonDataFactory<SPACE_DIM, GAUSS, DomainEleOp>(
1006 mField, pipeline, "U", "MAT_ELASTIC", Sev::inform);
1007 mat_p = common_ptr->getMatFirstPiolaStress();
1008 } else {
1009#ifdef WITH_ADOL_C
1012 modelType>::opPostProcFactory(mField, pipeline, "U",
1014 mat_p = physicalEquationsPtr->matOpsDataPtr->getCommonDataPtr(
1015 "P");
1016#else
1017 SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
1018 "ADOL-C support is not enabled. Please reconfigure with "
1019 "-DWITH_ADOL_C=ON and recompile to use MatOps material model.");
1020#endif
1021 }
1023 });
1025 };
1026
1027 boost::shared_ptr<MatrixDouble> mat_p;
1028 using DL = DataLayoutTraits<DataLayout::GaussByCoeffs>;
1029 // Infer the homogeneous fixture's response from the configured material
1030 // dispatcher. The default MetaPiolaResponse tag represents Neo-Hookean.
1031 std::string material_name = "Hencky";
1032#ifdef WITH_ADOL_C
1033 if (useAdolcMaterial) {
1034 int material_tag = physicalEquationsPtr->tAg;
1035 bool found_range = false;
1036 if (physicalEquationsPtr->tagVsRangePtr) {
1037 for (const auto &[tag, range] : *physicalEquationsPtr->tagVsRangePtr) {
1038 if (range.empty())
1039 continue;
1040 if (found_range && tag != material_tag)
1042 "The analytical fixture requires a homogeneous material");
1043 material_tag = tag;
1044 found_range = true;
1045 }
1046 }
1047 material_name = MatOps::MatOpsTagsRegistry::getTagName(material_tag);
1048 }
1049#endif
1050
1051#ifdef AXISYMMETRIC
1052 if (material_name != "MetaPiolaResponse")
1053 SETERRQ(
1055 "The axisymmetric analytical fixture requires Neo-Hookean material");
1056#endif
1057
1058 if (material_name == "Hencky") {
1059 // Homogeneous cube: E = 1, nu = 0.3.
1060 set_linear_elastic_piola(std::log(applied_F_zz), 1. / applied_F_zz);
1061 } else if (material_name == "MetaPiolaResponse") {
1062#ifdef AXISYMMETRIC
1063 // Uniform expansion, c10 = K = 1, including hoop stretch. The
1064 // deviatoric stress vanishes; P = K J (J - 1) F^{-T}.
1065 const double stretch = 1. + 0.01 * time;
1066 const double jacobian = stretch * stretch * stretch;
1067 const double piola = jacobian * (jacobian - 1.) / stretch;
1069 t_P_expected(i, J) = piola * delta(i, J);
1070 CHKERR eval_piola_at_point(mat_p, {1.37, 0.41, 0.});
1071 auto t_u = MatrixSizeHelper<GetFTensor1FromMatType<2, -1, DL>, DL>::get(
1072 *displacement_ptr, 1)();
1073 const double u_err = std::hypot(t_u(0) - (stretch - 1.) * 1.37,
1074 t_u(1) - (stretch - 1.) * 0.41);
1075 CHKERR mField.getInterface<TestingInterface>()
1076 ->checkError<TestType::POINTWISE>("axisymmetric displacement", u_err,
1077 0., {1e-8, 0.});
1078#else
1079 set_neohookean_piola(applied_F_zz, applied_F_zz);
1080#endif
1081 } else if (material_name == "Umat") {
1082 // Reference for this tutorial's linear-elastic UMAT fixture only.
1083 char strain_type[32] = "small";
1084 CHKERR PetscOptionsGetString(nullptr, "", "-umat_strain_type",
1085 strain_type, sizeof(strain_type), nullptr);
1086 if (std::string(strain_type) != "small")
1088 "The analytical UMAT fixture requires small strain");
1089 set_linear_elastic_piola(applied_F_zz - 1., 1.);
1090 } else {
1092 "No analytical fixture for material %s", material_name.c_str());
1093 }
1094
1095 if (!mat_p)
1096 CHKERR eval_piola_at_point(mat_p, {0.123, -0.087, 0.193});
1097 auto t_P =
1098 MatrixSizeHelper<GetFTensor2FromMatType<MAT_DIM, MAT_DIM, -1, DL>,
1099 DL>::get(*mat_p, 1)();
1100 t_P_diff(i, J) = t_P(i, J) - t_P_expected(i, J);
1101 const double p_err = std::sqrt(t_P_diff(i, J) * t_P_diff(i, J));
1102 for (int r = 0; r != MAT_DIM; ++r)
1103 for (int c = 0; c != MAT_DIM; ++c)
1104 MOFEM_LOG("EXAMPLE", Sev::inform)
1105 << "Piola stress (" << material_name << ") P(" << r << ", " << c
1106 << ") actual " << std::scientific << t_P(r, c) << " expected "
1107 << t_P_expected(r, c) << " diff " << t_P_diff(r, c);
1108 MOFEM_LOG("EXAMPLE", Sev::inform) << "Piola stress (" << material_name
1109 << ") error " << std::scientific << p_err;
1110 CHKERR mField.getInterface<TestingInterface>()
1111 ->checkError<TestType::POINTWISE>("Piola stress", p_err, 0.,
1112 {1e-8, 0.});
1113
1115 };
1116
1117 if (check_steps) {
1118 CHKERR mField.getInterface<TestingInterface>()->addTSMonitor(
1119 ts, [this, check_piola_stress](TS, PetscInt step, PetscReal time,
1120 Vec solution) {
1122 auto simple = mField.getInterface<Simple>();
1123 CHKERR VecGhostUpdateBegin(solution, INSERT_VALUES, SCATTER_FORWARD);
1124 CHKERR VecGhostUpdateEnd(solution, INSERT_VALUES, SCATTER_FORWARD);
1125 CHKERR DMoFEMMeshToLocalVector(simple->getDM(), solution,
1126 INSERT_VALUES, SCATTER_REVERSE);
1127 CHKERR check_piola_stress(time);
1128 MOFEM_LOG("EXAMPLE", Sev::inform)
1129 << "Numerical checks passed at TS step " << step << ", time "
1130 << time;
1132 });
1133 }
1134
1136 CHKERR TSSetPreStep(ts, TSElasticPostStep::preStepFun);
1137 CHKERR TSSetPostStep(ts, TSElasticPostStep::postStepFun);
1138 const auto solve_error = TSSolve(ts, nullptr);
1140 CHKERR solve_error;
1141
1142 // Solver convergence is cheap to check and carries no magic numbers, so it
1143 // stands alone right after the solve rather than being deferred to
1144 // checkResults() through stored state.
1145 {
1146 PetscReal expected_time;
1147 CHKERR TSGetMaxTime(ts, &expected_time);
1148 auto testing = mField.getInterface<TestingInterface>();
1149 CHKERR testing->checkSolver(ts, expected_time, {1e-12, 1e-12},
1150 "nonlinear elasticity");
1151 }
1152
1153 CHKERR TSGetTime(ts, &ftime);
1154
1155 PetscInt steps, snesfails, rejects, nonlinits, linits;
1156 CHKERR TSGetStepNumber(ts, &steps);
1157 CHKERR TSGetSNESFailures(ts, &snesfails);
1158 CHKERR TSGetStepRejections(ts, &rejects);
1159 CHKERR TSGetSNESIterations(ts, &nonlinits);
1160 CHKERR TSGetKSPIterations(ts, &linits);
1161 MOFEM_LOG_C("EXAMPLE", Sev::inform,
1162 "steps %d (%d rejected, %d SNES fails), ftime %g, nonlinits "
1163 "%d, linits %d",
1164 steps, rejects, snesfails, ftime, nonlinits, linits);
1165
1167}
1168//! [TS Solve]
1169
1170//! [Getting norms]
1173
1174 auto simple = mField.getInterface<Simple>();
1175 auto dm = simple->getDM();
1176
1177 auto T = createDMVector(simple->getDM());
1178 CHKERR DMoFEMMeshToLocalVector(simple->getDM(), T, INSERT_VALUES,
1179 SCATTER_FORWARD);
1180 double nrm2;
1181 CHKERR VecNorm(T, NORM_2, &nrm2);
1182 MOFEM_LOG("EXAMPLE", Sev::inform) << "Solution norm " << nrm2;
1183
1184 auto post_proc_norm_fe = boost::make_shared<DomainEle>(mField);
1185
1186 auto post_proc_norm_rule_hook = [](int, int, int p) -> int { return 2 * p; };
1187 post_proc_norm_fe->getRuleHook = post_proc_norm_rule_hook;
1188
1189 CHKERR AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
1190 post_proc_norm_fe->getOpPtrVector(), {H1}, "GEOMETRY");
1191
1192 enum NORMS { U_NORM_L2 = 0, PIOLA_NORM, LAST_NORM };
1193 auto norms_vec =
1194 createVectorMPI(mField.get_comm(),
1195 (mField.get_comm_rank() == 0) ? LAST_NORM : 0, LAST_NORM);
1196 CHKERR VecZeroEntries(norms_vec);
1197
1198 auto u_ptr = boost::make_shared<MatrixDouble>();
1199 post_proc_norm_fe->getOpPtrVector().push_back(
1200 new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_ptr));
1201
1202 post_proc_norm_fe->getOpPtrVector().push_back(
1203 new OpCalcNormL2Tensor1<SPACE_DIM>(u_ptr, norms_vec, U_NORM_L2));
1204
1205 if (useAdolcMaterial == PETSC_TRUE) {
1206#ifdef WITH_ADOL_C
1209 opPostProcFactory(mField, post_proc_norm_fe->getOpPtrVector(), "U",
1211 auto m_P = physicalEquationsPtr->matOpsDataPtr->getCommonDataPtr("P");
1212 post_proc_norm_fe->getOpPtrVector().push_back(
1213 new OpCalcNormL2Tensor2<MAT_DIM, MAT_DIM>(m_P, norms_vec,
1214 PIOLA_NORM));
1215 }
1216#else
1217 SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
1218 "ADOL-C support is not enabled. Please reconfigure with "
1219 "-DWITH_ADOL_C=ON and recompile to use AdolC material model.");
1220#endif
1221 } else {
1222 auto common_ptr = commonDataFactory<SPACE_DIM, GAUSS, DomainEleOp>(
1223 mField, post_proc_norm_fe->getOpPtrVector(), "U", "MAT_ELASTIC",
1224 Sev::inform);
1225 post_proc_norm_fe->getOpPtrVector().push_back(
1226 new OpCalcNormL2Tensor2<SPACE_DIM, SPACE_DIM>(
1227 common_ptr->getMatFirstPiolaStress(), norms_vec, PIOLA_NORM));
1228 }
1229
1230 CHKERR DMoFEMLoopFiniteElements(dm, simple->getDomainFEName(),
1231 post_proc_norm_fe);
1232
1233 CHKERR VecAssemblyBegin(norms_vec);
1234 CHKERR VecAssemblyEnd(norms_vec);
1235
1236 MOFEM_LOG_CHANNEL("SELF"); // Clear channel from old tags
1237 if (mField.get_comm_rank() == 0) {
1238 const double *norms;
1239 CHKERR VecGetArrayRead(norms_vec, &norms);
1240 MOFEM_TAG_AND_LOG("SELF", Sev::inform, "example")
1241 << "norm_u: " << std::scientific << std::sqrt(norms[U_NORM_L2]);
1242 MOFEM_TAG_AND_LOG("SELF", Sev::inform, "example")
1243 << "norm_piola: " << std::scientific << std::sqrt(norms[PIOLA_NORM]);
1244 CHKERR VecRestoreArrayRead(norms_vec, &norms);
1245 }
1246
1248}
1249//! [Getting norms]
1250
1251//! [Postprocessing results]
1256//! [Postprocessing results]
1257
1258//! [Check]
1261 auto testing = mField.getInterface<TestingInterface>();
1262
1263 // -test_solution_norm <value> both supplies the golden value and is the
1264 // trigger for this check, so it is read right here, where it is used,
1265 // rather than through addTestCommandLine's own "-test_nb"/"-test_name"
1266 // selectors, and rather than a class member set earlier in runProblem().
1267 PetscReal expected_solution_norm = 0;
1268 PetscBool test_solution_norm = PETSC_FALSE;
1269 CHKERR PetscOptionsGetReal(nullptr, "", "-test_solution_norm",
1270 &expected_solution_norm, &test_solution_norm);
1271 if (test_solution_norm) {
1272 CHKERR testing->addTest(1, "solution coefficient norm", [&]() {
1274 auto simple = mField.getInterface<Simple>();
1275 auto T = createDMVector(simple->getDM());
1276 CHKERR DMoFEMMeshToLocalVector(simple->getDM(), T, INSERT_VALUES,
1277 SCATTER_FORWARD);
1278 double nrm2;
1279 CHKERR VecNorm(T, NORM_2, &nrm2);
1280 MOFEM_LOG("EXAMPLE", Sev::verbose) << "Regression norm " << nrm2;
1281 CHKERR testing->checkValue<TestType::SCALAR>("solution coefficient norm",
1282 nrm2, expected_solution_norm,
1283 {1e-2, 0.});
1285 });
1286 }
1287
1288 CHKERR testing->runTests();
1290}
1291//! [Check]
#define MOFEM_LOG_C(channel, severity, format,...)
#define MOFEM_TAG_AND_LOG(channel, severity, tag)
Tag and log in channel.
SmartPetscObj< Mat > jacobian
#define FTENSOR_INDEX(DIM, I)
std::string name
void simple(double P1[], double P2[], double P3[], double c[], const int N)
Definition acoustic.cpp:69
static const double eps
constexpr int SPACE_DIM
Kronecker Delta class.
FieldApproximationBase
approximation base
Definition definitions.h:58
@ LASTBASE
Definition definitions.h:69
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base .
Definition definitions.h:60
@ DEMKOWICZ_JACOBI_BASE
Definition definitions.h:66
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
@ H1
continuous field
Definition definitions.h:85
#define MYPCOMM_INDEX
default communicator number PCOMM
#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
Definition definitions.h:40
@ MOFEM_DATA_INCONSISTENCY
Definition definitions.h:31
#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 ...
constexpr int order
auto integration_rule
#define MOFEM_LOG(channel, severity)
Log.
#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.
FTensor::Index< 'i', SPACE_DIM > i
static double lambda
PetscBool testing
const double c
speed of light (cm/ns)
double D
FTensor::Index< 'J', DIM1 > J
Definition level_set.cpp:30
MoFEMErrorCode configureSimpleDamage(MoFEM::Interface &m_field, boost::shared_ptr< MatOps::GenericElastic > physical_ptr)
@ MODEL_AXISYMMETRIC
Definition MatOps.hpp:212
@ MODEL_3D
Definition MatOps.hpp:209
@ MODEL_2D_PLANE_STRAIN
Definition MatOps.hpp:210
std::vector< StateTag > StateTags
Definition MatOps.hpp:21
boost::shared_ptr< PhysicalEquations > createMatOpsPhysicalEquationsPtr(boost::shared_ptr< MatOpsData > mat_ops_data_ptr, int tag)
boost::shared_ptr< MatOpsData > createMatOpsDataPtr()
Definition MatOps.cpp:709
PetscErrorCode PetscOptionsGetInt(PetscOptions *, const char pre[], const char name[], PetscInt *ivalue, PetscBool *set)
OpPostProcMapInMoab< SPACE_DIM, SPACE_DIM > OpPPMap
static constexpr double delta
static constexpr int approx_order
FTensor::Index< 'm', 3 > m
static MoFEMErrorCode hookEvaluateVariable(boost::shared_ptr< MatOps::MatOpsData > mat_ops_data_ptr, int, EntityHandle, int)
static MoFEMErrorCode hookEvaluateDerivatives(boost::shared_ptr< MatOps::MatOpsData > mat_ops_data_ptr, int, EntityHandle, int)
static MoFEMErrorCode hookUpdateState(boost::shared_ptr< MatOps::MatOpsData >, int, EntityHandle, int)
static int setTagName(std::string name, int tag=-1)
Definition MatOps.cpp:29
static std::string getTagName(int tag)
Definition MatOps.cpp:90
virtual moab::Interface & get_moab()=0
virtual MPI_Comm & get_comm() const =0
virtual int get_comm_rank() const =0
Deprecated interface functions.
Post post-proc data at points from hash maps.
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.
static NonlinearElasticExample * elasticExamplePtr
static MoFEMErrorCode postStepInitialise(NonlinearElasticExample *example_ptr)
NonlinearElasticExample(MoFEM::Interface &m_field)
FieldApproximationBase approximationBase
MoFEMErrorCode runProblem()
[Run problem]
boost::shared_ptr< PostProcEleBdy > postProcBdyFe
std::vector< Tag > listTagsToTransfer
list of tags to transfer to postprocessor
boost::shared_ptr< MatOps::PhysicalEquations > physicalEquationsPtr
MoFEMErrorCode setupProblem()
[Read mesh]
MoFEMErrorCode readMesh()
[Run problem]
MoFEMErrorCode assembleSystemHencky()
[Boundary condition]
MoFEMErrorCode boundaryCondition()
[Set up problem]
MoFEMErrorCode opTest()
[Push operators to pipeline]
boost::shared_ptr< PostProcEleDomain > postProcDomainFe
MoFEMErrorCode TsSolve()
[TS Solve]
MoFEMErrorCode outputResults()
[Getting norms]
static auto get_skin(MoFEM::Interface &m_field, Range body_ents)
static auto filter_true_skin(MoFEM::Interface &m_field, Range &&skin)
MoFEMErrorCode checkResults()
[Postprocessing results]
boost::shared_ptr< MatOps::PhysicalEquations > physicalHuHuPtr
MoFEMErrorCode gettingNorms()
[TS Solve]
boost::shared_ptr< DomainEle > updateFe