v0.16.3
Loading...
Searching...
No Matches
ElasticExample.hpp
Go to the documentation of this file.
1/**
2 * @file ElasticExample.hpp
3 *
4 * @brief Implementation of elastic example class
5 *
6 * @copyright Copyright (c) 2025
7 *
8 */
9
10#include <ElasticSpring.hpp>
11#include <FluidLevel.hpp>
12#include <CalculateTraction.hpp>
13#include <NaturalDomainBC.hpp>
14#include <NaturalBoundaryBC.hpp>
15#include <HookeOps.hpp>
16#include <ElasticPostProc.hpp>
17
19
20 ElasticExample(MoFEM::Interface &m_field) : mField(m_field) {}
21 virtual ~ElasticExample() =
22 default; // virtual destructor for proper cleanup in derived classes
23
24 MoFEMErrorCode runProblem();
25
26protected:
27 using Pipeline = boost::ptr_deque<ForcesAndSourcesCore::UserDataOperator>;
28
30 virtual MoFEMErrorCode readMesh();
31 virtual MoFEMErrorCode setupProblem();
32 virtual MoFEMErrorCode boundaryCondition();
33 virtual MoFEMErrorCode assembleSystem();
34 virtual MoFEMErrorCode solveSystem();
35 virtual MoFEMErrorCode outputResults();
36 virtual MoFEMErrorCode checkResults();
37
38 /** @brief Add constitutive operators to the domain assembly pipelines. */
39 virtual MoFEMErrorCode addDomainMaterialOps(Pipeline &lhs_pipeline,
40 Pipeline &rhs_pipeline);
41
42 // Auxiliary functions
43 virtual MoFEMErrorCode setUpSolver(SmartPetscObj<KSP> solver);
44 virtual MoFEMErrorCode kspSetUpAndSolve(SmartPetscObj<KSP> solver);
45};
46
47//! [Run problem]
59//! [Run problem]
60
61//! [Read mesh]
62MoFEMErrorCode ElasticExample::readMesh() {
64 auto simple = mField.getInterface<Simple>();
65 CHKERR simple->getOptions();
66 CHKERR simple->loadFile();
67 // Add meshsets if config file provided
68 CHKERR mField.getInterface<MeshsetsManager>()->setMeshsetFromFile();
70}
71//! [Read mesh]
72
73//! [Set up problem]
76 Simple *simple = mField.getInterface<Simple>();
77
78 enum bases { AINSWORTH, DEMKOWICZ, LASBASETOPT };
79 const char *list_bases[LASBASETOPT] = {"ainsworth", "demkowicz"};
80 PetscInt choice_base_value = AINSWORTH;
81 CHKERR PetscOptionsGetEList(PETSC_NULLPTR, NULL, "-base", list_bases,
82 LASBASETOPT, &choice_base_value, PETSC_NULLPTR);
83
85 switch (choice_base_value) {
86 case AINSWORTH:
88 MOFEM_LOG("WORLD", Sev::inform)
89 << "Set AINSWORTH_LEGENDRE_BASE for displacements";
90 break;
91 case DEMKOWICZ:
93 MOFEM_LOG("WORLD", Sev::inform)
94 << "Set DEMKOWICZ_JACOBI_BASE for displacements";
95 break;
96 default:
97 base = LASTBASE;
98 break;
99 }
100
101 // Add field
102 CHKERR simple->addDomainField("U", H1, base, SPACE_DIM);
103 CHKERR simple->addBoundaryField("U", H1, base, SPACE_DIM);
104 int order = 2;
105 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-order", &order, PETSC_NULLPTR);
106
107 CHKERR simple->addDataField("GEOMETRY", H1, base, SPACE_DIM);
108
109 CHKERR simple->setFieldOrder("U", order);
110 CHKERR simple->setFieldOrder("GEOMETRY", 2);
111 CHKERR simple->setUp();
112
113 auto project_ho_geometry = [&]() {
114 Projection10NodeCoordsOnField ent_method(mField, "GEOMETRY");
115 return mField.loop_dofs("GEOMETRY", ent_method);
116 };
117 CHKERR project_ho_geometry();
118
120}
121//! [Set up problem]
122
123//! [Boundary condition]
126 auto simple = mField.getInterface<Simple>();
127 auto bc_mng = mField.getInterface<BcManager>();
128
129 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "REMOVE_X",
130 "U", 0, 0);
131 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "REMOVE_Y",
132 "U", 1, 1);
133 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "REMOVE_Z",
134 "U", 2, 2);
135 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(),
136 "REMOVE_ALL", "U", 0, 3);
137 CHKERR bc_mng->pushMarkDOFsOnEntities<DisplacementCubitBcData>(
138 simple->getProblemName(), "U");
139
141}
142//! [Boundary condition]
143
144//! [Push operators to pipeline]
146 Pipeline &rhs_pipeline) {
148 // Add LHS operator for elasticity (stiffness matrix)
149 CHKERR HookeOps::opFactoryDomainLhs<SPACE_DIM, A, I, DomainEleOp>(
150 mField, lhs_pipeline, "U", "MAT_ELASTIC", Sev::verbose);
151 // Add RHS operator for internal forces
152 CHKERR HookeOps::opFactoryDomainRhs<SPACE_DIM, A, I, DomainEleOp>(
153 mField, rhs_pipeline, "U", "MAT_ELASTIC", Sev::verbose);
155}
156
159 auto pip = mField.getInterface<PipelineManager>();
160
161 //! [Integration rule]
162 auto integration_rule = [](int, int, int approx_order) {
163 return 2 * approx_order + 1;
164 };
165
166 auto integration_rule_bc = [](int, int, int approx_order) {
167 return 2 * approx_order + 1;
168 };
169
170 CHKERR pip->setDomainRhsIntegrationRule(integration_rule);
171 CHKERR pip->setDomainLhsIntegrationRule(integration_rule);
172 CHKERR pip->setBoundaryRhsIntegrationRule(integration_rule_bc);
173 CHKERR pip->setBoundaryLhsIntegrationRule(integration_rule_bc);
174 //! [Integration rule]
175
176 CHKERR AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
177 pip->getOpDomainLhsPipeline(), {H1}, "GEOMETRY");
178 CHKERR AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
179 pip->getOpDomainRhsPipeline(), {H1}, "GEOMETRY");
180 CHKERR AddHOOps<SPACE_DIM - 1, SPACE_DIM, SPACE_DIM>::add(
181 pip->getOpBoundaryRhsPipeline(), {NOSPACE}, "GEOMETRY");
182 CHKERR AddHOOps<SPACE_DIM - 1, SPACE_DIM, SPACE_DIM>::add(
183 pip->getOpBoundaryLhsPipeline(), {NOSPACE}, "GEOMETRY");
184
185 //! [Push domain stiffness matrix to pipeline]
186 CHKERR addDomainMaterialOps(pip->getOpDomainLhsPipeline(),
187 pip->getOpDomainRhsPipeline());
188 //! [Push domain stiffness matrix to pipeline]
189
190 //! [Push Body forces]
192 pip->getOpDomainRhsPipeline(), mField, "U", Sev::inform);
193 //! [Push Body forces]
194
195 //! [Push natural boundary conditions]
196 // Add force boundary condition
198 pip->getOpBoundaryRhsPipeline(), mField, "U", -1, Sev::inform);
199 // Add case for mix type of BCs
201 pip->getOpBoundaryLhsPipeline(), mField, "U", Sev::verbose);
202 //! [Push natural boundary conditions]
204}
205//! [Push operators to pipeline]
206
207MoFEMErrorCode ElasticExample::setUpSolver(SmartPetscObj<KSP>) { return 0; }
208
209// ! [KSP set up]
210MoFEMErrorCode ElasticExample::kspSetUpAndSolve(SmartPetscObj<KSP> solver) {
212
213 MOFEM_LOG_CHANNEL("TIMER");
214 MOFEM_LOG_TAG("TIMER", "timer");
215
216 BOOST_LOG_SCOPED_THREAD_ATTR("Timeline", attrs::timer());
217 MOFEM_LOG("TIMER", Sev::inform) << "KSPSetUp";
218 CHKERR KSPSetUp(solver);
219 MOFEM_LOG("TIMER", Sev::inform) << "KSPSetUp <= Done";
220
221 DM dm;
222 CHKERR KSPGetDM(solver, &dm);
223 auto D = createDMVector(dm);
224 auto F = vectorDuplicate(D);
225
226 MOFEM_LOG("TIMER", Sev::inform) << "KSPSolve";
227 CHKERR KSPSolve(solver, F, D);
228 CHKERR mField.getInterface<TestingInterface>()->checkSolver(solver,
229 "elasticity");
230 MOFEM_LOG("TIMER", Sev::inform) << "KSPSolve <= Done";
231
232 CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
233 CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
234 CHKERR DMoFEMMeshToLocalVector(dm, D, INSERT_VALUES, SCATTER_REVERSE);
235
237};
238// ! [KSP set up]
239
240//! [Solve]
243
244 auto pip = mField.getInterface<PipelineManager>();
245 auto solver = pip->createKSP();
246 CHKERR setUpSolver(solver);
247 CHKERR KSPSetFromOptions(solver);
248
249 auto set_essential_bc = [this]() {
251 // This is low level pushing finite elements (pipelines) to solver
252 auto simple = mField.getInterface<Simple>();
253 auto dm = simple->getDM();
254 auto ksp_ctx_ptr = getDMKspCtx(dm);
255
256 auto pre_proc_rhs = boost::make_shared<FEMethod>();
257 auto post_proc_rhs = boost::make_shared<FEMethod>();
258 auto post_proc_lhs = boost::make_shared<FEMethod>();
259
260 auto get_pre_proc_hook = [this, pre_proc_rhs]() {
261 return EssentialPreProc<DisplacementCubitBcData>(mField, pre_proc_rhs,
262 {});
263 };
264 pre_proc_rhs->preProcessHook = get_pre_proc_hook();
265
266 auto get_post_proc_hook_rhs = [this, post_proc_rhs]() {
268
269 CHKERR EssentialPostProcRhs<DisplacementCubitBcData>(mField,
270 post_proc_rhs, 1.)();
272 };
273
274 auto get_post_proc_hook_lhs = [this, post_proc_lhs]() {
276
277 CHKERR EssentialPostProcLhs<DisplacementCubitBcData>(mField,
278 post_proc_lhs, 1.)();
280 };
281
282 post_proc_rhs->postProcessHook = get_post_proc_hook_rhs;
283 post_proc_lhs->postProcessHook = get_post_proc_hook_lhs;
284
285 ksp_ctx_ptr->getPreProcComputeRhs().push_front(pre_proc_rhs);
286 ksp_ctx_ptr->getPostProcComputeRhs().push_back(post_proc_rhs);
287 ksp_ctx_ptr->getPostProcSetOperators().push_back(post_proc_lhs);
289 };
290
291 CHKERR set_essential_bc();
292 CHKERR kspSetUpAndSolve(solver);
293
295}
296//! [Solve]
297
298//! [Postprocess results]
301 auto simple = mField.getInterface<Simple>();
302 auto evaluate_field_at_the_point = [&]() {
304
305 int coords_dim = 3;
306 std::array<double, 3> field_eval_coords{0.0, 0.0, 0.0};
307 PetscBool do_eval_field = PETSC_FALSE;
308 CHKERR PetscOptionsGetRealArray(NULL, NULL, "-field_eval_coords",
309 field_eval_coords.data(), &coords_dim,
311
312 if (do_eval_field) {
313
314 auto vector_field_ptr = boost::make_shared<MatrixDouble>();
315 auto field_eval_data =
316 mField.getInterface<FieldEvaluatorInterface>()->getData<DomainEle>();
317
318 CHKERR mField.getInterface<FieldEvaluatorInterface>()
319 ->buildTree<SPACE_DIM>(field_eval_data, simple->getDomainFEName());
320
321 field_eval_data->setEvalPoints(field_eval_coords.data(), 1);
322 auto no_rule = [](int, int, int) { return -1; };
323 auto field_eval_fe_ptr = field_eval_data->feMethodPtr;
324 field_eval_fe_ptr->getRuleHook = no_rule;
325
326 field_eval_fe_ptr->getOpPtrVector().push_back(
327 new OpCalculateVectorFieldValues<SPACE_DIM>("U", vector_field_ptr));
328
329 CHKERR mField.getInterface<FieldEvaluatorInterface>()
330 ->evalFEAtThePoint<SPACE_DIM>(
331 field_eval_coords.data(), 1e-12, simple->getProblemName(),
332 simple->getDomainFEName(), field_eval_data,
334 QUIET);
335
336 if (vector_field_ptr->size1()) {
337 auto t_disp = getFTensor1FromMat<SPACE_DIM>(*vector_field_ptr);
338 if constexpr (SPACE_DIM == 2)
339 MOFEM_LOG("FieldEvaluator", Sev::inform)
340 << "U_X: " << t_disp(0) << " U_Y: " << t_disp(1);
341 else
342 MOFEM_LOG("FieldEvaluator", Sev::inform)
343 << "U_X: " << t_disp(0) << " U_Y: " << t_disp(1)
344 << " U_Z: " << t_disp(2);
345 }
346
348 }
350 };
351
352 CHKERR evaluate_field_at_the_point();
355 mField, simple->getDM(), simple->getDomainFEName(), "out_elastic.h5m");
357}
358//! [Postprocess results]
359
360//! [Check]
363 MOFEM_LOG_CHANNEL("WORLD");
364 auto simple = mField.getInterface<Simple>();
365 auto pip = mField.getInterface<PipelineManager>();
366 auto testing = mField.getInterface<TestingInterface>();
367
368 // Core owns the interfaces retained by these registry hooks.
369 auto check_residual_is_zero = [testing, simple, pip, &m_field = mField]() {
371 auto integration_rule = [](int, int, int p_data) { return 2 * p_data + 1; };
372 CHKERR pip->setEvaluationIntegrationRule(integration_rule);
373
374 auto &domain_evaluation_pipeline = pip->getOpEvaluationPipeline();
375
376 if (domain_evaluation_pipeline.empty()) {
377 CHKERR AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
378 domain_evaluation_pipeline, {H1}, "GEOMETRY");
379
380 auto op_loop_boundary = new OpLoopSide<BoundaryEle>(
381 m_field, simple->getBoundaryFEName(), SPACE_DIM - 1, Sev::verbose);
382 op_loop_boundary->getSideFEPtr()->getRuleHook = integration_rule;
383 auto &boundary_evaluation_pipeline = op_loop_boundary->getOpPtrVector();
384
385 CHKERR AddHOOps<SPACE_DIM - 1, SPACE_DIM, SPACE_DIM>::add(
386 boundary_evaluation_pipeline, {}, "GEOMETRY");
387
388 // Add RHS operators for internal forces
389 CHKERR HookeOps::opFactoryDomainRhs<SPACE_DIM, A, I, DomainEleOp>(
390 m_field, domain_evaluation_pipeline, "U", "MAT_ELASTIC",
391 Sev::verbose);
392
394 domain_evaluation_pipeline, m_field, "U", Sev::verbose);
395
397 boundary_evaluation_pipeline, m_field, "U", -1, Sev::verbose);
398 domain_evaluation_pipeline.push_back(op_loop_boundary);
399 }
400
401 auto dm = simple->getDM();
402 auto res = createDMVector(dm);
403 CHKERR VecSetDM(res, PETSC_NULLPTR);
404
405 pip->getEvaluationFE()->f = res;
406
407 CHKERR VecZeroEntries(res);
408
409 CHKERR pip->loopFiniteElementsEvaluation();
410 pip->getEvaluationFE()->f = PETSC_NULLPTR;
411
412 CHKERR VecGhostUpdateBegin(res, ADD_VALUES, SCATTER_REVERSE);
413 CHKERR VecGhostUpdateEnd(res, ADD_VALUES, SCATTER_REVERSE);
414 CHKERR VecAssemblyBegin(res);
415 CHKERR VecAssemblyEnd(res);
416
417 auto zero_residual_at_constrains = [&]() {
419 auto fe_post_proc_ptr = boost::make_shared<FEMethod>();
420 auto get_post_proc_hook_rhs = [&]() {
422 CHKERR EssentialPreProcReaction<DisplacementCubitBcData>(
423 m_field, fe_post_proc_ptr, res)();
424 CHKERR EssentialPostProcRhs<DisplacementCubitBcData>(
425 m_field, fe_post_proc_ptr, 0, res)();
427 };
428 fe_post_proc_ptr->postProcessHook = get_post_proc_hook_rhs;
429 CHKERR DMoFEMPostProcessFiniteElements(dm, fe_post_proc_ptr.get());
431 };
432
433 CHKERR zero_residual_at_constrains();
434
435 double nrm2;
436 CHKERR VecNorm(res.get(), NORM_2, &nrm2);
437 MOFEM_LOG_CHANNEL("WORLD");
438 MOFEM_LOG_C("WORLD", Sev::inform, "residual = %3.4e\n", nrm2);
439 CHKERR testing->checkValue<TestType::SCALAR>("residual norm", nrm2, 0.,
440 {1e-8, 0.});
442 };
443
444 auto check_point_displacement = [testing, simple,
445 comm = mField.get_comm()]() {
447 auto displacement_ptr = boost::make_shared<MatrixDouble>();
448 bool point_found = false;
449 CHKERR testing->addFieldEvaluator<SPACE_DIM>(
450 simple->getProblemName(), simple->getDomainFEName(), {4.5, 2.5, 0.},
451 [displacement_ptr](auto &pipeline) {
453 pipeline.push_back(new OpCalculateVectorFieldValues<SPACE_DIM>(
454 "U", displacement_ptr));
456 },
457 1e-12, &point_found);
458 const int local_found = point_found;
459 int found;
460 CHKERR MPI_Allreduce(&local_found, &found, 1, MPI_INT, MPI_SUM, comm);
461 CHKERR testing->checkError<TestType::POINTWISE>(
462 "point found on mesh", found ? 0. : 1., 0., {0., 0.});
463 // Only owners contribute errors; every rank participates in the checks.
464 double error_x = 0, error_y = 0;
465 if (local_found) {
466 using DL = DataLayoutTraits<DataLayout::GaussByCoeffs>;
467 auto t_disp =
468 MatrixSizeHelper<GetFTensor1FromMatType<SPACE_DIM, -1, DL>, DL>::get(
469 *displacement_ptr, 1)();
470 error_x = std::abs(t_disp(0) - 0.46);
471 error_y = std::abs(t_disp(1) + 0.03);
472 }
473 CHKERR testing->checkError<TestType::POINTWISE>("U_X at point", error_x,
474 0.46, {1e-8, 0.});
475 CHKERR testing->checkError<TestType::POINTWISE>("U_Y at point", error_y,
476 0.03, {1e-8, 0.});
478 };
479
480 CHKERR testing->addTestCommandLine("", 1, "residual is zero",
481 check_residual_is_zero);
482 CHKERR testing->addTestCommandLine(
483 "", 2, "point displacement",
484 [check_residual_is_zero, check_point_displacement]() {
486 CHKERR check_residual_is_zero();
487 CHKERR check_point_displacement();
489 });
490
491 CHKERR testing->runTests();
492
494}
495//! [Check]
Calculate traction for linear problem.
MPI_Comm comm
Implementation of elastic spring bc.
Natural boundary condition applying pressure from fluid.
Implementation of Hookes operator Hookes for linear elastic problems in MoFEM.
#define MOFEM_LOG_SYNCHRONISE(comm)
Synchronise "SYNC" channel.
#define MOFEM_LOG_C(channel, severity, format,...)
Implementation of natural boundary conditions.
Boundary conditions in domain, i.e. body forces.
void simple(double P1[], double P2[], double P3[], double c[], const int N)
Definition acoustic.cpp:69
constexpr int SPACE_DIM
ElementsAndOps< SPACE_DIM >::DomainEle DomainEle
ElementsAndOps< SPACE_DIM >::BoundaryEle BoundaryEle
@ QUIET
@ MF_EXIST
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 MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
#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
@ F
auto integration_rule
#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.
PetscBool testing
double D
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)
PetscBool do_eval_field
Evaluate field.
Definition plastic.cpp:120
ElementsAndOps< SPACE_DIM >::SideEle SideEle
Definition plastic.cpp:62
static constexpr int approx_order
virtual MoFEMErrorCode solveSystem()
[Solve]
virtual MoFEMErrorCode outputResults()
[Solve]
virtual MoFEMErrorCode assembleSystem()
virtual MoFEMErrorCode addDomainMaterialOps(Pipeline &lhs_pipeline, Pipeline &rhs_pipeline)
Add constitutive operators to the domain assembly pipelines.
virtual MoFEMErrorCode setupProblem()
[Read mesh]
virtual MoFEMErrorCode kspSetUpAndSolve(SmartPetscObj< KSP > solver)
MoFEMErrorCode runProblem()
[Run problem]
MoFEM::Interface & mField
virtual MoFEMErrorCode boundaryCondition()
[Set up problem]
virtual MoFEMErrorCode checkResults()
[Postprocess results]
boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > Pipeline
virtual ~ElasticExample()=default
virtual MoFEMErrorCode readMesh()
[Run problem]
ElasticExample(MoFEM::Interface &m_field)
virtual MoFEMErrorCode setUpSolver(SmartPetscObj< KSP > solver)
[Push operators to pipeline]
virtual MPI_Comm & get_comm() const =0
virtual int get_comm_rank() const =0
Deprecated interface functions.
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.