v0.16.3
Loading...
Searching...
No Matches
HMHNeohookean.cpp
Go to the documentation of this file.
1/**
2 * @file HMHNeohookean.cpp
3 * @brief Direct logarithmic Neo-Hookean material adapter.
4 */
5
8#include <cmath>
9#include <optional>
10#include <regex>
11#include <sstream>
12
13namespace EshelbianPlasticity {
14
19 using FormBase =
20 typename FormsIntegrators<VolUserDataOperator>::Assembly<A>::OpBase;
21
23 const EshelbianCore &ep, boost::ptr_deque<UserDataOperator> &pipeline,
24 boost::shared_ptr<DataAtIntegrationPts> data_ptr, bool lhs) override {
26 auto parameters = prepareAuxiliaryEvaluation(data_ptr);
28 ep, pipeline, data_ptr, data_ptr->auxiliaryMaterialData,
29 std::move(parameters), lhs);
31 }
32
34 const EshelbianCore &ep, boost::ptr_deque<UserDataOperator> &pipeline,
35 boost::shared_ptr<DataAtIntegrationPts> data_ptr, bool lhs) override {
38 ep, pipeline, data_ptr->auxiliaryMaterialData, lhs);
40 }
41
42 HMHNeohookean(MoFEM::Interface &m_field, const double c10,
43 const double bulk_modulus, const Features features)
45 defaultParameters{c10, bulk_modulus} {
46 if ((getFeatures() & noStretchMask).any())
49 "Neo-Hookean -no_stretch physical-stress recovery was "
50 "retired; omit -no_stretch and solve the material fields");
54 "Neo-Hookean requires natural logarithms: -stretches log");
55 CHK_THROW_MESSAGE(getOptions(), "Neo-Hookean options are invalid");
57 "Neo-Hookean material blocks are invalid");
58 }
59
60 Material::Parameters getParameters(const EntityHandle entity) const {
61 for (const auto &block : blockData)
62 if (block.entities.find(entity) != block.entities.end())
63 return block.parameters;
64 if (!blockData.empty())
67 "MAT_NEOHOOKEAN blocks must cover every material element");
68 return defaultParameters;
69 }
70
71 /** Map derivatives from five orthonormal coordinates and theta to the six
72 * raw symmetric coefficients. SymmLTensor supplies both shear occurrences.
73 */
74 static MoFEMErrorCode
76 const Material::SymmetricTensor &t_log_stretch, double &energy,
77 PackedStress *stress_ptr = nullptr,
78 PackedTangent *tangent_ptr = nullptr) {
80 FTENSOR_INDEXES(3, i, j);
82 FTensor::Index<'a', 5> a;
83 FTensor::Index<'b', 5> b;
84 const auto t_coordinates = Material::getCoordinates(t_log_stretch);
85 Material::Coordinates t_stress;
86 Material::Tangent t_hessian;
88 CHKERR Material::evaluateDeviator(parameters, t_coordinates, energy,
89 stress_ptr ? &t_stress : nullptr,
90 tangent_ptr ? &t_hessian : nullptr);
91 CHKERR Material::evaluateVolume(parameters, t_log_stretch(i, i), volume);
92 energy += volume.energy;
93 if (!std::isfinite(energy))
94 SETERRQ(PETSC_COMM_SELF, MOFEM_OPERATION_UNSUCCESSFUL,
95 "Neo-Hookean total strain energy is not representable");
96 const auto t_packed_basis = FTensor::SymmLTensor<double, 3>();
97 constexpr auto t_identity = FTensor::Kronecker_Delta_symmetric<int>();
98 if (stress_ptr) {
99 const auto t_deviatoric_stress = Material::getTensor(t_stress);
100 Material::SymmetricTensor t_total_stress;
101 t_total_stress(i, j) =
102 t_deviatoric_stress(i, j) + volume.firstDerivative * t_identity(i, j);
103 (*stress_ptr)(L) = t_packed_basis(i, j, L) * t_total_stress(i, j);
104 for (int component = 0; component != size_symm; ++component)
105 if (!std::isfinite((*stress_ptr)(component)))
106 SETERRQ(PETSC_COMM_SELF, MOFEM_OPERATION_UNSUCCESSFUL,
107 "Neo-Hookean packed material stress is not representable");
108 }
109 if (tangent_ptr) {
110 const auto &t_basis = Tensor2SymmetricDeviatorBasis::getBasis();
112 t_projection(a, L) = t_basis(i, j, a) * t_packed_basis(i, j, L);
113 PackedStress t_trace;
114 t_trace(L) = t_packed_basis(i, j, L) * t_identity(i, j);
115 FTensor::Tensor2<double, 5, size_symm> t_hessian_projection;
116 t_hessian_projection(a, J) = t_hessian(a, b) * t_projection(b, J);
117 (*tangent_ptr)(L, J) = t_projection(a, L) * t_hessian_projection(a, J) +
118 volume.secondDerivative * t_trace(L) * t_trace(J);
119 for (int row = 0; row != size_symm; ++row)
120 for (int col = 0; col != size_symm; ++col)
121 if (!std::isfinite((*tangent_ptr)(row, col)))
122 SETERRQ(PETSC_COMM_SELF, MOFEM_OPERATION_UNSUCCESSFUL,
123 "Neo-Hookean packed material tangent is not representable");
124 }
126 }
127
128 struct OpJacobian : public EshelbianPlasticity::OpJacobian {
129 using EshelbianPlasticity::OpJacobian::OpJacobian;
130 MoFEMErrorCode evaluateRhs(EntData &) override { return 0; }
131 MoFEMErrorCode evaluateLhs(EntData &) override { return 0; }
132 };
133
135 returnOpJacobian(const bool eval_rhs, const bool eval_lhs,
136 boost::shared_ptr<DataAtIntegrationPts> data_ptr,
137 boost::shared_ptr<PhysicalEquations> physics_ptr) override {
138 return new OpJacobian(eval_rhs, eval_lhs, std::move(data_ptr),
139 std::move(physics_ptr));
140 }
141
143 OpEnergy(boost::shared_ptr<DataAtIntegrationPts> data_ptr,
144 boost::shared_ptr<double> total_energy_ptr)
145 : VolUserDataOperator(NOSPACE, OPSPACE), dataAtPts(std::move(data_ptr)),
146 totalEnergyPtr(std::move(total_energy_ptr)) {}
147
148 MoFEMErrorCode doWork(int, EntityType, EntData &) override {
150 const auto material_ptr = getMaterial(dataAtPts);
151 const auto parameters = material_ptr->getParameters(getFEEntityHandle());
152 const int nb_integration_pts = getGaussPts().size2();
153 auto t_eigenvalues = dataAtPts->getFTensorEigenVals(nb_integration_pts);
154 dataAtPts->energyAtPts.resize(nb_integration_pts, false);
155 auto t_energy = getFTensor0FromVec(dataAtPts->energyAtPts);
156 auto t_weight = getFTensor0IntegrationWeight();
157 double element_energy = 0.;
158 for (int gg = 0; gg != nb_integration_pts; ++gg) {
159 // Isotropic energy uses the principal logarithms supplied by either
160 // configuration pipeline, independently of its displacement gradient.
161 const Material::SymmetricTensor t_log_stretch(
162 t_eigenvalues(0), 0., 0., t_eigenvalues(1), 0., t_eigenvalues(2));
163 double energy;
164 CHKERR evaluateDirect(parameters, t_log_stretch, energy);
165 t_energy = energy;
166 element_energy += t_weight * energy;
167 ++t_eigenvalues;
168 ++t_energy;
169 ++t_weight;
170 }
171 if (totalEnergyPtr)
172 *totalEnergyPtr += getMeasure() * element_energy;
174 }
175
176 private:
177 boost::shared_ptr<DataAtIntegrationPts> dataAtPts;
178 boost::shared_ptr<double> totalEnergyPtr;
179 };
180
182 boost::shared_ptr<DataAtIntegrationPts> data_ptr,
183 boost::shared_ptr<double> total_energy_ptr) override {
184 return new OpEnergy(std::move(data_ptr), std::move(total_energy_ptr));
185 }
186
187 bool providesHelmholtzFreeEnergy() const override { return true; }
188
191 boost::shared_ptr<DataAtIntegrationPts> data_ptr,
192 boost::shared_ptr<MatrixDouble> deviator_gradient_ptr,
193 boost::shared_ptr<MatrixDouble> volume_gradient_ptr)
194 : VolUserDataOperator(NOSPACE, OPSPACE), dataAtPts(std::move(data_ptr)),
195 deviatorGradientPtr(std::move(deviator_gradient_ptr)),
196 volumeGradientPtr(std::move(volume_gradient_ptr)) {}
197
198 MoFEMErrorCode doWork(int, EntityType, EntData &) override {
200 const auto material_ptr = getMaterial(dataAtPts);
201 const auto parameters = material_ptr->getParameters(getFEEntityHandle());
202 const int nb_gauss = getGaussPts().size2();
203 const auto fields = dataAtPts->auxiliaryData;
204 using DL = DataLayoutTraits<DataLayout::GaussByCoeffs>;
205 auto t_d = MatrixSizeHelper<GetFTensor1FromMatType<5, -1, DL>, DL>::get(
206 *fields->logDeviator, nb_gauss)();
207 auto t_theta =
208 MatrixSizeHelper<GetFTensor1FromMatType<1, -1, DL>, DL>::get(
209 *fields->logJacobian, nb_gauss)();
210 auto t_deviator_gradient =
211 MatrixSizeHelper<GetFTensor1FromMatType<5, -1, DL>, DL>::size(
212 *deviatorGradientPtr, nb_gauss)();
213 auto t_volume_gradient =
214 MatrixSizeHelper<GetFTensor1FromMatType<1, -1, DL>, DL>::size(
215 *volumeGradientPtr, nb_gauss)();
216 FTENSOR_INDEX(5, L);
217 for (int gg = 0; gg != nb_gauss; ++gg) {
218 Material::Coordinates t_coordinates, t_stress;
219 t_coordinates(L) = t_d(L);
220 double energy;
222 CHKERR Material::evaluateDeviator(parameters, t_coordinates, energy,
223 &t_stress);
224 CHKERR Material::evaluateVolume(parameters, t_theta(0), volume);
225 // Differentiate the physical energy at D_k. Weak copy closure does
226 // not make the independent T_d its pointwise derivative.
227 t_deviator_gradient(L) = t_stress(L);
228 t_volume_gradient(0) = volume.firstDerivative;
229 ++t_d;
230 ++t_theta;
231 ++t_deviator_gradient;
232 ++t_volume_gradient;
233 }
235 }
236
237 private:
238 boost::shared_ptr<DataAtIntegrationPts> dataAtPts;
239 boost::shared_ptr<MatrixDouble> deviatorGradientPtr;
240 boost::shared_ptr<MatrixDouble> volumeGradientPtr;
241 };
242
244 const EshelbianCore &ep, boost::ptr_deque<UserDataOperator> &pipeline,
245 boost::shared_ptr<DataAtIntegrationPts> data_ptr) override {
249 data_ptr);
251 }
252 auto deviator_gradient = boost::make_shared<MatrixDouble>();
253 auto volume_gradient = boost::make_shared<MatrixDouble>();
254 pipeline.push_back(new OpAuxiliaryHelmholtzGradient(
255 data_ptr, deviator_gradient, volume_gradient));
256 using OpDeviatorGradient = FormsIntegrators<VolUserDataOperator>::Assembly<
258 using OpVolumeGradient = FormsIntegrators<VolUserDataOperator>::Assembly<
260 pipeline.push_back(
261 new OpDeviatorGradient(ep.logDeviator, deviator_gradient));
262 pipeline.push_back(new OpVolumeGradient(ep.logJacobian, volume_gradient));
264 }
265
266 struct OpResidual : public FormBase {
267 OpResidual(const std::string &field,
268 boost::shared_ptr<DataAtIntegrationPts> data_ptr,
269 const double alpha_u)
270 : FormBase(field, field, FormBase::OPROW),
271 dataAtPts(std::move(data_ptr)), alphaU(alpha_u) {
273 "Unsupported direct Neo-Hookean configuration");
274 if (!std::isfinite(alphaU))
276 "Neo-Hookean stretch viscosity must be finite");
277 }
278
279 MoFEMErrorCode iNtegrate(EntData &row_data) override {
281 FTENSOR_INDEXES(3, i, j);
283 const auto t_packed_basis = FTensor::SymmLTensor<double, 3>();
284 const auto material_ptr = getMaterial(dataAtPts);
285 const auto parameters = material_ptr->getParameters(getFEEntityHandle());
286 const double alpha_grad_u = material_ptr->alphaGradU;
287 auto t_h = dataAtPts->getFTensorLogStretch(nbIntegrationPts);
288 auto t_physical = dataAtPts->getFTensorAdjointPdU(nbIntegrationPts);
289 // Inactive viscosity terms do not introduce rate-data dependencies.
290 std::optional<decltype(dataAtPts->getFTensorLogStretchDot(
291 nbIntegrationPts))>
292 t_dot_h;
293 std::optional<decltype(dataAtPts->getFTensorGradLogStretchDot(
294 nbIntegrationPts))>
295 t_grad_dot_h;
296 if (alphaU != 0.)
297 t_dot_h.emplace(dataAtPts->getFTensorLogStretchDot(nbIntegrationPts));
298 if (alpha_grad_u != 0.)
299 t_grad_dot_h.emplace(
300 dataAtPts->getFTensorGradLogStretchDot(nbIntegrationPts));
301 auto t_row = row_data.getFTensor0N();
302 auto t_grad_row = row_data.getFTensor1DiffN<3>();
303 auto t_weight = getFTensor0IntegrationWeight();
304 for (int gg = 0; gg != nbIntegrationPts; ++gg) {
305 Material::SymmetricTensor t_log_stretch;
306 t_log_stretch(i, j) = t_h(i, j);
307 PackedStress t_stress;
308 double energy;
309 CHKERR evaluateDirect(parameters, t_log_stretch, energy, &t_stress);
310 const double alpha = getMeasure() * t_weight;
311 PackedStress t_residual;
312 t_residual(L) = t_stress(L) - t_physical(L);
313 if (t_dot_h)
314 t_residual(L) +=
315 alphaU * (t_packed_basis(i, j, L) * (*t_dot_h)(i, j));
317 t_gradient(L, i) = 0.;
318 if (t_grad_dot_h)
319 t_gradient(L, i) = alpha_grad_u * (*t_grad_dot_h)(L, i);
320 auto t_nf = getNf<size_symm>();
321 int rr = 0;
322 for (; rr != nbRows / size_symm; ++rr) {
323 t_nf(L) += alpha *
324 (t_row * t_residual(L) + t_grad_row(i) * t_gradient(L, i));
325 ++t_nf;
326 ++t_row;
327 ++t_grad_row;
328 }
329 for (; rr != nbRowBaseFunctions; ++rr) {
330 ++t_row;
331 ++t_grad_row;
332 }
333 ++t_weight;
334 ++t_h;
335 ++t_physical;
336 if (t_dot_h)
337 ++*t_dot_h;
338 if (t_grad_dot_h)
339 ++*t_grad_dot_h;
340 }
342 }
343
344 private:
345 boost::shared_ptr<DataAtIntegrationPts> dataAtPts;
346 const double alphaU;
347 };
348
350 returnOpSpatialPhysical(const std::string &field,
351 boost::shared_ptr<DataAtIntegrationPts> data_ptr,
352 const double alpha_u) override {
353 return new OpResidual(field, std::move(data_ptr), alpha_u);
354 }
355
356 struct OpTangent : public FormBase {
357 OpTangent(const std::string &row_field, const std::string &col_field,
358 boost::shared_ptr<DataAtIntegrationPts> data_ptr,
359 const double alpha_u)
360 : FormBase(row_field, col_field, FormBase::OPROWCOL),
361 dataAtPts(std::move(data_ptr)), alphaU(alpha_u) {
362 sYmm = false;
364 "Unsupported direct Neo-Hookean configuration");
365 if (!std::isfinite(alphaU))
367 "Neo-Hookean stretch viscosity must be finite");
368 }
369
370 MoFEMErrorCode iNtegrate(EntData &row_data, EntData &col_data) override {
372 FTENSOR_INDEXES(3, i, j, k, l);
374 const auto material_ptr = getMaterial(dataAtPts);
375 const auto parameters = material_ptr->getParameters(getFEEntityHandle());
376 const auto t_packed_basis = FTensor::SymmLTensor<double, 3>();
377 constexpr auto t_identity = FTensor::Kronecker_Delta<int>();
378 PackedTangent t_viscous_metric;
379 t_viscous_metric(L, J) =
380 t_packed_basis(i, j, L) * t_packed_basis(i, j, J);
381 const double ts_a = getTSa();
382 const double alpha_grad_u = material_ptr->alphaGradU;
383 auto t_h = dataAtPts->getFTensorLogStretch(nbIntegrationPts);
384 auto t_pullback = dataAtPts->getFTensorAdjointPdstretch(nbIntegrationPts);
385 auto t_eigenvalues = dataAtPts->getFTensorEigenVals(nbIntegrationPts);
386 auto t_eigenvectors = dataAtPts->getFTensorEigenVecs(nbIntegrationPts);
387 auto t_row = row_data.getFTensor0N();
388 auto t_grad_row = row_data.getFTensor1DiffN<3>();
389 auto t_weight = getFTensor0IntegrationWeight();
390#ifndef NDEBUG
391 if (dataAtPts->nbUniq.size() != nbIntegrationPts)
392 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
393 "Neo-Hookean tangent requires current geometric eigendata");
394#endif
395 for (int gg = 0; gg != nbIntegrationPts; ++gg) {
396 Material::SymmetricTensor t_log_stretch;
397 t_log_stretch(i, j) = t_h(i, j);
398 PackedTangent t_tangent;
399 double energy;
400 CHKERR evaluateDirect(parameters, t_log_stretch, energy, nullptr,
401 &t_tangent);
402 Material::SymmetricTensor t_symmetric_pullback;
403 t_symmetric_pullback(i, j) =
404 (t_pullback(i, j) || t_pullback(j, i)) / 2.;
405 const auto t_work_curvature = EigenMatrix::getDiffDiffMat(
406 t_eigenvalues, t_eigenvectors, EshelbianCore::f, EshelbianCore::d_f,
407 EshelbianCore::dd_f, t_symmetric_pullback, dataAtPts->nbUniq[gg]);
408 t_tangent(L, J) -=
409 t_packed_basis(i, j, L) *
410 (t_work_curvature(i, j, k, l) * t_packed_basis(k, l, J));
411 t_tangent(L, J) += (alphaU * ts_a) * t_viscous_metric(L, J);
412 const double alpha = getMeasure() * t_weight;
413 int rr = 0;
414 for (; rr != nbRows / size_symm; ++rr) {
415 auto t_col = col_data.getFTensor0N(gg, 0);
416 auto t_grad_col = col_data.getFTensor1DiffN<3>(gg, 0);
417 auto t_matrix = getLocMat<size_symm>(size_symm * rr);
418 for (int cc = 0; cc != nbCols / size_symm; ++cc) {
419 t_matrix(L, J) += alpha * t_row * t_col * t_tangent(L, J);
420 const double gradient_weight =
421 alpha * alpha_grad_u * ts_a * (t_grad_row(i) * t_grad_col(i));
422 t_matrix(L, J) += gradient_weight * t_identity(L, J);
423 ++t_matrix;
424 ++t_col;
425 ++t_grad_col;
426 }
427 ++t_row;
428 ++t_grad_row;
429 }
430 for (; rr != nbRowBaseFunctions; ++rr) {
431 ++t_row;
432 ++t_grad_row;
433 }
434 ++t_weight;
435 ++t_h;
436 ++t_pullback;
437 ++t_eigenvalues;
438 ++t_eigenvectors;
439 }
441 }
442
443 private:
444 boost::shared_ptr<DataAtIntegrationPts> dataAtPts;
445 const double alphaU;
446 };
447
449 std::string row_field, std::string col_field,
450 boost::shared_ptr<DataAtIntegrationPts> data_ptr,
451 const double alpha_u) override {
452 return new OpTangent(row_field, col_field, std::move(data_ptr), alpha_u);
453 }
454
455 struct OpExternalStrain : public FormBase {
457 const std::string &field,
458 boost::shared_ptr<ExternalStrainVec> external_strain_ptr,
459 std::map<std::string, boost::shared_ptr<ScalingMethod>> scaling_methods)
460 : FormBase(field, field, FormBase::OPROW),
461 externalStrainPtr(std::move(external_strain_ptr)),
462 scalingMethods(std::move(scaling_methods)) {}
463
464 MoFEMErrorCode iNtegrate(EntData &row_data) override {
468 const double time = EshelbianCore::physicalTimeFlg
470 : getFEMethod()->ts_t;
471 double pressure = 0.;
472 for (const auto &block : *externalStrainPtr) {
473 if (block.blockName.find("ANALYTICAL_EXTERNALSTRAIN") !=
474 std::string::npos)
475 SETERRQ(
476 PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
477 "Analytical external strain is not implemented for Neo-Hookean");
478 if (block.ents.find(getFEEntityHandle()) == block.ents.end())
479 continue;
480 const auto scaling = scalingMethods.find(block.blockName);
481 double scale = 1.;
482 if (scaling != scalingMethods.end())
483 scale = scaling->second->getScale(time);
484 else
485 MOFEM_LOG("SELF", Sev::warning)
486 << "No scaling method found for " << block.blockName;
487 pressure += 3. * block.bulkModulusK * block.val * scale;
488 }
489 if (!std::isfinite(pressure))
490 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
491 "Neo-Hookean prescribed external pressure must be finite");
492 FTENSOR_INDEXES(3, i, j);
494 const auto t_packed_basis = FTensor::SymmLTensor<double, 3>();
495 constexpr auto t_identity = FTensor::Kronecker_Delta_symmetric<int>();
496 PackedStress t_load;
497 t_load(L) = pressure * (t_packed_basis(i, j, L) * t_identity(i, j));
498 auto t_row = row_data.getFTensor0N();
499 auto t_weight = getFTensor0IntegrationWeight();
500 for (int gg = 0; gg != nbIntegrationPts; ++gg) {
501 const double alpha = getMeasure() * t_weight;
502 auto t_nf = getNf<size_symm>();
503 int rr = 0;
504 for (; rr != nbRows / size_symm; ++rr) {
505 t_nf(L) -= alpha * t_row * t_load(L);
506 ++t_nf;
507 ++t_row;
508 }
509 for (; rr != nbRowBaseFunctions; ++rr)
510 ++t_row;
511 ++t_weight;
512 }
514 }
515
516 private:
517 boost::shared_ptr<ExternalStrainVec> externalStrainPtr;
518 std::map<std::string, boost::shared_ptr<ScalingMethod>> scalingMethods;
519 };
520
522 const std::string &field, boost::shared_ptr<DataAtIntegrationPts>,
523 boost::shared_ptr<ExternalStrainVec> external_strain_ptr,
524 std::map<std::string, boost::shared_ptr<ScalingMethod>> scaling_methods)
525 override {
526 return new OpExternalStrain(field, std::move(external_strain_ptr),
527 std::move(scaling_methods));
528 }
529
531 VectorPtr pressure_ptr,
532 boost::shared_ptr<ExternalStrainVec> external_strain_ptr,
533 std::map<std::string, boost::shared_ptr<ScalingMethod>> scaling_methods)
534 override {
535 return new OpCalculateExternalPressure(std::move(pressure_ptr),
536 std::move(external_strain_ptr),
537 std::move(scaling_methods));
538 }
539
541 returnOpCalculateStretchFromStress(boost::shared_ptr<DataAtIntegrationPts>,
542 boost::shared_ptr<PhysicalEquations>,
543 boost::shared_ptr<MatrixDouble>) override {
544 return retiredInverse();
545 }
547 returnOpCalculateStretchFromStress(boost::shared_ptr<DataAtIntegrationPts>,
548 boost::shared_ptr<PhysicalEquations>,
549 boost::shared_ptr<MatrixDouble>,
550 VectorPtr) override {
551 return retiredInverse();
552 }
554 boost::shared_ptr<DataAtIntegrationPts>,
555 boost::shared_ptr<PhysicalEquations>, boost::shared_ptr<MatrixDouble>,
556 boost::shared_ptr<MatrixDouble>, VectorPtr) override {
557 return retiredInverse();
558 }
560 boost::shared_ptr<DataAtIntegrationPts>,
561 boost::shared_ptr<PhysicalEquations>) override {
562 return retiredInverse();
563 }
564
565private:
567 const boost::shared_ptr<DataAtIntegrationPts> &data_ptr) {
568 if (!data_ptr)
570 "Auxiliary material evaluation requires field data");
571 if (!data_ptr->auxiliaryMaterialData)
572 data_ptr->auxiliaryMaterialData =
573 boost::make_shared<AuxiliaryLogarithmicStressMaterialData>();
574 return [this](EntityHandle entity) { return getParameters(entity); };
575 }
576
577 static MoFEMErrorCode checkDirectConfiguration() {
580 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
581 "Neo-Hookean direct material equations require -grad no_h1");
584 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
585 "Neo-Hookean direct material equations require "
586 "-rotations large or -rotations small");
588 }
589
590 static boost::shared_ptr<HMHNeohookean>
591 getMaterial(const boost::shared_ptr<DataAtIntegrationPts> &data_ptr) {
592 if (!data_ptr)
594 "Neo-Hookean integration-point data is missing");
595 const auto material_ptr =
596 boost::dynamic_pointer_cast<HMHNeohookean>(data_ptr->physicsPtr);
597 if (!material_ptr)
599 "Neo-Hookean material pointer is missing");
600 return material_ptr;
601 }
602
605 "Neo-Hookean physical-stress-to-stretch recovery was "
606 "retired; solve the logarithmic material fields");
607 return nullptr;
608 }
609
610 MoFEMErrorCode getOptions() {
612 PetscOptionsBegin(mField.get_comm(), "neo_hookean_", "Neo-Hookean material",
613 "none");
614 CHKERR PetscOptionsScalar("-c10", "C10", "", defaultParameters.c10,
615 &defaultParameters.c10, nullptr);
616 CHKERR PetscOptionsScalar("-K", "Bulk modulus", "",
619 CHKERR PetscOptionsScalar("-viscosity_alpha_grad_u",
620 "Logarithmic-stretch-gradient rate viscosity", "",
621 alphaGradU, &alphaGradU, nullptr);
622 PetscOptionsEnd();
624 if (!std::isfinite(alphaGradU))
625 SETERRQ(
627 "Neo-Hookean logarithmic-stretch-gradient viscosity must be finite");
628 char *options_ptr = nullptr;
629 CHKERR PetscOptionsGetAll(nullptr, &options_ptr);
630 std::istringstream options(options_ptr ? options_ptr : "");
631 CHKERR PetscFree(options_ptr);
632 std::string option;
633 while (options >> option)
634 if (option.rfind("-nh_stretch_", 0) == 0 ||
635 option == "-neo_hookean_min_eigen_value")
637 "Option %s belongs to the retired Neo-Hookean physical inverse "
638 "or tangent projection; remove it",
639 option.c_str());
640 MOFEM_LOG("EP", Sev::inform) << "Neo-Hookean C10=" << defaultParameters.c10
642 << " alphaGradU=" << alphaGradU;
644 }
645
646 MoFEMErrorCode extractBlockData() {
648 auto meshsets = mField.getInterface<MeshsetsManager>();
649 auto json_config = mField.getInterface<JsonConfigManager>();
650 for (const auto block :
651 meshsets->getCubitMeshsetPtr(std::regex("MAT_NEOHOOKEAN(.*)"))) {
652 Material::Parameters parameters;
653 const auto json_parameters = json_config->getParamsFromBlockset(
654 "MAT_NEOHOOKEAN", block->getMeshsetId());
655 if (!json_parameters.empty()) {
656 if (json_parameters.size() != 2 || !json_parameters.count("c10") ||
657 !json_parameters.count("k"))
659 "MAT_NEOHOOKEAN JSON block must contain exactly c10,k");
660 parameters = {json_parameters.at("c10"), json_parameters.at("k")};
661 } else {
662 std::vector<double> attributes;
663 CHKERR block->getAttributes(attributes);
664 if (attributes.size() < 2)
666 "MAT_NEOHOOKEAN block requires C10,K attributes");
667 parameters = {attributes[0], attributes[1]};
668 }
670 Range entities;
671 CHKERR mField.get_moab().get_entities_by_handle(block->getMeshset(),
672 entities, true);
673 blockData.push_back({parameters, std::move(entities)});
674 MOFEM_LOG("EP", Sev::inform)
675 << "MAT_NEOHOOKEAN " << block->getMeshsetId()
676 << " C10=" << parameters.c10 << " K=" << parameters.bulkModulus;
677 }
679 }
680
687 double alphaGradU = 0.;
688 std::vector<BlockData> blockData;
689};
690
691} // namespace EshelbianPlasticity
Material and stress-work blocks for the independent D/theta/Td fields.
Neo-Hookean material law in orthonormal logarithmic coordinates.
#define FTENSOR_INDEXES(DIM,...)
#define FTENSOR_INDEX(DIM, I)
constexpr double a
Kronecker Delta class symmetric.
Kronecker Delta class.
#define CHK_THROW_MESSAGE(err, msg)
Check and throw MoFEM exception.
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
@ NOSPACE
Definition definitions.h:83
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
@ MOFEM_OPERATION_UNSUCCESSFUL
Definition definitions.h:34
@ MOFEM_DATA_INCONSISTENCY
Definition definitions.h:31
@ MOFEM_NOT_IMPLEMENTED
Definition definitions.h:32
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
const char features[]
#define MOFEM_LOG(channel, severity)
Log.
FTensor::Index< 'i', SPACE_DIM > i
FTensor::Index< 'J', DIM1 > J
Definition level_set.cpp:30
FTensor::Index< 'l', 3 > l
FTensor::Index< 'j', 3 > j
FTensor::Index< 'k', 3 > k
auto getDiffDiffMat(A &&t_val, B &&t_vec, Fun< double > f, Fun< double > d_f, Fun< double > dd_f, C &&t_S, const int nb)
Get the Diff Diff Mat object.
MoFEMErrorCode pushAuxiliaryLogarithmicMaterialEvaluation(const EshelbianCore &ep, boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > &pipeline, boost::shared_ptr< DataAtIntegrationPts > data, boost::shared_ptr< AuxiliaryLogarithmicStressMaterialData > material_data, AuxiliaryLogarithmicMaterialParameters parameters, bool lhs=false)
std::function< NeoHookeanLogarithmicMaterial::Parameters(EntityHandle)> AuxiliaryLogarithmicMaterialParameters
Return parameters already checked by the material's setup validation.
static constexpr auto size_symm
MoFEMErrorCode pushAuxiliaryLogarithmicMaterialOps(const EshelbianCore &ep, boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > &pipeline, boost::shared_ptr< AuxiliaryLogarithmicStressMaterialData > material_data, bool lhs)
boost::shared_ptr< VectorDouble > VectorPtr
constexpr AssemblyType A
OpBaseImpl< PETSC, EdgeEleOp > OpBase
Definition radiation.cpp:29
static enum StretchSelector stretchSelector
static enum RotSelector rotSelector
static enum RotSelector gradApproximator
const std::string logDeviator
const std::string logJacobian
static PetscBool physicalTimeFlg
static double currentPhysicalTime
static boost::function< double(const double)> f
static boost::function< double(const double)> dd_f
static boost::function< double(const double)> d_f
OpAuxiliaryHelmholtzGradient(boost::shared_ptr< DataAtIntegrationPts > data_ptr, boost::shared_ptr< MatrixDouble > deviator_gradient_ptr, boost::shared_ptr< MatrixDouble > volume_gradient_ptr)
MoFEMErrorCode doWork(int, EntityType, EntData &) override
OpEnergy(boost::shared_ptr< DataAtIntegrationPts > data_ptr, boost::shared_ptr< double > total_energy_ptr)
boost::shared_ptr< DataAtIntegrationPts > dataAtPts
MoFEMErrorCode doWork(int, EntityType, EntData &) override
OpExternalStrain(const std::string &field, boost::shared_ptr< ExternalStrainVec > external_strain_ptr, std::map< std::string, boost::shared_ptr< ScalingMethod > > scaling_methods)
boost::shared_ptr< ExternalStrainVec > externalStrainPtr
MoFEMErrorCode iNtegrate(EntData &row_data) override
std::map< std::string, boost::shared_ptr< ScalingMethod > > scalingMethods
MoFEMErrorCode evaluateLhs(EntData &) override
MoFEMErrorCode evaluateRhs(EntData &) override
boost::shared_ptr< DataAtIntegrationPts > dataAtPts
OpResidual(const std::string &field, boost::shared_ptr< DataAtIntegrationPts > data_ptr, const double alpha_u)
MoFEMErrorCode iNtegrate(EntData &row_data) override
OpTangent(const std::string &row_field, const std::string &col_field, boost::shared_ptr< DataAtIntegrationPts > data_ptr, const double alpha_u)
MoFEMErrorCode iNtegrate(EntData &row_data, EntData &col_data) override
boost::shared_ptr< DataAtIntegrationPts > dataAtPts
MoFEMErrorCode pushAuxiliaryLogarithmicStressOps(const EshelbianCore &ep, boost::ptr_deque< UserDataOperator > &pipeline, boost::shared_ptr< DataAtIntegrationPts > data_ptr, bool lhs) override
Assemble the selected material field group after kinematic reconstruction.
VolUserDataOperator * returnOpSpatialPhysical(const std::string &field, boost::shared_ptr< DataAtIntegrationPts > data_ptr, const double alpha_u) override
static boost::shared_ptr< HMHNeohookean > getMaterial(const boost::shared_ptr< DataAtIntegrationPts > &data_ptr)
static MoFEMErrorCode checkDirectConfiguration()
MoFEMErrorCode pushAuxiliaryLogarithmicMaterialEvaluation(const EshelbianCore &ep, boost::ptr_deque< UserDataOperator > &pipeline, boost::shared_ptr< DataAtIntegrationPts > data_ptr, bool lhs) override
Evaluate the auxiliary material copy and energies without assembly.
std::vector< BlockData > blockData
VolUserDataOperator * returnOpCalculateHelmholtzFreeEnergy(boost::shared_ptr< DataAtIntegrationPts > data_ptr, boost::shared_ptr< double > total_energy_ptr) override
VolUserDataOperator * returnOpSpatialPhysical_du_du(std::string row_field, std::string col_field, boost::shared_ptr< DataAtIntegrationPts > data_ptr, const double alpha_u) override
UserDataOperator * returnOpJacobian(const bool eval_rhs, const bool eval_lhs, boost::shared_ptr< DataAtIntegrationPts > data_ptr, boost::shared_ptr< PhysicalEquations > physics_ptr) override
VolUserDataOperator * returnOpCalculateStretchFromStress(boost::shared_ptr< DataAtIntegrationPts >, boost::shared_ptr< PhysicalEquations >, boost::shared_ptr< MatrixDouble >) override
MoFEMErrorCode pushHelmholtzStateGradient(const EshelbianCore &ep, boost::ptr_deque< UserDataOperator > &pipeline, boost::shared_ptr< DataAtIntegrationPts > data_ptr) override
Assemble the physical Helmholtz state derivative at equilibrium.
Material::Parameters getParameters(const EntityHandle entity) const
VolUserDataOperator * returnOpCalculateStretchFromStress(boost::shared_ptr< DataAtIntegrationPts >, boost::shared_ptr< PhysicalEquations >, boost::shared_ptr< MatrixDouble >, boost::shared_ptr< MatrixDouble >, VectorPtr) override
bool providesHelmholtzFreeEnergy() const override
HMHNeohookean(MoFEM::Interface &m_field, const double c10, const double bulk_modulus, const Features features)
AuxiliaryLogarithmicMaterialParameters prepareAuxiliaryEvaluation(const boost::shared_ptr< DataAtIntegrationPts > &data_ptr)
static MoFEMErrorCode evaluateDirect(const Material::Parameters &parameters, const Material::SymmetricTensor &t_log_stretch, double &energy, PackedStress *stress_ptr=nullptr, PackedTangent *tangent_ptr=nullptr)
static VolUserDataOperator * retiredInverse()
VolUserDataOperator * returnOpCalculateExternalPressure(VectorPtr pressure_ptr, boost::shared_ptr< ExternalStrainVec > external_strain_ptr, std::map< std::string, boost::shared_ptr< ScalingMethod > > scaling_methods) override
VolUserDataOperator * returnOpSpatialPhysicalExternalStrain(const std::string &field, boost::shared_ptr< DataAtIntegrationPts >, boost::shared_ptr< ExternalStrainVec > external_strain_ptr, std::map< std::string, boost::shared_ptr< ScalingMethod > > scaling_methods) override
VolUserDataOperator * returnOpCalculateVarStretchFromStress(boost::shared_ptr< DataAtIntegrationPts >, boost::shared_ptr< PhysicalEquations >) override
VolUserDataOperator * returnOpCalculateStretchFromStress(boost::shared_ptr< DataAtIntegrationPts >, boost::shared_ptr< PhysicalEquations >, boost::shared_ptr< MatrixDouble >, VectorPtr) override
static MoFEMErrorCode validateParameters(const Parameters &parameters)
Check finite, strictly positive C10, K and representable mu = 2*C10.
static SymmetricTensor getTensor(const Coordinates &t_coordinates, double theta=0.)
Reconstruct H = D + theta*I/3 from the fixed five-coordinate basis.
static MoFEMErrorCode evaluateDeviator(const Parameters &parameters, const Coordinates &t_deviator, double &energy, Coordinates *stress_ptr=nullptr, Tangent *hessian_ptr=nullptr)
Evaluate f(D), optionally its five-component gradient and Hessian.
static Coordinates getCoordinates(const SymmetricTensor &t_tensor)
Project a symmetric tensor onto the fixed trace-free basis.
static MoFEMErrorCode evaluateVolume(const Parameters &parameters, double theta, VolumeState &state)
Evaluate g(J) = K*(J-1)^2/2 and its logarithmic-volume derivatives.
virtual MoFEMErrorCode pushHelmholtzStateGradient(const EshelbianCore &ep, boost::ptr_deque< UserDataOperator > &pipeline, boost::shared_ptr< DataAtIntegrationPts > data_ptr)
Assemble the physical Helmholtz state derivative at equilibrium.
@ AUXILIARY_LOGARITHMIC_STRESS
Auxiliary logarithmic stress formulation.
virtual moab::Interface & get_moab()=0
virtual MPI_Comm & get_comm() const =0
Deprecated interface functions.
Data on single entity (This is passed as argument to DataOperator::doWork)
FTensor::Tensor0< FTensor::PackPtr< double *, 1 > > getFTensor0N(const FieldApproximationBase base)
Get base function as Tensor0.
auto getFTensor1DiffN(const FieldApproximationBase base)
Get derivatives of base functions.
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.
Calculate q = 3 K_ext epsilon_ext at integration points.
double scale
Definition plastic.cpp:123