v0.16.0
Loading...
Searching...
No Matches
elastic_tie_mesh.cpp
Go to the documentation of this file.
1/**
2 * @file elastic_tie_mesh.cpp
3 * @example mofem/tutorials/vec-11_elastic_tie_mesh/elastic_tie_mesh.cpp
4 * @brief Elastic mesh tie example with a tie-aware partitioned mesh loader
5 *
6 * @copyright Anonymous authors (c) 2025 under the MIT license
7 */
8
9#include <MoFEM.hpp>
10
11using namespace MoFEM;
12
14constexpr AssemblyType A =
15 (SCHUR_ASSEMBLE) ? AssemblyType::BLOCK_SCHUR : AssemblyType::PETSC;
16constexpr IntegrationType I = IntegrationType::GAUSS;
17
22using DomainEleOp = DomainEle::UserDataOperator;
23using BoundaryEleOp = BoundaryEle::UserDataOperator;
24
25struct DomainBCs {};
26struct BoundaryBCs {};
27
35
36#include <ElasticExample.hpp>
37#include <ElasticTie.hpp>
39
40namespace ElasticTie {
41
42MoFEMErrorCode makeClosureMeshset(moab::Interface &moab, const Range &ents,
43 const int max_dim, EntityHandle &meshset) {
45 Range closure(ents);
46 for (int d = 0; d < max_dim; ++d) {
47 Range adj;
48 CHKERR moab.get_adjacencies(ents, d, false, adj, moab::Interface::UNION);
49 closure.merge(adj);
50 }
51 CHKERR moab.create_meshset(MESHSET_SET, meshset);
52 CHKERR moab.add_entities(meshset, closure);
54}
55
57 Range physical_ents = ents.subset_by_type(MBTET);
58 physical_ents.merge(ents.subset_by_type(MBHEX));
59 return physical_ents;
60}
61
62MoFEMErrorCode getPrismTriangleFaces(moab::Interface &moab, const Range &ents,
63 Range &triangle_faces) {
65 triangle_faces.clear();
66 const auto prisms = ents.subset_by_type(MBPRISM);
67 if (!prisms.empty()) {
68 CHKERR moab.get_adjacencies(prisms, 2, false, triangle_faces,
69 moab::Interface::UNION);
70 triangle_faces = triangle_faces.subset_by_type(MBTRI);
71 }
73}
74} // namespace ElasticTie
75
77
79
80 boost::shared_ptr<ElasticTie::CommonData> tieData = nullptr;
82
83 MoFEMErrorCode readMesh() override;
88
89private:
90 MoFEMErrorCode checkStressError(const int test);
91};
92
96 auto meshset_mng = mField.getInterface<MeshsetsManager>();
97 auto comm_interface = mField.getInterface<CommInterface>();
98 CHKERR simple->getOptions();
100
101 if (SPACE_DIM == 3 && mField.get_comm_size() > 1) {
102 auto load_fun = [&](MoFEM::Interface &mf, const char *file_name,
103 const char *) -> MoFEMErrorCode {
105 auto &moab = mf.get_moab();
106 CHKERR moab.load_file(file_name, 0,
107 "PARALLEL=BCAST;PARTITION=PARALLEL_PARTITION;");
108
109 auto *pcomm = ParallelComm::get_pcomm(&moab, MYPCOMM_INDEX);
110 if (pcomm == nullptr)
111 pcomm = new ParallelComm(&moab, mf.get_comm());
112
113 const auto rank = pcomm->rank();
114 Tag part_tag = pcomm->part_tag();
115 Range all_ents, tagged_sets, proc_ents, off_proc_ents;
116 CHKERR moab.get_entities_by_handle(0, all_ents, false);
117 CHKERR moab.get_entities_by_type_and_tag(
118 0, MBENTITYSET, &part_tag, NULL, 1, tagged_sets,
119 moab::Interface::UNION);
120
121 for (auto meshset : tagged_sets) {
122 int part = -1;
123 CHKERR moab.tag_get_data(part_tag, &meshset, 1, &part);
124 Range meshset_ents;
125 CHKERR moab.get_entities_by_handle(meshset, meshset_ents, true);
126 if (part == rank)
127 proc_ents.merge(meshset_ents);
128 else
129 off_proc_ents.merge(meshset_ents);
130 CHKERR moab.tag_clear_data(part_tag, meshset_ents, &part);
131 }
132
133 const auto all_volume_ents = all_ents.subset_by_dimension(3);
134 const auto proc_volume_ents = proc_ents.subset_by_dimension(3);
135 const auto all_phys_ents = ElasticTie::getPhysicalVolumeEntities(all_ents);
136 const auto proc_phys_ents = ElasticTie::getPhysicalVolumeEntities(proc_ents);
137
138 std::array<Range, 4> proc_ents_skin;
139 Skinner skin(&moab);
140 Range all_skin, proc_skin;
141 CHKERR skin.find_skin(0, all_volume_ents, false, all_skin);
142 CHKERR skin.find_skin(0, proc_volume_ents, false, proc_skin);
143 proc_ents_skin[2] = subtract(proc_skin, all_skin);
144
145 Range all_phys_skin, local_phys_faces, physical_boundary_faces;
146 CHKERR skin.find_skin(0, all_phys_ents.subset_by_dimension(3), false,
147 all_phys_skin);
148 CHKERR moab.get_adjacencies(proc_phys_ents, 2, false, local_phys_faces,
149 moab::Interface::UNION);
150 physical_boundary_faces = intersect(all_phys_skin, local_phys_faces);
151 if (!physical_boundary_faces.empty()) {
152 CHKERR moab.tag_clear_data(pcomm->partition_tag(), physical_boundary_faces,
153 &rank);
154 }
155 proc_ents_skin[2].merge(physical_boundary_faces);
156
157 Range prism_triangle_faces;
158 CHKERR ElasticTie::getPrismTriangleFaces(moab, proc_ents, prism_triangle_faces);
159 proc_ents_skin[2].merge(prism_triangle_faces);
160 CHKERR moab.get_adjacencies(proc_ents_skin[2], 1, false,
161 proc_ents_skin[1],
162 moab::Interface::UNION);
163 CHKERR moab.get_connectivity(proc_ents_skin[2], proc_ents_skin[0],
164 false);
165
166 auto to_remove = off_proc_ents;
167 for (int d = 2; d >= 0; --d)
168 to_remove = subtract(to_remove, proc_ents_skin[d]);
169
170 Range all_meshsets;
171 CHKERR moab.get_entities_by_type(0, MBENTITYSET, all_meshsets, true);
172 for (auto meshset : all_meshsets)
173 CHKERR moab.remove_entities(meshset, to_remove);
174
175 for (int d = 3; d > 0; --d) {
176 Range ents = to_remove.subset_by_dimension(d);
177 if (!ents.empty())
178 CHKERR moab.delete_entities(ents);
179 }
180
181 physicalBoundaryFaces = physical_boundary_faces;
182 CHKERR pcomm->resolve_shared_ents(0, proc_ents, 3, -1,
183 proc_ents_skin.data());
184
186 };
187
188 CHKERR simple->loadFile("", "", load_fun);
189 } else {
190 CHKERR simple->loadFile();
191 }
192
193 if (SPACE_DIM == 3 && mField.get_comm_size() > 1) {
194 CHKERR comm_interface->synchroniseEntities(physicalBoundaryFaces);
195 }
196
197 CHKERR meshset_mng->setMeshsetFromFile();
199}
200
204
205 enum bases { AINSWORTH, DEMKOWICZ, LASBASETOPT };
206 const char *list_bases[LASBASETOPT] = {"ainsworth", "demkowicz"};
207 PetscInt choice_base_value = AINSWORTH;
208 CHKERR PetscOptionsGetEList(PETSC_NULLPTR, NULL, "-base", list_bases,
209 LASBASETOPT, &choice_base_value, PETSC_NULLPTR);
210
212 switch (choice_base_value) {
213 case AINSWORTH:
215 break;
216 case DEMKOWICZ:
218 break;
219 default:
220 base = LASTBASE;
221 break;
222 }
223
224 int order = 3;
225 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-order", &order, PETSC_NULLPTR);
226
227 if (SPACE_DIM == 3) {
228 Range domain_ents;
229 CHKERR mField.get_moab().get_entities_by_handle(simple->getMeshset(),
230 domain_ents, true);
231 auto tet_hex_ents = ElasticTie::getPhysicalVolumeEntities(domain_ents);
232
233 if (!tet_hex_ents.empty()) {
234 EntityHandle domain_meshset;
236 domain_meshset);
237 simple->getMeshset() = domain_meshset;
238
239 Range boundary_faces;
240 if (mField.get_comm_size() > 1) {
241 Skinner skin(&mField.get_moab());
242 Range local_skin;
243 CHKERR skin.find_skin(0, tet_hex_ents, false, local_skin);
244 boundary_faces = intersect(physicalBoundaryFaces, local_skin);
245 } else if (!physicalBoundaryFaces.empty()) {
246 boundary_faces = physicalBoundaryFaces;
247 } else {
248 Skinner skin(&mField.get_moab());
249 CHKERR skin.find_skin(0, tet_hex_ents, false, boundary_faces);
250 }
251 EntityHandle boundary_meshset;
253 SPACE_DIM - 1, boundary_meshset);
254 simple->getBoundaryMeshSet() = boundary_meshset;
255 }
256 }
257
260 order);
261
263}
264
270
279
282
284
285 auto norm_fe = boost::make_shared<DomainEle>(mField);
286 norm_fe->getRuleHook = [](int, int, int approx_order) {
287 return 2 * approx_order + 1;
288 };
289
291 norm_fe->getOpPtrVector(), {H1}, "GEOMETRY");
292
293 auto common_ptr = HookeOps::commonDataFactory<SPACE_DIM, GAUSS, DomainEle>(
294 mField, norm_fe->getOpPtrVector(), "U", "MAT_ELASTIC", Sev::verbose);
295
296 auto exact_stress_ptr = boost::make_shared<MatrixDouble>();
297
298 constexpr double uniaxial_stress_xx = 1e3 * 0.3 / 3.0;
299 auto uniaxial_stress = [](const double, const double, const double) {
300 MatrixDouble stress((SPACE_DIM * (SPACE_DIM + 1)) / 2, 1);
301 stress.clear();
302 auto t_stress = getFTensor2SymmetricFromMat<
304 t_stress(0, 0) = uniaxial_stress_xx;
305 return stress;
306 };
307
309 lame_solution(0.5, 1.0, 2.0, 1.0, 1e3, 0.3);
310 auto lame_stress = [&lame_solution](const double x, const double y,
311 const double z) {
312 return lame_solution.stress(x, y, z);
313 };
314
315 MatrixFunc stress_func = (test == 11) ? MatrixFunc(lame_stress)
316 : MatrixFunc(uniaxial_stress);
317 norm_fe->getOpPtrVector().push_back(
319 exact_stress_ptr, stress_func));
320
321 enum Norms { STRESS_ERROR_L2 = 0, STRESS_EXACT_L2, LAST_NORM };
322 auto norms_vec =
324 (mField.get_comm_rank() == 0) ? LAST_NORM : 0,
325 LAST_NORM);
326 CHKERR VecZeroEntries(norms_vec);
327
328 norm_fe->getOpPtrVector().push_back(
330 exact_stress_ptr, norms_vec, STRESS_EXACT_L2));
331 norm_fe->getOpPtrVector().push_back(
333 common_ptr->getMatCauchyStress(), norms_vec, STRESS_ERROR_L2,
334 exact_stress_ptr));
335
336 CHKERR DMoFEMLoopFiniteElements(simple->getDM(), simple->getDomainFEName(),
337 norm_fe);
338 CHKERR VecAssemblyBegin(norms_vec);
339 CHKERR VecAssemblyEnd(norms_vec);
340
341 if (mField.get_comm_rank() == 0) {
342 const double *norms;
343 CHKERR VecGetArrayRead(norms_vec, &norms);
344
345 const double error_l2 = std::sqrt(norms[STRESS_ERROR_L2]);
346 const double exact_l2 = std::sqrt(norms[STRESS_EXACT_L2]);
347
348 MOFEM_LOG_C("WORLD", Sev::inform, "STRESS_ERROR_L2 = %.16e\n", error_l2);
349 MOFEM_LOG_C("WORLD", Sev::inform, "STRESS_EXACT_L2 = %.16e\n", exact_l2);
350
351 CHKERR VecRestoreArrayRead(norms_vec, &norms);
352
353 double max_error_l2 = 1e-2;
354 CHKERR PetscOptionsGetReal(PETSC_NULLPTR, "", "-stress_error_l2_tol",
355 &max_error_l2, PETSC_NULLPTR);
356 if (error_l2 >= max_error_l2) {
357 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
358 "Stress L2 error %.16e exceeds tolerance %.16e", error_l2,
359 max_error_l2);
360 }
361 }
362
364}
365
368
369 int test = 0;
370 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-test", &test, PETSC_NULLPTR);
371 if (test == 10 || test == 11)
374}
375
376static char help[] = "...\n\n";
377
378int main(int argc, char *argv[]) {
379
380 const char param_file[] = "param_file.petsc";
381 MoFEM::Core::Initialize(&argc, &argv, param_file, help);
382
384
385 auto core_log = logging::core::get();
386 core_log->add_sink(
388 core_log->add_sink(
390 LogManager::setLog("FieldEvaluator");
391 MOFEM_LOG_TAG("FieldEvaluator", "field_eval");
392
393 try {
394 DMType dm_name = "DMMOFEM";
395 CHKERR DMRegister_MoFEM(dm_name);
396 DMType dm_name_mg = "DMMOFEM_MG";
398
399 moab::Core mb_instance;
400 moab::Interface &moab = mb_instance;
401
402 MoFEM::Core core(moab);
403 MoFEM::Interface &m_field = core;
404
405 ElasticTieMeshExample ex(m_field);
406 CHKERR ex.runProblem();
407 }
409
411}
Implementation of elastic example class.
TIE constraint support for the elastic tutorial.
#define MOFEM_LOG_C(channel, severity, format,...)
void simple(double P1[], double P2[], double P3[], double c[], const int N)
Definition acoustic.cpp:69
int main()
ElementsAndOps< SPACE_DIM >::DomainEle DomainEle
ElementsAndOps< SPACE_DIM >::BoundaryEle BoundaryEle
#define CATCH_ERRORS
Catch errors.
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 MYPCOMM_INDEX
default communicator number PCOMM
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
@ 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.
constexpr int order
static char help[]
constexpr int SPACE_DIM
constexpr IntegrationType I
constexpr AssemblyType A
PetscErrorCode DMRegister_MoFEM(const char sname[])
Register MoFEM problem.
Definition DMMoFEM.cpp:43
MoFEMErrorCode DMRegister_MGViaApproxOrders(const char sname[])
Register DM for Multi-Grid via approximation orders.
PetscErrorCode DMoFEMLoopFiniteElements(DM dm, const char fe_name[], MoFEM::FEMethod *method, CacheTupleWeakPtr cache_ptr=CacheTupleSharedPtr())
Executes FEMethod for finite elements in DM.
Definition DMMoFEM.cpp:576
IntegrationType
Form integrator integration types.
AssemblyType
[Storage and set boundary conditions]
@ PETSC
Standard PETSc assembly.
static LoggerType & setLog(const std::string channel)
Set ans resset chanel logger.
#define MOFEM_LOG_TAG(channel, tag)
Tag channel.
Range getPhysicalVolumeEntities(const Range &ents)
MoFEMErrorCode initializeTieConstraints(MoFEM::Interface &mField, boost::shared_ptr< CommonData > &tie_data, const std::string &field_name, FieldApproximationBase base, int order)
MoFEMErrorCode getPrismTriangleFaces(moab::Interface &moab, const Range &ents, Range &triangle_faces)
MoFEMErrorCode logTieDisplacementNorms(MoFEM::Interface &mField, const boost::shared_ptr< CommonData > &tie_data, const std::string &field_name)
MoFEMErrorCode makeClosureMeshset(moab::Interface &moab, const Range &ents, const int max_dim, EntityHandle &meshset)
MoFEMErrorCode setupTieSolver(MoFEM::Interface &mField, boost::shared_ptr< CommonData > tie_data, SmartPetscObj< KSP > solver)
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
implementation of Data Operators for Forces and Sources
Definition Common.hpp:10
PetscErrorCode PetscOptionsGetInt(PetscOptions *, const char pre[], const char name[], PetscInt *ivalue, PetscBool *set)
PetscErrorCode PetscOptionsGetReal(PetscOptions *, const char pre[], const char name[], PetscReal *dval, PetscBool *set)
static auto getFTensor2SymmetricFromMat(M &data)
Get symmetric tensor rank 2 (matrix) form data matrix.
auto createVectorMPI(MPI_Comm comm, PetscInt n, PetscInt N)
Create MPI Vector.
boost::function< MatrixDouble(const double, const double, const double)> MatrixFunc
PetscErrorCode PetscOptionsGetEList(PetscOptions *, const char pre[], const char name[], const char *const *list, PetscInt next, PetscInt *value, PetscBool *set)
static constexpr int approx_order
Lamé analytical solution for a hollow cylinder under radial pressure with a linear isotropic Hooke ma...
MoFEM::MatrixDouble stress(const double x, const double y, const double) const
Return the Cauchy stress in symmetric tensor storage at point (x, y, z).
Boundary conditions marker.
Definition elastic.cpp:39
[Define entities]
Definition elastic.cpp:38
virtual MoFEMErrorCode setupProblem()
[Read mesh]
virtual MoFEMErrorCode kspSetUpAndSolve(SmartPetscObj< KSP > solver)
MoFEMErrorCode runProblem()
[Run problem]
MoFEM::Interface & mField
ElasticExample(MoFEM::Interface &m_field)
MoFEMErrorCode readMesh() override
[Run problem]
MoFEMErrorCode setupProblem() override
[Read mesh]
boost::shared_ptr< ElasticTie::CommonData > tieData
MoFEMErrorCode checkStressError(const int test)
MoFEMErrorCode checkResults() override
[Postprocess results]
MoFEMErrorCode setUpSolver(SmartPetscObj< KSP > solver) override
[Push operators to pipeline]
MoFEMErrorCode kspSetUpAndSolve(SmartPetscObj< KSP > solver) override
Add operators pushing bases from local to physical configuration.
Managing BitRefLevels.
virtual int get_comm_size() const =0
virtual moab::Interface & get_moab()=0
virtual MPI_Comm & get_comm() const =0
virtual int get_comm_rank() const =0
Core (interface) class.
Definition Core.hpp:83
static MoFEMErrorCode Initialize(int *argc, char ***args, const char file[], const char help[])
Initializes the MoFEM database PETSc, MOAB and MPI.
Definition Core.cpp:68
static MoFEMErrorCode Finalize()
Checks for options to be called at the conclusion of the program.
Definition Core.cpp:123
Deprecated interface functions.
Data on single entity (This is passed as argument to DataOperator::doWork)
static boost::shared_ptr< SinkType > createSink(boost::shared_ptr< std::ostream > stream_ptr, std::string comm_filter)
Create a sink object.
static boost::shared_ptr< std::ostream > getStrmWorld()
Get the strm world object.
static boost::shared_ptr< std::ostream > getStrmSync()
Get the strm sync object.
Interface for managing meshsets containing materials and boundary conditions.
Assembly methods.
Definition Natural.hpp:65
Get norm of input MatrixDouble for symmetric Tensor2.
Get values from matrix function in symmetric tensor storage at integration points and save them to Ma...
Template struct for dimension-specific finite element types.
Simple interface for fast problem set-up.
Definition Simple.hpp:27
intrusive_ptr for managing petsc objects
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.
#define EXECUTABLE_DIMENSION
Definition plastic.cpp:13
ElementsAndOps< SPACE_DIM >::SideEle SideEle
Definition plastic.cpp:62
#define SCHUR_ASSEMBLE
Definition contact.cpp:18