v0.16.0
Loading...
Searching...
No Matches
mofem/tutorials/vec-11_elastic_tie_mesh/elastic_tie_mesh.cpp

Elastic mesh tie example with a tie-aware partitioned mesh loader.

Elastic mesh tie example with a tie-aware partitioned mesh loader

/**
* @file elastic_tie_mesh.cpp
* @example mofem/tutorials/vec-11_elastic_tie_mesh/elastic_tie_mesh.cpp
* @brief Elastic mesh tie example with a tie-aware partitioned mesh loader
*
* @copyright Anonymous authors (c) 2025 under the MIT license
*/
#include <MoFEM.hpp>
using namespace MoFEM;
constexpr AssemblyType A =
(SCHUR_ASSEMBLE) ? AssemblyType::BLOCK_SCHUR : AssemblyType::PETSC;
constexpr IntegrationType I = IntegrationType::GAUSS;
using BoundaryEle =
using DomainEleOp = DomainEle::UserDataOperator;
using BoundaryEleOp = BoundaryEle::UserDataOperator;
struct DomainBCs {};
struct BoundaryBCs {};
using OpDomainRhsBCs = DomainRhsBCs::OpFlux<DomainBCs, 1, SPACE_DIM>;
using OpBoundaryRhsBCs = BoundaryRhsBCs::OpFlux<BoundaryBCs, 1, SPACE_DIM>;
using OpBoundaryLhsBCs = BoundaryLhsBCs::OpFlux<BoundaryBCs, 1, SPACE_DIM>;
#include <ElasticTie.hpp>
namespace ElasticTie {
MoFEMErrorCode makeClosureMeshset(moab::Interface &moab, const Range &ents,
const int max_dim, EntityHandle &meshset) {
Range closure(ents);
for (int d = 0; d < max_dim; ++d) {
Range adj;
CHKERR moab.get_adjacencies(ents, d, false, adj, moab::Interface::UNION);
closure.merge(adj);
}
CHKERR moab.create_meshset(MESHSET_SET, meshset);
CHKERR moab.add_entities(meshset, closure);
}
Range physical_ents = ents.subset_by_type(MBTET);
physical_ents.merge(ents.subset_by_type(MBHEX));
return physical_ents;
}
MoFEMErrorCode getPrismTriangleFaces(moab::Interface &moab, const Range &ents,
Range &triangle_faces) {
triangle_faces.clear();
const auto prisms = ents.subset_by_type(MBPRISM);
if (!prisms.empty()) {
CHKERR moab.get_adjacencies(prisms, 2, false, triangle_faces,
moab::Interface::UNION);
triangle_faces = triangle_faces.subset_by_type(MBTRI);
}
}
} // namespace ElasticTie
boost::shared_ptr<ElasticTie::CommonData> tieData = nullptr;
private:
};
auto meshset_mng = mField.getInterface<MeshsetsManager>();
auto comm_interface = mField.getInterface<CommInterface>();
CHKERR simple->getOptions();
if (SPACE_DIM == 3 && mField.get_comm_size() > 1) {
auto load_fun = [&](MoFEM::Interface &mf, const char *file_name,
const char *) -> MoFEMErrorCode {
auto &moab = mf.get_moab();
CHKERR moab.load_file(file_name, 0,
"PARALLEL=BCAST;PARTITION=PARALLEL_PARTITION;");
auto *pcomm = ParallelComm::get_pcomm(&moab, MYPCOMM_INDEX);
if (pcomm == nullptr)
pcomm = new ParallelComm(&moab, mf.get_comm());
const auto rank = pcomm->rank();
Tag part_tag = pcomm->part_tag();
Range all_ents, tagged_sets, proc_ents, off_proc_ents;
CHKERR moab.get_entities_by_handle(0, all_ents, false);
CHKERR moab.get_entities_by_type_and_tag(
0, MBENTITYSET, &part_tag, NULL, 1, tagged_sets,
moab::Interface::UNION);
for (auto meshset : tagged_sets) {
int part = -1;
CHKERR moab.tag_get_data(part_tag, &meshset, 1, &part);
Range meshset_ents;
CHKERR moab.get_entities_by_handle(meshset, meshset_ents, true);
if (part == rank)
proc_ents.merge(meshset_ents);
else
off_proc_ents.merge(meshset_ents);
CHKERR moab.tag_clear_data(part_tag, meshset_ents, &part);
}
const auto all_volume_ents = all_ents.subset_by_dimension(3);
const auto proc_volume_ents = proc_ents.subset_by_dimension(3);
const auto all_phys_ents = ElasticTie::getPhysicalVolumeEntities(all_ents);
const auto proc_phys_ents = ElasticTie::getPhysicalVolumeEntities(proc_ents);
std::array<Range, 4> proc_ents_skin;
Skinner skin(&moab);
Range all_skin, proc_skin;
CHKERR skin.find_skin(0, all_volume_ents, false, all_skin);
CHKERR skin.find_skin(0, proc_volume_ents, false, proc_skin);
proc_ents_skin[2] = subtract(proc_skin, all_skin);
Range all_phys_skin, local_phys_faces, physical_boundary_faces;
CHKERR skin.find_skin(0, all_phys_ents.subset_by_dimension(3), false,
all_phys_skin);
CHKERR moab.get_adjacencies(proc_phys_ents, 2, false, local_phys_faces,
moab::Interface::UNION);
physical_boundary_faces = intersect(all_phys_skin, local_phys_faces);
if (!physical_boundary_faces.empty()) {
CHKERR moab.tag_clear_data(pcomm->partition_tag(), physical_boundary_faces,
&rank);
}
proc_ents_skin[2].merge(physical_boundary_faces);
Range prism_triangle_faces;
CHKERR ElasticTie::getPrismTriangleFaces(moab, proc_ents, prism_triangle_faces);
proc_ents_skin[2].merge(prism_triangle_faces);
CHKERR moab.get_adjacencies(proc_ents_skin[2], 1, false,
proc_ents_skin[1],
moab::Interface::UNION);
CHKERR moab.get_connectivity(proc_ents_skin[2], proc_ents_skin[0],
false);
auto to_remove = off_proc_ents;
for (int d = 2; d >= 0; --d)
to_remove = subtract(to_remove, proc_ents_skin[d]);
Range all_meshsets;
CHKERR moab.get_entities_by_type(0, MBENTITYSET, all_meshsets, true);
for (auto meshset : all_meshsets)
CHKERR moab.remove_entities(meshset, to_remove);
for (int d = 3; d > 0; --d) {
Range ents = to_remove.subset_by_dimension(d);
if (!ents.empty())
CHKERR moab.delete_entities(ents);
}
physicalBoundaryFaces = physical_boundary_faces;
CHKERR pcomm->resolve_shared_ents(0, proc_ents, 3, -1,
proc_ents_skin.data());
};
CHKERR simple->loadFile("", "", load_fun);
} else {
CHKERR simple->loadFile();
}
if (SPACE_DIM == 3 && mField.get_comm_size() > 1) {
CHKERR comm_interface->synchroniseEntities(physicalBoundaryFaces);
}
CHKERR meshset_mng->setMeshsetFromFile();
}
enum bases { AINSWORTH, DEMKOWICZ, LASBASETOPT };
const char *list_bases[LASBASETOPT] = {"ainsworth", "demkowicz"};
PetscInt choice_base_value = AINSWORTH;
CHKERR PetscOptionsGetEList(PETSC_NULLPTR, NULL, "-base", list_bases,
LASBASETOPT, &choice_base_value, PETSC_NULLPTR);
switch (choice_base_value) {
case AINSWORTH:
break;
case DEMKOWICZ:
break;
default:
base = LASTBASE;
break;
}
int order = 3;
CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-order", &order, PETSC_NULLPTR);
if (SPACE_DIM == 3) {
Range domain_ents;
CHKERR mField.get_moab().get_entities_by_handle(simple->getMeshset(),
domain_ents, true);
auto tet_hex_ents = ElasticTie::getPhysicalVolumeEntities(domain_ents);
if (!tet_hex_ents.empty()) {
EntityHandle domain_meshset;
domain_meshset);
simple->getMeshset() = domain_meshset;
Range boundary_faces;
if (mField.get_comm_size() > 1) {
Skinner skin(&mField.get_moab());
Range local_skin;
CHKERR skin.find_skin(0, tet_hex_ents, false, local_skin);
boundary_faces = intersect(physicalBoundaryFaces, local_skin);
} else if (!physicalBoundaryFaces.empty()) {
boundary_faces = physicalBoundaryFaces;
} else {
Skinner skin(&mField.get_moab());
CHKERR skin.find_skin(0, tet_hex_ents, false, boundary_faces);
}
EntityHandle boundary_meshset;
SPACE_DIM - 1, boundary_meshset);
simple->getBoundaryMeshSet() = boundary_meshset;
}
}
}
}
}
auto norm_fe = boost::make_shared<DomainEle>(mField);
norm_fe->getRuleHook = [](int, int, int approx_order) {
return 2 * approx_order + 1;
};
norm_fe->getOpPtrVector(), {H1}, "GEOMETRY");
auto common_ptr = HookeOps::commonDataFactory<SPACE_DIM, GAUSS, DomainEle>(
mField, norm_fe->getOpPtrVector(), "U", "MAT_ELASTIC", Sev::verbose);
auto exact_stress_ptr = boost::make_shared<MatrixDouble>();
constexpr double uniaxial_stress_xx = 1e3 * 0.3 / 3.0;
auto uniaxial_stress = [](const double, const double, const double) {
MatrixDouble stress((SPACE_DIM * (SPACE_DIM + 1)) / 2, 1);
stress.clear();
auto t_stress = getFTensor2SymmetricFromMat<
t_stress(0, 0) = uniaxial_stress_xx;
return stress;
};
lame_solution(0.5, 1.0, 2.0, 1.0, 1e3, 0.3);
auto lame_stress = [&lame_solution](const double x, const double y,
const double z) {
return lame_solution.stress(x, y, z);
};
MatrixFunc stress_func = (test == 11) ? MatrixFunc(lame_stress)
: MatrixFunc(uniaxial_stress);
norm_fe->getOpPtrVector().push_back(
exact_stress_ptr, stress_func));
enum Norms { STRESS_ERROR_L2 = 0, STRESS_EXACT_L2, LAST_NORM };
auto norms_vec =
(mField.get_comm_rank() == 0) ? LAST_NORM : 0,
LAST_NORM);
CHKERR VecZeroEntries(norms_vec);
norm_fe->getOpPtrVector().push_back(
exact_stress_ptr, norms_vec, STRESS_EXACT_L2));
norm_fe->getOpPtrVector().push_back(
common_ptr->getMatCauchyStress(), norms_vec, STRESS_ERROR_L2,
exact_stress_ptr));
CHKERR DMoFEMLoopFiniteElements(simple->getDM(), simple->getDomainFEName(),
norm_fe);
CHKERR VecAssemblyBegin(norms_vec);
CHKERR VecAssemblyEnd(norms_vec);
if (mField.get_comm_rank() == 0) {
const double *norms;
CHKERR VecGetArrayRead(norms_vec, &norms);
const double error_l2 = std::sqrt(norms[STRESS_ERROR_L2]);
const double exact_l2 = std::sqrt(norms[STRESS_EXACT_L2]);
MOFEM_LOG_C("WORLD", Sev::inform, "STRESS_ERROR_L2 = %.16e\n", error_l2);
MOFEM_LOG_C("WORLD", Sev::inform, "STRESS_EXACT_L2 = %.16e\n", exact_l2);
CHKERR VecRestoreArrayRead(norms_vec, &norms);
double max_error_l2 = 1e-2;
CHKERR PetscOptionsGetReal(PETSC_NULLPTR, "", "-stress_error_l2_tol",
&max_error_l2, PETSC_NULLPTR);
if (error_l2 >= max_error_l2) {
SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
"Stress L2 error %.16e exceeds tolerance %.16e", error_l2,
max_error_l2);
}
}
}
int test = 0;
CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-test", &test, PETSC_NULLPTR);
if (test == 10 || test == 11)
}
static char help[] = "...\n\n";
int main(int argc, char *argv[]) {
const char param_file[] = "param_file.petsc";
MoFEM::Core::Initialize(&argc, &argv, param_file, help);
MeshsetsManager::broadcastMeshsetsOn = false;
auto core_log = logging::core::get();
core_log->add_sink(
LogManager::createSink(LogManager::getStrmWorld(), "TIMER"));
core_log->add_sink(
LogManager::createSink(LogManager::getStrmSync(), "FieldEvaluator"));
LogManager::setLog("FieldEvaluator");
MOFEM_LOG_TAG("FieldEvaluator", "field_eval");
try {
DMType dm_name = "DMMOFEM";
DMType dm_name_mg = "DMMOFEM_MG";
moab::Core mb_instance;
moab::Interface &moab = mb_instance;
MoFEM::Core core(moab);
MoFEM::Interface &m_field = core;
ElasticTieMeshExample ex(m_field);
CHKERR ex.runProblem();
}
}
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
static char help[]
int main()
constexpr int SPACE_DIM
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
constexpr int SPACE_DIM
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]
#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.
UBlasMatrix< double > MatrixDouble
Definition Types.hpp:77
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)
constexpr IntegrationType I
constexpr AssemblyType A
static constexpr int approx_order
Lamé analytical solution for a hollow cylinder under radial pressure with a linear isotropic Hooke ma...
Boundary conditions marker.
Definition elastic.cpp:39
[Define entities]
Definition elastic.cpp:38
virtual MoFEMErrorCode setupProblem()
[Read mesh]
virtual MoFEMErrorCode kspSetUpAndSolve(SmartPetscObj< KSP > solver)
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
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)
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.
NaturalBC< BoundaryEleOp >::Assembly< AT >::BiLinearForm< IT > BoundaryLhsBCs
Definition plastic.cpp:176
NaturalBC< BoundaryEleOp >::Assembly< AT >::LinearForm< IT > BoundaryRhsBCs
Definition plastic.cpp:173
#define EXECUTABLE_DIMENSION
Definition plastic.cpp:13
BoundaryLhsBCs::OpFlux< PlasticOps::BoundaryBCs, 1, SPACE_DIM > OpBoundaryLhsBCs
Definition plastic.cpp:178
NaturalBC< DomainEleOp >::Assembly< AT >::LinearForm< IT > DomainRhsBCs
Definition plastic.cpp:170
DomainRhsBCs::OpFlux< PlasticOps::DomainBCs, 1, SPACE_DIM > OpDomainRhsBCs
Definition plastic.cpp:172
BoundaryRhsBCs::OpFlux< PlasticOps::BoundaryBCs, 1, SPACE_DIM > OpBoundaryRhsBCs
Definition plastic.cpp:175
ElementsAndOps< SPACE_DIM >::SideEle SideEle
Definition plastic.cpp:62
#define SCHUR_ASSEMBLE
Definition contact.cpp:18