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
129 EntityHandle entity, int, DataAtIntegrationPts &,
130 const Material::SymmetricTensor &elastic_log_stretch,
131 Material::Tangent &hessian) override {
133 double energy = 0.;
135 getParameters(entity), Material::getCoordinates(elastic_log_stretch),
136 energy, nullptr, &hessian);
138 }
139
140 bool providesHelmholtzCurvature() const override { return true; }
141
142 MoFEMErrorCode
143 evaluateHelmholtzCurvature(EntityHandle entity, int point,
147 using namespace LogarithmicDirectionalDerivatives;
148 FTENSOR_INDEXES(3, i, j);
149 FTensor::Index<'a', 5> a;
150 FTensor::Index<'b', 5> b;
151 FTensor::Index<'A', 6> A;
152 const auto parameters = getParameters(entity);
153 const bool auxiliary = getFeatures().test(AUXILIARY_LOGARITHMIC_STRESS);
154 const double jac = std::exp(c.stretch(i, i));
155 const double g2 = parameters.bulkModulus * jac * (2 * jac - 1);
156 const double g3 = parameters.bulkModulus * jac * (4 * jac - 1);
157 const auto basis = FTensor::SymmLTensor<double, 3>();
158 c.stressResult(a) = 0.;
159 const auto curvature =
160 deviatorCurvature(parameters.c10, c.stretch, c.adjoint, c.direction);
161 for (int n = 0; n != 6; ++n) {
163 unit(A) = 0.;
164 unit(n) = 1.;
166 e(i, j) = basis(i, j, A) * unit(A);
167 c.stretchResult(n) =
168 curvature.second(i, j) * e(i, j) -
169 (auxiliary ? 0. : curvature.third(i, j) * e(i, j)) +
170 (g2 - c.adjoint(i, i) * g3) * c.direction(i, i) * e(i, i);
171 }
172 if (auxiliary) {
173 using DL = DataLayoutTraits<DataLayout::GaussByCoeffs>;
174 const int count = data.auxiliaryMaterialData->compliance->size1();
175 auto compliance =
176 MatrixSizeHelper<GetFTensor2FromMatType<5, 5, -1, DL>, DL>::get(
177 *data.auxiliaryMaterialData->compliance, count)();
178 auto dm = MatrixSizeHelper<GetFTensor1FromMatType<5, -1, DL>, DL>::get(
179 *data.auxiliaryMaterialData->materialDeviator, count)();
180 for (int gg = 0; gg != point; ++gg) {
181 ++compliance;
182 ++dm;
183 }
184 Material::Coordinates p, s, e;
185 p(a) = compliance(a, b) * c.stressAdjoint(b);
186 s(a) = compliance(a, b) * c.stressDirection(b);
187 const auto h = Tensor2SymmetricDeviatorBasis::getTensor(dm);
188 const auto pt = Material::getTensor(p);
189 const auto st = Material::getTensor(s);
190 const auto stress_curvature =
191 deviatorCurvature(parameters.c10, h, pt, st);
192 for (int n = 0; n != 5; ++n) {
194 unit(a) = 0.;
195 unit(n) = 1.;
196 e(a) = compliance(a, b) * unit(b);
197 c.stressResult(n) =
198 -stress_curvature.third(i, j) * Material::getTensor(e)(i, j);
199 }
200 }
202 }
203
204 struct OpJacobian : public EshelbianPlasticity::OpJacobian {
205 using EshelbianPlasticity::OpJacobian::OpJacobian;
206 MoFEMErrorCode evaluateRhs(EntData &) override { return 0; }
207 MoFEMErrorCode evaluateLhs(EntData &) override { return 0; }
208 };
209
211 returnOpJacobian(const bool eval_rhs, const bool eval_lhs,
212 boost::shared_ptr<DataAtIntegrationPts> data_ptr,
213 boost::shared_ptr<PhysicalEquations> physics_ptr) override {
214 return new OpJacobian(eval_rhs, eval_lhs, std::move(data_ptr),
215 std::move(physics_ptr));
216 }
217
219 OpEnergy(boost::shared_ptr<DataAtIntegrationPts> data_ptr,
220 boost::shared_ptr<double> total_energy_ptr)
221 : VolUserDataOperator(NOSPACE, OPSPACE), dataAtPts(std::move(data_ptr)),
222 totalEnergyPtr(std::move(total_energy_ptr)) {}
223
224 MoFEMErrorCode doWork(int, EntityType, EntData &) override {
226 const auto material_ptr = getMaterial(dataAtPts);
227 const auto parameters = material_ptr->getParameters(getFEEntityHandle());
228 const int nb_integration_pts = getGaussPts().size2();
229 auto t_eigenvalues = dataAtPts->getFTensorEigenVals(nb_integration_pts);
230 dataAtPts->energyAtPts.resize(nb_integration_pts, false);
231 auto t_energy = getFTensor0FromVec(dataAtPts->energyAtPts);
232 auto t_weight = getFTensor0IntegrationWeight();
233 auto t_plasticF = dataAtPts->getFTensorPlasticF(nb_integration_pts);
234 double element_energy = 0.;
235 for (int gg = 0; gg != nb_integration_pts; ++gg) {
236 // Isotropic energy uses the principal logarithms supplied by either
237 // configuration pipeline, independently of its displacement gradient.
238 const Material::SymmetricTensor t_log_stretch(
239 t_eigenvalues(0), 0., 0., t_eigenvalues(1), 0., t_eigenvalues(2));
240 double energy;
241 CHKERR evaluateDirect(parameters, t_log_stretch, energy);
242 t_energy = energy;
243 // Pull the intermediate-volume density back to the reference cell.
244 const double det_plasticF = determinantTensor3by3(t_plasticF);
245 element_energy += t_weight * energy * det_plasticF;
246 ++t_eigenvalues;
247 ++t_energy;
248 ++t_weight;
249 ++t_plasticF;
250 }
251 if (totalEnergyPtr)
252 *totalEnergyPtr += getMeasure() * element_energy;
254 }
255
256 private:
257 boost::shared_ptr<DataAtIntegrationPts> dataAtPts;
258 boost::shared_ptr<double> totalEnergyPtr;
259 };
260
262 boost::shared_ptr<DataAtIntegrationPts> data_ptr,
263 boost::shared_ptr<double> total_energy_ptr) override {
264 return new OpEnergy(std::move(data_ptr), std::move(total_energy_ptr));
265 }
266
267 bool providesHelmholtzFreeEnergy() const override { return true; }
268
271 boost::shared_ptr<DataAtIntegrationPts> data_ptr,
272 boost::shared_ptr<MatrixDouble> deviator_gradient_ptr,
273 boost::shared_ptr<MatrixDouble> volume_gradient_ptr)
274 : VolUserDataOperator(NOSPACE, OPSPACE), dataAtPts(std::move(data_ptr)),
275 deviatorGradientPtr(std::move(deviator_gradient_ptr)),
276 volumeGradientPtr(std::move(volume_gradient_ptr)) {}
277
278 MoFEMErrorCode doWork(int, EntityType, EntData &) override {
280 const auto material_ptr = getMaterial(dataAtPts);
281 const auto parameters = material_ptr->getParameters(getFEEntityHandle());
282 const int nb_gauss = getGaussPts().size2();
283 const auto fields = dataAtPts->auxiliaryData;
284 using DL = DataLayoutTraits<DataLayout::GaussByCoeffs>;
285 auto t_d = MatrixSizeHelper<GetFTensor1FromMatType<5, -1, DL>, DL>::get(
286 *fields->logDeviator, nb_gauss)();
287 auto t_theta =
288 MatrixSizeHelper<GetFTensor1FromMatType<1, -1, DL>, DL>::get(
289 *fields->logJacobian, nb_gauss)();
290 auto t_deviator_gradient =
291 MatrixSizeHelper<GetFTensor1FromMatType<5, -1, DL>, DL>::size(
292 *deviatorGradientPtr, nb_gauss)();
293 auto t_volume_gradient =
294 MatrixSizeHelper<GetFTensor1FromMatType<1, -1, DL>, DL>::size(
295 *volumeGradientPtr, nb_gauss)();
296 FTENSOR_INDEX(5, L);
297 for (int gg = 0; gg != nb_gauss; ++gg) {
298 Material::Coordinates t_coordinates, t_stress;
299 t_coordinates(L) = t_d(L);
300 double energy;
302 CHKERR Material::evaluateDeviator(parameters, t_coordinates, energy,
303 &t_stress);
304 CHKERR Material::evaluateVolume(parameters, t_theta(0), volume);
305 // Differentiate the physical energy at D_k. Weak copy closure does
306 // not make the independent T_d its pointwise derivative.
307 t_deviator_gradient(L) = t_stress(L);
308 t_volume_gradient(0) = volume.firstDerivative;
309 ++t_d;
310 ++t_theta;
311 ++t_deviator_gradient;
312 ++t_volume_gradient;
313 }
315 }
316
317 private:
318 boost::shared_ptr<DataAtIntegrationPts> dataAtPts;
319 boost::shared_ptr<MatrixDouble> deviatorGradientPtr;
320 boost::shared_ptr<MatrixDouble> volumeGradientPtr;
321 };
322
324 const EshelbianCore &ep, boost::ptr_deque<UserDataOperator> &pipeline,
325 boost::shared_ptr<DataAtIntegrationPts> data_ptr) override {
329 data_ptr);
331 }
332 auto deviator_gradient = boost::make_shared<MatrixDouble>();
333 auto volume_gradient = boost::make_shared<MatrixDouble>();
334 pipeline.push_back(new OpAuxiliaryHelmholtzGradient(
335 data_ptr, deviator_gradient, volume_gradient));
336 using OpDeviatorGradient = FormsIntegrators<VolUserDataOperator>::Assembly<
338 using OpVolumeGradient = FormsIntegrators<VolUserDataOperator>::Assembly<
340 pipeline.push_back(
341 new OpDeviatorGradient(ep.logDeviator, deviator_gradient));
342 pipeline.push_back(new OpVolumeGradient(ep.logJacobian, volume_gradient));
344 }
345
346 struct OpResidual : public FormBase {
347 OpResidual(const std::string &field,
348 boost::shared_ptr<DataAtIntegrationPts> data_ptr,
349 const double alpha_u)
350 : FormBase(field, field, FormBase::OPROW),
351 dataAtPts(std::move(data_ptr)), alphaU(alpha_u) {
353 "Unsupported direct Neo-Hookean configuration");
354 if (!std::isfinite(alphaU))
356 "Neo-Hookean stretch viscosity must be finite");
357 }
358
359 MoFEMErrorCode iNtegrate(EntData &row_data) override {
361 FTENSOR_INDEXES(3, i, j);
363 const auto t_packed_basis = FTensor::SymmLTensor<double, 3>();
364 const auto material_ptr = getMaterial(dataAtPts);
365 const auto parameters = material_ptr->getParameters(getFEEntityHandle());
366 const double alpha_grad_u = material_ptr->alphaGradU;
367 auto t_h = dataAtPts->getFTensorLogStretch(nbIntegrationPts);
368 auto t_physical = dataAtPts->getFTensorAdjointPdU(nbIntegrationPts);
369 // Inactive viscosity terms do not introduce rate-data dependencies.
370 std::optional<decltype(dataAtPts->getFTensorLogStretchDot(
371 nbIntegrationPts))>
372 t_dot_h;
373 std::optional<decltype(dataAtPts->getFTensorGradLogStretchDot(
374 nbIntegrationPts))>
375 t_grad_dot_h;
376 if (alphaU != 0.)
377 t_dot_h.emplace(dataAtPts->getFTensorLogStretchDot(nbIntegrationPts));
378 if (alpha_grad_u != 0.)
379 t_grad_dot_h.emplace(
380 dataAtPts->getFTensorGradLogStretchDot(nbIntegrationPts));
381 auto t_row = row_data.getFTensor0N();
382 auto t_grad_row = row_data.getFTensor1DiffN<3>();
383 auto t_weight = getFTensor0IntegrationWeight();
384 for (int gg = 0; gg != nbIntegrationPts; ++gg) {
385 Material::SymmetricTensor t_log_stretch;
386 t_log_stretch(i, j) = t_h(i, j);
387 PackedStress t_stress;
388 double energy;
389 CHKERR evaluateDirect(parameters, t_log_stretch, energy, &t_stress);
390 const double alpha = getMeasure() * t_weight;
391 PackedStress t_residual;
392 t_residual(L) = t_stress(L) - t_physical(L);
393 if (t_dot_h)
394 t_residual(L) +=
395 alphaU * (t_packed_basis(i, j, L) * (*t_dot_h)(i, j));
397 t_gradient(L, i) = 0.;
398 if (t_grad_dot_h)
399 t_gradient(L, i) = alpha_grad_u * (*t_grad_dot_h)(L, i);
400 auto t_nf = getNf<size_symm>();
401 int rr = 0;
402 for (; rr != nbRows / size_symm; ++rr) {
403 t_nf(L) += alpha *
404 (t_row * t_residual(L) + t_grad_row(i) * t_gradient(L, i));
405 ++t_nf;
406 ++t_row;
407 ++t_grad_row;
408 }
409 for (; rr != nbRowBaseFunctions; ++rr) {
410 ++t_row;
411 ++t_grad_row;
412 }
413 ++t_weight;
414 ++t_h;
415 ++t_physical;
416 if (t_dot_h)
417 ++*t_dot_h;
418 if (t_grad_dot_h)
419 ++*t_grad_dot_h;
420 }
422 }
423
424 private:
425 boost::shared_ptr<DataAtIntegrationPts> dataAtPts;
426 const double alphaU;
427 };
428
430 returnOpSpatialPhysical(const std::string &field,
431 boost::shared_ptr<DataAtIntegrationPts> data_ptr,
432 const double alpha_u) override {
433 return new OpResidual(field, std::move(data_ptr), alpha_u);
434 }
435
436 struct OpTangent : public FormBase {
437 OpTangent(const std::string &row_field, const std::string &col_field,
438 boost::shared_ptr<DataAtIntegrationPts> data_ptr,
439 const double alpha_u)
440 : FormBase(row_field, col_field, FormBase::OPROWCOL),
441 dataAtPts(std::move(data_ptr)), alphaU(alpha_u) {
442 sYmm = false;
444 "Unsupported direct Neo-Hookean configuration");
445 if (!std::isfinite(alphaU))
447 "Neo-Hookean stretch viscosity must be finite");
448 }
449
450 MoFEMErrorCode iNtegrate(EntData &row_data, EntData &col_data) override {
452 FTENSOR_INDEXES(3, i, j, k, l);
454 const auto material_ptr = getMaterial(dataAtPts);
455 const auto parameters = material_ptr->getParameters(getFEEntityHandle());
456 const auto t_packed_basis = FTensor::SymmLTensor<double, 3>();
457 constexpr auto t_identity = FTensor::Kronecker_Delta<int>();
458 PackedTangent t_viscous_metric;
459 t_viscous_metric(L, J) =
460 t_packed_basis(i, j, L) * t_packed_basis(i, j, J);
461 const double ts_a = getTSa();
462 const double alpha_grad_u = material_ptr->alphaGradU;
463 auto t_h = dataAtPts->getFTensorLogStretch(nbIntegrationPts);
464 auto t_pullback = dataAtPts->getFTensorAdjointPdstretch(nbIntegrationPts);
465 auto t_eigenvalues = dataAtPts->getFTensorEigenVals(nbIntegrationPts);
466 auto t_eigenvectors = dataAtPts->getFTensorEigenVecs(nbIntegrationPts);
467 auto t_row = row_data.getFTensor0N();
468 auto t_grad_row = row_data.getFTensor1DiffN<3>();
469 auto t_weight = getFTensor0IntegrationWeight();
470#ifndef NDEBUG
471 if (dataAtPts->nbUniq.size() != nbIntegrationPts)
472 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
473 "Neo-Hookean tangent requires current geometric eigendata");
474#endif
475 for (int gg = 0; gg != nbIntegrationPts; ++gg) {
476 Material::SymmetricTensor t_log_stretch;
477 t_log_stretch(i, j) = t_h(i, j);
478 PackedTangent t_tangent;
479 double energy;
480 CHKERR evaluateDirect(parameters, t_log_stretch, energy, nullptr,
481 &t_tangent);
482 Material::SymmetricTensor t_symmetric_pullback;
483 t_symmetric_pullback(i, j) =
484 (t_pullback(i, j) || t_pullback(j, i)) / 2.;
485 const auto t_work_curvature = EigenMatrix::getDiffDiffMat(
486 t_eigenvalues, t_eigenvectors, EshelbianCore::f, EshelbianCore::d_f,
487 EshelbianCore::dd_f, t_symmetric_pullback, dataAtPts->nbUniq[gg]);
488 t_tangent(L, J) -=
489 t_packed_basis(i, j, L) *
490 (t_work_curvature(i, j, k, l) * t_packed_basis(k, l, J));
491 t_tangent(L, J) += (alphaU * ts_a) * t_viscous_metric(L, J);
492 const double alpha = getMeasure() * t_weight;
493 int rr = 0;
494 for (; rr != nbRows / size_symm; ++rr) {
495 auto t_col = col_data.getFTensor0N(gg, 0);
496 auto t_grad_col = col_data.getFTensor1DiffN<3>(gg, 0);
497 auto t_matrix = getLocMat<size_symm>(size_symm * rr);
498 for (int cc = 0; cc != nbCols / size_symm; ++cc) {
499 t_matrix(L, J) += alpha * t_row * t_col * t_tangent(L, J);
500 const double gradient_weight =
501 alpha * alpha_grad_u * ts_a * (t_grad_row(i) * t_grad_col(i));
502 t_matrix(L, J) += gradient_weight * t_identity(L, J);
503 ++t_matrix;
504 ++t_col;
505 ++t_grad_col;
506 }
507 ++t_row;
508 ++t_grad_row;
509 }
510 for (; rr != nbRowBaseFunctions; ++rr) {
511 ++t_row;
512 ++t_grad_row;
513 }
514 ++t_weight;
515 ++t_h;
516 ++t_pullback;
517 ++t_eigenvalues;
518 ++t_eigenvectors;
519 }
521 }
522
523 private:
524 boost::shared_ptr<DataAtIntegrationPts> dataAtPts;
525 const double alphaU;
526 };
527
529 std::string row_field, std::string col_field,
530 boost::shared_ptr<DataAtIntegrationPts> data_ptr,
531 const double alpha_u) override {
532 return new OpTangent(row_field, col_field, std::move(data_ptr), alpha_u);
533 }
534
535 struct OpExternalStrain : public FormBase {
537 const std::string &field,
538 boost::shared_ptr<ExternalStrainVec> external_strain_ptr,
539 std::map<std::string, boost::shared_ptr<ScalingMethod>> scaling_methods)
540 : FormBase(field, field, FormBase::OPROW),
541 externalStrainPtr(std::move(external_strain_ptr)),
542 scalingMethods(std::move(scaling_methods)) {}
543
544 MoFEMErrorCode iNtegrate(EntData &row_data) override {
548 const double time = EshelbianCore::physicalTimeFlg
550 : getFEMethod()->ts_t;
551 double pressure = 0.;
552 for (const auto &block : *externalStrainPtr) {
553 if (block.blockName.find("ANALYTICAL_EXTERNALSTRAIN") !=
554 std::string::npos)
555 SETERRQ(
556 PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
557 "Analytical external strain is not implemented for Neo-Hookean");
558 if (block.ents.find(getFEEntityHandle()) == block.ents.end())
559 continue;
560 const auto scaling = scalingMethods.find(block.blockName);
561 double scale = 1.;
562 if (scaling != scalingMethods.end())
563 scale = scaling->second->getScale(time);
564 else
565 MOFEM_LOG("SELF", Sev::warning)
566 << "No scaling method found for " << block.blockName;
567 pressure += 3. * block.bulkModulusK * block.val * scale;
568 }
569 if (!std::isfinite(pressure))
570 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
571 "Neo-Hookean prescribed external pressure must be finite");
572 FTENSOR_INDEXES(3, i, j);
574 const auto t_packed_basis = FTensor::SymmLTensor<double, 3>();
575 constexpr auto t_identity = FTensor::Kronecker_Delta_symmetric<int>();
576 PackedStress t_load;
577 t_load(L) = pressure * (t_packed_basis(i, j, L) * t_identity(i, j));
578 auto t_row = row_data.getFTensor0N();
579 auto t_weight = getFTensor0IntegrationWeight();
580 for (int gg = 0; gg != nbIntegrationPts; ++gg) {
581 const double alpha = getMeasure() * t_weight;
582 auto t_nf = getNf<size_symm>();
583 int rr = 0;
584 for (; rr != nbRows / size_symm; ++rr) {
585 t_nf(L) -= alpha * t_row * t_load(L);
586 ++t_nf;
587 ++t_row;
588 }
589 for (; rr != nbRowBaseFunctions; ++rr)
590 ++t_row;
591 ++t_weight;
592 }
594 }
595
596 private:
597 boost::shared_ptr<ExternalStrainVec> externalStrainPtr;
598 std::map<std::string, boost::shared_ptr<ScalingMethod>> scalingMethods;
599 };
600
602 const std::string &field, boost::shared_ptr<DataAtIntegrationPts>,
603 boost::shared_ptr<ExternalStrainVec> external_strain_ptr,
604 std::map<std::string, boost::shared_ptr<ScalingMethod>> scaling_methods)
605 override {
606 return new OpExternalStrain(field, std::move(external_strain_ptr),
607 std::move(scaling_methods));
608 }
609
611 VectorPtr pressure_ptr,
612 boost::shared_ptr<ExternalStrainVec> external_strain_ptr,
613 std::map<std::string, boost::shared_ptr<ScalingMethod>> scaling_methods)
614 override {
615 return new OpCalculateExternalPressure(std::move(pressure_ptr),
616 std::move(external_strain_ptr),
617 std::move(scaling_methods));
618 }
619
621 returnOpCalculateStretchFromStress(boost::shared_ptr<DataAtIntegrationPts>,
622 boost::shared_ptr<PhysicalEquations>,
623 boost::shared_ptr<MatrixDouble>) override {
624 return retiredInverse();
625 }
627 returnOpCalculateStretchFromStress(boost::shared_ptr<DataAtIntegrationPts>,
628 boost::shared_ptr<PhysicalEquations>,
629 boost::shared_ptr<MatrixDouble>,
630 VectorPtr) override {
631 return retiredInverse();
632 }
634 boost::shared_ptr<DataAtIntegrationPts>,
635 boost::shared_ptr<PhysicalEquations>, boost::shared_ptr<MatrixDouble>,
636 boost::shared_ptr<MatrixDouble>, VectorPtr) override {
637 return retiredInverse();
638 }
640 boost::shared_ptr<DataAtIntegrationPts>,
641 boost::shared_ptr<PhysicalEquations>) override {
642 return retiredInverse();
643 }
644
645private:
647 const boost::shared_ptr<DataAtIntegrationPts> &data_ptr) {
648 if (!data_ptr)
650 "Auxiliary material evaluation requires field data");
651 if (!data_ptr->auxiliaryMaterialData)
652 data_ptr->auxiliaryMaterialData =
653 boost::make_shared<AuxiliaryLogarithmicStressMaterialData>();
654 return [this](EntityHandle entity) { return getParameters(entity); };
655 }
656
657 static MoFEMErrorCode checkDirectConfiguration() {
660 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
661 "Neo-Hookean direct material equations require -grad no_h1");
664 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
665 "Neo-Hookean direct material equations require "
666 "-rotations large or -rotations small");
668 }
669
670 static boost::shared_ptr<HMHNeohookean>
671 getMaterial(const boost::shared_ptr<DataAtIntegrationPts> &data_ptr) {
672 if (!data_ptr)
674 "Neo-Hookean integration-point data is missing");
675 const auto material_ptr =
676 boost::dynamic_pointer_cast<HMHNeohookean>(data_ptr->physicsPtr);
677 if (!material_ptr)
679 "Neo-Hookean material pointer is missing");
680 return material_ptr;
681 }
682
685 "Neo-Hookean physical-stress-to-stretch recovery was "
686 "retired; solve the logarithmic material fields");
687 return nullptr;
688 }
689
690 MoFEMErrorCode getOptions() {
692 PetscOptionsBegin(mField.get_comm(), "neo_hookean_", "Neo-Hookean material",
693 "none");
694 CHKERR PetscOptionsScalar("-c10", "C10", "", defaultParameters.c10,
695 &defaultParameters.c10, nullptr);
696 CHKERR PetscOptionsScalar("-K", "Bulk modulus", "",
699 CHKERR PetscOptionsScalar("-viscosity_alpha_grad_u",
700 "Logarithmic-stretch-gradient rate viscosity", "",
701 alphaGradU, &alphaGradU, nullptr);
702 PetscOptionsEnd();
704 if (!std::isfinite(alphaGradU))
705 SETERRQ(
707 "Neo-Hookean logarithmic-stretch-gradient viscosity must be finite");
708 char *options_ptr = nullptr;
709 CHKERR PetscOptionsGetAll(nullptr, &options_ptr);
710 std::istringstream options(options_ptr ? options_ptr : "");
711 CHKERR PetscFree(options_ptr);
712 std::string option;
713 while (options >> option)
714 if (option.rfind("-nh_stretch_", 0) == 0 ||
715 option == "-neo_hookean_min_eigen_value")
717 "Option %s belongs to the retired Neo-Hookean physical inverse "
718 "or tangent projection; remove it",
719 option.c_str());
720 MOFEM_LOG("EP", Sev::inform) << "Neo-Hookean C10=" << defaultParameters.c10
722 << " alphaGradU=" << alphaGradU;
724 }
725
726 MoFEMErrorCode extractBlockData() {
728 auto meshsets = mField.getInterface<MeshsetsManager>();
729 auto json_config = mField.getInterface<JsonConfigManager>();
730 for (const auto block :
731 meshsets->getCubitMeshsetPtr(std::regex("MAT_NEOHOOKEAN(.*)"))) {
732 Material::Parameters parameters;
733 const auto json_parameters = json_config->getParamsFromBlockset(
734 "MAT_NEOHOOKEAN", block->getMeshsetId());
735 if (!json_parameters.empty()) {
736 if (json_parameters.size() != 2 || !json_parameters.count("c10") ||
737 !json_parameters.count("k"))
739 "MAT_NEOHOOKEAN JSON block must contain exactly c10,k");
740 parameters = {json_parameters.at("c10"), json_parameters.at("k")};
741 } else {
742 std::vector<double> attributes;
743 CHKERR block->getAttributes(attributes);
744 if (attributes.size() < 2)
746 "MAT_NEOHOOKEAN block requires C10,K attributes");
747 parameters = {attributes[0], attributes[1]};
748 }
750 Range entities;
751 CHKERR mField.get_moab().get_entities_by_handle(block->getMeshset(),
752 entities, true);
753 blockData.push_back({parameters, std::move(entities)});
754 MOFEM_LOG("EP", Sev::inform)
755 << "MAT_NEOHOOKEAN " << block->getMeshsetId()
756 << " C10=" << parameters.c10 << " K=" << parameters.bulkModulus;
757 }
759 }
760
767 double alphaGradU = 0.;
768 std::vector<BlockData> blockData;
769};
770
771} // namespace EshelbianPlasticity
Material and stress-work blocks for the independent D/theta/Td fields.
Neo-Hookean material law in orthonormal logarithmic coordinates.
boost::shared_ptr< DataAtIntegrationPts > data
EshelbianCore * ep
PetscInt size
#define FTENSOR_INDEXES(DIM,...)
#define FTENSOR_INDEX(DIM, I)
constexpr double a
Kronecker Delta class symmetric.
Kronecker Delta class.
Mapping from symmetric tensor indices to packed storage index.
#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
const double c
speed of light (cm/ns)
const double n
refractive index of diffusive medium
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
double h
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
MoFEMErrorCode evaluateHelmholtzCurvature(EntityHandle entity, int point, DataAtIntegrationPts &data, LogarithmicMaterialCurvature &c) override
bool providesHelmholtzCurvature() const override
Contract material curvature for the incremental material-energy adjoint.
static boost::shared_ptr< HMHNeohookean > getMaterial(const boost::shared_ptr< DataAtIntegrationPts > &data_ptr)
static MoFEMErrorCode checkDirectConfiguration()
MoFEMErrorCode evaluateElasticLogarithmicMaterialHessian(EntityHandle entity, int, DataAtIntegrationPts &, const Material::SymmetricTensor &elastic_log_stretch, Material::Tangent &hessian) override
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:124