v0.16.0
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<TopoMatElasticImpl<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) {
30 return 2. * c10;
31 }
32
33 static inline double getAbaqusD1(const double K) {
34 return 2. / K;
35 }
36
38 const double K,
39 const char *source) {
41 if (!std::isfinite(c10) || c10 <= 0.) {
42 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
43 "Neohookean C10 must be finite and positive in %s", source);
44 }
45 if (!std::isfinite(K) || K <= 0.) {
46 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
47 "Neohookean bulk modulus K must be finite and positive in %s "
48 "(received C10=%.16g, K=%.16g)",
49 source, c10, K);
50 }
52 }
53
54 MoFEMErrorCode getOptions(MoFEM::Interface *m_field_ptr = nullptr) override {
56
57 MOFEM_LOG_CHANNEL("WORLD");
58
59 if (!A::paramVecByRange.empty()) {
60 for (const auto &[range, parameters] : A::paramVecByRange) {
61 (void)range;
62 if (parameters.size() != 2) {
63 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
64 "Neohookean material range needs exactly C10 and K");
65 }
66 CHKERR validateMaterialParameters(parameters[0], parameters[1],
67 "preconfigured material range");
68 }
70 }
71
72 PetscOptionsBegin(PETSC_COMM_WORLD, "neo_hookean_", "", "none");
73 CHKERR PetscOptionsScalar("-c10", "C10", "", C10, &C10, PETSC_NULLPTR);
74 CHKERR PetscOptionsScalar("-K", "Bulk modulus K", "", K, &K,
75 PETSC_NULLPTR);
76 PetscOptionsEnd();
77 CHKERR validateMaterialParameters(C10, K, "command-line parameters");
79
80 std::string block_name = "MAT_NEOHOOKEAN";
81
82 for (auto &m :
83
84 m_field_ptr->getInterface<MeshsetsManager>()->
85
86 getCubitMeshsetPtr(
87 std::regex((boost::format("%s(.*)") % block_name).str()))
88
89 ) {
90
91 std::vector<double> block_data;
92 CHKERR m->getAttributes(block_data);
93 auto get_block_ents = [&]() {
94 Range ents;
95 CHK_MOAB_THROW(m_field_ptr->get_moab().get_entities_by_handle(
96 m->meshset, ents, true),
97 "can not get block entities");
98 return ents;
99 };
100
101 CHKERR addBlockParameters(*m_field_ptr, m->getName(),
102 m->getMeshsetId(), get_block_ents(),
103 block_data);
104 }
105
106 if (A::paramVecByRange.empty()) {
108 MOFEM_TAG_AND_LOG("WORLD", Sev::inform,
109 "Command line Neohookean parameters")
110 << "C10 = " << C10 << " K = " << K
111 << " mu = " << getShearModulus(C10)
112 << " Abaqus D1 = " << getAbaqusD1(K);
113 }
114
116 }
117
119 addBlockParameters(MoFEM::Interface &m_field, const std::string &block_name,
120 int block_id, const Range &block_entities,
121 const std::vector<double> &block_data) override {
123
124 const auto json_params =
125 m_field.getInterface<JsonConfigManager>()->getParamsFromBlockset(
126 "MAT_NEOHOOKEAN", block_id);
127 std::vector<double> params;
128 if (!json_params.empty()) {
129 if (json_params.size() != 2 ||
130 json_params.find("c10") == json_params.end() ||
131 json_params.find("k") == json_params.end()) {
132 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
133 "Neohookean JSON block %s needs exactly C10 and K attributes",
134 block_name.c_str());
135 }
136 params = {json_params.at("c10"), json_params.at("k")};
137 } else {
138 if (block_data.size() < 2) {
139 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
140 "Neohookean block %s has %d attributes; expected C10 and K",
141 block_name.c_str(), static_cast<int>(block_data.size()));
142 }
143 params = {block_data[0], block_data[1]};
144 }
145
146 CHKERR validateMaterialParameters(params[0], params[1],
147 block_name.c_str());
148
149 A::paramVecByRange.push_back({block_entities, params});
150
151 MOFEM_TAG_AND_LOG("WORLD", Sev::inform, "MatBlock for Neohookean")
152 << block_name << " C10 = " << params[0] << " K = " << params[1]
153 << " mu = " << getShearModulus(params[0])
154 << " Abaqus D1 = " << getAbaqusD1(params[1]);
155
157 }
158
159protected:
160 double C10 = 1;
161 double K = 2;
162 std::vector<double> defaultMaterialParameters = {C10, K};
163 std::vector<double> commandLineParameters;
164};
165
166template <int DIM>
167struct MatNeohookean : public MatNeohookeanGeneric<MatElasticImpl<DIM>> {
169 using A::A;
170
171 MoFEMErrorCode setParams(FEMethod *fe_ptr, int gg) override {
172 (void)gg;
173 const auto ent = fe_ptr->getFEEntityHandle();
174 for (auto &[range, param_vec] : A::paramVecByRange) {
175 if (std::find(range.begin(), range.end(), ent) != range.end()) {
176 set_param_vec(A::tAg, param_vec.size(), param_vec.data());
177 return 0;
178 }
179 }
180 // command line overrides block parameters
181 if (!this->commandLineParameters.empty()) {
182 set_param_vec(A::tAg, this->commandLineParameters.size(),
183 this->commandLineParameters.data());
184 return 0;
185 }
186 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
187 "Neohookean material parameters not found for entity %lu",
188 static_cast<unsigned long>(ent));
189 }
190
193
194 A::matOpsDataPtr->insertCommonData("grad", MatrixDouble());
195 A::matOpsDataPtr->insertCommonData("P", MatrixDouble());
196 A::matOpsDataPtr->insertCommonData("P_dF", MatrixDouble());
197
198 A::matOpsDataPtr->insertActiveData("F", MatrixDouble());
199 A::matOpsDataPtr->insertDependentData("P", MatrixDouble());
200 A::matOpsDataPtr->insertDependentDerivativesData("P_dF", MatrixDouble());
201
202 A::matOpsDataPtr->getActiveDataPtr("F")->resize(DIM, DIM, false);
203 A::matOpsDataPtr->getDependentDataPtr("P")->resize(DIM, DIM, false);
204
205 auto t_F = getFTensor2FromPtr<DIM, DIM>(
206 A::matOpsDataPtr->getActiveDataPtr("F")->data().data());
207 auto t_P = getFTensor2FromPtr<DIM, DIM>(
208 A::matOpsDataPtr->getDependentDataPtr("P")->data().data());
209
211
212 FTENSOR_INDEX(DIM, i);
213 FTENSOR_INDEX(DIM, j);
214 FTENSOR_INDEX(DIM, I);
215 FTENSOR_INDEX(DIM, J);
216
217 t_F(i, J) = 0;
218
221
222 adouble det_aF, I1;
224
225 trace_on(A::tAg);
226 auto p_c10 = mkparam(this->C10);
227 auto p_K = mkparam(this->K);
228
229 ta_F(i, J) <<= t_F(i, J);
230 // assume that gradient from approximated displacement, that why we add diagonal
232 ta_F(i, J) += t_kd(i, J);
233 }
234
235 det_aF = determinantTensor(ta_F);
236 I1 = ta_F(i, I) * ta_F(i, I);
237 if constexpr (DIM == 2) {
238 // Abaqus plane strain uses the three-dimensional potential with F33=1.
239 I1 += 1.;
240 }
241 CHKERR invertTensor(ta_F, det_aF, ta_invF);
242
243 // Abaqus compressible Neo-Hookean potential (reduced polynomial N=1):
244 //
245 // W = C10 * (I1_bar - 3) + (1 / D1) * (J - 1)^2,
246 // I1_bar = J^(-2/3) * I1, mu0 = 2*C10, D1 = 2/K0.
247 //
248 // Its first Piola stress is
249 //
250 // P = 2*C10*J^(-2/3)*(F - I1/3*F^(-T))
251 // + K0*J*(J - 1)*F^(-T).
252 const auto jacobian_to_minus_two_thirds = pow(det_aF, -2. / 3.);
253 ta_P(i, I) =
254 2. * p_c10 * jacobian_to_minus_two_thirds *
255 (ta_F(i, I) - (I1 / 3.) * ta_invF(I, i)) +
256 p_K * det_aF * (det_aF - 1.) * ta_invF(I, i);
257
258 ta_P(i, I) >>= t_P(i, I);
259
260 trace_off();
261
263 }
264
265};
266
267template <>
268boost::shared_ptr<PhysicalEquations>
270 boost::shared_ptr<MatOpsData> mat_ops_data_ptr, int tag) {
271 return boost::make_shared<MatNeohookean<3>>(mat_ops_data_ptr, tag);
272}
273
274template <>
275boost::shared_ptr<PhysicalEquations>
277 boost::shared_ptr<MatOpsData> mat_ops_data_ptr, int tag) {
278 return boost::make_shared<MatNeohookean<2>>(mat_ops_data_ptr, tag);
279}
280
281} // 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_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 bool useDeformationGradient
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
std::vector< std::pair< Range, std::vector< double > > > paramVecByRange
Definition MatOps.hpp:162
boost::shared_ptr< MatOpsData > matOpsDataPtr
Definition MatOps.hpp:164
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.