v0.16.0
Loading...
Searching...
No Matches
mofem/tutorials/vec-2_nonlinear_elasticity/src/NonlinearElasticExample.hpp
Date
2025-10-5
/**
* @file NonlinearElasticExample.hpp
* @example mofem/tutorials/vec-2_nonlinear_elasticity/src/NonlinearElasticExample.hpp
* @date 2025-10-5
*
* @copyright Anonymous authors (c) 2025 under the MIT license (see LICENSE for
* details)
*/
#ifdef WITH_ADOL_C
#include <MatOps.hpp>
#include <MatElastic.hpp>
#include <MatHuHu.hpp>
#include <MatUmat.hpp>
#ifdef WITH_ADOL_C_SIMPLE_DAMAGE
#endif
#endif
MoFEMErrorCode runProblem();
protected:
boost::shared_ptr<DomainEle> updateFe;
boost::shared_ptr<PostProcEleDomain> postProcDomainFe;
boost::shared_ptr<PostProcEleBdy> postProcBdyFe;
PetscBool useAdolcMaterial = PETSC_FALSE;
MoFEMErrorCode readMesh();
MoFEMErrorCode setupProblem();
MoFEMErrorCode boundaryCondition();
MoFEMErrorCode assembleSystemHencky();
MoFEMErrorCode assembleSystemAdolc();
MoFEMErrorCode opTest();
MoFEMErrorCode TsSolve();
MoFEMErrorCode gettingNorms();
MoFEMErrorCode outputResults();
MoFEMErrorCode checkPiolaStress(PetscInt test_nb);
MoFEMErrorCode checkResults();
struct TSElasticPostStep {
static MoFEMErrorCode
elasticExamplePtr = example_ptr;
return 0;
}
static MoFEMErrorCode postStepDestroy() {
elasticExamplePtr = nullptr;
return 0;
}
static MoFEMErrorCode preStepFun(TS ts) { return 0; }
static MoFEMErrorCode postStepFun(TS ts) {
(void)ts;
auto dm = simple->getDM();
CHKERR DMoFEMLoopFiniteElements(dm, simple->getDomainFEName(),
}
}
private:
};
std::vector<Tag>
listTagsToTransfer; ///< list of tags to transfer to postprocessor
#ifdef WITH_ADOL_C
static inline constexpr int modelType =
boost::shared_ptr<MatOps::PhysicalEquations> physicalEquationsPtr;
boost::shared_ptr<MatOps::PhysicalEquations> physicalHuHuPtr;
#endif
static auto get_skin(MoFEM::Interface &m_field, Range body_ents) {
Skinner skin(&m_field.get_moab());
Range skin_ents;
CHK_MOAB_THROW(skin.find_skin(0, body_ents, false, skin_ents), "find_skin");
return skin_ents;
};
static auto filter_true_skin(MoFEM::Interface &m_field, Range &&skin) {
Range boundary_ents;
ParallelComm *pcomm =
ParallelComm::get_pcomm(&m_field.get_moab(), MYPCOMM_INDEX);
CHK_MOAB_THROW(pcomm->filter_pstatus(skin,
PSTATUS_SHARED | PSTATUS_MULTISHARED,
PSTATUS_NOT, -1, &boundary_ents),
"filter_pstatus");
return boundary_ents;
};
};
//! [Run problem]
PetscBool test_op = PETSC_FALSE;
CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-test_op", &test_op,
PETSC_NULLPTR);
if (useAdolcMaterial == PETSC_TRUE) {
} else {
}
if (test_op == PETSC_TRUE) {
}
}
//! [Run problem]
//! [Read mesh]
auto simple = mField.getInterface<Simple>();
CHKERR simple->getOptions();
CHKERR simple->loadFile();
CHKERR mField.getInterface<MeshsetsManager>()->setMeshsetFromFile();
}
//! [Read mesh]
//! [Set up problem]
Simple *simple = mField.getInterface<Simple>();
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:
MOFEM_LOG("WORLD", Sev::inform)
<< "Set AINSWORTH_LEGENDRE_BASE for displacements";
break;
case DEMKOWICZ:
MOFEM_LOG("WORLD", Sev::inform)
<< "Set DEMKOWICZ_JACOBI_BASE for displacements";
break;
default:
break;
}
// Add field
CHKERR simple->addDomainField("U", H1, approximationBase, SPACE_DIM);
CHKERR simple->addBoundaryField("U", H1, approximationBase, SPACE_DIM);
CHKERR simple->addDataField("GEOMETRY", H1, approximationBase, SPACE_DIM);
int order = 2;
CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-order", &order, PETSC_NULLPTR);
CHKERR simple->setFieldOrder("U", order);
CHKERR simple->setFieldOrder("GEOMETRY", 2);
CHKERR simple->setUp();
auto project_ho_geometry = [&]() {
Projection10NodeCoordsOnField ent_method(mField, "GEOMETRY");
return mField.loop_dofs("GEOMETRY", ent_method);
};
CHKERR project_ho_geometry();
CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-use_adolc_material",
&useAdolcMaterial, PETSC_NULLPTR);
#ifndef WITH_ADOL_C
if (useAdolcMaterial == PETSC_TRUE) {
SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
"ADOL-C support is not enabled. Please reconfigure with "
"-DWITH_ADOL_C=ON and recompile to use AdolC material model.");
}
#endif
if (useAdolcMaterial == PETSC_TRUE) {
MOFEM_LOG("WORLD", Sev::inform) << "Use ADOL-C material model";
} else {
MOFEM_LOG("WORLD", Sev::inform) << "Use Hencky material model";
}
auto tag_meshest = [&]() {
auto set_block = [&](auto name, int dim) {
std::map<int, Range> map;
auto set_tag_impl = [&](auto name) {
auto mesh_mng = mField.getInterface<MeshsetsManager>();
auto bcs = mesh_mng->getCubitMeshsetPtr(
std::regex((boost::format("%s(.*)") % name).str())
);
std::map<int, int> ids_map;
int bit_id = 1;
for (auto bc : bcs) {
int id = bc->getMeshsetId();
ids_map[id] = bit_id;
bit_id <<= 1;
}
for (auto bc : bcs) {
CHKERR bc->getMeshsetIdEntitiesByDimension(mField.get_moab(), dim, r,
true);
map[ids_map[bc->getMeshsetId()]] = r;
MOFEM_LOG("EXAMPLE", Sev::inform)
<< "Block " << name << " id " << bc->getMeshsetId() << " : "
<< ids_map[bc->getMeshsetId()] << " has " << r.size()
<< " entities";
}
};
CHKERR set_tag_impl(name);
return std::make_pair(name, map);
};
auto set_skin = [&](auto &&map) {
for (auto &m : map.second) {
auto s = filter_true_skin(mField, get_skin(mField, m.second));
m.second.swap(s);
MOFEM_LOG("EXAMPLE", Sev::inform)
<< "Skin for block " << map.first << " id " << m.first << " has "
<< m.second.size() << " entities";
}
return map;
};
auto set_tag = [&](auto &&map) {
auto name = map.first;
int def_val[] = {-1};
CHK_MOAB_THROW(mField.get_moab().tag_get_handle(
name, 1, MB_TYPE_INTEGER, th,
MB_TAG_SPARSE | MB_TAG_CREAT, def_val),
"create tag");
for (auto &m : map.second) {
int id = m.first;
for (auto ent : m.second) {
int current_id;
mField.get_moab().tag_get_data(th, &ent, 1, &current_id),
"get tag data");
if (current_id != -1) {
id |= current_id;
}
CHK_MOAB_THROW(mField.get_moab().tag_set_data(th, &ent, 1, &id),
"set tag data");
}
}
return th;
};
if (SPACE_DIM == 3) {
listTagsToTransfer.push_back(set_tag(set_block("MAT_", 3)));
listTagsToTransfer.push_back(set_tag(set_skin(set_block("MAT_", 3))));
} else {
listTagsToTransfer.push_back(set_tag(set_block("MAT_", 2)));
}
};
CHKERR tag_meshest();
}
//! [Set up problem]
//! [Boundary condition]
auto *pipeline_mng = mField.getInterface<PipelineManager>();
auto simple = mField.getInterface<Simple>();
auto bc_mng = mField.getInterface<BcManager>();
auto time_scale = boost::make_shared<ExampleTimeScale>();
CHKERR BoundaryNaturalBC::AddFluxToPipeline<OpForce>::add(
pipeline_mng->getOpBoundaryRhsPipeline(), mField, "U", {time_scale},
"FORCE", "PRESSURE", Sev::inform);
//! [Define gravity vector]
CHKERR DomainNaturalBC::AddFluxToPipeline<OpBodyForce>::add(
pipeline_mng->getOpDomainRhsPipeline(), mField, "U", {time_scale},
"BODY_FORCE", Sev::inform);
// Essential BC
CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "REMOVE_X",
"U", 0, 0);
CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "REMOVE_Y",
"U", 1, 1);
CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "REMOVE_Z",
"U", 2, 2);
CHKERR bc_mng->pushMarkDOFsOnEntities<DisplacementCubitBcData>(
simple->getProblemName(), "U");
}
//! [Boundary condition]
//! [Push operators to pipeline]
auto *pipeline_mng = mField.getInterface<PipelineManager>();
auto integration_rule = [](int, int, int approx_order) {
return 2 * (approx_order - 1) + 1;
};
CHKERR pipeline_mng->setDomainRhsIntegrationRule(integration_rule);
CHKERR pipeline_mng->setDomainLhsIntegrationRule(integration_rule);
CHKERR pipeline_mng->setBoundaryRhsIntegrationRule(integration_rule);
CHKERR pipeline_mng->setEvaluationIntegrationRule(integration_rule);
auto add_domain_ops_lhs = [&](auto &pip) {
"GEOMETRY");
HenckyOps::opFactoryDomainLhs<SPACE_DIM, PETSC, GAUSS, DomainEleOp>(
mField, pip, "U", "MAT_ELASTIC", Sev::inform);
};
auto add_domain_ops_rhs = [&](auto &pip) {
"GEOMETRY");
HenckyOps::opFactoryDomainRhs<SPACE_DIM, PETSC, GAUSS, DomainEleOp>(
mField, pip, "U", "MAT_ELASTIC", Sev::inform);
};
CHKERR add_domain_ops_lhs(pipeline_mng->getOpDomainLhsPipeline());
CHKERR add_domain_ops_rhs(pipeline_mng->getOpDomainRhsPipeline());
// push operators to evaluation pipeline
CHKERR add_domain_ops_rhs(pipeline_mng->getOpEvaluationPipeline());
auto &domain_reaction_fe = pipeline_mng->getEvaluationFE();
domain_reaction_fe->postProcessHook =
EssentialPreProcReaction<DisplacementCubitBcData>(mField,
domain_reaction_fe);
PetscBool post_proc_vol;
PetscBool post_proc_skin;
if constexpr (SPACE_DIM == 2) {
post_proc_vol = PETSC_TRUE;
post_proc_skin = PETSC_FALSE;
} else {
post_proc_vol = PETSC_FALSE;
post_proc_skin = PETSC_TRUE;
}
CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-post_proc_vol",
&post_proc_vol, PETSC_NULLPTR);
CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-post_proc_skin",
&post_proc_skin, PETSC_NULLPTR);
// Setup postprocessing
auto create_post_proc_fe = [&]() {
auto post_proc_ele_domain = [this](auto &pip_domain) {
"GEOMETRY");
auto common_ptr = commonDataFactory<SPACE_DIM, GAUSS, DomainEleOp>(
mField, pip_domain, "U", "MAT_ELASTIC", Sev::inform);
return common_ptr;
};
auto post_proc_map = [&](auto &pip, auto u_ptr, auto common_ptr) {
using OpPPMap = OpPostProcMapInMoab<SPACE_DIM, SPACE_DIM>;
pip->getOpPtrVector().push_back(
new OpPPMap(pip->getPostProcMesh(), pip->getMapGaussPts(), {},
{{"U", u_ptr}},
{{"GRAD", common_ptr->matGradPtr},
{"FIRST_PIOLA", common_ptr->getMatFirstPiolaStress()}},
{}));
};
auto push_post_proc_bdy = [&](auto &pip_bdy) {
if (post_proc_skin == PETSC_FALSE)
return boost::shared_ptr<PostProcEleBdy>();
auto simple = mField.getInterface<Simple>();
auto domain_fe_name = simple->getDomainFEName();
auto u_ptr = boost::make_shared<MatrixDouble>();
pip_bdy->getOpPtrVector().push_back(
new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_ptr));
auto op_loop_side =
new OpLoopSide<SideEle>(mField, domain_fe_name, SPACE_DIM);
auto common_ptr = post_proc_ele_domain(op_loop_side->getOpPtrVector());
pip_bdy->getOpPtrVector().push_back(op_loop_side);
CHKERR post_proc_map(pip_bdy, u_ptr, common_ptr);
return pip_bdy;
};
auto push_post_proc_domain = [&](auto &pip_domain) {
if (post_proc_vol == PETSC_FALSE)
return boost::shared_ptr<PostProcEleDomain>();
auto u_ptr = boost::make_shared<MatrixDouble>();
pip_domain->getOpPtrVector().push_back(
new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_ptr));
auto common_ptr = post_proc_ele_domain(pip_domain->getOpPtrVector());
CHKERR post_proc_map(pip_domain, u_ptr, common_ptr);
return pip_domain;
};
auto post_proc_fe_domain = boost::make_shared<PostProcEleDomain>(mField);
auto post_proc_fe_bdy = boost::make_shared<PostProcEleBdy>(mField);
return std::make_pair(push_post_proc_domain(post_proc_fe_domain),
push_post_proc_bdy(post_proc_fe_bdy));
};
auto post_proc_pair = create_post_proc_fe();
postProcDomainFe = post_proc_pair.first;
postProcBdyFe = post_proc_pair.second;
}
//! [Push operators to pipeline]
// get operators tester
auto simple = mField.getInterface<Simple>();
auto opt = mField.getInterface<OperatorsTester>(); // get interface to
// OperatorsTester
auto pip = mField.getInterface<PipelineManager>(); // get interface to
// pipeline manager
constexpr double eps = 1e-9;
auto x = opt->setRandomFields(simple->getDM(), {
{"U", {-1e-6, 1e-6}}
});
auto dot_x = opt->setRandomFields(simple->getDM(), {
{"U", {-1, 1}}
});
auto diff_x = opt->setRandomFields(simple->getDM(), {
{"U", {-1, 1}}
});
auto test_domain_ops = [&](auto fe_name, auto lhs_pipeline,
auto rhs_pipeline) {
auto diff_res = opt->checkCentralFiniteDifference(
simple->getDM(), fe_name, rhs_pipeline, lhs_pipeline, x, dot_x,
SmartPetscObj<Vec>(), diff_x, 0, 0.5, eps);
// Calculate norm of difference between directional derivative calculated
// from finite difference, and tangent matrix.
double fnorm;
CHKERR VecNorm(diff_res, NORM_2, &fnorm);
MOFEM_LOG_C("EXAMPLE", Sev::inform,
"Test consistency of tangent matrix %3.4e", fnorm);
constexpr double err = 1e-5;
if (fnorm > err)
SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
"Norm of directional derivative too large err = %3.4e", fnorm);
};
MOFEM_LOG("EXAMPLE", Sev::inform)
<< "Test operators with finite difference of directional "
"derivative";
CHKERR test_domain_ops(simple->getDomainFEName(), pip->getDomainLhsFE(),
pip->getDomainRhsFE());
}
auto *simple = mField.getInterface<Simple>();
auto *pipeline_mng = mField.getInterface<PipelineManager>();
auto integration_rule = [](int, int, int approx_order) {
return 2 * (approx_order - 1) + 1;
};
CHKERR pipeline_mng->setDomainRhsIntegrationRule(integration_rule);
CHKERR pipeline_mng->setDomainLhsIntegrationRule(integration_rule);
CHKERR pipeline_mng->setBoundaryRhsIntegrationRule(integration_rule);
CHKERR pipeline_mng->setEvaluationIntegrationRule(integration_rule);
#ifdef WITH_ADOL_C
auto mat_ops_data_ptr = MatOps::createMatOpsDataPtr();
#ifdef WITH_ADOL_C_UMAT
{
constexpr int umat_model_type =
auto umat_physical_equations_ptr =
umat_model_type>(
mat_ops_data_ptr, MatOps::MatOpsTagsRegistry::setTagName("Umat"));
CHKERR umat_physical_equations_ptr->getOptions(&mField);
CHKERR umat_physical_equations_ptr->recordTape();
physicalEquationsPtr = umat_physical_equations_ptr;
}
#else
mat_ops_data_ptr,
}
#ifdef WITH_ADOL_C_GENERIC_ELASTIC
{
auto generic_physical_equations_ptr =
mat_ops_data_ptr,
// In example, lets do a simple linear elastic material, so we can verify the tangent matrix
generic_physical_equations_ptr->hookEvaluateVariable =
generic_physical_equations_ptr->hookEvaluateDerivatives =
generic_physical_equations_ptr->hookUpdateState =
CHKERR generic_physical_equations_ptr->getOptions(&mField);
CHKERR generic_physical_equations_ptr->recordTape();
auto &material_map = getMetaElasticMap(physicalEquationsPtr);
material_map[generic_physical_equations_ptr->tAg] =
generic_physical_equations_ptr;
physicalEquationsPtr->tAg = generic_physical_equations_ptr->tAg;
}
#endif // WITH_ADOL_C_GENERIC_ELASTIC
#ifdef WITH_ADOL_C_SIMPLE_DAMAGE
{
auto generic_physical_equations_ptr =
"GenericElasticSimpleDamage"));
mField, boost::dynamic_pointer_cast<MatOps::GenericElastic>(
generic_physical_equations_ptr));
CHKERR generic_physical_equations_ptr->getOptions(&mField);
CHKERR generic_physical_equations_ptr->recordTape();
auto &material_map = getMetaElasticMap(physicalEquationsPtr);
material_map[generic_physical_equations_ptr->tAg] =
generic_physical_equations_ptr;
physicalEquationsPtr->tAg = generic_physical_equations_ptr->tAg;
}
#endif // WITH_ADOL_C_SIMPLE_DAMAGE
}
const int tag_hu_hu = MatOps::MatOpsTagsRegistry::setTagName("HuHU");
MatOps::createMatOpsPhysicalEquationsPtr<MatOps::HUHU, modelType>(
CHKERR physicalHuHuPtr->getOptions(&mField);
CHKERR physicalHuHuPtr->recordTape();
}
#endif // WITH_ADOL_C_UMAT
auto add_domain_ops_lhs = [&](auto &pip) {
"GEOMETRY");
template opLhsFactory<PETSC, GAUSS, DomainEleOp>(
}
template opLhsFactory<PETSC, GAUSS, DomainEleOp>(
mField, pip, simple->getDomainFEName(), "U", physicalHuHuPtr);
}
};
auto add_domain_ops_rhs = [&](auto &pip) {
"GEOMETRY");
template opRhsFactory<PETSC, GAUSS, DomainEleOp>(
}
template opRhsFactory<PETSC, GAUSS, DomainEleOp>(
mField, pip, simple->getDomainFEName(), "U", physicalHuHuPtr);
}
};
auto add_domain_ops_update = [&](auto &pip) {
"GEOMETRY");
}
};
CHKERR add_domain_ops_lhs(pipeline_mng->getOpDomainLhsPipeline());
CHKERR add_domain_ops_rhs(pipeline_mng->getOpDomainRhsPipeline());
updateFe = boost::make_shared<DomainEle>(mField);
updateFe->getRuleHook = integration_rule;
CHKERR add_domain_ops_update(updateFe->getOpPtrVector());
CHKERR add_domain_ops_rhs(pipeline_mng->getOpEvaluationPipeline());
auto &domain_reaction_fe = pipeline_mng->getEvaluationFE();
domain_reaction_fe->postProcessHook =
EssentialPreProcReaction<DisplacementCubitBcData>(mField,
domain_reaction_fe);
PetscBool post_proc_vol;
PetscBool post_proc_skin;
if constexpr (SPACE_DIM == 2) {
post_proc_vol = PETSC_TRUE;
post_proc_skin = PETSC_FALSE;
} else {
post_proc_vol = PETSC_FALSE;
post_proc_skin = PETSC_TRUE;
}
CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-post_proc_vol",
&post_proc_vol, PETSC_NULLPTR);
CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-post_proc_skin",
&post_proc_skin, PETSC_NULLPTR);
// Setup postprocessing
auto create_post_proc_fe = [&]() {
using OpPPMap = OpPostProcMapInMoab<SPACE_DIM, SPACE_DIM>;
auto post_proc_ele_domain = [&](auto &pip_domain) {
"GEOMETRY");
}
};
auto post_proc_map = [&](auto &pip, auto u_ptr) {
auto grad_ptr =
physicalEquationsPtr->matOpsDataPtr->getCommonDataPtr("grad");
auto first_piola_ptr =
physicalEquationsPtr->matOpsDataPtr->getCommonDataPtr("P");
pip->getOpPtrVector().push_back(new OpPPMap(
pip->getPostProcMesh(), pip->getMapGaussPts(), {}, {{"U", u_ptr}},
{{"GRAD", grad_ptr}, {"FIRST_PIOLA", first_piola_ptr}}, {}));
}
};
auto push_post_proc_bdy = [&](auto &pip_bdy) {
if (post_proc_skin == PETSC_FALSE)
return boost::shared_ptr<PostProcEleBdy>();
auto simple = mField.getInterface<Simple>();
auto domain_fe_name = simple->getDomainFEName();
auto u_ptr = boost::make_shared<MatrixDouble>();
pip_bdy->getOpPtrVector().push_back(
new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_ptr));
auto op_loop_side =
new OpLoopSide<SideEle>(mField, domain_fe_name, SPACE_DIM);
CHKERR post_proc_ele_domain(op_loop_side->getOpPtrVector());
pip_bdy->getOpPtrVector().push_back(op_loop_side);
CHKERR post_proc_map(pip_bdy, u_ptr);
return pip_bdy;
};
auto push_post_proc_domain = [&](auto &pip_domain) {
if (post_proc_vol == PETSC_FALSE)
return boost::shared_ptr<PostProcEleDomain>();
auto u_ptr = boost::make_shared<MatrixDouble>();
pip_domain->getOpPtrVector().push_back(
new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_ptr));
CHKERR post_proc_ele_domain(pip_domain->getOpPtrVector());
auto state_tags = physicalEquationsPtr->matOpsDataPtr->getStateTags();
if (!state_tags.empty()) {
MatOps::StateTags selected_state_tags;
MatOps::StateTags statev_tags;
selected_state_tags.reserve(state_tags.size());
statev_tags.reserve(state_tags.size());
constexpr auto statev_prefix = "UMAT_STATEV_";
constexpr auto statev_prefix_len = sizeof("UMAT_STATEV_") - 1;
auto get_statev_index = [&](const std::string &name) {
return std::stoi(name.substr(statev_prefix_len));
};
for (const auto &state_tag : state_tags) {
const auto &name = state_tag.name;
if (name == "UMAT_DFGRD0" || name == "UMAT_STRESS") {
selected_state_tags.push_back(state_tag);
continue;
}
if (name.rfind(statev_prefix, 0) == 0) {
statev_tags.push_back(state_tag);
}
}
std::sort(statev_tags.begin(), statev_tags.end(),
[&](const auto &lhs, const auto &rhs) {
return get_statev_index(lhs.name) <
get_statev_index(rhs.name);
});
if (statev_tags.size() > 10)
statev_tags.resize(10);
selected_state_tags.insert(selected_state_tags.end(),
statev_tags.begin(), statev_tags.end());
if (selected_state_tags.empty())
return pip_domain;
auto simple = mField.getInterface<Simple>();
int state_order = 2;
CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-order", &state_order,
PETSC_NULLPTR);
auto op_loop_this = new OpLoopThis<DomainEle>(
mField, simple->getDomainFEName(), Sev::noisy);
op_loop_this->getThisFEPtr()->getRuleHook = integration_rule;
pip_domain->getOpPtrVector().push_back(op_loop_this);
CHKERR addTagDGProjectionOps<SPACE_DIM, SPACE_DIM>(
mField.get_moab(), pip_domain->getOpPtrVector(),
op_loop_this->getThisFEPtr()->getOpPtrVector(),
pip_domain->getPostProcMesh(), pip_domain->getMapGaussPts(),
selected_state_tags, state_order, approximationBase);
}
}
CHKERR post_proc_map(pip_domain, u_ptr);
return pip_domain;
};
auto post_proc_fe_domain = boost::make_shared<PostProcEleDomain>(mField);
auto post_proc_fe_bdy = boost::make_shared<PostProcEleBdy>(mField);
return std::make_pair(push_post_proc_domain(post_proc_fe_domain),
push_post_proc_bdy(post_proc_fe_bdy));
};
auto post_proc_pair = create_post_proc_fe();
postProcDomainFe = post_proc_pair.first;
postProcBdyFe = post_proc_pair.second;
#else
SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
"ADOL-C support is not enabled. Please reconfigure with "
"-DWITH_ADOL_C=ON and recompile to use AdolC material model.");
#endif // WITH_ADOL
}
//! [TS Solve]
auto *simple = mField.getInterface<Simple>();
auto *pipeline_mng = mField.getInterface<PipelineManager>();
auto dm = simple->getDM();
auto ts = pipeline_mng->createTSIM();
auto add_extra_finite_elements_to_solver_pipelines = [&]() {
auto pre_proc_ptr = boost::make_shared<FEMethod>();
auto post_proc_rhs_ptr = boost::make_shared<FEMethod>();
auto post_proc_lhs_ptr = boost::make_shared<FEMethod>();
auto time_scale = boost::make_shared<ExampleTimeScale>();
auto get_bc_hook_rhs = [this, pre_proc_ptr, time_scale]() {
CHKERR EssentialPreProc<DisplacementCubitBcData>(mField, pre_proc_ptr,
{time_scale}, false)();
};
pre_proc_ptr->preProcessHook = get_bc_hook_rhs;
auto get_post_proc_hook_rhs = [this, post_proc_rhs_ptr]() {
CHKERR EssentialPreProcReaction<DisplacementCubitBcData>(
mField, post_proc_rhs_ptr, nullptr, Sev::verbose)();
CHKERR EssentialPostProcRhs<DisplacementCubitBcData>(
mField, post_proc_rhs_ptr, 1.)();
};
auto get_post_proc_hook_lhs = [this, post_proc_lhs_ptr]() {
CHKERR EssentialPostProcLhs<DisplacementCubitBcData>(
mField, post_proc_lhs_ptr, 1.)();
};
post_proc_rhs_ptr->postProcessHook = get_post_proc_hook_rhs;
post_proc_lhs_ptr->postProcessHook = get_post_proc_hook_lhs;
// This is low level pushing finite elements (pipelines) to solver
auto ts_ctx_ptr = getDMTsCtx(simple->getDM());
ts_ctx_ptr->getPreProcessIFunction().push_front(pre_proc_ptr);
ts_ctx_ptr->getPreProcessIJacobian().push_front(pre_proc_ptr);
ts_ctx_ptr->getPostProcessIFunction().push_back(post_proc_rhs_ptr);
ts_ctx_ptr->getPostProcessIJacobian().push_back(post_proc_lhs_ptr);
};
// Add extra finite elements to SNES solver pipelines to resolve essential
// boundary conditions
CHKERR add_extra_finite_elements_to_solver_pipelines();
auto create_monitor_fe = [dm](auto &&post_proc_fe) {
return boost::make_shared<Monitor>(dm.get(), post_proc_fe);
};
// Set monitor which postprocessing results and saves them to the hard drive
boost::shared_ptr<FEMethod> null_fe;
CHKERR postProcDomainFe->setTagsToTransfer(
std::vector<Tag>(listTagsToTransfer));
CHKERR postProcBdyFe->setTagsToTransfer(
std::vector<Tag>(listTagsToTransfer));
auto monitor_ptr =
create_monitor_fe(std::make_pair(postProcDomainFe, postProcBdyFe));
CHKERR DMMoFEMTSSetMonitor(dm, ts, simple->getDomainFEName(), null_fe,
null_fe, monitor_ptr);
// Set time solver
double ftime = 1;
CHKERR TSSetMaxTime(ts, ftime);
CHKERR TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP);
auto B = createDMMatrix(dm);
CHKERR TSSetI2Jacobian(ts, B, B, PETSC_NULLPTR, PETSC_NULLPTR);
auto D = createDMVector(simple->getDM());
CHKERR TSSetSolution(ts, D);
CHKERR TSSetFromOptions(ts);
CHKERR TSSolve(ts, NULL);
CHKERR TSGetTime(ts, &ftime);
PetscInt steps, snesfails, rejects, nonlinits, linits;
CHKERR TSGetStepNumber(ts, &steps);
CHKERR TSGetSNESFailures(ts, &snesfails);
CHKERR TSGetStepRejections(ts, &rejects);
CHKERR TSGetSNESIterations(ts, &nonlinits);
CHKERR TSGetKSPIterations(ts, &linits);
MOFEM_LOG_C("EXAMPLE", Sev::inform,
"steps %d (%d rejected, %d SNES fails), ftime %g, nonlinits "
"%d, linits %d",
steps, rejects, snesfails, ftime, nonlinits, linits);
}
//! [TS Solve]
//! [Getting norms]
auto simple = mField.getInterface<Simple>();
auto dm = simple->getDM();
auto T = createDMVector(simple->getDM());
CHKERR DMoFEMMeshToLocalVector(simple->getDM(), T, INSERT_VALUES,
SCATTER_FORWARD);
double nrm2;
CHKERR VecNorm(T, NORM_2, &nrm2);
MOFEM_LOG("EXAMPLE", Sev::inform) << "Solution norm " << nrm2;
auto post_proc_norm_fe = boost::make_shared<DomainEle>(mField);
auto post_proc_norm_rule_hook = [](int, int, int p) -> int { return 2 * p; };
post_proc_norm_fe->getRuleHook = post_proc_norm_rule_hook;
post_proc_norm_fe->getOpPtrVector(), {H1}, "GEOMETRY");
enum NORMS { U_NORM_L2 = 0, PIOLA_NORM, LAST_NORM };
auto norms_vec =
(mField.get_comm_rank() == 0) ? LAST_NORM : 0, LAST_NORM);
CHKERR VecZeroEntries(norms_vec);
auto u_ptr = boost::make_shared<MatrixDouble>();
post_proc_norm_fe->getOpPtrVector().push_back(
new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_ptr));
post_proc_norm_fe->getOpPtrVector().push_back(
new OpCalcNormL2Tensor1<SPACE_DIM>(u_ptr, norms_vec, U_NORM_L2));
if (useAdolcMaterial == PETSC_TRUE) {
#ifdef WITH_ADOL_C
opPostProcFactory(mField, post_proc_norm_fe->getOpPtrVector(), "U",
auto m_P = physicalEquationsPtr->matOpsDataPtr->getCommonDataPtr("P");
post_proc_norm_fe->getOpPtrVector().push_back(
new OpCalcNormL2Tensor2<SPACE_DIM, SPACE_DIM>(m_P, norms_vec,
PIOLA_NORM));
}
#else
SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
"ADOL-C support is not enabled. Please reconfigure with "
"-DWITH_ADOL_C=ON and recompile to use AdolC material model.");
#endif
} else {
auto common_ptr = commonDataFactory<SPACE_DIM, GAUSS, DomainEleOp>(
mField, post_proc_norm_fe->getOpPtrVector(), "U", "MAT_ELASTIC",
Sev::inform);
post_proc_norm_fe->getOpPtrVector().push_back(
new OpCalcNormL2Tensor2<SPACE_DIM, SPACE_DIM>(
common_ptr->getMatFirstPiolaStress(), norms_vec, PIOLA_NORM));
}
CHKERR DMoFEMLoopFiniteElements(dm, simple->getDomainFEName(),
post_proc_norm_fe);
CHKERR VecAssemblyBegin(norms_vec);
CHKERR VecAssemblyEnd(norms_vec);
MOFEM_LOG_CHANNEL("SELF"); // Clear channel from old tags
if (mField.get_comm_rank() == 0) {
const double *norms;
CHKERR VecGetArrayRead(norms_vec, &norms);
MOFEM_TAG_AND_LOG("SELF", Sev::inform, "example")
<< "norm_u: " << std::scientific << std::sqrt(norms[U_NORM_L2]);
MOFEM_TAG_AND_LOG("SELF", Sev::inform, "example")
<< "norm_piola: " << std::scientific << std::sqrt(norms[PIOLA_NORM]);
CHKERR VecRestoreArrayRead(norms_vec, &norms);
}
}
//! [Getting norms]
//! [Postprocessing results]
}
//! [Postprocessing results]
auto simple = mField.getInterface<Simple>();
constexpr double applied_F_zz = 0.99;
t_P_expected(i, J) = 0.;
auto set_linear_elastic_piola = [&](const double strain_zz,
const double d_strain_d_F_zz) {
constexpr double E = 1.;
constexpr double nu = 0.3;
const double lambda = E * nu / ((1. + nu) * (1. - 2. * nu));
const double mu = E / (2. * (1. + nu));
for (int d = 0; d != SPACE_DIM - 1; ++d)
t_P_expected(d, d) = lambda * strain_zz;
t_P_expected(SPACE_DIM - 1, SPACE_DIM - 1) =
(lambda + 2. * mu) * strain_zz * d_strain_d_F_zz;
};
auto set_neohookean_piola = [&](const double F_zz, const double J) {
constexpr double c10 = 1.;
constexpr double K = 1.;
double I1 = (SPACE_DIM - 1) + F_zz * F_zz;
if constexpr (SPACE_DIM == 2)
I1 += 1.; // Plane strain has F33 = 1.
const double J_to_minus_two_thirds = std::pow(J, -2. / 3.);
for (int d = 0; d != SPACE_DIM; ++d) {
const double F_dd = d == SPACE_DIM - 1 ? F_zz : 1.;
const double inv_F_dd = 1. / F_dd;
t_P_expected(d, d) =
2. * c10 * J_to_minus_two_thirds *
(F_dd - (I1 / 3.) * inv_F_dd) +
K * J * (J - 1.) * inv_F_dd;
}
};
auto eval_piola_at_point = [&](boost::shared_ptr<MatrixDouble> &mat_p) {
std::array<double, 3> field_eval_coords = {0.123, -0.087, 0.193};
auto field_eval_ptr = mField.getInterface<FieldEvaluatorInterface>();
auto field_eval_data = field_eval_ptr->getData<DomainEle>();
CHKERR field_eval_ptr->buildTree<SPACE_DIM>(field_eval_data,
simple->getDomainFEName());
field_eval_data->setEvalPoints(field_eval_coords.data(), 1);
auto fe = field_eval_data->feMethodPtr;
fe->getRuleHook = [](int, int, int) { return -1; };
auto &pipeline = fe->getOpPtrVector();
"GEOMETRY");
if (useAdolcMaterial == PETSC_FALSE) {
auto common_ptr = commonDataFactory<SPACE_DIM, GAUSS, DomainEleOp>(
mField, pipeline, "U", "MAT_ELASTIC", Sev::inform);
mat_p = common_ptr->getMatFirstPiolaStress();
} else {
#ifdef WITH_ADOL_C
mat_p = physicalEquationsPtr->matOpsDataPtr->getCommonDataPtr("P");
#else
SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
"ADOL-C support is not enabled. Please reconfigure with "
"-DWITH_ADOL_C=ON and recompile to use MatOps material model.");
#endif
}
CHKERR field_eval_ptr->evalFEAtThePoint<SPACE_DIM>(
field_eval_coords.data(), 1e-12, simple->getProblemName(),
simple->getDomainFEName(), field_eval_data, mField.get_comm_rank(),
};
switch (test_nb) {
case 100: {
// Hencky, homogeneous strain_z on cube: E = 1, nu = 0.3.
const double hencky_strain_zz = std::log(applied_F_zz);
set_linear_elastic_piola(hencky_strain_zz, 1. / applied_F_zz);
break;
}
case 101: {
// Neo-Hookean, homogeneous strain_z on cube: c10 = K = 1.
const double J = applied_F_zz;
set_neohookean_piola(applied_F_zz, J);
break;
}
case 102: {
// UMAT small strain, homogeneous strain_z on cube: E = 1, nu = 0.3.
const double small_strain_zz = applied_F_zz - 1.;
set_linear_elastic_piola(small_strain_zz, 1.);
break;
}
default:
SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
"Wrong Piola stress test number.");
break;
}
boost::shared_ptr<MatrixDouble> mat_p;
CHKERR eval_piola_at_point(mat_p);
auto t_P = getFTensor2FromMat<SPACE_DIM, SPACE_DIM>(*mat_p);
t_P_diff(i, J) = t_P(i, J) - t_P_expected(i, J);
const double p_err = std::sqrt(t_P_diff(i, J) * t_P_diff(i, J));
for (int r = 0; r != SPACE_DIM; ++r)
for (int c = 0; c != SPACE_DIM; ++c)
MOFEM_LOG("EXAMPLE", Sev::inform)
<< "Piola stress test " << test_nb << " P(" << r << ", " << c
<< ") actual " << std::scientific << t_P(r, c) << " expected "
<< t_P_expected(r, c) << " diff " << t_P_diff(r, c);
MOFEM_LOG("EXAMPLE", Sev::inform)
<< "Piola stress test " << test_nb << " error " << std::scientific
<< p_err;
if (p_err > 1e-8)
SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
"Wrong Piola stress. Error %6.4e", p_err);
}
//! [Check]
PetscInt test_nb = 0;
PetscBool test_flg = PETSC_FALSE;
CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-test", &test_nb, &test_flg);
if (test_flg) {
if (test_nb >= 100) {
}
auto simple = mField.getInterface<Simple>();
auto T = createDMVector(simple->getDM());
CHKERR DMoFEMMeshToLocalVector(simple->getDM(), T, INSERT_VALUES,
SCATTER_FORWARD);
double nrm2;
CHKERR VecNorm(T, NORM_2, &nrm2);
MOFEM_LOG("EXAMPLE", Sev::verbose) << "Regression norm " << nrm2;
double regression_value = 0;
switch (test_nb) {
case 1:
regression_value = 3.5112e-01;
break;
case 2:
regression_value = 1.8841e+00;
break;
case 3:
regression_value = 1.8841e+00;
break;
default:
SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID, "Wrong test number.");
break;
}
if (fabs(nrm2 - regression_value) > 1e-2)
SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
"Regression test field; wrong norm value. %6.4e != %6.4e", nrm2,
regression_value);
}
}
//! [Check]
#define MOFEM_LOG_C(channel, severity, format,...)
#define MOFEM_TAG_AND_LOG(channel, severity, tag)
Tag and log in channel.
#define FTENSOR_INDEX(DIM, I)
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
@ 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 MYPCOMM_INDEX
default communicator number PCOMM
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
#define CHK_MOAB_THROW(err, msg)
Check error code of MoAB function and throw MoFEM exception.
@ 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
auto integration_rule
PetscErrorCode DMoFEMMeshToLocalVector(DM dm, Vec l, InsertMode mode, ScatterMode scatter_mode, RowColData rc=RowColData::COL)
set local (or ghosted) vector values on mesh for partition only
Definition DMMoFEM.cpp:514
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
auto createDMVector(DM dm, RowColData rc=RowColData::COL)
Get smart vector from DM.
Definition DMMoFEM.hpp:1237
auto createDMMatrix(DM dm)
Get smart matrix from DM.
Definition DMMoFEM.hpp:1194
#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.
FTensor::Index< 'i', SPACE_DIM > i
static double lambda
const double c
speed of light (cm/ns)
double D
FTensor::Index< 'J', DIM1 > J
Definition level_set.cpp:30
MoFEMErrorCode configureSimpleDamage(MoFEM::Interface &m_field, boost::shared_ptr< MatOps::GenericElastic > physical_ptr)
std::map< int, boost::shared_ptr< PhysicalEquations > > & getMetaElasticMap(boost::shared_ptr< PhysicalEquations > meta_ptr)
@ MODEL_3D
Definition MatOps.hpp:181
@ MODEL_2D_PLANE_STRAIN
Definition MatOps.hpp:182
std::vector< StateTag > StateTags
Definition MatOps.hpp:21
boost::shared_ptr< PhysicalEquations > createMatOpsPhysicalEquationsPtr(boost::shared_ptr< MatOpsData > mat_ops_data_ptr, int tag)
boost::shared_ptr< MatOpsData > createMatOpsDataPtr()
Definition MatOps.cpp:671
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
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:1279
PetscErrorCode PetscOptionsGetInt(PetscOptions *, const char pre[], const char name[], PetscInt *ivalue, PetscBool *set)
PetscErrorCode PetscOptionsGetBool(PetscOptions *, const char pre[], const char name[], PetscBool *bval, PetscBool *set)
auto createVectorMPI(MPI_Comm comm, PetscInt n, PetscInt N)
Create MPI Vector.
PetscErrorCode PetscOptionsGetEList(PetscOptions *, const char pre[], const char name[], const char *const *list, PetscInt next, PetscInt *value, PetscBool *set)
int r
Definition sdf.py:205
OpPostProcMapInMoab< SPACE_DIM, SPACE_DIM > OpPPMap
static constexpr int approx_order
FTensor::Index< 'm', 3 > m
static MoFEMErrorCode hookEvaluateVariable(boost::shared_ptr< MatOps::MatOpsData > mat_ops_data_ptr, int, EntityHandle, int)
static MoFEMErrorCode hookEvaluateDerivatives(boost::shared_ptr< MatOps::MatOpsData > mat_ops_data_ptr, int, EntityHandle, int)
static MoFEMErrorCode hookUpdateState(boost::shared_ptr< MatOps::MatOpsData >, int, EntityHandle, int)
static int setTagName(std::string name, int tag=-1)
Definition MatOps.cpp:30
virtual moab::Interface & get_moab()=0
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.
static NonlinearElasticExample * elasticExamplePtr
static MoFEMErrorCode postStepInitialise(NonlinearElasticExample *example_ptr)
FieldApproximationBase approximationBase
MoFEMErrorCode runProblem()
[Run problem]
MoFEMErrorCode checkPiolaStress(PetscInt test_nb)
[Postprocessing results]
boost::shared_ptr< PostProcEleBdy > postProcBdyFe
std::vector< Tag > listTagsToTransfer
list of tags to transfer to postprocessor
boost::shared_ptr< MatOps::PhysicalEquations > physicalEquationsPtr
MoFEMErrorCode setupProblem()
[Read mesh]
MoFEMErrorCode readMesh()
[Run problem]
MoFEMErrorCode assembleSystemHencky()
[Boundary condition]
MoFEMErrorCode boundaryCondition()
[Set up problem]
MoFEMErrorCode opTest()
[Push operators to pipeline]
boost::shared_ptr< PostProcEleDomain > postProcDomainFe
MoFEMErrorCode TsSolve()
[TS Solve]
MoFEMErrorCode outputResults()
[Getting norms]
static auto get_skin(MoFEM::Interface &m_field, Range body_ents)
static auto filter_true_skin(MoFEM::Interface &m_field, Range &&skin)
MoFEMErrorCode checkResults()
[Check]
boost::shared_ptr< MatOps::PhysicalEquations > physicalHuHuPtr
MoFEMErrorCode gettingNorms()
[TS Solve]
boost::shared_ptr< DomainEle > updateFe