v0.16.0
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() = default; // virtual destructor for proper cleanup in derived classes
22
23 MoFEMErrorCode runProblem();
24
25protected:
27 boost::shared_ptr<MatrixDouble> vectorFieldPtr = nullptr;
28 virtual MoFEMErrorCode readMesh();
29 virtual MoFEMErrorCode setupProblem();
30 virtual MoFEMErrorCode boundaryCondition();
31 virtual MoFEMErrorCode assembleSystem();
32 virtual MoFEMErrorCode solveSystem();
33 virtual MoFEMErrorCode outputResults();
34 virtual MoFEMErrorCode checkResults();
35
36 // Auxiliary functions
37 virtual MoFEMErrorCode setUpSolver(SmartPetscObj<KSP> solver);
38 virtual MoFEMErrorCode kspSetUpAndSolve(SmartPetscObj<KSP> solver);
39};
40
41//! [Run problem]
53//! [Run problem]
54
55//! [Read mesh]
56MoFEMErrorCode ElasticExample::readMesh() {
58 auto simple = mField.getInterface<Simple>();
59 CHKERR simple->getOptions();
60 CHKERR simple->loadFile();
61 // Add meshsets if config file provided
62 CHKERR mField.getInterface<MeshsetsManager>()->setMeshsetFromFile();
64}
65//! [Read mesh]
66
67//! [Set up problem]
70 Simple *simple = mField.getInterface<Simple>();
71
72 enum bases { AINSWORTH, DEMKOWICZ, LASBASETOPT };
73 const char *list_bases[LASBASETOPT] = {"ainsworth", "demkowicz"};
74 PetscInt choice_base_value = AINSWORTH;
75 CHKERR PetscOptionsGetEList(PETSC_NULLPTR, NULL, "-base", list_bases,
76 LASBASETOPT, &choice_base_value, PETSC_NULLPTR);
77
79 switch (choice_base_value) {
80 case AINSWORTH:
82 MOFEM_LOG("WORLD", Sev::inform)
83 << "Set AINSWORTH_LEGENDRE_BASE for displacements";
84 break;
85 case DEMKOWICZ:
87 MOFEM_LOG("WORLD", Sev::inform)
88 << "Set DEMKOWICZ_JACOBI_BASE for displacements";
89 break;
90 default:
91 base = LASTBASE;
92 break;
93 }
94
95 // Add field
96 CHKERR simple->addDomainField("U", H1, base, SPACE_DIM);
97 CHKERR simple->addBoundaryField("U", H1, base, SPACE_DIM);
98 int order = 2;
99 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-order", &order, PETSC_NULLPTR);
100
101 CHKERR simple->addDataField("GEOMETRY", H1, base, SPACE_DIM);
102
103 CHKERR simple->setFieldOrder("U", order);
104 CHKERR simple->setFieldOrder("GEOMETRY", 2);
105 CHKERR simple->setUp();
106
107 auto project_ho_geometry = [&]() {
108 Projection10NodeCoordsOnField ent_method(mField, "GEOMETRY");
109 return mField.loop_dofs("GEOMETRY", ent_method);
110 };
111 CHKERR project_ho_geometry();
112
114}
115//! [Set up problem]
116
117//! [Boundary condition]
120 auto simple = mField.getInterface<Simple>();
121 auto bc_mng = mField.getInterface<BcManager>();
122
123 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "REMOVE_X",
124 "U", 0, 0);
125 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "REMOVE_Y",
126 "U", 1, 1);
127 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "REMOVE_Z",
128 "U", 2, 2);
129 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(),
130 "REMOVE_ALL", "U", 0, 3);
131 CHKERR bc_mng->pushMarkDOFsOnEntities<DisplacementCubitBcData>(
132 simple->getProblemName(), "U");
133
135}
136//! [Boundary condition]
137
138//! [Push operators to pipeline]
141 auto pip = mField.getInterface<PipelineManager>();
142
143 //! [Integration rule]
144 auto integration_rule = [](int, int, int approx_order) {
145 return 2 * approx_order + 1;
146 };
147
148 auto integration_rule_bc = [](int, int, int approx_order) {
149 return 2 * approx_order + 1;
150 };
151
152 CHKERR pip->setDomainRhsIntegrationRule(integration_rule);
153 CHKERR pip->setDomainLhsIntegrationRule(integration_rule);
154 CHKERR pip->setBoundaryRhsIntegrationRule(integration_rule_bc);
155 CHKERR pip->setBoundaryLhsIntegrationRule(integration_rule_bc);
156 //! [Integration rule]
157
159 pip->getOpDomainLhsPipeline(), {H1}, "GEOMETRY");
161 pip->getOpDomainRhsPipeline(), {H1}, "GEOMETRY");
163 pip->getOpBoundaryRhsPipeline(), {NOSPACE}, "GEOMETRY");
165 pip->getOpBoundaryLhsPipeline(), {NOSPACE}, "GEOMETRY");
166
167 //! [Push domain stiffness matrix to pipeline]
168 // Add LHS operator for elasticity (stiffness matrix)
169 CHKERR HookeOps::opFactoryDomainLhs<SPACE_DIM, A, I, DomainEleOp>(
170 mField, pip->getOpDomainLhsPipeline(), "U", "MAT_ELASTIC", Sev::verbose);
171 //! [Push domain stiffness matrix to pipeline]
172
173 // Add RHS operator for internal forces
174 CHKERR HookeOps::opFactoryDomainRhs<SPACE_DIM, A, I, DomainEleOp>(
175 mField, pip->getOpDomainRhsPipeline(), "U", "MAT_ELASTIC", Sev::verbose);
176
177 //! [Push Body forces]
179 pip->getOpDomainRhsPipeline(), mField, "U", Sev::inform);
180 //! [Push Body forces]
181
182 //! [Push natural boundary conditions]
183 // Add force boundary condition
185 pip->getOpBoundaryRhsPipeline(), mField, "U", -1, Sev::inform);
186 // Add case for mix type of BCs
188 pip->getOpBoundaryLhsPipeline(), mField, "U", Sev::verbose);
189 //! [Push natural boundary conditions]
191}
192//! [Push operators to pipeline]
193
194MoFEMErrorCode ElasticExample::setUpSolver(SmartPetscObj<KSP>) { return 0; }
195
196// ! [KSP set up]
197MoFEMErrorCode ElasticExample::kspSetUpAndSolve(SmartPetscObj<KSP> solver) {
199
200 MOFEM_LOG_CHANNEL("TIMER");
201 MOFEM_LOG_TAG("TIMER", "timer");
202
203 BOOST_LOG_SCOPED_THREAD_ATTR("Timeline", attrs::timer());
204 MOFEM_LOG("TIMER", Sev::inform) << "KSPSetUp";
205 CHKERR KSPSetUp(solver);
206 MOFEM_LOG("TIMER", Sev::inform) << "KSPSetUp <= Done";
207
208 DM dm;
209 CHKERR KSPGetDM(solver, &dm);
210 auto D = createDMVector(dm);
211 auto F = vectorDuplicate(D);
212
213 MOFEM_LOG("TIMER", Sev::inform) << "KSPSolve";
214 CHKERR KSPSolve(solver, F, D);
215 MOFEM_LOG("TIMER", Sev::inform) << "KSPSolve <= Done";
216
217 CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
218 CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
219 CHKERR DMoFEMMeshToLocalVector(dm, D, INSERT_VALUES, SCATTER_REVERSE);
220
222};
223// ! [KSP set up]
224
225//! [Solve]
228
229 auto simple = mField.getInterface<Simple>();
230 auto pip = mField.getInterface<PipelineManager>();
231 auto solver = pip->createKSP();
232 CHKERR setUpSolver(solver);
233 CHKERR KSPSetFromOptions(solver);
234
235 auto set_essential_bc = [this]() {
237 // This is low level pushing finite elements (pipelines) to solver
238 auto simple = mField.getInterface<Simple>();
239 auto dm = simple->getDM();
240 auto ksp_ctx_ptr = getDMKspCtx(dm);
241
242 auto pre_proc_rhs = boost::make_shared<FEMethod>();
243 auto post_proc_rhs = boost::make_shared<FEMethod>();
244 auto post_proc_lhs = boost::make_shared<FEMethod>();
245
246 auto get_pre_proc_hook = [this, pre_proc_rhs]() {
247 return EssentialPreProc<DisplacementCubitBcData>(mField, pre_proc_rhs,
248 {});
249 };
250 pre_proc_rhs->preProcessHook = get_pre_proc_hook();
251
252 auto get_post_proc_hook_rhs = [this, post_proc_rhs]() {
254
255 CHKERR EssentialPostProcRhs<DisplacementCubitBcData>(mField,
256 post_proc_rhs, 1.)();
258 };
259
260 auto get_post_proc_hook_lhs = [this, post_proc_lhs]() {
262
263 CHKERR EssentialPostProcLhs<DisplacementCubitBcData>(mField,
264 post_proc_lhs, 1.)();
266 };
267
268 post_proc_rhs->postProcessHook = get_post_proc_hook_rhs;
269 post_proc_lhs->postProcessHook = get_post_proc_hook_lhs;
270
271 ksp_ctx_ptr->getPreProcComputeRhs().push_front(pre_proc_rhs);
272 ksp_ctx_ptr->getPostProcComputeRhs().push_back(post_proc_rhs);
273 ksp_ctx_ptr->getPostProcSetOperators().push_back(post_proc_lhs);
275 };
276
277 auto evaluate_field_at_the_point = [&]() {
279
280 int coords_dim = 3;
281 std::array<double, 3> field_eval_coords{0.0, 0.0, 0.0};
282 PetscBool do_eval_field = PETSC_FALSE;
283 CHKERR PetscOptionsGetRealArray(NULL, NULL, "-field_eval_coords",
284 field_eval_coords.data(), &coords_dim,
286
287 if (do_eval_field) {
288
289 vectorFieldPtr = boost::make_shared<MatrixDouble>();
290 auto field_eval_data =
291 mField.getInterface<FieldEvaluatorInterface>()->getData<DomainEle>();
292
293 CHKERR mField.getInterface<FieldEvaluatorInterface>()
294 ->buildTree<SPACE_DIM>(field_eval_data, simple->getDomainFEName());
295
296 field_eval_data->setEvalPoints(field_eval_coords.data(), 1);
297 auto no_rule = [](int, int, int) { return -1; };
298 auto field_eval_fe_ptr = field_eval_data->feMethodPtr;
299 field_eval_fe_ptr->getRuleHook = no_rule;
300
301 field_eval_fe_ptr->getOpPtrVector().push_back(
302 new OpCalculateVectorFieldValues<SPACE_DIM>("U", vectorFieldPtr));
303
304 CHKERR mField.getInterface<FieldEvaluatorInterface>()
305 ->evalFEAtThePoint<SPACE_DIM>(
306 field_eval_coords.data(), 1e-12, simple->getProblemName(),
307 simple->getDomainFEName(), field_eval_data,
309 QUIET);
310
311 if (vectorFieldPtr->size1()) {
312 auto t_disp = getFTensor1FromMat<SPACE_DIM>(*vectorFieldPtr);
313 if constexpr (SPACE_DIM == 2)
314 MOFEM_LOG("FieldEvaluator", Sev::inform)
315 << "U_X: " << t_disp(0) << " U_Y: " << t_disp(1);
316 else
317 MOFEM_LOG("FieldEvaluator", Sev::inform)
318 << "U_X: " << t_disp(0) << " U_Y: " << t_disp(1)
319 << " U_Z: " << t_disp(2);
320 }
321
323 }
325 };
326
327 CHKERR set_essential_bc();
328 CHKERR kspSetUpAndSolve(solver);
329 CHKERR evaluate_field_at_the_point();
330
332}
333//! [Solve]
334
335//! [Postprocess results]
338 auto simple = mField.getInterface<Simple>();
341 mField, simple->getDM(), simple->getDomainFEName(), "out_elastic.h5m");
343}
344//! [Postprocess results]
345
346//! [Check]
348 MOFEM_LOG_CHANNEL("WORLD");
349 auto simple = mField.getInterface<Simple>();
350 auto pip = mField.getInterface<PipelineManager>();
352
353 auto integration_rule = [](int, int, int p_data) { return 2 * p_data + 1; };
354 CHKERR pip->setEvaluationIntegrationRule(integration_rule);
355
356 auto &domain_evaluation_pipeline = pip->getOpEvaluationPipeline();
357
358 if (domain_evaluation_pipeline.empty()) {
360 domain_evaluation_pipeline, {H1}, "GEOMETRY");
361
362 auto op_loop_boundary = new OpLoopSide<BoundaryEle>(
363 mField, simple->getBoundaryFEName(), SPACE_DIM - 1, Sev::verbose);
364 op_loop_boundary->getSideFEPtr()->getRuleHook = integration_rule;
365 auto &boundary_evaluation_pipeline = op_loop_boundary->getOpPtrVector();
366
368 boundary_evaluation_pipeline, {}, "GEOMETRY");
369
370 // Add RHS operators for internal forces
371 CHKERR HookeOps::opFactoryDomainRhs<SPACE_DIM, A, I, DomainEleOp>(
372 mField, domain_evaluation_pipeline, "U", "MAT_ELASTIC", Sev::verbose);
373
375 domain_evaluation_pipeline, mField, "U", Sev::verbose);
376
378 boundary_evaluation_pipeline, mField, "U", -1, Sev::verbose);
379 domain_evaluation_pipeline.push_back(op_loop_boundary);
380 }
381
382 auto dm = simple->getDM();
383 auto res = createDMVector(dm);
384 CHKERR VecSetDM(res, PETSC_NULLPTR);
385
386 pip->getEvaluationFE()->f = res;
387
388 CHKERR VecZeroEntries(res);
389
390 CHKERR pip->loopFiniteElementsEvaluation();
391 // CHKERR mField.getInterface<FieldBlas>()->fieldScale(-1, "U");
392
393 CHKERR VecGhostUpdateBegin(res, ADD_VALUES, SCATTER_REVERSE);
394 CHKERR VecGhostUpdateEnd(res, ADD_VALUES, SCATTER_REVERSE);
395 CHKERR VecAssemblyBegin(res);
396 CHKERR VecAssemblyEnd(res);
397
398 auto zero_residual_at_constrains = [&]() {
400 auto fe_post_proc_ptr = boost::make_shared<FEMethod>();
401 auto get_post_proc_hook_rhs = [&]() {
403 CHKERR EssentialPreProcReaction<DisplacementCubitBcData>(
404 mField, fe_post_proc_ptr, res)();
405 CHKERR EssentialPostProcRhs<DisplacementCubitBcData>(
406 mField, fe_post_proc_ptr, 0, res)();
408 };
409 fe_post_proc_ptr->postProcessHook = get_post_proc_hook_rhs;
410 CHKERR DMoFEMPostProcessFiniteElements(dm, fe_post_proc_ptr.get());
412 };
413
414 CHKERR zero_residual_at_constrains();
415
416 double nrm2;
417 CHKERR VecNorm(res, NORM_2, &nrm2);
418 MOFEM_LOG_CHANNEL("WORLD");
419 MOFEM_LOG_C("WORLD", Sev::inform, "residual = %3.4e\n", nrm2);
420
421 int test = 0;
422 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-test", &test, PETSC_NULLPTR);
423 if (test > 0) {
424 auto post_proc_residual = [&](auto dm, auto f_res, auto out_name) {
426 auto post_proc_fe =
427 boost::make_shared<PostProcBrokenMeshInMoab<DomainEle>>(mField);
428 using OpPPMap = OpPostProcMapInMoab<SPACE_DIM, SPACE_DIM>;
429 auto u_vec = boost::make_shared<MatrixDouble>();
430 post_proc_fe->getOpPtrVector().push_back(
431 new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_vec, f_res));
432 post_proc_fe->getOpPtrVector().push_back(
433
434 new OpPPMap(
435
436 post_proc_fe->getPostProcMesh(), post_proc_fe->getMapGaussPts(),
437
438 {},
439
440 {{"RES", u_vec}},
441
442 {}, {})
443
444 );
445
446 CHKERR DMoFEMLoopFiniteElements(dm, simple->getDomainFEName(),
447 post_proc_fe);
448 post_proc_fe->writeFile(out_name);
450 };
451
452 CHKERR post_proc_residual(simple->getDM(), res, "res.h5m");
453
454 constexpr double eps = 1e-8;
455 if (nrm2 > eps)
456 SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
457 "Residual is not zero");
458 }
459 if (test == 2) {
460 if (!vectorFieldPtr || vectorFieldPtr->size1() == 0) {
461 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
462 "atom test %d failed: Field Evaluator did not provide result",
463 test);
464 }
465 auto t_disp = getFTensor1FromMat<SPACE_DIM>(*vectorFieldPtr);
466 double Ux_ref = 0.46;
467 double Uy_ref = -0.03;
468 constexpr double eps = 1e-8;
469 if (fabs(t_disp(0) - Ux_ref) > eps || fabs(t_disp(1) - Uy_ref) > eps) {
470 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
471 "atom test %d failed: Ux_ref = %3.6e, computed = %3.6e, Uy_ref "
472 "= %3.6e, computed = %3.6e",
473 test, Ux_ref, t_disp(0), Uy_ref, t_disp(1));
474 }
475 }
477}
478//! [Check]
#define MOFEM_LOG_SYNCHRONISE(comm)
Synchronise "SYNC" channel.
#define MOFEM_LOG_C(channel, severity, format,...)
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
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 ...
@ 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
@ 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.
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)
OpPostProcMapInMoab< SPACE_DIM, SPACE_DIM > OpPPMap
static constexpr int approx_order
virtual MoFEMErrorCode solveSystem()
[Solve]
virtual MoFEMErrorCode outputResults()
[Solve]
virtual MoFEMErrorCode assembleSystem()
[Boundary condition]
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]
virtual ~ElasticExample()=default
virtual MoFEMErrorCode readMesh()
[Run problem]
boost::shared_ptr< MatrixDouble > vectorFieldPtr
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.
Post post-proc data at points from hash maps.
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.
PetscBool do_eval_field
Evaluate field.
Definition plastic.cpp:120
ElementsAndOps< SPACE_DIM >::SideEle SideEle
Definition plastic.cpp:62
Calculate traction for linear problem.
Implementation of elastic spring bc.
Natural boundary condition applying pressure from fluid.
Implementation of Hookes operator Hookes for linear elastic problems in MoFEM.
Implementation of natural boundary conditions.
Boundary conditions in domain, i.e. body forces.