v0.16.3
Loading...
Searching...
No Matches
PlasticIncrementalConstitutive.cpp
Go to the documentation of this file.
1/**
2 * @file PlasticIncrementalConstitutive.cpp
3 * @brief Local constitutive maps for incremental optimization
4 */
5
6#define SINGULARITY
7#include <MoFEM.hpp>
8using namespace MoFEM;
9
11
14#include <sstream>
15
16namespace EshelbianPlasticity {
17
18using namespace PlasticIncrementalOptimizationInternal;
19
20namespace PlasticIncrementalOptimizationInternal {
21
22namespace {
23
24using PlasticIncrementalEle = VolumeElementForcesAndSourcesCore;
25using PlasticIncrementalOp = PlasticIncrementalEle::UserDataOperator;
26
27void addTetrahedronOperator(const boost::shared_ptr<PlasticIncrementalEle> &fe,
29 op->doEntities.fill(false);
30 op->doEntities[MBTET] = true;
31 fe->getOpPtrVector().push_back(op);
32}
33
34double getCellMeasure(PlasticIncrementalOp &op) {
35 auto t_weight = op.getFTensor0IntegrationWeight();
36 double weight_sum = 0;
37 for (int gg = 0; gg != op.getGaussPts().size2(); ++gg) {
38 weight_sum += t_weight;
39 ++t_weight;
40 }
41 return op.getMeasure() * weight_sum;
42}
43
44boost::shared_ptr<PlasticIncrementalEle> createPlasticIncrementalElement(
46 auto fe = boost::make_shared<PlasticIncrementalEle>(
47 *getInterfacePtr(problem.getControlDM()));
48 // The parent volume FE also carries the USER_BASE bubble field. Although
49 // these algebraic P0 operators do not use basis values directly, the FE
50 // lifecycle prepares every registered approximation base.
51 fe->getUserPolynomialBase() =
52 boost::make_shared<CGGUserPolynomialBase>(nullptr, true);
53 // Keep the constitutive P0 measure identical to the mechanical volume
54 // integration for both affine and high-order geometry.
55 fe->getRuleHook = [](int, int, int order_data) {
56 return 2 * (order_data + 1);
57 };
59 problem.addConstitutiveGeometryOperators(fe->getOpPtrVector()),
60 "Add plastic constitutive geometry operators");
61 return fe;
62}
63
64struct PlasticValidationMetrics {
65 double minWork = std::numeric_limits<double>::max();
66 double maxYieldFunction = 0;
67 double maxYieldExcess = 0;
68 double minConstraint = std::numeric_limits<double>::max();
69 double minMultiplier = std::numeric_limits<double>::max();
73 double maxKktResidual = 0;
75 int nonfinite = 0;
77};
78
79} // namespace
80
82 const PlasticIncrementalOptimizationProblem &problem, Vec control,
83 double &value) {
85 value = 0;
86 const auto &kappa_field = problem.getPlasticKappaFieldName();
87
88 auto fe = createPlasticIncrementalElement(problem);
89 DM control_dm = problem.getControlDM();
90 const auto control_data_dm = SmartPetscObj<DM>(control_dm, true);
91 const auto control_vec = SmartPetscObj<Vec>(control, true);
92 auto kappa_increment_ptr = boost::make_shared<VectorDouble>();
93 auto committed_kappa_ptr = boost::make_shared<VectorDouble>();
94 auto local_value_ptr = boost::make_shared<double>(0);
95
96 addTetrahedronOperator(fe, new OpCalculateScalarFieldValues(
97 control_data_dm, PlasticIncrementalOp::OPCOL,
98 kappa_field, kappa_increment_ptr, control_vec,
99 MBTET));
100 addTetrahedronOperator(fe, new OpCalculateScalarFieldValues(
101 kappa_field, committed_kappa_ptr, MBTET));
102
103 auto *resistance_op =
104 new PlasticIncrementalOp(kappa_field, PlasticIncrementalOp::OPROW);
105 resistance_op->doWorkRhsHook =
106 [&, local_value_ptr](
107 DataOperator *base_op_ptr, int, EntityType,
110 if (row_data.getIndices().empty())
112 const auto t_kappa_increment = getFTensor0FromVec(*kappa_increment_ptr);
113 const auto t_committed_kappa = getFTensor0FromVec(*committed_kappa_ptr);
114 auto *op_ptr = static_cast<PlasticIncrementalOp *>(base_op_ptr);
115 // Irreversible work plus the linear-hardening Helmholtz-energy increment.
116 // Both P0 values are element-constant, so the first Gauss-point values
117 // define this cell contribution.
118 const double delta_kappa = t_kappa_increment;
119 const double block_value =
120 getCellMeasure(*op_ptr) *
121 ((problem.getInitialYieldStress() +
122 problem.getIsotropicHardeningModulus() * t_committed_kappa) *
123 delta_kappa +
124 0.5 * problem.getIsotropicHardeningModulus() * delta_kappa *
125 delta_kappa);
126 if (!std::isfinite(block_value))
127 *local_value_ptr = std::numeric_limits<double>::infinity();
128 else
129 *local_value_ptr += block_value;
131 };
132 addTetrahedronOperator(fe, resistance_op);
133
135 fe);
136 CHKERR MPI_Allreduce(local_value_ptr.get(), &value, 1, MPI_DOUBLE, MPI_SUM,
137 PetscObjectComm(reinterpret_cast<PetscObject>(control)));
139}
140
142 PlasticIncrementalOptimizationProblem &problem, Vec control,
143 Vec smooth_gradient, Vec objective_gradient) {
145 CHKERR VecCopy(smooth_gradient, objective_gradient);
146 const auto &kappa_field = problem.getPlasticKappaFieldName();
147
148 auto fe = createPlasticIncrementalElement(problem);
149 fe->f = objective_gradient;
150
151 DM control_dm = problem.getControlDM();
152 const auto control_data_dm = SmartPetscObj<DM>(control_dm, true);
153 const auto control_vec = SmartPetscObj<Vec>(control, true);
154 auto kappa_increment_ptr = boost::make_shared<VectorDouble>();
155 auto committed_kappa_ptr = boost::make_shared<VectorDouble>();
156
157 addTetrahedronOperator(fe, new OpCalculateScalarFieldValues(
158 control_data_dm, PlasticIncrementalOp::OPCOL,
159 kappa_field, kappa_increment_ptr, control_vec,
160 MBTET));
161 addTetrahedronOperator(fe, new OpCalculateScalarFieldValues(
162 kappa_field, committed_kappa_ptr, MBTET));
163
164 auto *kappa_op =
165 new PlasticIncrementalOp(kappa_field, PlasticIncrementalOp::OPROW);
166 kappa_op->doWorkRhsHook =
167 [&](DataOperator *base_op_ptr, int, EntityType,
170 if (row_data.getIndices().empty())
172 const auto t_kappa_increment = getFTensor0FromVec(*kappa_increment_ptr);
173 const auto t_committed_kappa = getFTensor0FromVec(*committed_kappa_ptr);
174 auto *op_ptr = static_cast<PlasticIncrementalOp *>(base_op_ptr);
175 // Second block of Eq. (1.70), label
176 // eq:constrained-objective-gradient. These P0 producer values are
177 // element-constant, so the first Gauss-point values define the row.
178 const double local_gradient =
179 getCellMeasure(*op_ptr) * (problem.getInitialYieldStress() +
181 (t_committed_kappa + t_kappa_increment));
182 CHKERR VecSetValues<AssemblyTypeSelector<PETSC>>(
183 op_ptr->getKSPf(), row_data, &local_gradient, ADD_VALUES);
185 };
186 addTetrahedronOperator(fe, kappa_op);
187
189 fe);
190 CHKERR VecAssemblyBegin(objective_gradient);
191 CHKERR VecAssemblyEnd(objective_gradient);
192 CHKERR VecGhostUpdateBegin(objective_gradient, INSERT_VALUES,
193 SCATTER_FORWARD);
194 CHKERR VecGhostUpdateEnd(objective_gradient, INSERT_VALUES, SCATTER_FORWARD);
196}
197
199 const PlasticIncrementalOptimizationProblem &problem, DM constraint_dm,
200 Vec multipliers) {
202 if (!constraint_dm || !multipliers)
203 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
204 "Plastic multiplier initialization requires a constraint DM and "
205 "multiplier vector");
206
207 const auto &kappa_field = problem.getPlasticKappaFieldName();
208 auto fe = createPlasticIncrementalElement(problem);
209 fe->f = multipliers;
210 auto committed_kappa_ptr = boost::make_shared<VectorDouble>();
211
212 addTetrahedronOperator(fe, new OpCalculateScalarFieldValues(
213 kappa_field, committed_kappa_ptr, MBTET));
214 auto *multiplier_op =
215 new PlasticIncrementalOp(kappa_field, PlasticIncrementalOp::OPROW);
216 multiplier_op->doWorkRhsHook =
217 [&](DataOperator *base_op_ptr, int, EntityType,
220 if (row_data.getIndices().empty())
222 auto *op_ptr = static_cast<PlasticIncrementalOp *>(base_op_ptr);
223 const double committed_kappa =
224 getFTensor0FromVec(*committed_kappa_ptr);
225 if (!std::isfinite(committed_kappa) || committed_kappa < 0)
226 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
227 "Committed plastic kappa must be finite and non-negative; got "
228 "%g",
229 committed_kappa);
230 const double current_yield =
231 problem.getInitialYieldStress() +
232 problem.getIsotropicHardeningModulus() * committed_kappa;
233 if (!std::isfinite(current_yield) || !(current_yield > 0))
234 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
235 "Current plastic yield stress must be finite and positive; got "
236 "%g",
237 current_yield);
238 const double constraint_scale = std::sqrt(getCellMeasure(*op_ptr));
239 // J_eta=sqrt(V), so eta stationarity requires lambda_TAO=sqrt(V)*sigma_y.
240 const double local_multiplier = constraint_scale * current_yield;
241 CHKERR VecSetValues<AssemblyTypeSelector<PETSC>>(
242 op_ptr->getKSPf(), row_data, &local_multiplier, INSERT_VALUES);
244 };
245 addTetrahedronOperator(fe, multiplier_op);
246
247 CHKERR DMoFEMLoopFiniteElements(constraint_dm,
248 problem.getVolumeElementName(), fe);
249 CHKERR VecAssemblyBegin(multipliers);
250 CHKERR VecAssemblyEnd(multipliers);
252}
253
255 const PlasticIncrementalOptimizationProblem &problem, Vec control,
256 Vec constraints) {
258 const auto &plastic_field = problem.getPlasticFlowFieldName();
259 const auto &kappa_field = problem.getPlasticKappaFieldName();
260 DM constraint_dm = nullptr;
261 CHKERR VecGetDM(constraints, &constraint_dm);
262 if (!constraint_dm)
263 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
264 "Plastic inequality vector has no constraint DM");
265
266 auto fe = createPlasticIncrementalElement(problem);
267 fe->f = constraints;
268 const auto control_dm = SmartPetscObj<DM>(problem.getControlDM(), true);
269 const auto control_vec = SmartPetscObj<Vec>(control, true);
270 auto plastic_increment_ptr = boost::make_shared<MatrixDouble>();
271 auto kappa_increment_ptr = boost::make_shared<VectorDouble>();
272
273 addTetrahedronOperator(fe, new OpCalculateVectorFieldValues<
275 control_dm, PlasticIncrementalOp::OPCOL,
276 plastic_field, plastic_increment_ptr,
277 control_vec, MBTET));
278 addTetrahedronOperator(fe, new OpCalculateScalarFieldValues(
279 control_dm, PlasticIncrementalOp::OPCOL,
280 kappa_field, kappa_increment_ptr, control_vec,
281 MBTET));
282
283 const double regularization_epsilon =
285
286 auto *constraint_op =
287 new PlasticIncrementalOp(kappa_field, PlasticIncrementalOp::OPROW);
288 constraint_op->doWorkRhsHook =
289 [&](DataOperator *base_op_ptr, int, EntityType,
292 if (row_data.getIndices().empty())
294 auto *op_ptr = static_cast<PlasticIncrementalOp *>(base_op_ptr);
295 const int nb_integration_pts = op_ptr->getGaussPts().size2();
297 auto get_increment = MatrixSizeHelper<
299 DL>::get(*plastic_increment_ptr, nb_integration_pts);
300 const auto t_increment = get_increment();
301 const auto t_kappa_increment = getFTensor0FromVec(*kappa_increment_ptr);
302 const double constraint_scale = std::sqrt(getCellMeasure(*op_ptr));
303 // Scale the exact or rounded P0 cone row by the reference-volume root.
304 const double local_constraint =
305 constraint_scale *
306 (t_kappa_increment -
308 regularization_epsilon));
309 CHKERR VecSetValues<AssemblyTypeSelector<PETSC>>(
310 op_ptr->getKSPf(), row_data, &local_constraint, INSERT_VALUES);
312 };
313 addTetrahedronOperator(fe, constraint_op);
314
316 fe);
317 CHKERR VecAssemblyBegin(constraints);
318 CHKERR VecAssemblyEnd(constraints);
319 CHKERR VecGhostUpdateBegin(constraints, INSERT_VALUES, SCATTER_FORWARD);
320 CHKERR VecGhostUpdateEnd(constraints, INSERT_VALUES, SCATTER_FORWARD);
322}
323
325 PlasticIncrementalOptimizationProblem &problem, Vec control,
326 Vec smooth_gradient, Mat jacobian) {
328 const auto &plastic_field = problem.getPlasticFlowFieldName();
329 const auto &kappa_field = problem.getPlasticKappaFieldName();
330 DM constraint_dm = nullptr;
331 CHKERR MatGetDM(jacobian, &constraint_dm);
332 if (!constraint_dm)
333 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
334 "Plastic inequality Jacobian has no constraint DM");
335
336 auto fe = createPlasticIncrementalElement(problem);
337 fe->ksp_B = jacobian;
338 const double regularization_epsilon =
340
341 const auto control_dm = SmartPetscObj<DM>(problem.getControlDM(), true);
342 const auto control_vec = SmartPetscObj<Vec>(control, true);
343 const auto gradient_vec = SmartPetscObj<Vec>(smooth_gradient, true);
344 auto increment_ptr = boost::make_shared<MatrixDouble>();
345 auto gradient_ptr = boost::make_shared<MatrixDouble>();
346 auto committed_kappa_ptr = boost::make_shared<VectorDouble>();
347
348 addTetrahedronOperator(fe,
351 control_dm, PlasticIncrementalOp::OPCOL,
352 plastic_field, increment_ptr, control_vec, MBTET));
353 addTetrahedronOperator(fe,
356 control_dm, PlasticIncrementalOp::OPCOL,
357 plastic_field, gradient_ptr, gradient_vec, MBTET));
358 addTetrahedronOperator(fe, new OpCalculateScalarFieldValues(
359 kappa_field, committed_kappa_ptr, MBTET));
360
361 auto *flow_op = new PlasticIncrementalOp(
362 kappa_field, plastic_field, PlasticIncrementalOp::OPROWCOL, false);
363 flow_op->doWorkLhsHook =
364 [&](DataOperator *base_op_ptr, int, int, EntityType, EntityType,
368 if (row_data.getIndices().empty() || col_data.getIndices().empty())
370 auto *op_ptr = static_cast<PlasticIncrementalOp *>(base_op_ptr);
371 const int nb_integration_pts = op_ptr->getGaussPts().size2();
373 auto get_increment = MatrixSizeHelper<
375 DL>::get(*increment_ptr, nb_integration_pts);
376 auto get_gradient = MatrixSizeHelper<
378 DL>::get(*gradient_ptr, nb_integration_pts);
379 const auto t_increment = get_increment();
380 const auto t_gradient = get_gradient();
381 const auto t_committed_kappa = getFTensor0FromVec(*committed_kappa_ptr);
382 // These P0 producer values are element-constant, so the first Gauss-point
383 // view supplies the complete local constitutive block.
384 const double increment_norm = plasticCoordinateNorm(t_increment);
386 t_constraint_slope;
388 const double gradient_denominator =
389 std::hypot(plasticEquivalentIncrementScale * increment_norm,
390 regularization_epsilon);
391 // Eq. (1.83), label eq:regularised-dissipation-gradient, when epsilon>0;
392 // otherwise the exact selection in Eq. (1.74), label
393 // eq:exact-constraint-branch-selection.
394 if (gradient_denominator > 0) {
395 t_constraint_slope(L) = plasticEquivalentIncrementScaleSquared *
396 t_increment(L) / gradient_denominator;
397 } else {
398 const double cell_measure = getCellMeasure(*op_ptr);
399 if (!(cell_measure > 0))
400 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
401 "Plastic P0 block has no positive cell measure");
403 t_cell_force;
404 t_cell_force(L) = -t_gradient(L) / cell_measure;
405 const double q =
407 const double current_yield =
408 problem.getInitialYieldStress() +
409 problem.getIsotropicHardeningModulus() * t_committed_kappa;
410 t_constraint_slope(L) = t_cell_force(L) / std::max(current_yield, q);
411 }
412
413 const double constraint_scale = std::sqrt(getCellMeasure(*op_ptr));
415 auto t_local_matrix =
416 getFTensor1FromPtr<plasticLogarithmicStretchCoordinateSize>(
417 local_matrix.data().data());
418 t_local_matrix(L) = -constraint_scale * t_constraint_slope(L);
419 CHKERR MatSetValues<AssemblyTypeSelector<PETSC>>(
420 op_ptr->getKSPB(), row_data, col_data, local_matrix.data().data(),
421 ADD_VALUES);
423 };
424 addTetrahedronOperator(fe, flow_op);
425
426 auto *kappa_op = new PlasticIncrementalOp(
427 kappa_field, kappa_field, PlasticIncrementalOp::OPROWCOL, false);
428 kappa_op->doWorkLhsHook =
429 [&](DataOperator *base_op_ptr, int, int, EntityType, EntityType,
433 if (row_data.getIndices().empty() || col_data.getIndices().empty())
435 auto *op_ptr = static_cast<PlasticIncrementalOp *>(base_op_ptr);
436 const double constraint_scale = std::sqrt(getCellMeasure(*op_ptr));
437 MatrixDouble local_matrix(1, 1);
438 local_matrix(0, 0) = constraint_scale;
439 CHKERR MatSetValues<AssemblyTypeSelector<PETSC>>(
440 op_ptr->getKSPB(), row_data, col_data, local_matrix.data().data(),
441 ADD_VALUES);
443 };
444 addTetrahedronOperator(fe, kappa_op);
445
447 fe);
448 CHKERR MatAssemblyBegin(jacobian, MAT_FINAL_ASSEMBLY);
449 CHKERR MatAssemblyEnd(jacobian, MAT_FINAL_ASSEMBLY);
451}
452
454 PlasticIncrementalOptimizationProblem &problem, DM constraint_dm,
455 Vec control, Vec smooth_gradient, Vec inequality_multipliers,
456 PetscReal gradient_tolerance, PetscReal constraint_tolerance,
457 std::string &diagnostics) {
459 if (!constraint_dm || !control || !smooth_gradient ||
460 !inequality_multipliers)
461 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
462 "Plastic solution validation requires control and constraint DMs "
463 "with control, gradient, and multiplier vectors");
464
465 const auto &plastic_field = problem.getPlasticFlowFieldName();
466 const auto &kappa_field = problem.getPlasticKappaFieldName();
467 const auto control_dm = SmartPetscObj<DM>(problem.getControlDM(), true);
468 const auto constraint_data_dm = SmartPetscObj<DM>(constraint_dm, true);
469 const auto control_vec = SmartPetscObj<Vec>(control, true);
470 const auto gradient_vec = SmartPetscObj<Vec>(smooth_gradient, true);
471 const auto multiplier_vec = SmartPetscObj<Vec>(inequality_multipliers, true);
472
473 auto plastic_increment_ptr = boost::make_shared<MatrixDouble>();
474 auto kappa_increment_ptr = boost::make_shared<VectorDouble>();
475 auto gradient_ptr = boost::make_shared<MatrixDouble>();
476 auto multiplier_ptr = boost::make_shared<VectorDouble>();
477 auto committed_kappa_ptr = boost::make_shared<VectorDouble>();
478 auto metrics_ptr = boost::make_shared<PlasticValidationMetrics>();
479
480 auto fe = createPlasticIncrementalElement(problem);
481 addTetrahedronOperator(fe, new OpCalculateVectorFieldValues<
483 control_dm, PlasticIncrementalOp::OPCOL,
484 plastic_field, plastic_increment_ptr,
485 control_vec, MBTET));
486 addTetrahedronOperator(fe, new OpCalculateScalarFieldValues(
487 control_dm, PlasticIncrementalOp::OPCOL,
488 kappa_field, kappa_increment_ptr, control_vec,
489 MBTET));
490 addTetrahedronOperator(fe,
493 control_dm, PlasticIncrementalOp::OPCOL,
494 plastic_field, gradient_ptr, gradient_vec, MBTET));
495 addTetrahedronOperator(fe, new OpCalculateScalarFieldValues(
496 constraint_data_dm,
497 PlasticIncrementalOp::OPROW, kappa_field,
498 multiplier_ptr, multiplier_vec, MBTET));
499 addTetrahedronOperator(fe, new OpCalculateScalarFieldValues(
500 kappa_field, committed_kappa_ptr, MBTET));
501
502 auto *validation_op =
503 new PlasticIncrementalOp(kappa_field, PlasticIncrementalOp::OPROW);
504 validation_op->doWorkRhsHook =
505 [&, metrics_ptr](DataOperator *base_op_ptr, int, EntityType,
508 if (row_data.getIndices().empty())
510 auto *op_ptr = static_cast<PlasticIncrementalOp *>(base_op_ptr);
511 const int nb_integration_pts = op_ptr->getGaussPts().size2();
513 auto get_increment = MatrixSizeHelper<
515 DL>::get(*plastic_increment_ptr, nb_integration_pts);
516 auto get_gradient = MatrixSizeHelper<
518 DL>::get(*gradient_ptr, nb_integration_pts);
519 const auto t_increment = get_increment();
520 const auto t_gradient = get_gradient();
521 const double delta_kappa = getFTensor0FromVec(*kappa_increment_ptr);
522 const double kappa_n = getFTensor0FromVec(*committed_kappa_ptr);
523 const double cell_measure = getCellMeasure(*op_ptr);
524 // Recover the multiplier of the unscaled cone for physical KKT checks.
525 const double multiplier =
526 std::sqrt(cell_measure) * getFTensor0FromVec(*multiplier_ptr);
527 const double current_yield =
528 problem.getInitialYieldStress() +
529 problem.getIsotropicHardeningModulus() * (kappa_n + delta_kappa);
530
532 bool finite_block =
533 std::isfinite(cell_measure) && std::isfinite(delta_kappa) &&
534 std::isfinite(kappa_n) && kappa_n >= 0 &&
535 std::isfinite(current_yield) &&
536 current_yield > 0 && std::isfinite(multiplier) &&
537 std::isfinite(plasticCoordinateNorm(t_increment)) &&
538 std::isfinite(plasticCoordinateNorm(t_gradient));
539 if (!finite_block) {
540 metrics_ptr->nonfinite = 1;
542 }
543 if (!(cell_measure > std::numeric_limits<double>::epsilon())) {
544 metrics_ptr->invalidMeasure = 1;
546 }
547
549 t_force_coordinates;
550 t_force_coordinates(L) = -t_gradient(L) / cell_measure;
551 const auto t_flow =
553 const auto t_force =
556 const double work = cell_measure * t_force(i, j) * t_flow(i, j);
557 const double q =
559 const double flow_norm = plasticCoordinateNorm(t_increment);
560 const double equivalent_increment = plasticEquivalentIncrement(
561 flow_norm, problem.getDissipationRegularizationEpsilon());
562 const double constraint = delta_kappa - equivalent_increment;
564 const double gradient_denominator = std::hypot(
567 if (gradient_denominator > 0)
568 t_slope(L) = plasticEquivalentIncrementScaleSquared * t_increment(L) /
569 gradient_denominator;
570 else
571 t_slope(L) =
572 t_force_coordinates(L) / std::max(current_yield, q);
574 t_kkt_residual;
575 // Unscaled c and its physical multiplier retain the original tolerances.
576 t_kkt_residual(L) = t_gradient(L) + multiplier * t_slope(L);
577 const double eta_stationarity_residual =
578 std::abs(cell_measure * current_yield - multiplier);
579 const double complementarity_residual =
580 std::abs(multiplier * constraint);
581
582 metrics_ptr->minWork = std::min(metrics_ptr->minWork, work);
583 metrics_ptr->maxYieldFunction =
584 std::max(metrics_ptr->maxYieldFunction, q);
585 metrics_ptr->maxYieldExcess =
586 std::max(metrics_ptr->maxYieldExcess, q - current_yield);
587 metrics_ptr->minConstraint =
588 std::min(metrics_ptr->minConstraint, constraint);
589 metrics_ptr->minMultiplier =
590 std::min(metrics_ptr->minMultiplier, multiplier);
591 metrics_ptr->maxActiveConstraint =
592 std::max(metrics_ptr->maxActiveConstraint, std::abs(constraint));
593 metrics_ptr->maxEtaStationarityResidual =
594 std::max(metrics_ptr->maxEtaStationarityResidual,
595 eta_stationarity_residual);
596 metrics_ptr->maxComplementarityResidual =
597 std::max(metrics_ptr->maxComplementarityResidual,
598 complementarity_residual);
599 metrics_ptr->maxKktResidual =
600 std::max(metrics_ptr->maxKktResidual,
601 plasticCoordinateNorm(t_kkt_residual));
602 metrics_ptr->maxEquivalentIncrement =
603 std::max(metrics_ptr->maxEquivalentIncrement, equivalent_increment);
605 };
606 addTetrahedronOperator(fe, validation_op);
607
608 CHKERR DMoFEMLoopFiniteElements(constraint_dm,
609 problem.getVolumeElementName(), fe);
610
611 PlasticValidationMetrics global_metrics;
612 const MPI_Comm comm =
613 PetscObjectComm(reinterpret_cast<PetscObject>(constraint_dm));
614 const auto reduce_max = [&](const double local, double &global) {
615 return MPI_Allreduce(&local, &global, 1, MPI_DOUBLE, MPI_MAX, comm);
616 };
617 const auto reduce_min = [&](const double local, double &global) {
618 return MPI_Allreduce(&local, &global, 1, MPI_DOUBLE, MPI_MIN, comm);
619 };
620 CHKERR reduce_min(metrics_ptr->minWork, global_metrics.minWork);
621 CHKERR reduce_max(metrics_ptr->maxYieldFunction,
622 global_metrics.maxYieldFunction);
623 CHKERR reduce_max(metrics_ptr->maxYieldExcess,
624 global_metrics.maxYieldExcess);
625 CHKERR reduce_min(metrics_ptr->minConstraint, global_metrics.minConstraint);
626 CHKERR reduce_min(metrics_ptr->minMultiplier, global_metrics.minMultiplier);
627 CHKERR reduce_max(metrics_ptr->maxActiveConstraint,
628 global_metrics.maxActiveConstraint);
629 CHKERR reduce_max(metrics_ptr->maxEtaStationarityResidual,
630 global_metrics.maxEtaStationarityResidual);
631 CHKERR reduce_max(metrics_ptr->maxComplementarityResidual,
632 global_metrics.maxComplementarityResidual);
633 CHKERR reduce_max(metrics_ptr->maxKktResidual,
634 global_metrics.maxKktResidual);
635 CHKERR reduce_max(metrics_ptr->maxEquivalentIncrement,
636 global_metrics.maxEquivalentIncrement);
637 CHKERR MPI_Allreduce(&metrics_ptr->nonfinite, &global_metrics.nonfinite, 1,
638 MPI_INT, MPI_MAX, comm);
639 CHKERR MPI_Allreduce(&metrics_ptr->invalidMeasure,
640 &global_metrics.invalidMeasure, 1, MPI_INT, MPI_MAX,
641 comm);
642
643 const double kkt_tolerance =
644 10 * std::max<double>(gradient_tolerance, 1e-10);
645 const double feasibility_tolerance =
646 10 * std::max<double>(constraint_tolerance, 1e-10);
647 const bool plastic_flow_active =
648 global_metrics.maxEquivalentIncrement > feasibility_tolerance;
649 if (global_metrics.nonfinite || global_metrics.invalidMeasure ||
650 global_metrics.minWork < -kkt_tolerance ||
651 global_metrics.minConstraint < -feasibility_tolerance ||
652 global_metrics.minMultiplier < -kkt_tolerance ||
653 global_metrics.maxActiveConstraint > feasibility_tolerance ||
654 global_metrics.maxEtaStationarityResidual > kkt_tolerance ||
655 global_metrics.maxComplementarityResidual > kkt_tolerance ||
656 global_metrics.maxKktResidual > kkt_tolerance)
657 SETERRQ(comm, MOFEM_OPERATION_UNSUCCESSFUL,
658 "Incremental-optimization plastic acceptance failed: non-finite "
659 "%d, invalid measure %d, minimum work %g, max "
660 "yield excess %g, minimum constraint %g, minimum multiplier %g, "
661 "active residual %g, eta stationarity %g, complementarity %g, "
662 "plastic KKT residual %g",
663 global_metrics.nonfinite, global_metrics.invalidMeasure,
664 global_metrics.minWork,
665 global_metrics.maxYieldExcess, global_metrics.minConstraint,
666 global_metrics.minMultiplier, global_metrics.maxActiveConstraint,
667 global_metrics.maxEtaStationarityResidual,
668 global_metrics.maxComplementarityResidual,
669 global_metrics.maxKktResidual);
670
671 std::ostringstream stream;
672 stream << "max yield function " << global_metrics.maxYieldFunction
673 << ", max yield excess " << global_metrics.maxYieldExcess
674 << ", min plastic work " << global_metrics.minWork
675 << ", min constraint " << global_metrics.minConstraint
676 << ", min multiplier " << global_metrics.minMultiplier
677 << ", active residual " << global_metrics.maxActiveConstraint
678 << ", eta stationarity "
679 << global_metrics.maxEtaStationarityResidual
680 << ", complementarity "
681 << global_metrics.maxComplementarityResidual
682 << ", plastic KKT residual " << global_metrics.maxKktResidual
683 << ", max equivalent plastic increment "
684 << global_metrics.maxEquivalentIncrement << ", plastic flow active "
685 << (plastic_flow_active ? "true" : "false")
686 << ", dissipation epsilon "
688 diagnostics = stream.str();
690}
691
692} // namespace PlasticIncrementalOptimizationInternal
693
694} // namespace EshelbianPlasticity
Eshelbian plasticity interface.
double maxEquivalentIncrement
double maxEtaStationarityResidual
double maxComplementarityResidual
Shared implementation details for plastic incremental optimization.
Plasticity implementation of incremental optimization.
#define FTENSOR_INDEXES(DIM,...)
#define FTENSOR_INDEX(DIM, I)
constexpr int SPACE_DIM
#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()
#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_INVALID_DATA
Definition definitions.h:36
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
PetscErrorCode DMoFEMLoopFiniteElements(DM dm, const char fe_name[], MoFEM::FEMethod *method, CacheTupleWeakPtr cache_ptr=CacheTupleSharedPtr())
Executes FEMethod for finite elements in DM.
Definition DMMoFEM.cpp:576
FTensor::Index< 'i', SPACE_DIM > i
FTensor::Index< 'j', 3 > j
MoFEMErrorCode assemblePlasticInequalityJacobian(PlasticIncrementalOptimizationProblem &problem, Vec control, Vec smooth_gradient, Mat jacobian)
MoFEMErrorCode assembleIncrementalObjectiveGradient(PlasticIncrementalOptimizationProblem &problem, Vec control, Vec smooth_gradient, Vec objective_gradient)
MoFEMErrorCode initialisePlasticInequalityMultipliers(const PlasticIncrementalOptimizationProblem &problem, DM constraint_dm, Vec multipliers)
MoFEMErrorCode evaluatePlasticInequalityConstraints(const PlasticIncrementalOptimizationProblem &problem, Vec control, Vec constraints)
double plasticCoordinateNorm(const FTensor::Tensor1< T, plasticLogarithmicStretchCoordinateSize > &t_values)
MoFEMErrorCode validatePlasticIncrementalSolution(PlasticIncrementalOptimizationProblem &problem, DM constraint_dm, Vec control, Vec smooth_gradient, Vec inequality_multipliers, PetscReal gradient_tolerance, PetscReal constraint_tolerance, std::string &diagnostics)
MoFEMErrorCode evaluatePlasticIncrementalResistanceValue(const PlasticIncrementalOptimizationProblem &problem, Vec control, double &value)
double plasticEquivalentIncrement(const double coordinate_norm, const double epsilon)
FTensor::Tensor2_symmetric< double, SPACE_DIM > plasticLogarithmicStretchTensorFromCoordinates(const FTensor::Tensor1< T, plasticLogarithmicStretchCoordinateSize > &t_coordinates)
double plasticFrobeniusNorm(const FTensor::Tensor2_symmetric< T, SPACE_DIM > &t_values)
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
implementation of Data Operators for Forces and Sources
Definition Common.hpp:10
auto getInterfacePtr(DM dm)
Get the Interface Ptr object.
Definition DMMoFEM.hpp:1171
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.
double q
MoFEMErrorCode addConstitutiveGeometryOperators(boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > &pipeline) const
base operator to do operations at Gauss Pt. level
std::array< bool, MBMAXTYPE > doEntities
If true operator is executed for entity.
Data on single entity (This is passed as argument to DataOperator::doWork)
Specialization for double precision scalar field values calculation.
Specialization for MatrixDouble vector field values calculation.
intrusive_ptr for managing petsc objects