v0.16.3
Loading...
Searching...
No Matches
AuxiliaryLogarithmicStress.cpp
Go to the documentation of this file.
1/**
2 * @file AuxiliaryLogarithmicStress.cpp
3 * @brief Auxiliary logarithmic fields, material equations and postprocessing.
4 */
5
6#include <MoFEM.hpp>
7using namespace MoFEM;
8
13#include <MatrixFunction.hpp>
14
15#include <cmath>
16#include <optional>
17
18namespace EshelbianPlasticity {
19namespace {
20
21using Material = NeoHookeanLogarithmicMaterial;
22using MaterialData = AuxiliaryLogarithmicStressMaterialData;
24
25/** Nonassembling producer; the field evaluators own its input storage. */
26struct OpReconstructAuxiliaryLogarithmicStretch : public VolUserDataOperator {
27 OpReconstructAuxiliaryLogarithmicStretch(
28 boost::shared_ptr<AuxiliaryLogarithmicStressData> values,
29 MatrixPtr reconstructed_log_stretch)
30 : VolUserDataOperator(NOSPACE, OPSPACE), valuesPtr(std::move(values)),
31 logStretchPtr(std::move(reconstructed_log_stretch)) {}
32
33 MoFEMErrorCode doWork(int, EntityType, EntData &) override {
35 const int nb_gauss = getGaussPts().size2();
36 auto get_d =
38 *valuesPtr->logDeviatorTensor, nb_gauss);
39 auto get_theta =
41 *valuesPtr->logJacobian, nb_gauss);
42 auto get_h =
44 *logStretchPtr, nb_gauss);
45 auto t_d = get_d();
46 auto t_theta = get_theta();
47 auto t_h = get_h();
48 FTENSOR_INDEXES(3, i, j);
49 constexpr auto t_identity = FTensor::Kronecker_Delta_symmetric<int>();
50 for (int gg = 0; gg != nb_gauss; ++gg) {
51 t_h(i, j) = t_d(i, j) + (t_theta(0) / 3.) * t_identity(i, j);
52 ++t_d;
53 ++t_theta;
54 ++t_h;
55 }
57 }
58
59private:
60 boost::shared_ptr<AuxiliaryLogarithmicStressData> valuesPtr;
62};
63
64/** Raw symmetric coordinates are (00,01,02,11,12,22), without shear scaling.
65 * Each column is a symmetric tensor's six distinct entries. Contracting the
66 * full SymmLTensor with B here would incorrectly double the shear entries.
67 */
68const FTensor::Tensor2<double, 6, 5> &getPackedDeviatorBasis() {
69 static const auto t_projection = [] {
70 FTensor::Index<'a', 5> a;
71 const auto &t_basis = Tensor2SymmetricDeviatorBasis::getBasis();
72 const FTensor::Number<0> n0;
73 const FTensor::Number<1> n1;
74 const FTensor::Number<2> n2;
75 const FTensor::Number<3> n3;
76 const FTensor::Number<4> n4;
77 const FTensor::Number<5> n5;
79 t_projection(n0, a) = t_basis(n0, n0, a);
80 t_projection(n1, a) = t_basis(n0, n1, a);
81 t_projection(n2, a) = t_basis(n0, n2, a);
82 t_projection(n3, a) = t_basis(n1, n1, a);
83 t_projection(n4, a) = t_basis(n1, n2, a);
84 t_projection(n5, a) = t_basis(n2, n2, a);
85 return t_projection;
86 }();
87 return t_projection;
88}
89
90const FTensor::Tensor1<double, 6> &getPackedVolumeBasis() {
91 static const FTensor::Tensor1<double, 6> t_projection(1. / 3., 0., 0.,
92 1. / 3., 0., 1. / 3.);
93 return t_projection;
94}
95
96MoFEMErrorCode validateValues(const MatrixDouble &values) {
98 if (!std::all_of(values.data().begin(), values.data().end(),
99 [](const double value) { return std::isfinite(value); }))
100 SETERRQ(PETSC_COMM_SELF, MOFEM_OPERATION_UNSUCCESSFUL,
101 "Auxiliary logarithmic material or stress-work values are not "
102 "representable");
104}
105
106/** Nonassembling producer. Geometry and total P (including bubbles) precede it.
107 */
108struct OpCalculateAuxiliaryLogarithmicMaterial : public VolUserDataOperator {
109 OpCalculateAuxiliaryLogarithmicMaterial(
110 boost::shared_ptr<DataAtIntegrationPts> data,
111 boost::shared_ptr<MaterialData> material_data,
112 AuxiliaryLogarithmicMaterialParameters parameters, const double alpha_u,
113 const bool lhs)
114 : VolUserDataOperator(NOSPACE, OPSPACE), dataAtPts(std::move(data)),
115 materialData(std::move(material_data)),
116 parameterFun(std::move(parameters)), alphaU(alpha_u),
117 calculateLhs(lhs) {
118 if (!std::isfinite(alphaU))
120 "Neo-Hookean deviator viscosity must be finite");
121 }
122
123 MoFEMErrorCode doWork(int, EntityType, EntData &) override {
125 const int nb_gauss = getGaussPts().size2();
126 const auto parameters = parameterFun(getFEEntityHandle());
127 const MoFEMErrorCode material_error =
128 calculateMaterial(parameters, nb_gauss);
129 if (material_error == MOFEM_OPERATION_UNSUCCESSFUL && !calculateLhs &&
130 getSNESCtx() == SnesMethod::CTX_SNESSETFUNCTION &&
131 getFEMethod()->snes) {
132 // Let SNES reject an unrepresentable trial and release its work vectors.
133 // Returning a raw callback error leaves the solver unusable on retry.
134 CHKERR SNESSetFunctionDomainError(getFEMethod()->snes);
135 materialData->residualDeviator->clear();
136 materialData->residualJacobian->clear();
137 materialData->residualStress->clear();
139 }
140 CHKERR material_error;
141 if (calculateLhs)
142 CHKERR calculateTangent(nb_gauss);
144 }
145
146private:
147 boost::shared_ptr<DataAtIntegrationPts> dataAtPts;
148 boost::shared_ptr<MaterialData> materialData;
150 const double alphaU;
152
153 MoFEMErrorCode calculateMaterial(const Material::Parameters &parameters,
154 const int nb_gauss) {
156 const auto fields = dataAtPts->auxiliaryData;
157 auto get_d = MatrixSizeHelper<GetFTensor1FromMatType<5, -1, DL>, DL>::get(
158 *fields->logDeviator, nb_gauss);
159 auto get_theta =
161 *fields->logJacobian, nb_gauss);
162 auto get_stress =
164 *fields->stress, nb_gauss);
165 auto get_elastic_stress =
167 *materialData->elasticStress, nb_gauss);
168 auto get_dm = MatrixSizeHelper<GetFTensor1FromMatType<5, -1, DL>, DL>::size(
169 *materialData->materialDeviator, nb_gauss);
170 auto get_compliance =
171 MatrixSizeHelper<GetFTensor2FromMatType<5, 5, -1, DL>, DL>::size(
172 *materialData->compliance, nb_gauss);
173 auto get_energy =
175 *materialData->energy, nb_gauss);
176 auto get_volume =
178 *materialData->volume, nb_gauss);
179 auto get_rd = MatrixSizeHelper<GetFTensor1FromMatType<5, -1, DL>, DL>::size(
180 *materialData->residualDeviator, nb_gauss);
181 auto get_rtheta =
183 *materialData->residualJacobian, nb_gauss);
184 auto get_rt = MatrixSizeHelper<GetFTensor1FromMatType<5, -1, DL>, DL>::size(
185 *materialData->residualStress, nb_gauss);
186 auto t_d = get_d();
187 auto t_theta = get_theta();
188 auto t_stress = get_stress();
189 auto t_elastic_stress = get_elastic_stress();
190 std::optional<decltype(t_d)> t_dot_d;
191 if (alphaU != 0.)
192 t_dot_d.emplace(
194 *fields->logDeviatorDot, nb_gauss)());
195 auto t_dm = get_dm();
196 auto t_compliance = get_compliance();
197 auto t_energy = get_energy();
198 auto t_volume = get_volume();
199 auto t_rd = get_rd();
200 auto t_rtheta = get_rtheta();
201 auto t_rt = get_rt();
202 auto t_work = dataAtPts->getFTensorAdjointPdU(nb_gauss);
203 auto t_plastic_f = dataAtPts->getFTensorPlasticF(nb_gauss);
204 const auto &t_projection = getPackedDeviatorBasis();
205 const auto &t_volume_projection = getPackedVolumeBasis();
206 FTensor::Index<'a', 5> a;
207 FTensor::Index<'b', 5> b;
208 FTensor::Index<'L', 6> L;
209
210 for (int gg = 0; gg != nb_gauss; ++gg) {
211 Material::Coordinates t_current_d, t_current_stress;
212 t_current_d(a) = t_d(a);
213 t_current_stress(a) = t_stress(a);
214 if (t_dot_d)
215 t_current_stress(a) -= alphaU * (*t_dot_d)(a);
216 t_elastic_stress(a) = t_current_stress(a);
219 CHKERR Material::evaluateInverse(parameters, t_current_stress, inverse);
220 CHKERR Material::evaluateVolume(parameters, t_theta(0), volume);
221 double deviatoric_energy;
222 CHKERR Material::evaluateDeviator(parameters, t_current_d,
223 deviatoric_energy);
224 t_dm(a) = inverse.tMaterialDeviator(a);
225 t_compliance(a, b) = inverse.tCompliance(a, b);
226 t_energy(MaterialData::DEVIATORIC) = deviatoric_energy;
227 t_energy(MaterialData::VOLUMETRIC) = volume.energy;
228 t_energy(MaterialData::CONJUGATE) = inverse.conjugateEnergy;
229 t_volume(MaterialData::JACOBIAN) = volume.jacobian;
230 t_volume(MaterialData::FIRST_DERIVATIVE) = volume.firstDerivative;
231 t_volume(MaterialData::SECOND_DERIVATIVE) = volume.secondDerivative;
232
233 // P_bar=P Fp^T/Jp. Total Td balances stress work; the elastic part
234 // Td-alphaU*dotD determines Dm through the pointwise material inverse.
235 const double det_plastic_f = determinantTensor3by3(t_plastic_f);
236 t_rd(a) = det_plastic_f * (t_stress(a) - t_projection(L, a) * t_work(L));
237 t_rtheta(0) = det_plastic_f * (volume.firstDerivative -
238 t_volume_projection(L) * t_work(L));
239 t_rt(a) = det_plastic_f * (t_d(a) - inverse.tMaterialDeviator(a));
240 ++t_d;
241 ++t_theta;
242 ++t_stress;
243 ++t_elastic_stress;
244 if (t_dot_d)
245 ++*t_dot_d;
246 ++t_dm;
247 ++t_compliance;
248 ++t_energy;
249 ++t_volume;
250 ++t_rd;
251 ++t_rtheta;
252 ++t_rt;
253 ++t_work;
254 ++t_plastic_f;
255 }
256 CHKERR validateValues(*materialData->residualDeviator);
257 CHKERR validateValues(*materialData->residualJacobian);
258 CHKERR validateValues(*materialData->residualStress);
260 }
261
262 MoFEMErrorCode calculateTangent(const int nb_gauss) {
264#ifndef NDEBUG
265 if (getTSCtx() != TSMethod::CTX_TSSETIJACOBIAN)
266 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
267 "Auxiliary tangent evaluation requires the current geometry "
268 "Jacobian context");
269 if (dataAtPts->nbUniq.size() != nb_gauss)
270 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
271 "Auxiliary work curvature requires the current stretch spectrum");
272#endif
273 auto get_compliance =
275 *materialData->compliance, nb_gauss);
276 auto get_volume =
278 *materialData->volume, nb_gauss);
279 auto get_dd =
280 MatrixSizeHelper<GetFTensor2FromMatType<5, 5, -1, DL>, DL>::size(
281 *materialData->tangentDeviator, nb_gauss);
282 auto get_dtheta =
283 MatrixSizeHelper<GetFTensor2FromMatType<5, 1, -1, DL>, DL>::size(
284 *materialData->tangentDeviatorJacobian, nb_gauss);
285 auto get_dt =
286 MatrixSizeHelper<GetFTensor2FromMatType<5, 5, -1, DL>, DL>::size(
287 *materialData->tangentDeviatorStress, nb_gauss);
288 auto get_td =
289 MatrixSizeHelper<GetFTensor2FromMatType<5, 5, -1, DL>, DL>::size(
290 *materialData->tangentStressDeviator, nb_gauss);
291 auto get_thetatheta =
292 MatrixSizeHelper<GetFTensor2FromMatType<1, 1, -1, DL>, DL>::size(
293 *materialData->tangentJacobian, nb_gauss);
294 auto get_tt =
295 MatrixSizeHelper<GetFTensor2FromMatType<5, 5, -1, DL>, DL>::size(
296 *materialData->tangentStress, nb_gauss);
297 auto get_domega =
298 MatrixSizeHelper<GetFTensor2FromMatType<5, 3, -1, DL>, DL>::size(
299 *materialData->deviatorRotation, nb_gauss);
300 auto get_thetaomega =
301 MatrixSizeHelper<GetFTensor2FromMatType<1, 3, -1, DL>, DL>::size(
302 *materialData->jacobianRotation, nb_gauss);
303 auto get_fd =
304 MatrixSizeHelper<GetFTensor3FromMatType<3, 3, 5, -1, DL>, DL>::size(
305 *materialData->deformationDeviator, nb_gauss);
306 auto get_ftheta =
307 MatrixSizeHelper<GetFTensor3FromMatType<3, 3, 1, -1, DL>, DL>::size(
308 *materialData->deformationJacobian, nb_gauss);
309 auto t_compliance = get_compliance();
310 auto t_volume = get_volume();
311 auto t_dd = get_dd();
312 auto t_dtheta = get_dtheta();
313 auto t_dt = get_dt();
314 auto t_td = get_td();
315 auto t_thetatheta = get_thetatheta();
316 auto t_tt = get_tt();
317 auto t_domega = get_domega();
318 auto t_thetaomega = get_thetaomega();
319 auto t_fd = get_fd();
320 auto t_ftheta = get_ftheta();
321 auto t_work = dataAtPts->getFTensorAdjointPdU(nb_gauss);
322 auto t_work_omega = dataAtPts->getFTensorAdjointPdUdOmega(nb_gauss);
323 auto t_fh = dataAtPts->getFTensorAdjointPdUdP(nb_gauss);
324 auto t_adjoint_p = dataAtPts->getFTensorAdjointPdstretch(nb_gauss);
325 auto t_eigen_values = dataAtPts->getFTensorEigenVals(nb_gauss);
326 auto t_eigen_vectors = dataAtPts->getFTensorEigenVecs(nb_gauss);
327 auto t_plastic_f = dataAtPts->getFTensorPlasticF(nb_gauss);
328 const auto &t_basis = Tensor2SymmetricDeviatorBasis::getBasis();
329 const auto &t_projection = getPackedDeviatorBasis();
330 const auto &t_volume_projection = getPackedVolumeBasis();
331 const EigenMatrix::Fun<double> exp_fun = [](const double value) {
332 return std::exp(value);
333 };
334 FTENSOR_INDEXES(3, i, j, k, l);
335 FTensor::Index<'a', 5> a;
336 FTensor::Index<'b', 5> b;
337 FTensor::Index<'L', 6> L;
338 FTensor::Index<'z', 1> z;
339 const FTensor::Tensor1<double, 1> t_scalar_component(1.);
340 const FTensor::Number<0> n0;
341 constexpr auto t_identity = FTensor::Kronecker_Delta<double>();
342 const double alpha_u_shift = alphaU * getTSa();
343
344 for (int gg = 0; gg != nb_gauss; ++gg) {
345 FTensor::Tensor2_symmetric<double, 3> t_symmetric_adjoint;
346 t_symmetric_adjoint(i, j) = (t_adjoint_p(i, j) || t_adjoint_p(j, i)) / 2.;
347 const auto t_curvature = EigenMatrix::getDiffDiffMat(
348 t_eigen_values, t_eigen_vectors, exp_fun, exp_fun, exp_fun,
349 t_symmetric_adjoint, dataAtPts->nbUniq[gg]);
350
351 const double det_plastic_f = determinantTensor3by3(t_plastic_f);
352 t_dd(a, b) =
353 -det_plastic_f *
354 (t_basis(i, j, a) * (t_curvature(i, j, k, l) * t_basis(k, l, b)));
355 // exp(D+theta*I/3) separates exactly, including noncommuting D modes.
356 t_dtheta(a, n0) = -det_plastic_f * (t_projection(L, a) * t_work(L)) / 3.;
357 t_thetatheta(0, 0) =
358 det_plastic_f * (t_volume(MaterialData::SECOND_DERIVATIVE) -
359 (t_volume_projection(L) * t_work(L)) / 3.);
360 t_dt(a, b) = det_plastic_f * t_identity(a, b);
361 t_td(a, b) = det_plastic_f *
362 (t_identity(a, b) + alpha_u_shift * t_compliance(a, b));
363 t_tt(a, b) = -det_plastic_f * t_compliance(a, b);
364 t_domega(a, k) =
365 -det_plastic_f * (t_projection(L, a) * t_work_omega(k, L));
366 t_thetaomega(n0, k) =
367 -det_plastic_f * (t_volume_projection(L) * t_work_omega(k, L));
368 // P and bubble coefficients are reference stresses, so these blocks
369 // differentiate Fe Fp, not Fe. Jp cancels the Piola pullback factor.
371 t_reference_fh(i, j, L) = t_fh(i, k, L) * t_plastic_f(k, j);
372 t_fd(i, j, a) = t_reference_fh(i, j, L) * t_projection(L, a);
373 t_ftheta(i, j, z) = (t_reference_fh(i, j, L) * t_volume_projection(L)) *
374 t_scalar_component(z);
375
376 ++t_compliance;
377 ++t_volume;
378 ++t_dd;
379 ++t_dtheta;
380 ++t_dt;
381 ++t_td;
382 ++t_thetatheta;
383 ++t_tt;
384 ++t_domega;
385 ++t_thetaomega;
386 ++t_fd;
387 ++t_ftheta;
388 ++t_work;
389 ++t_work_omega;
390 ++t_fh;
391 ++t_adjoint_p;
392 ++t_eigen_values;
393 ++t_eigen_vectors;
394 ++t_plastic_f;
395 }
396 for (const auto &values :
397 {materialData->tangentDeviator, materialData->tangentDeviatorJacobian,
398 materialData->tangentDeviatorStress,
399 materialData->tangentStressDeviator, materialData->tangentJacobian,
400 materialData->tangentStress, materialData->deviatorRotation,
401 materialData->jacobianRotation, materialData->deformationDeviator,
402 materialData->deformationJacobian})
403 CHKERR validateValues(*values);
405 }
406};
407
408/** Scalar shape functions with a rectangular material coefficient block. */
409template <int RowDim, int ColDim>
410struct OpAuxiliaryCoefficientMass : public OpBase {
411 OpAuxiliaryCoefficientMass(const std::string &row_field,
412 const std::string &col_field, MatrixPtr values,
413 const bool assemble_transpose = true)
414 : OpBase(row_field, col_field, OPROWCOL), valuesPtr(std::move(values)) {
415 sYmm = row_field == col_field;
416 assembleTranspose = assemble_transpose && !sYmm;
417 }
418
419 MoFEMErrorCode iNtegrate(EntData &row_data, EntData &col_data) override {
421 FTensor::Index<'a', RowDim> a;
422 FTensor::Index<'b', ColDim> b;
423 auto get_values =
424 MatrixSizeHelper<GetFTensor2FromMatType<RowDim, ColDim, -1, DL>,
425 DL>::get(*valuesPtr, nbIntegrationPts);
426 auto t_values = get_values();
427 auto t_w = getFTensor0IntegrationWeight();
428 auto t_row = row_data.getFTensor0N();
429 for (int gg = 0; gg != nbIntegrationPts; ++gg) {
430 const double alpha = t_w * getMeasure();
431 int rr = 0;
432 for (; rr != nbRows / RowDim; ++rr) {
433 auto t_col = col_data.getFTensor0N(gg, 0);
434 auto t_m = getLocMat<RowDim, ColDim>(RowDim * rr);
435 for (int cc = 0; cc != nbCols / ColDim; ++cc) {
436 t_m(a, b) += (alpha * t_row * t_col) * t_values(a, b);
437 ++t_m;
438 ++t_col;
439 }
440 ++t_row;
441 }
442 for (; rr < nbRowBaseFunctions; ++rr)
443 ++t_row;
444 ++t_values;
445 ++t_w;
446 }
448 }
449
450private:
452};
453
454template <int BASE_DIM, int FIELD_DIM>
457
458template <int Dim>
459using OpAuxiliaryResidual = FormsIntegrators<VolUserDataOperator>::Assembly<
461
462/** D_m is computed by the material map rather than interpolated as a field. */
463struct OpFormatDeviator : public VolUserDataOperator {
464 OpFormatDeviator(const std::string &name, MatrixPtr coordinates,
465 MaterialPostProcData &output)
466 : VolUserDataOperator(NOSPACE, OPSPACE),
467 coordinatesPtr(std::move(coordinates)),
468 tensorPtr(boost::make_shared<MatrixDouble>()) {
469 output.symmetricFields[name] = tensorPtr;
470 }
471
472 MoFEMErrorCode doWork(int, EntityType, EntData &) override {
474 const int nb_gauss = getGaussPts().size2();
475 auto get_coordinates =
477 *coordinatesPtr, nb_gauss);
478 auto get_tensor =
480 *tensorPtr, nb_gauss);
481 auto t_coordinates = get_coordinates();
482 auto t_tensor = get_tensor();
483 FTENSOR_INDEXES(3, i, j);
484 for (int gg = 0; gg != nb_gauss; ++gg) {
485 const auto t_deviator =
486 Tensor2SymmetricDeviatorBasis::getTensor(t_coordinates);
487 t_tensor(i, j) = t_deviator(i, j);
488 ++t_coordinates;
489 ++t_tensor;
490 }
492 }
493
494private:
497};
498
499struct OpFormatMaterial : public VolUserDataOperator {
500 OpFormatMaterial(boost::shared_ptr<DataAtIntegrationPts> data,
501 MaterialPostProcData &output)
502 : VolUserDataOperator(NOSPACE, OPSPACE), dataAtPts(std::move(data)) {
503 physicalEnergyPtr = boost::make_shared<VectorDouble>();
504 mixedEnergyPtr = boost::make_shared<VectorDouble>();
505 jacobianPtr = boost::make_shared<VectorDouble>();
506 output.scalarFields["PhysicalEnergy"] = physicalEnergyPtr;
507 output.scalarFields["MixedStoredEnergy"] = mixedEnergyPtr;
508 output.scalarFields["J"] = jacobianPtr;
509 }
510
511 MoFEMErrorCode doWork(int, EntityType, EntData &) override {
513 const int nb_gauss = getGaussPts().size2();
514 const auto fields = dataAtPts->auxiliaryData;
515 const auto material = dataAtPts->auxiliaryMaterialData;
516 auto get_energy =
518 *material->energy, nb_gauss);
519 auto get_volume =
521 *material->volume, nb_gauss);
522 for (const auto &values_ptr :
524 values_ptr->resize(nb_gauss, false);
526 *mixedEnergyPtr);
527 dataAtPts->energyAtPts.resize(nb_gauss, false);
528 auto t_material_energy = get_energy();
529 auto t_volume = get_volume();
530 auto t_physical = getFTensor0FromVec(*physicalEnergyPtr);
531 auto t_jacobian = getFTensor0FromVec(*jacobianPtr);
532 auto t_energy = getFTensor0FromVec(dataAtPts->energyAtPts);
533 for (int gg = 0; gg != nb_gauss; ++gg) {
534 const double physical_energy =
535 t_material_energy(MaterialData::DEVIATORIC) +
536 t_material_energy(MaterialData::VOLUMETRIC);
537 if (!std::isfinite(physical_energy))
538 SETERRQ(PETSC_COMM_SELF, MOFEM_OPERATION_UNSUCCESSFUL,
539 "Logarithmic material diagnostic output is not representable");
540 t_physical = physical_energy;
541 t_energy = physical_energy;
542 t_jacobian = t_volume(MaterialData::JACOBIAN);
543 ++t_material_energy;
544 ++t_volume;
545 ++t_physical;
546 ++t_energy;
547 ++t_jacobian;
548 }
550 }
551
552private:
553 boost::shared_ptr<DataAtIntegrationPts> dataAtPts;
557};
558
559} // namespace
560
562 const EshelbianCore &ep, boost::ptr_deque<UserDataOperator> &pipeline,
563 boost::shared_ptr<AuxiliaryLogarithmicStressData> values,
564 MatrixPtr reconstructed_log_stretch, SmartPetscObj<Vec> state) {
566 if (!ep.physicalEquations->getFeatures().test(
568 !values || !reconstructed_log_stretch)
570 "Auxiliary field evaluation requires the auxiliary layout and "
571 "valid output storage");
572 pipeline.push_back(new OpCalculateTensor2SymmetricDeviatorFieldValues<3>(
573 ep.logDeviator, values->logDeviatorTensor, state, MBTET, 0,
574 values->logDeviator));
575 pipeline.push_back(new OpCalculateVectorFieldValues<1>(
576 ep.logJacobian, values->logJacobian, state, MBTET));
577 pipeline.push_back(new OpCalculateTensor2SymmetricDeviatorFieldValues<3>(
578 ep.auxiliaryLogStress, values->stressTensor, state, MBTET, 0,
579 values->stress));
580 pipeline.push_back(new OpReconstructAuxiliaryLogarithmicStretch(
581 std::move(values), std::move(reconstructed_log_stretch)));
583}
584
586 const AuxiliaryLogarithmicStressData &fields,
588 VectorDouble &mixed_energy) {
590 const int nb_gauss = fields.logDeviator->size1();
591 auto get_d = MatrixSizeHelper<GetFTensor1FromMatType<5, -1, DL>, DL>::get(
592 *fields.logDeviator, nb_gauss);
593 auto get_stress =
595 *material.elasticStress, nb_gauss);
596 auto get_material_energy =
598 *material.energy, nb_gauss);
599 mixed_energy.resize(nb_gauss, false);
600 auto t_d = get_d();
601 auto t_stress = get_stress();
602 auto t_material_energy = get_material_energy();
603 auto t_mixed = getFTensor0FromVec(mixed_energy);
604 FTensor::Index<'a', 5> a;
605 for (int gg = 0; gg != nb_gauss; ++gg) {
606 const double energy = t_stress(a) * t_d(a) -
607 t_material_energy(MaterialData::CONJUGATE) +
608 t_material_energy(MaterialData::VOLUMETRIC);
609 if (!std::isfinite(energy))
610 SETERRQ(PETSC_COMM_SELF, MOFEM_OPERATION_UNSUCCESSFUL,
611 "Mixed stored-energy contribution is not representable");
612 t_mixed = energy;
613 ++t_d;
614 ++t_stress;
615 ++t_material_energy;
616 ++t_mixed;
617 }
619}
620
622 const EshelbianCore &ep,
623 boost::ptr_deque<ForcesAndSourcesCore::UserDataOperator> &pipeline,
624 boost::shared_ptr<DataAtIntegrationPts> data,
625 boost::shared_ptr<AuxiliaryLogarithmicStressMaterialData> material_data,
626 AuxiliaryLogarithmicMaterialParameters parameters, const bool lhs) {
628 if (!data || !data->auxiliaryData || !material_data || !parameters)
630 "Auxiliary material operators require field data, material data "
631 "and an element parameter callback");
632 if (!ep.physicalEquations->getFeatures().test(
637 "Auxiliary material operators require the symmetric "
638 "no_h1 formulation");
639 // Mesh-only diagnostics have no TS rate vector. The existing evaluator
640 // clears their rate data, rather than reusing scratch from a previous solve.
641 if (ep.alphaU != 0.)
642 pipeline.push_back(new OpCalculateVectorFieldValuesDot<5>(
643 ep.logDeviator, data->auxiliaryData->logDeviatorDot, MBTET, false));
644 pipeline.push_back(new OpCalculateAuxiliaryLogarithmicMaterial(
645 std::move(data), std::move(material_data), std::move(parameters),
646 ep.alphaU, lhs));
648}
649
651 const EshelbianCore &ep,
652 boost::ptr_deque<ForcesAndSourcesCore::UserDataOperator> &pipeline,
653 boost::shared_ptr<AuxiliaryLogarithmicStressMaterialData> material_data,
654 const bool lhs) {
656 if (!lhs) {
657 pipeline.push_back(new OpAuxiliaryResidual<5>(
658 ep.logDeviator, material_data->residualDeviator));
659 pipeline.push_back(new OpAuxiliaryResidual<1>(
660 ep.logJacobian, material_data->residualJacobian));
661 pipeline.push_back(new OpAuxiliaryResidual<5>(
662 ep.auxiliaryLogStress, material_data->residualStress));
664 }
665
666 pipeline.push_back(new OpAuxiliaryCoefficientMass<5, 5>(
667 ep.logDeviator, ep.logDeviator, material_data->tangentDeviator));
668 pipeline.push_back(new OpAuxiliaryCoefficientMass<5, 1>(
669 ep.logDeviator, ep.logJacobian, material_data->tangentDeviatorJacobian));
670 pipeline.push_back(new OpAuxiliaryCoefficientMass<1, 1>(
671 ep.logJacobian, ep.logJacobian, material_data->tangentJacobian));
672 pipeline.push_back(new OpAuxiliaryCoefficientMass<5, 5>(
674 material_data->tangentDeviatorStress, false));
675 pipeline.push_back(new OpAuxiliaryCoefficientMass<5, 5>(
677 material_data->tangentStressDeviator, false));
678 pipeline.push_back(new OpAuxiliaryCoefficientMass<5, 5>(
680 material_data->tangentStress));
681 pipeline.push_back(new OpAuxiliaryCoefficientMass<5, 3>(
682 ep.logDeviator, ep.rotAxis, material_data->deviatorRotation));
683 pipeline.push_back(new OpAuxiliaryCoefficientMass<1, 3>(
684 ep.logJacobian, ep.rotAxis, material_data->jacobianRotation));
685 // The mixed potential contributes -P:F, including the tensor bubble field.
686 constexpr auto work_sign = []() constexpr { return -1.; };
687 pipeline.push_back(new OpBaseTensorBase<3, 5>(
688 ep.logDeviator, ep.piolaStress, material_data->deformationDeviator,
689 work_sign, true));
690 pipeline.push_back(new OpBaseTensorBase<3, 1>(
691 ep.logJacobian, ep.piolaStress, material_data->deformationJacobian,
692 work_sign, true));
693 pipeline.push_back(new OpBaseTensorBase<9, 5>(
694 ep.logDeviator, ep.bubbleField, material_data->deformationDeviator,
695 work_sign, true));
696 pipeline.push_back(new OpBaseTensorBase<9, 1>(
697 ep.logJacobian, ep.bubbleField, material_data->deformationJacobian,
698 work_sign, true));
700}
701
703 boost::ptr_deque<UserDataOperator> &,
704 boost::shared_ptr<AuxiliaryLogarithmicStressData> values,
705 const std::string &prefix, MaterialPostProcData &output) {
707 if (!values)
708 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
709 "Auxiliary postprocessing requires evaluated material fields");
710 output.symmetricFields[prefix + "D"] = values->logDeviatorTensor;
711 output.symmetricFields[prefix + "Td"] = values->stressTensor;
712 output.scalarFields[prefix + "theta"] = values->logJacobian;
714}
715
717pushAuxiliaryLogarithmicPostProc(boost::ptr_deque<UserDataOperator> &pipeline,
718 boost::shared_ptr<DataAtIntegrationPts> data,
719 MaterialPostProcData &output) {
721 if (!data || !data->auxiliaryData || !data->auxiliaryMaterialData)
722 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
723 "Auxiliary postprocessing requires field and material producers");
724 CHKERR pushAuxiliaryLogarithmicStatePostProc(pipeline, data->auxiliaryData,
725 "", output);
726 pipeline.push_back(new OpFormatDeviator(
727 "D_m", data->auxiliaryMaterialData->materialDeviator, output));
728 pipeline.push_back(new OpFormatMaterial(std::move(data), output));
730}
731
732} // namespace EshelbianPlasticity
Material and stress-work blocks for the independent D/theta/Td fields.
Distinct kinematic and material copies for diagnostic output.
AuxiliaryLogarithmicMaterialParameters parameterFun
boost::shared_ptr< MaterialData > materialData
VectorPtr physicalEnergyPtr
MatrixPtr tensorPtr
MatrixPtr logStretchPtr
boost::shared_ptr< AuxiliaryLogarithmicStressData > valuesPtr
VectorPtr mixedEnergyPtr
boost::shared_ptr< DataAtIntegrationPts > dataAtPts
const double alphaU
VectorPtr jacobianPtr
MatrixPtr coordinatesPtr
Evaluation of independent logarithmic material fields.
Eshelbian plasticity interface.
#define FTENSOR_INDEXES(DIM,...)
constexpr double a
constexpr int SPACE_DIM
constexpr int FIELD_DIM
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.
constexpr int BASE_DIM
FTensor::Index< 'i', SPACE_DIM > i
FTensor::Index< 'l', 3 > l
FTensor::Index< 'j', 3 > j
FTensor::Index< 'k', 3 > k
boost::function< T(const T)> Fun
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 pushAuxiliaryLogarithmicPostProc(boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > &pipeline, boost::shared_ptr< DataAtIntegrationPts > data, MaterialPostProcData &output)
boost::shared_ptr< MatrixDouble > MatrixPtr
VolumeElementForcesAndSourcesCore::UserDataOperator VolUserDataOperator
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)
MoFEMErrorCode pushAuxiliaryLogarithmicStatePostProc(boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > &pipeline, boost::shared_ptr< AuxiliaryLogarithmicStressData > values, const std::string &prefix, MaterialPostProcData &output)
std::function< NeoHookeanLogarithmicMaterial::Parameters(EntityHandle)> AuxiliaryLogarithmicMaterialParameters
Return parameters already checked by the material's setup validation.
MoFEMErrorCode evaluateAuxiliaryMixedStoredEnergy(const AuxiliaryLogarithmicStressData &fields, const AuxiliaryLogarithmicStressMaterialData &material, VectorDouble &mixed_energy)
DataLayoutTraits< DataLayout::GaussByCoeffs > DL
MoFEMErrorCode pushAuxiliaryLogarithmicMaterialOps(const EshelbianCore &ep, boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > &pipeline, boost::shared_ptr< AuxiliaryLogarithmicStressMaterialData > material_data, bool lhs)
boost::shared_ptr< VectorDouble > VectorPtr
MoFEMErrorCode pushAuxiliaryLogarithmicFields(const EshelbianCore &ep, boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > &pipeline, boost::shared_ptr< AuxiliaryLogarithmicStressData > values, boost::shared_ptr< MatrixDouble > reconstructed_log_stretch, SmartPetscObj< Vec > state=nullptr)
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
UBlasVector< double > VectorDouble
Definition Types.hpp:68
implementation of Data Operators for Forces and Sources
Definition Common.hpp:10
decltype(GetFTensor2SymmetricFromMatImpl< Tensor_Dim, S, DL, M >::get(std::declval< M & >(), 0, 0)) GetFTensor2SymmetricFromMatType
decltype(GetFTensor1FromMatImpl< Tensor_Dim, S, DL, M >::get(std::declval< M & >(), 0, 0)) GetFTensor1FromMatType
static auto getFTensor0FromVec(V &data)
Get tensor rank 0 (scalar) form data vector.
static auto determinantTensor3by3(T &t)
Calculate the determinant of a 3x3 matrix or a tensor of rank 2.
decltype(GetFTensor3FromMatImpl< Tensor_Dim0, Tensor_Dim1, Tensor_Dim2, S, DL, M >::get(std::declval< M & >(), 0, 0)) GetFTensor3FromMatType
decltype(GetFTensor2FromMatImpl< Tensor_Dim0, Tensor_Dim1, S, DL, M >::get(std::declval< M & >(), 0, 0)) GetFTensor2FromMatType
constexpr AssemblyType A
MoFEM::Interface & mField
static enum RotSelector gradApproximator
const std::string logDeviator
const std::string piolaStress
const std::string logJacobian
const std::string bubbleField
static constexpr enum SymmetrySelector symmetrySelector
const std::string auxiliaryLogStress
boost::shared_ptr< PhysicalEquations > physicalEquations
const std::string rotAxis
static MoFEMErrorCode evaluateInverse(const Parameters &parameters, const Coordinates &t_stress, InverseState &state)
Recover Dm(Td), its compliance and conjugate energy; no state is cached.
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 MoFEMErrorCode evaluateVolume(const Parameters &parameters, double theta, VolumeState &state)
Evaluate g(J) = K*(J-1)^2/2 and its logarithmic-volume derivatives.
@ AUXILIARY_LOGARITHMIC_STRESS
Auxiliary logarithmic stress formulation.
virtual MPI_Comm & get_comm() const =0
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.
Approximate field values for given petsc vector.
Specialization for MatrixDouble vector field values calculation.
intrusive_ptr for managing petsc objects
@ CTX_SNESSETFUNCTION
Setting up nonlinear function evaluation.
@ CTX_TSSETIJACOBIAN
Setting up implicit Jacobian.