v0.15.0
Loading...
Searching...
No Matches
ExampleNonlinearElastic.hpp
Go to the documentation of this file.
1/**
2 * @file ExampleNonlinearElastic.hpp
3 * @example ExampleNonlinearElastic.hpp
4 * @date 2025-10-5
5 *
6 * @copyright Anonymous authors (c) 2025 under the MIT license (see LICENSE for
7 * details)
8 */
9
11
13
14 MoFEMErrorCode runProblem();
15
16protected:
18 boost::shared_ptr<DomainEle> reactionFe;
19
20 MoFEMErrorCode readMesh();
21 MoFEMErrorCode setupProblem();
22 MoFEMErrorCode boundaryCondition();
23 MoFEMErrorCode assembleSystem();
24 MoFEMErrorCode TsSolve();
25 MoFEMErrorCode gettingNorms();
26 MoFEMErrorCode outputResults();
27 MoFEMErrorCode checkResults();
28};
29
30//! [Run problem]
43//! [Run problem]
44
45//! [Read mesh]
48 auto simple = mField.getInterface<Simple>();
49 CHKERR simple->getOptions();
50 CHKERR simple->loadFile();
52}
53//! [Read mesh]
54
55//! [Set up problem]
58 Simple *simple = mField.getInterface<Simple>();
59
60 enum bases { AINSWORTH, DEMKOWICZ, LASBASETOPT };
61 const char *list_bases[LASBASETOPT] = {"ainsworth", "demkowicz"};
62 PetscInt choice_base_value = AINSWORTH;
63 CHKERR PetscOptionsGetEList(PETSC_NULLPTR, NULL, "-base", list_bases,
64 LASBASETOPT, &choice_base_value, PETSC_NULLPTR);
65
67 switch (choice_base_value) {
68 case AINSWORTH:
70 MOFEM_LOG("WORLD", Sev::inform)
71 << "Set AINSWORTH_LEGENDRE_BASE for displacements";
72 break;
73 case DEMKOWICZ:
75 MOFEM_LOG("WORLD", Sev::inform)
76 << "Set DEMKOWICZ_JACOBI_BASE for displacements";
77 break;
78 default:
79 base = LASTBASE;
80 break;
81 }
82
83 // Add field
84 CHKERR simple->addDomainField("U", H1, base, SPACE_DIM);
85 CHKERR simple->addBoundaryField("U", H1, base, SPACE_DIM);
86 CHKERR simple->addDataField("GEOMETRY", H1, base, SPACE_DIM);
87 int order = 2;
88 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-order", &order, PETSC_NULLPTR);
89 CHKERR simple->setFieldOrder("U", order);
90 CHKERR simple->setFieldOrder("GEOMETRY", 2);
91 CHKERR simple->setUp();
92
93 auto project_ho_geometry = [&]() {
94 Projection10NodeCoordsOnField ent_method(mField, "GEOMETRY");
95 return mField.loop_dofs("GEOMETRY", ent_method);
96 };
97 CHKERR project_ho_geometry();
98
100}
101//! [Set up problem]
102
103//! [Boundary condition]
104
107 auto *pipeline_mng = mField.getInterface<PipelineManager>();
108 auto simple = mField.getInterface<Simple>();
109 auto bc_mng = mField.getInterface<BcManager>();
110 auto time_scale = boost::make_shared<ExampleTimeScale>();
111
112 auto integration_rule = [](int, int, int approx_order) {
113 return 2 * (approx_order - 1) + 1;
114 };
115
116 CHKERR pipeline_mng->setDomainRhsIntegrationRule(integration_rule);
117 CHKERR pipeline_mng->setDomainLhsIntegrationRule(integration_rule);
118 CHKERR pipeline_mng->setBoundaryRhsIntegrationRule(integration_rule);
119
120 reactionFe = boost::make_shared<DomainEle>(mField);
121 reactionFe->getRuleHook = integration_rule;
122
124 pipeline_mng->getOpBoundaryRhsPipeline(), mField, "U", {time_scale},
125 "FORCE", Sev::inform);
126
127 //! [Define gravity vector]
129 pipeline_mng->getOpDomainRhsPipeline(), mField, "U", {time_scale},
130 "BODY_FORCE", Sev::inform);
131
132 // Essential BC
133 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "REMOVE_X",
134 "U", 0, 0);
135 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "REMOVE_Y",
136 "U", 1, 1);
137 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "REMOVE_Z",
138 "U", 2, 2);
139 CHKERR bc_mng->pushMarkDOFsOnEntities<DisplacementCubitBcData>(
140 simple->getProblemName(), "U");
141
143}
144//! [Boundary condition]
145
146//! [Push operators to pipeline]
149 auto *pipeline_mng = mField.getInterface<PipelineManager>();
150
151 auto add_domain_ops_lhs = [&](auto &pip) {
154 "GEOMETRY");
156 mField, pip, "U", "MAT_ELASTIC", Sev::inform);
158 };
159
160 auto add_domain_ops_rhs = [&](auto &pip) {
163 "GEOMETRY");
165 mField, pip, "U", "MAT_ELASTIC", Sev::inform);
167 };
168
169 CHKERR add_domain_ops_lhs(pipeline_mng->getOpDomainLhsPipeline());
170 CHKERR add_domain_ops_rhs(pipeline_mng->getOpDomainRhsPipeline());
171
172 // push operators to reaction pipeline
173 CHKERR add_domain_ops_rhs(reactionFe->getOpPtrVector());
174 reactionFe->postProcessHook =
175 EssentialPreProcReaction<DisplacementCubitBcData>(mField, reactionFe);
176
178}
179//! [Push operators to pipeline]
180
181//! [TS Solve]
184 auto *simple = mField.getInterface<Simple>();
185 auto *pipeline_mng = mField.getInterface<PipelineManager>();
186
187 auto dm = simple->getDM();
188 auto ts = pipeline_mng->createTSIM();
189
190 PetscBool post_proc_vol;
191 PetscBool post_proc_skin;
192
193 if constexpr (SPACE_DIM == 2) {
194 post_proc_vol = PETSC_TRUE;
195 post_proc_skin = PETSC_FALSE;
196 } else {
197 post_proc_vol = PETSC_FALSE;
198 post_proc_skin = PETSC_TRUE;
199 }
200 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-post_proc_vol",
201 &post_proc_vol, PETSC_NULLPTR);
202 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-post_proc_skin",
203 &post_proc_skin, PETSC_NULLPTR);
204
205 // Setup postprocessing
206 auto create_post_proc_fe = [dm, this, simple, post_proc_vol,
207 post_proc_skin]() {
208 auto post_proc_ele_domain = [dm, this](auto &pip_domain) {
210 "GEOMETRY");
211 auto common_ptr = commonDataFactory<SPACE_DIM, GAUSS, DomainEleOp>(
212 mField, pip_domain, "U", "MAT_ELASTIC", Sev::inform);
213 return common_ptr;
214 };
215
216 auto post_proc_map = [this](auto &pip, auto u_ptr, auto common_ptr) {
218
219 using OpPPMap = OpPostProcMapInMoab<SPACE_DIM, SPACE_DIM>;
220
221 pip->getOpPtrVector().push_back(
222
223 new OpPPMap(pip->getPostProcMesh(), pip->getMapGaussPts(), {},
224 {{"U", u_ptr}},
225 {{"GRAD", common_ptr->matGradPtr},
226 {"FIRST_PIOLA", common_ptr->getMatFirstPiolaStress()}},
227 {}));
229 };
230
231 auto push_post_proc_bdy = [dm, this, simple, post_proc_skin,
232 &post_proc_ele_domain,
233 &post_proc_map](auto &pip_bdy) {
234 if (post_proc_skin == PETSC_FALSE)
235 return boost::shared_ptr<PostProcEleBdy>();
236
237 auto u_ptr = boost::make_shared<MatrixDouble>();
238 pip_bdy->getOpPtrVector().push_back(
239 new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_ptr));
240 auto op_loop_side =
241 new OpLoopSide<SideEle>(mField, simple->getDomainFEName(), SPACE_DIM);
242 auto common_ptr = post_proc_ele_domain(op_loop_side->getOpPtrVector());
243 pip_bdy->getOpPtrVector().push_back(op_loop_side);
244
245 CHKERR post_proc_map(pip_bdy, u_ptr, common_ptr);
246
247 return pip_bdy;
248 };
249
250 auto push_post_proc_domain = [dm, this, simple, post_proc_vol,
251 &post_proc_ele_domain,
252 &post_proc_map](auto &pip_domain) {
253 if (post_proc_vol == PETSC_FALSE)
254 return boost::shared_ptr<PostProcEleDomain>();
255
256 auto u_ptr = boost::make_shared<MatrixDouble>();
257 pip_domain->getOpPtrVector().push_back(
258 new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_ptr));
259 auto common_ptr = post_proc_ele_domain(pip_domain->getOpPtrVector());
260
261 CHKERR post_proc_map(pip_domain, u_ptr, common_ptr);
262
263 return pip_domain;
264 };
265
266 auto post_proc_fe_domain = boost::make_shared<PostProcEleDomain>(mField);
267 auto post_proc_fe_bdy = boost::make_shared<PostProcEleBdy>(mField);
268
269 return std::make_pair(push_post_proc_domain(post_proc_fe_domain),
270 push_post_proc_bdy(post_proc_fe_bdy));
271 };
272
273 auto add_extra_finite_elements_to_solver_pipelines = [&]() {
275
276 auto pre_proc_ptr = boost::make_shared<FEMethod>();
277 auto post_proc_rhs_ptr = boost::make_shared<FEMethod>();
278 auto post_proc_lhs_ptr = boost::make_shared<FEMethod>();
279
280 auto time_scale = boost::make_shared<ExampleTimeScale>();
281
282 auto get_bc_hook_rhs = [this, pre_proc_ptr, time_scale]() {
284 CHKERR EssentialPreProc<DisplacementCubitBcData>(mField, pre_proc_ptr,
285 {time_scale}, false)();
287 };
288
289 pre_proc_ptr->preProcessHook = get_bc_hook_rhs;
290
291 auto get_post_proc_hook_rhs = [this, post_proc_rhs_ptr]() {
293 CHKERR EssentialPreProcReaction<DisplacementCubitBcData>(
294 mField, post_proc_rhs_ptr, nullptr, Sev::verbose)();
295 CHKERR EssentialPostProcRhs<DisplacementCubitBcData>(
296 mField, post_proc_rhs_ptr, 1.)();
298 };
299 auto get_post_proc_hook_lhs = [this, post_proc_lhs_ptr]() {
301 CHKERR EssentialPostProcLhs<DisplacementCubitBcData>(
302 mField, post_proc_lhs_ptr, 1.)();
304 };
305 post_proc_rhs_ptr->postProcessHook = get_post_proc_hook_rhs;
306 post_proc_lhs_ptr->postProcessHook = get_post_proc_hook_lhs;
307
308 // This is low level pushing finite elements (pipelines) to solver
309 auto ts_ctx_ptr = getDMTsCtx(simple->getDM());
310 ts_ctx_ptr->getPreProcessIFunction().push_front(pre_proc_ptr);
311 ts_ctx_ptr->getPreProcessIJacobian().push_front(pre_proc_ptr);
312 ts_ctx_ptr->getPostProcessIFunction().push_back(post_proc_rhs_ptr);
313 ts_ctx_ptr->getPostProcessIJacobian().push_back(post_proc_lhs_ptr);
315 };
316
317 // Add extra finite elements to SNES solver pipelines to resolve essential
318 // boundary conditions
319 CHKERR add_extra_finite_elements_to_solver_pipelines();
320
321 auto create_monitor_fe = [dm](auto &&post_proc_fe, auto &&reactionFe) {
322 return boost::make_shared<Monitor>(dm, post_proc_fe, reactionFe);
323 };
324
325 // Set monitor which postprocessing results and saves them to the hard drive
326 boost::shared_ptr<FEMethod> null_fe;
327 auto monitor_ptr = create_monitor_fe(create_post_proc_fe(), reactionFe);
328 CHKERR DMMoFEMTSSetMonitor(dm, ts, simple->getDomainFEName(), null_fe,
329 null_fe, monitor_ptr);
330
331 // Set time solver
332 double ftime = 1;
333 CHKERR TSSetMaxTime(ts, ftime);
334 CHKERR TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP);
335
336 auto B = createDMMatrix(dm);
337 CHKERR TSSetI2Jacobian(ts, B, B, PETSC_NULLPTR, PETSC_NULLPTR);
338 auto D = createDMVector(simple->getDM());
339 CHKERR TSSetSolution(ts, D);
340 CHKERR TSSetFromOptions(ts);
341
342 CHKERR TSSolve(ts, NULL);
343 CHKERR TSGetTime(ts, &ftime);
344
345 PetscInt steps, snesfails, rejects, nonlinits, linits;
346 CHKERR TSGetStepNumber(ts, &steps);
347 CHKERR TSGetSNESFailures(ts, &snesfails);
348 CHKERR TSGetStepRejections(ts, &rejects);
349 CHKERR TSGetSNESIterations(ts, &nonlinits);
350 CHKERR TSGetKSPIterations(ts, &linits);
351 MOFEM_LOG_C("EXAMPLE", Sev::inform,
352 "steps %d (%d rejected, %d SNES fails), ftime %g, nonlinits "
353 "%d, linits %d",
354 steps, rejects, snesfails, ftime, nonlinits, linits);
355
357}
358//! [TS Solve]
359
360//! [Getting norms]
363
364 auto simple = mField.getInterface<Simple>();
365 auto dm = simple->getDM();
366
367 auto T = createDMVector(simple->getDM());
368 CHKERR DMoFEMMeshToLocalVector(simple->getDM(), T, INSERT_VALUES,
369 SCATTER_FORWARD);
370 double nrm2;
371 CHKERR VecNorm(T, NORM_2, &nrm2);
372 MOFEM_LOG("EXAMPLE", Sev::inform) << "Solution norm " << nrm2;
373
374 auto post_proc_norm_fe = boost::make_shared<DomainEle>(mField);
375
376 auto post_proc_norm_rule_hook = [](int, int, int p) -> int { return 2 * p; };
377 post_proc_norm_fe->getRuleHook = post_proc_norm_rule_hook;
378
380 post_proc_norm_fe->getOpPtrVector(), {H1}, "GEOMETRY");
381
382 enum NORMS { U_NORM_L2 = 0, PIOLA_NORM, LAST_NORM };
383 auto norms_vec =
384 createVectorMPI(mField.get_comm(),
385 (mField.get_comm_rank() == 0) ? LAST_NORM : 0, LAST_NORM);
386 CHKERR VecZeroEntries(norms_vec);
387
388 auto u_ptr = boost::make_shared<MatrixDouble>();
389 post_proc_norm_fe->getOpPtrVector().push_back(
390 new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_ptr));
391
392 post_proc_norm_fe->getOpPtrVector().push_back(
393 new OpCalcNormL2Tensor1<SPACE_DIM>(u_ptr, norms_vec, U_NORM_L2));
394
395 auto common_ptr = commonDataFactory<SPACE_DIM, GAUSS, DomainEleOp>(
396 mField, post_proc_norm_fe->getOpPtrVector(), "U", "MAT_ELASTIC",
397 Sev::inform);
398
399 post_proc_norm_fe->getOpPtrVector().push_back(
400 new OpCalcNormL2Tensor2<SPACE_DIM, SPACE_DIM>(
401 common_ptr->getMatFirstPiolaStress(), norms_vec, PIOLA_NORM));
402
403 CHKERR DMoFEMLoopFiniteElements(dm, simple->getDomainFEName(),
404 post_proc_norm_fe);
405
406 CHKERR VecAssemblyBegin(norms_vec);
407 CHKERR VecAssemblyEnd(norms_vec);
408
409 MOFEM_LOG_CHANNEL("SELF"); // Clear channel from old tags
410 if (mField.get_comm_rank() == 0) {
411 const double *norms;
412 CHKERR VecGetArrayRead(norms_vec, &norms);
413 MOFEM_TAG_AND_LOG("SELF", Sev::inform, "example")
414 << "norm_u: " << std::scientific << std::sqrt(norms[U_NORM_L2]);
415 MOFEM_TAG_AND_LOG("SELF", Sev::inform, "example")
416 << "norm_piola: " << std::scientific << std::sqrt(norms[PIOLA_NORM]);
417 CHKERR VecRestoreArrayRead(norms_vec, &norms);
418 }
419
421}
422//! [Getting norms]
423
424//! [Postprocessing results]
429//! [Postprocessing results]
430
431//! [Check]
434 PetscInt test_nb = 0;
435 PetscBool test_flg = PETSC_FALSE;
436 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-test", &test_nb, &test_flg);
437
438 if (test_flg) {
439 auto simple = mField.getInterface<Simple>();
440 auto T = createDMVector(simple->getDM());
441 CHKERR DMoFEMMeshToLocalVector(simple->getDM(), T, INSERT_VALUES,
442 SCATTER_FORWARD);
443 double nrm2;
444 CHKERR VecNorm(T, NORM_2, &nrm2);
445 MOFEM_LOG("EXAMPLE", Sev::verbose) << "Regression norm " << nrm2;
446 double regression_value = 0;
447 switch (test_nb) {
448 case 1:
449 regression_value = 1.02789;
450 break;
451 case 2:
452 regression_value = 1.8841e+00;
453 break;
454 case 3:
455 regression_value = 1.8841e+00;
456 break;
457 default:
458 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID, "Wrong test number.");
459 break;
460 }
461 if (fabs(nrm2 - regression_value) > 1e-2)
462 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
463 "Regression test field; wrong norm value. %6.4e != %6.4e", nrm2,
464 regression_value);
465 }
467}
468//! [Check]
#define MOFEM_LOG_C(channel, severity, format,...)
#define MOFEM_TAG_AND_LOG(channel, severity, tag)
Tag and log in channel.
void simple(double P1[], double P2[], double P3[], double c[], const int N)
Definition acoustic.cpp:69
constexpr int SPACE_DIM
FieldApproximationBase
approximation base
Definition definitions.h:58
@ LASTBASE
Definition definitions.h:69
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base nme:nme847.
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 MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
@ MOFEM_ATOM_TEST_INVALID
Definition definitions.h:40
#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
auto createDMVector(DM dm)
Get smart vector from DM.
Definition DMMoFEM.hpp:1102
auto createDMMatrix(DM dm)
Get smart matrix from DM.
Definition DMMoFEM.hpp:1059
#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.
double D
MoFEMErrorCode opFactoryDomainLhs(MoFEM::Interface &m_field, boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > &pip, std::string field_name, boost::shared_ptr< HenckyOps::CommonData > common_ptr, Sev sev)
MoFEMErrorCode opFactoryDomainRhs(MoFEM::Interface &m_field, boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > &pip, std::string field_name, boost::shared_ptr< HenckyOps::CommonData > common_ptr, Sev sev)
PetscErrorCode DMMoFEMTSSetMonitor(DM dm, TS ts, const std::string fe_name, boost::shared_ptr< MoFEM::FEMethod > method, boost::shared_ptr< MoFEM::BasicMethod > pre_only, boost::shared_ptr< MoFEM::BasicMethod > post_only)
Set Monitor To TS solver.
Definition DMMoFEM.cpp:1046
auto getDMTsCtx(DM dm)
Get TS context data structure used by DM.
Definition DMMoFEM.hpp:1144
OpPostProcMapInMoab< SPACE_DIM, SPACE_DIM > OpPPMap
static constexpr int approx_order
MoFEMErrorCode TsSolve()
[Push operators to pipeline]
MoFEMErrorCode runProblem()
[Run problem]
MoFEMErrorCode readMesh()
[Run problem]
MoFEMErrorCode gettingNorms()
[TS Solve]
MoFEMErrorCode outputResults()
[Getting norms]
MoFEMErrorCode assembleSystem()
[Boundary condition]
MoFEMErrorCode checkResults()
[Postprocessing results]
MoFEMErrorCode setupProblem()
[Read mesh]
ExampleNonlinearElastic(MoFEM::Interface &m_field)
boost::shared_ptr< DomainEle > reactionFe
MoFEMErrorCode boundaryCondition()
[Set up problem]
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.