v0.16.3
Loading...
Searching...
No Matches
MatNeohookean.cpp
Go to the documentation of this file.
1/**
2 * @file MatNeohookean.cpp
3 * @author your name (you@domain.com)
4 * @brief Abaqus-compatible compressible Neo-Hookean material
5 * @version 0.1
6 * @date 2026-03-26
7 *
8 * @copyright Copyright (c) 2026
9 *
10 */
11
12namespace MatOps {
13template <typename M> struct MatNeohookeanOptions {
14 static constexpr auto optionsPrefix = "neo_hookean_";
15 static constexpr auto defaultLogTag = "Default Neohookean parameters:";
16 static constexpr auto blockLogTag = "MatBlock for Neohookean";
17};
18
19template <int DIM> struct MatNeohookeanOptions<TopoMatObjectiveImpl<DIM>> {
20 static constexpr auto optionsPrefix = "topo_neo_hookean_";
21 static constexpr auto defaultLogTag = "Default Topo Neohookean parameters:";
22 static constexpr auto blockLogTag = "MatBlock for Topo Neohookean";
23};
24
25template <typename M> struct MatNeohookeanGeneric : public M {
26 using A = M;
27 using A::A;
28
29 static inline double getShearModulus(const double c10) { return 2. * c10; }
30
31 static inline double getAbaqusD1(const double K) { return 2. / K; }
32
34 const double K,
35 const char *source) {
37 if (!std::isfinite(c10) || c10 <= 0.) {
38 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
39 "Neohookean C10 must be finite and positive in %s", source);
40 }
41 if (!std::isfinite(K) || K <= 0.) {
42 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
43 "Neohookean bulk modulus K must be finite and positive in %s "
44 "(received C10=%.16g, K=%.16g)",
45 source, c10, K);
46 }
48 }
49
50 MoFEMErrorCode getOptions(MoFEM::Interface *m_field_ptr = nullptr) override {
52
53 MOFEM_LOG_CHANNEL("WORLD");
54
55 if (!A::paramVecByRange.empty()) {
56 for (const auto &[range, parameters] : A::paramVecByRange) {
57 (void)range;
58 if (parameters.size() != 2) {
59 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
60 "Neohookean material range needs exactly C10 and K");
61 }
62 CHKERR validateMaterialParameters(parameters[0], parameters[1],
63 "preconfigured material range");
64 }
66 }
67
68 PetscOptionsBegin(PETSC_COMM_WORLD, "neo_hookean_", "", "none");
69 CHKERR PetscOptionsScalar("-c10", "C10", "", C10, &C10, PETSC_NULLPTR);
70 CHKERR PetscOptionsScalar("-K", "Bulk modulus K", "", K, &K, PETSC_NULLPTR);
71 PetscOptionsEnd();
72 CHKERR validateMaterialParameters(C10, K, "command-line parameters");
74
75 std::string block_name = "MAT_NEOHOOKEAN";
76
77 for (auto &m :
78
79 m_field_ptr->getInterface<MeshsetsManager>()->
80
81 getCubitMeshsetPtr(
82 std::regex((boost::format("%s(.*)") % block_name).str()))
83
84 ) {
85
86 std::vector<double> block_data;
87 CHKERR m->getAttributes(block_data);
88 auto get_block_ents = [&]() {
89 Range ents;
90 CHK_MOAB_THROW(m_field_ptr->get_moab().get_entities_by_handle(
91 m->meshset, ents, true),
92 "can not get block entities");
93 return ents;
94 };
95
96 CHKERR addBlockParameters(*m_field_ptr, m->getName(), m->getMeshsetId(),
97 get_block_ents(), block_data);
98 }
99
100 if (A::paramVecByRange.empty()) {
102 MOFEM_TAG_AND_LOG("WORLD", Sev::inform,
103 "Command line Neohookean parameters")
104 << "C10 = " << C10 << " K = " << K << " mu = " << getShearModulus(C10)
105 << " Abaqus D1 = " << getAbaqusD1(K);
106 }
107
109 }
110
112 addBlockParameters(MoFEM::Interface &m_field, const std::string &block_name,
113 int block_id, const Range &block_entities,
114 const std::vector<double> &block_data) override {
116
117 const auto json_params =
118 m_field.getInterface<JsonConfigManager>()->getParamsFromBlockset(
119 "MAT_NEOHOOKEAN", block_id);
120 std::vector<double> params;
121 if (!json_params.empty()) {
122 if (json_params.size() != 2 ||
123 json_params.find("c10") == json_params.end() ||
124 json_params.find("k") == json_params.end()) {
125 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
126 "Neohookean JSON block %s needs exactly C10 and K attributes",
127 block_name.c_str());
128 }
129 params = {json_params.at("c10"), json_params.at("k")};
130 } else {
131 if (block_data.size() < 2) {
132 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
133 "Neohookean block %s has %d attributes; expected C10 and K",
134 block_name.c_str(), static_cast<int>(block_data.size()));
135 }
136 params = {block_data[0], block_data[1]};
137 }
138
139 CHKERR validateMaterialParameters(params[0], params[1], block_name.c_str());
140
141 A::paramVecByRange.push_back({block_entities, params});
142
143 MOFEM_TAG_AND_LOG("WORLD", Sev::inform, "MatBlock for Neohookean")
144 << block_name << " C10 = " << params[0] << " K = " << params[1]
145 << " mu = " << getShearModulus(params[0])
146 << " Abaqus D1 = " << getAbaqusD1(params[1]);
147
149 }
150
151protected:
152 double C10 = 1;
153 double K = 2;
154 std::vector<double> defaultMaterialParameters = {C10, K};
155 std::vector<double> commandLineParameters;
156};
157
158template <int DIM>
159struct MatNeohookean : public MatNeohookeanGeneric<MatElasticImpl<DIM>> {
161 using A::A;
162
163 MoFEMErrorCode setParams(FEMethod *fe_ptr, int gg) override {
164 (void)gg;
165 const auto ent = fe_ptr->getFEEntityHandle();
166 for (auto &[range, param_vec] : A::paramVecByRange) {
167 if (std::find(range.begin(), range.end(), ent) != range.end()) {
168 set_param_vec(A::tAg, param_vec.size(), param_vec.data());
169 return 0;
170 }
171 }
172 // command line overrides block parameters
173 if (!this->commandLineParameters.empty()) {
174 set_param_vec(A::tAg, this->commandLineParameters.size(),
175 this->commandLineParameters.data());
176 return 0;
177 }
178 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
179 "Neohookean material parameters not found for entity %lu",
180 static_cast<unsigned long>(ent));
181 }
182
185
186 A::matOpsDataPtr->insertCommonData("grad", MatrixDouble());
187 A::matOpsDataPtr->insertCommonData("P", MatrixDouble());
188 A::matOpsDataPtr->insertCommonData("P_dF", MatrixDouble());
189
190 A::matOpsDataPtr->insertActiveData("F", MatrixDouble());
191 A::matOpsDataPtr->insertDependentData("P", MatrixDouble());
192 A::matOpsDataPtr->insertDependentData("energy", MatrixDouble());
193 A::matOpsDataPtr->insertDependentDerivativesData("P_dF", MatrixDouble());
194 A::matOpsDataPtr->insertDependentDerivativesData("energy_dF",
195 MatrixDouble());
196
197 A::matOpsDataPtr->getActiveDataPtr("F")->resize(DIM, DIM, false);
198 A::matOpsDataPtr->getDependentDataPtr("P")->resize(DIM, DIM, false);
199 A::matOpsDataPtr->getDependentDataPtr("energy")->resize(1, 1, false);
200 A::matOpsDataPtr->getDependentDerivativesDataPtr("energy_dF")
201 ->resize(1, DIM * DIM, false);
202
203 auto t_F = getFTensor2FromPtr<DIM, DIM>(
204 A::matOpsDataPtr->getActiveDataPtr("F")->data().data());
205 auto t_P = getFTensor2FromPtr<DIM, DIM>(
206 A::matOpsDataPtr->getDependentDataPtr("P")->data().data());
207 auto energy_ptr = A::matOpsDataPtr->getDependentDataPtr("energy");
208
210
211 FTENSOR_INDEX(DIM, i);
212 FTENSOR_INDEX(DIM, j);
213 FTENSOR_INDEX(DIM, I);
214 FTENSOR_INDEX(DIM, J);
215
216 t_F(i, J) = 0;
217
220
221 adouble det_aF, I1, ta_energy;
223
224 trace_on(A::tAg);
225 auto p_c10 = mkparam(this->C10);
226 auto p_K = mkparam(this->K);
227
228 ta_F(i, J) <<= t_F(i, J);
229 // assume that gradient from approximated displacement, that why we add diagonal
231 ta_F(i, J) += t_kd(i, J);
232 }
233
234 det_aF = determinantTensor(ta_F);
235 I1 = ta_F(i, I) * ta_F(i, I);
236 if constexpr (DIM == 2) {
237 // Abaqus plane strain uses the three-dimensional potential with F33=1.
238 I1 += 1.;
239 }
240 CHKERR invertTensor(ta_F, det_aF, ta_invF);
241
242 // Abaqus compressible Neo-Hookean potential (reduced polynomial N=1):
243 //
244 // W = C10 * (I1_bar - 3) + (1 / D1) * (J - 1)^2,
245 // I1_bar = J^(-2/3) * I1, mu0 = 2*C10, D1 = 2/K0.
246 //
247 // Its first Piola stress is
248 //
249 // P = 2*C10*J^(-2/3)*(F - I1/3*F^(-T))
250 // + K0*J*(J - 1)*F^(-T).
251 const auto jacobian_to_minus_two_thirds = pow(det_aF, -2. / 3.);
252 ta_P(i, I) = 2. * p_c10 * jacobian_to_minus_two_thirds *
253 (ta_F(i, I) - (I1 / 3.) * ta_invF(I, i)) +
254 p_K * det_aF * (det_aF - 1.) * ta_invF(I, i);
255
256 ta_energy = p_c10 * (jacobian_to_minus_two_thirds * I1 - 3.) +
257 0.5 * p_K * (det_aF - 1.) * (det_aF - 1.);
258
259 ta_P(i, I) >>= t_P(i, I);
260 ta_energy >>= (*energy_ptr)(0, 0);
261
262 trace_off();
263
265 }
266};
267
268template <>
269boost::shared_ptr<PhysicalEquations>
271 boost::shared_ptr<MatOpsData> mat_ops_data_ptr, int tag) {
272 return boost::make_shared<MatNeohookean<3>>(mat_ops_data_ptr, tag);
273}
274
275template <>
276boost::shared_ptr<PhysicalEquations>
278 boost::shared_ptr<MatOpsData> mat_ops_data_ptr, int tag) {
279 return boost::make_shared<MatNeohookean<2>>(mat_ops_data_ptr, tag);
280}
281
282template <>
283boost::shared_ptr<PhysicalEquations>
285 boost::shared_ptr<MatOpsData> mat_ops_data_ptr, int tag) {
286 return boost::make_shared<MatNeohookean<3>>(mat_ops_data_ptr, tag);
287}
288
289} // namespace MatOps
#define MOFEM_TAG_AND_LOG(channel, severity, tag)
Tag and log in channel.
#define FTENSOR_INDEX(DIM, I)
Kronecker Delta class.
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#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_DATA_INCONSISTENCY
Definition definitions.h:31
@ MOFEM_INVALID_DATA
Definition definitions.h:36
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
constexpr auto t_kd
#define MOFEM_LOG_CHANNEL(channel)
Set and reset channel.
FTensor::Index< 'i', SPACE_DIM > i
FTensor::Index< 'J', DIM1 > J
Definition level_set.cpp:30
FTensor::Index< 'j', 3 > j
boost::shared_ptr< PhysicalEquations > createMatOpsPhysicalEquationsPtr< ELASTICITY::NEOHOOKEAN, MODEL_AXISYMMETRIC >(boost::shared_ptr< MatOpsData > mat_ops_data_ptr, int tag)
boost::shared_ptr< PhysicalEquations > createMatOpsPhysicalEquationsPtr< ELASTICITY::NEOHOOKEAN, MODEL_3D >(boost::shared_ptr< MatOpsData > mat_ops_data_ptr, int tag)
boost::shared_ptr< PhysicalEquations > createMatOpsPhysicalEquationsPtr< ELASTICITY::NEOHOOKEAN, MODEL_2D_PLANE_STRAIN >(boost::shared_ptr< MatOpsData > mat_ops_data_ptr, int tag)
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
UBlasMatrix< double > MatrixDouble
Definition Types.hpp:77
static MoFEMErrorCode invertTensor(FTensor::Tensor2< T1, DIM, DIM > &t, T2 &det, FTensor::Tensor2< T3, DIM, DIM > &inv_t)
static auto determinantTensor(FTensor::Tensor2< T, DIM, DIM > &t)
Calculate the determinant of a tensor of rank DIM.
constexpr IntegrationType I
FTensor::Index< 'm', 3 > m
static double getShearModulus(const double c10)
std::vector< double > commandLineParameters
std::vector< double > defaultMaterialParameters
static MoFEMErrorCode validateMaterialParameters(const double c10, const double K, const char *source)
MoFEMErrorCode getOptions(MoFEM::Interface *m_field_ptr=nullptr) override
static double getAbaqusD1(const double K)
MoFEMErrorCode addBlockParameters(MoFEM::Interface &m_field, const std::string &block_name, int block_id, const Range &block_entities, const std::vector< double > &block_data) override
static constexpr auto defaultLogTag
static constexpr auto blockLogTag
static constexpr auto optionsPrefix
MoFEMErrorCode recordTape() override
MoFEMErrorCode setParams(FEMethod *fe_ptr, int gg) override
static bool useDeformationGradient
Otherwise the displacement gradient is supplied and I is added.
Definition MatOps.hpp:189
std::vector< std::pair< Range, std::vector< double > > > paramVecByRange
Definition MatOps.hpp:174
boost::shared_ptr< MatOpsData > matOpsDataPtr
Definition MatOps.hpp:176
Deprecated interface functions.
Structure for user loop methods on finite elements.
EntityHandle getFEEntityHandle() const
Get the entity handle of the current finite element.
Interface for managing meshsets containing materials and boundary conditions.
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.