v0.16.3
Loading...
Searching...
No Matches
PlasticIncrementalOptimizationOperators.cpp
Go to the documentation of this file.
1/**
2 * @file PlasticIncrementalOptimizationOperators.cpp
3 * @brief Finite-element operators for incremental optimization
4 */
5
6#define SINGULARITY
7#include <MoFEM.hpp>
8using namespace MoFEM;
9
11
13#include <Lie.hpp>
14#include <MatrixFunction.hpp>
16
17namespace EshelbianPlasticity {
18
19using namespace PlasticIncrementalOptimizationInternal;
20
21namespace PlasticIncrementalOptimizationInternal {
22
24
27 boost::shared_ptr<DataAtIntegrationPts> data_ptr,
29 boost::shared_ptr<double> conjugate_work_ptr)
30 : VolUserDataOperator(NOSPACE, OPSPACE), dataAtPts(std::move(data_ptr)),
31 t_direction(std::move(t_direction_in)),
32 conjugateWorkPtr(std::move(conjugate_work_ptr)) {
35 "Plastic work operator has a null data pointer");
36 }
37
38 MoFEMErrorCode doWork(int side, EntityType type, EntData &data) override {
40 (void)side;
41 (void)type;
42 (void)data;
43
44 constexpr int dim = SPACE_DIM;
45 const int nb_integration_pts = getGaussPts().size2();
46 auto t_p = dataAtPts->getFTensorApproxP(nb_integration_pts);
47 auto t_f_e = dataAtPts->getFTensorSmallH(nb_integration_pts);
48 auto t_h_p = dataAtPts->getFTensorPlasticH(nb_integration_pts);
50
51 FTENSOR_INDEXES(dim, i, j, k, l);
52 const EigenMatrix::Fun<double> exp_fun = [](const double value) {
53 return std::exp(value);
54 };
55
56 double local_work = 0;
57 for (int gg = 0; gg != nb_integration_pts; ++gg) {
58 FTensor::Tensor1<double, dim> t_eigen_values;
60 t_eigen_vectors(i, j) = t_h_p(i, j);
61 if (computeEigenValuesSymmetric(t_eigen_vectors, t_eigen_values) !=
62 MB_SUCCESS)
63 SETERRQ(PETSC_COMM_SELF, MOFEM_OPERATION_UNSUCCESSFUL,
64 "Failed to diagonalise the current plastic logarithmic "
65 "stretch");
66 const int nb_unique = getUniqNb<dim>(t_eigen_values);
67 if (nb_unique < dim)
68 CHKERR sortEigenVals<dim>(t_eigen_values, t_eigen_vectors);
69
70 const auto t_diff_exp = EigenMatrix::getDiffMat(
71 t_eigen_values, t_eigen_vectors, exp_fun, exp_fun, nb_unique);
73 t_diff_f_p(i, j) = t_diff_exp(i, j, k, l) * t_direction(k, l);
74
75 // Eqs. (1.22) and (1.29)--(1.30), labels
76 // eq:variation-Fp-from-Hp, eq:fixed-state-plastic-variation, and
77 // eq:plastic-variation-conjugacy. This is the exact mixed-discrete
78 // variation; the logarithmic Mandel rewrite needs continuum
79 // compatibility and is retained separately as a diagnostic.
80 local_work -= t_w * (t_p(i, j) * (t_f_e(i, k) * t_diff_f_p(k, j)));
81
82 ++t_p;
83 ++t_f_e;
84 ++t_h_p;
85 ++t_w;
86 }
87 *conjugateWorkPtr += getMeasure() * local_work;
88
90 }
91
92private:
93 boost::shared_ptr<DataAtIntegrationPts> dataAtPts;
95 boost::shared_ptr<double> conjugateWorkPtr;
96};
97
100 GAUSS>::OpBaseTimesVector<1, plasticLogarithmicStretchCoordinateSize,
102
104 std::map<EntityHandle,
105 std::array<PetscInt, plasticLogarithmicStretchCoordinateSize>>;
106
107/**
108 * Assemble -R_{H^p}^T p for one plastic P0 cell.
109 *
110 * The adjoint fields p are interpolated with the elastic DM. Since the
111 * plastic field is cellwise constant, this OPSPACE operator can integrate all
112 * five coefficient directions and insert them directly into their control
113 * DOFs without introducing a mixed auxiliary DM.
114 */
117 boost::shared_ptr<DataAtIntegrationPts> data_ptr,
118 boost::shared_ptr<MatrixDouble> adjoint_piola_ptr,
119 boost::shared_ptr<MatrixDouble> adjoint_stretch_ptr,
120 boost::shared_ptr<MatrixDouble> adjoint_rotation_ptr,
121 boost::shared_ptr<MatrixDouble> adjoint_rotation_gradient_ptr,
122 boost::shared_ptr<const PlasticControlDofIndices> control_indices_ptr,
123 Vec gradient, const double alpha_omega)
124 : VolUserDataOperator(NOSPACE, OPSPACE), dataAtPts(std::move(data_ptr)),
125 adjointPiolaPtr(std::move(adjoint_piola_ptr)),
126 adjointStretchPtr(std::move(adjoint_stretch_ptr)),
127 adjointRotationPtr(std::move(adjoint_rotation_ptr)),
128 adjointRotationGradientPtr(std::move(adjoint_rotation_gradient_ptr)),
129 controlIndicesPtr(std::move(control_indices_ptr)), gradient(gradient),
130 alphaOmega(alpha_omega) {
136 "Reduced Helmholtz-gradient operator has a null data pointer");
137 }
138
139 MoFEMErrorCode doWork(int, EntityType, EntData &) override {
141 constexpr int dim = SPACE_DIM;
142 constexpr int coordinate_size =
144 constexpr int stretch_size = dim * (dim + 1) / 2;
145 const int nb_integration_pts = getGaussPts().size2();
146 const auto indices_it = controlIndicesPtr->find(getFEEntityHandle());
147 if (indices_it == controlIndicesPtr->end())
148 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
149 "Plastic cell %llu has no control-DOF layout",
150 static_cast<unsigned long long>(getFEEntityHandle()));
151
152#ifndef NDEBUG
153 const auto check_matrix =
154 [nb_integration_pts](const boost::shared_ptr<MatrixDouble> &matrix_ptr,
155 const int columns, const char *name) {
157 if (matrix_ptr->size1() != nb_integration_pts ||
158 matrix_ptr->size2() != columns)
159 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
160 "Inconsistent %s data in reduced Helmholtz gradient",
161 name);
163 };
164 CHKERR check_matrix(adjointPiolaPtr, dim * dim, "Piola adjoint");
165 CHKERR check_matrix(adjointStretchPtr, stretch_size, "stretch adjoint");
166 CHKERR check_matrix(adjointRotationPtr, dim, "rotation adjoint");
167 CHKERR check_matrix(adjointRotationGradientPtr, dim * dim,
168 "rotation-adjoint gradient");
169#endif
170
172 auto t_adjoint_piola =
173 MatrixSizeHelper<GetFTensor2FromMatType<dim, dim, -1, DL>, DL>::get(
174 *adjointPiolaPtr, nb_integration_pts)();
175 auto t_adjoint_stretch =
176 MatrixSizeHelper<GetFTensor1FromMatType<stretch_size, -1, DL>, DL>::get(
177 *adjointStretchPtr, nb_integration_pts)();
178 auto t_adjoint_rotation =
180 *adjointRotationPtr, nb_integration_pts)();
181 auto t_adjoint_rotation_gradient =
182 MatrixSizeHelper<GetFTensor2FromMatType<dim, dim, -1, DL>, DL>::get(
183 *adjointRotationGradientPtr, nb_integration_pts)();
184 auto t_reference_p = dataAtPts->getFTensorApproxP(nb_integration_pts);
185 auto t_elastic_f = dataAtPts->getFTensorSmallH(nb_integration_pts);
186 auto t_plastic_h = dataAtPts->getFTensorPlasticH(nb_integration_pts);
187 auto t_plastic_f = dataAtPts->getFTensorPlasticF(nb_integration_pts);
188 auto t_inv_plastic_f =
189 dataAtPts->getFTensorInvPlasticF(nb_integration_pts);
190 auto t_adjoint_stress_d_p =
191 dataAtPts->getFTensorAdjointPdUdP(nb_integration_pts);
192 auto t_levi_d_p =
193 dataAtPts->getFTensorLeviKirchhoffP(nb_integration_pts);
194 auto t_rotation_gradient =
195 dataAtPts->getFTensorRotAxisGrad(nb_integration_pts);
196 auto t_w = getFTensor0IntegrationWeight();
197
198 std::array<PetscScalar, coordinate_size> local_gradient{};
199 FTENSOR_INDEXES(dim, i, j, k, l, m, n);
200 FTensor::Index<'S', stretch_size> S;
201 FTensor::Index<'C', coordinate_size> C;
202 const EigenMatrix::Fun<double> exp_fun = [](const double value) {
203 return std::exp(value);
204 };
205
206 for (int gg = 0; gg != nb_integration_pts; ++gg) {
207 FTensor::Tensor1<double, dim> t_eigen_values;
209 t_eigen_vectors(i, j) = t_plastic_h(i, j);
210 if (computeEigenValuesSymmetric(t_eigen_vectors, t_eigen_values) !=
211 MB_SUCCESS)
212 SETERRQ(PETSC_COMM_SELF, MOFEM_OPERATION_UNSUCCESSFUL,
213 "Failed to diagonalise plastic logarithmic stretch while "
214 "assembling its reduced gradient");
215 const int nb_unique = getUniqNb<dim>(t_eigen_values);
216 if (nb_unique < dim)
217 CHKERR sortEigenVals<dim>(t_eigen_values, t_eigen_vectors);
218 const auto t_diff_exp = EigenMatrix::getDiffMat(
219 t_eigen_values, t_eigen_vectors, exp_fun, exp_fun, nb_unique);
220 const double det_plastic_f = determinantTensor3by3(t_plastic_f);
221
222 FTensor::Tensor2<double, dim, dim> t_adjoint_rotation_gradient_pull;
223 FTensor::Tensor2<double, dim, dim> t_rotation_gradient_pull;
224 t_adjoint_rotation_gradient_pull(k, j) =
225 t_adjoint_rotation_gradient(k, i) * t_inv_plastic_f(i, j);
226 t_rotation_gradient_pull(k, j) =
227 t_rotation_gradient(k, i) * t_inv_plastic_f(i, j);
228
229 for (int coordinate = 0; coordinate != coordinate_size; ++coordinate) {
230 FTensor::Tensor1<double, coordinate_size> t_coordinate_direction;
231 t_coordinate_direction(C) = 0.;
232 t_coordinate_direction(coordinate) = 1.;
233 const auto t_direction =
235 t_coordinate_direction);
237 t_d_plastic_f(i, j) =
238 t_diff_exp(i, j, k, l) * t_direction(k, l);
239 FTensor::Tensor2<double, dim, dim> t_d_inv_plastic_f;
240 t_d_inv_plastic_f(i, j) =
241 -t_inv_plastic_f(i, k) * t_d_plastic_f(k, l) *
242 t_inv_plastic_f(l, j);
243
244 // Piola/bubble compatibility block. The divergence transform is
245 // invariant because H^p and every coordinate direction are
246 // trace-free, hence J_p=1 and dJ_p=0.
247 double residual_derivative_contraction =
248 -t_adjoint_piola(i, k) * t_elastic_f(i, j) *
249 t_d_plastic_f(j, k);
250
251 FTensor::Tensor2<double, dim, dim> t_d_intermediate_p;
252 t_d_intermediate_p(i, j) =
253 t_reference_p(i, k) * t_d_plastic_f(j, k) / det_plastic_f;
255 t_d_adjoint_stress(S) =
256 t_adjoint_stress_d_p(i, j, S) * t_d_intermediate_p(i, j);
257 // The explicit-stretch residual contains minus the stress conjugate
258 // induced by the intermediate Piola transform.
259 residual_derivative_contraction -=
260 det_plastic_f *
261 (t_adjoint_stretch(S) * t_d_adjoint_stress(S));
262
264 t_d_levi(k) = t_levi_d_p(k, i, j) * t_d_intermediate_p(i, j);
265 residual_derivative_contraction -=
266 det_plastic_f * t_adjoint_rotation(k) * t_d_levi(k);
267
268 if (alphaOmega != 0.) {
270 t_d_adjoint_rotation_gradient_pull;
271 FTensor::Tensor2<double, dim, dim> t_d_rotation_gradient_pull;
272 t_d_adjoint_rotation_gradient_pull(k, j) =
273 t_adjoint_rotation_gradient(k, i) *
274 t_d_inv_plastic_f(i, j);
275 t_d_rotation_gradient_pull(k, j) =
276 t_rotation_gradient(k, i) * t_d_inv_plastic_f(i, j);
277 residual_derivative_contraction +=
278 det_plastic_f * alphaOmega *
279 (t_d_adjoint_rotation_gradient_pull(k, j) *
280 t_rotation_gradient_pull(k, j) +
281 t_adjoint_rotation_gradient_pull(k, j) *
282 t_d_rotation_gradient_pull(k, j));
283 }
284
285 // L=Psi-p.R has derivative -p.R_Hp because the bulk Helmholtz
286 // energy has no explicit H^p dependence in this independent elastic-
287 // stretch, trace-free discretization.
288 local_gradient[coordinate] -=
289 getMeasure() * t_w * residual_derivative_contraction;
290 }
291
292 ++t_adjoint_piola;
293 ++t_adjoint_stretch;
294 ++t_adjoint_rotation;
295 ++t_adjoint_rotation_gradient;
296 ++t_reference_p;
297 ++t_elastic_f;
298 ++t_plastic_h;
299 ++t_plastic_f;
300 ++t_inv_plastic_f;
301 ++t_adjoint_stress_d_p;
302 ++t_levi_d_p;
303 ++t_rotation_gradient;
304 ++t_w;
305 }
306
307 CHKERR VecSetValues(gradient, coordinate_size, indices_it->second.data(),
308 local_gradient.data(), ADD_VALUES);
310 }
311
312private:
313 boost::shared_ptr<DataAtIntegrationPts> dataAtPts;
314 boost::shared_ptr<MatrixDouble> adjointPiolaPtr;
315 boost::shared_ptr<MatrixDouble> adjointStretchPtr;
316 boost::shared_ptr<MatrixDouble> adjointRotationPtr;
317 boost::shared_ptr<MatrixDouble> adjointRotationGradientPtr;
318 boost::shared_ptr<const PlasticControlDofIndices> controlIndicesPtr;
320 const double alphaOmega;
321};
322
323/**
324 * Produce the five trace-free coefficient forces in Gauss-by-coefficients
325 * layout.
326 *
327 * Implements Eqs. (1.29)--(1.30), labels
328 * eq:fixed-state-plastic-variation and eq:plastic-variation-conjugacy, in the
329 * coefficient form of Eq. (1.69), label eq:baseline-smooth-gradient.
330 */
332 OpCalculatePlasticForce(boost::shared_ptr<DataAtIntegrationPts> data_ptr,
333 boost::shared_ptr<MatrixDouble> coefficient_force_ptr)
334 : VolUserDataOperator(NOSPACE, OPSPACE), dataAtPts(std::move(data_ptr)),
335 coefficientForcePtr(std::move(coefficient_force_ptr)) {
339 "Plastic-force operator has a null integration-point data or "
340 "coefficient-force pointer");
341 }
342
343 MoFEMErrorCode doWork(int, EntityType, EntData &) override {
345 constexpr int dim = SPACE_DIM;
346 constexpr int coordinate_size = plasticLogarithmicStretchCoordinateSize;
347 const int nb_integration_pts = getGaussPts().size2();
349 auto get_force =
350 MatrixSizeHelper<GetFTensor1FromMatType<coordinate_size, coordinate_size,
351 DL>,
352 DL>::size(*coefficientForcePtr, nb_integration_pts);
353 auto t_force = get_force();
354 auto t_p = dataAtPts->getFTensorApproxP(nb_integration_pts);
355 auto t_f_e = dataAtPts->getFTensorSmallH(nb_integration_pts);
356 auto t_h_p = dataAtPts->getFTensorPlasticH(nb_integration_pts);
357
358 FTENSOR_INDEXES(dim, i, j, k, m, n);
359 FTENSOR_INDEX(coordinate_size, L);
360 const EigenMatrix::Fun<double> exp_fun = [](const double value) {
361 return std::exp(value);
362 };
363
364 for (int gg = 0; gg != nb_integration_pts; ++gg) {
365 FTensor::Tensor1<double, dim> t_eigen_values;
367 t_eigen_vectors(i, j) = t_h_p(i, j);
368 if (computeEigenValuesSymmetric(t_eigen_vectors, t_eigen_values) !=
369 MB_SUCCESS)
370 SETERRQ(PETSC_COMM_SELF, MOFEM_OPERATION_UNSUCCESSFUL,
371 "Failed to diagonalise the current plastic logarithmic "
372 "stretch");
373 const int nb_unique = getUniqNb<dim>(t_eigen_values);
374 if (nb_unique < dim)
375 CHKERR sortEigenVals<dim>(t_eigen_values, t_eigen_vectors);
376 const auto t_diff_exp = EigenMatrix::getDiffMat(
377 t_eigen_values, t_eigen_vectors, exp_fun, exp_fun, nb_unique);
378
379 FTensor::Tensor2<double, dim, dim> t_elastic_pull_back;
381 t_elastic_pull_back(k, j) = t_f_e(i, k) * t_p(i, j);
382 t_tensor_force(m, n) =
383 -t_diff_exp(k, j, m, n) * t_elastic_pull_back(k, j);
384 const auto t_coordinate_force =
386 t_force(L) = t_coordinate_force(L);
387
388 ++t_force;
389 ++t_p;
390 ++t_f_e;
391 ++t_h_p;
392 }
394 }
395
396private:
397 boost::shared_ptr<DataAtIntegrationPts> dataAtPts;
398 boost::shared_ptr<MatrixDouble> coefficientForcePtr;
399};
400
401} // namespace PlasticIncrementalOptimizationInternal
402
404 boost::ptr_deque<ForcesAndSourcesCore::UserDataOperator> &pipeline,
405 const std::string &field_name,
406 boost::shared_ptr<MatrixDouble> tensor_values,
407 const EntityType zero_type, SmartPetscObj<DM> data_dm,
408 SmartPetscObj<Vec> data_vector) {
410 if (!tensor_values)
411 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
412 "Plastic logarithmic-stretch output is null");
413 if (data_dm && !data_vector)
414 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
415 "Cross-DM plastic logarithmic-stretch evaluation requires a "
416 "data vector");
417
418 if (data_dm)
419 pipeline.push_back(new OpCalculateTensor2SymmetricDeviatorFieldValues<SPACE_DIM>(
421 tensor_values, data_vector, zero_type));
422 else
423 pipeline.push_back(new OpCalculateTensor2SymmetricDeviatorFieldValues<SPACE_DIM>(
424 field_name, tensor_values, data_vector, zero_type));
426}
427
430 double &value) {
433 if (!ep.physicalEquations || !ep.dataAtPts)
435 "Material equations or integration-point data are not set");
436
437 auto local_helmholtz_free_energy = boost::make_shared<double>(0);
438 auto fe = boost::make_shared<MechanicalValueEle>(ep.mField);
439 fe->data_ctx |= PetscData::CTX_SET_TIME;
440 if (ts) {
441 CHKERR TSGetTime(ts, &fe->ts_t);
442 CHKERR TSGetTimeStep(ts, &fe->ts_dt);
443 }
444 CHKERR ep.setBaseVolumeElementOps(1, false, false, false, fe);
445 auto *helmholtz_free_energy_op =
446 ep.physicalEquations->returnOpCalculateHelmholtzFreeEnergy(
447 ep.dataAtPts, local_helmholtz_free_energy);
448 if (!helmholtz_free_energy_op)
450 "Selected material does not provide a Helmholtz free energy");
451 fe->getOpPtrVector().push_back(helmholtz_free_energy_op);
452
453 TetPolynomialBase::switchCacheBaseOn<HDIV>({fe.get()});
454 const MoFEMErrorCode loop_error =
456 TetPolynomialBase::switchCacheBaseOff<HDIV>({fe.get()});
457 CHKERR loop_error;
458
459 double global_helmholtz_free_energy = 0;
460 const int mpi_error =
461 MPI_Allreduce(local_helmholtz_free_energy.get(),
462 &global_helmholtz_free_energy, 1, MPI_DOUBLE, MPI_SUM,
463 ep.mField.get_comm());
464 if (mpi_error != MPI_SUCCESS)
466 "MPI reduction of the equilibrated mechanical value failed");
467
468 // This is intentionally only the bulk material Helmholtz free energy.
469 // Springs, loads, and discretization-stabilization terms belong to the
470 // equilibrium constraint; they affect the reduced derivative through the
471 // static adjoint but are never added to this objective value.
472 value = global_helmholtz_free_energy;
473
475}
476
478 EshelbianCore &ep,
480 double &conjugate_work) {
483 if (!ep.plasticVolume || !ep.plasticVolumes || ep.plasticVolumes->empty())
485 "Plastic conjugate work requires a non-empty plastic volume");
486
487 auto local_work = boost::make_shared<double>(0);
488 auto fe = boost::make_shared<MechanicalValueEle>(ep.mField);
489 CHKERR ep.setBaseVolumeElementOps(1, false, false, false, fe);
490 fe->getOpPtrVector().push_back(new OpIntegratePlasticConjugateWork(
491 ep.dataAtPts, t_direction, local_work));
492 fe->exeTestHook = [&ep](FEMethod *fe_method_ptr) {
493 return ep.plasticVolumes->find(fe_method_ptr->getFEEntityHandle()) !=
494 ep.plasticVolumes->end();
495 };
496
497 TetPolynomialBase::switchCacheBaseOn<HDIV>({fe.get()});
498 const MoFEMErrorCode loop_error =
500 TetPolynomialBase::switchCacheBaseOff<HDIV>({fe.get()});
501 CHKERR loop_error;
502
503 const int mpi_error =
504 MPI_Allreduce(local_work.get(), &conjugate_work, 1, MPI_DOUBLE, MPI_SUM,
505 ep.mField.get_comm());
506 if (mpi_error != MPI_SUCCESS)
508 "MPI reduction of the plastic conjugate work failed");
509
511}
512
513namespace PlasticIncrementalOptimizationInternal {
514
517 // Exact coefficient gradient: Eq. (1.69), label
518 // eq:baseline-smooth-gradient, from Eqs. (1.29)--(1.30).
519 if (!force)
521 "Plastic-force vector is null");
522 CHKERR VecZeroEntries(force);
523 if (!ep.plasticVolume)
525
526 auto force_at_points = boost::make_shared<MatrixDouble>();
527 auto fe = boost::make_shared<MechanicalValueEle>(ep.mField);
528 fe->ksp_f = force;
529 CHKERR ep.setBaseVolumeElementOps(1, false, false, false, fe);
530 fe->getOpPtrVector().push_back(
531 new OpCalculatePlasticForce(ep.dataAtPts, force_at_points));
532 fe->getOpPtrVector().push_back(
533 new OpAssemblePlasticForce(ep.plasticFlowField, force_at_points));
534 fe->exeTestHook = [&ep](FEMethod *method) {
535 return ep.plasticVolumes->find(method->getFEEntityHandle()) !=
536 ep.plasticVolumes->end();
537 };
538
539 TetPolynomialBase::switchCacheBaseOn<HDIV>({fe.get()});
540 const MoFEMErrorCode loop_error = DMoFEMLoopFiniteElements(
542 TetPolynomialBase::switchCacheBaseOff<HDIV>({fe.get()});
543 CHKERR loop_error;
544 CHKERR VecAssemblyBegin(force);
545 CHKERR VecAssemblyEnd(force);
547}
548
549namespace {
550
551MoFEMErrorCode createPlasticControlDofIndices(
552 EshelbianCore &ep,
553 boost::shared_ptr<PlasticControlDofIndices> &control_indices_ptr) {
555 control_indices_ptr = boost::make_shared<PlasticControlDofIndices>();
556 const Problem *problem_ptr = nullptr;
558 if (!problem_ptr || !problem_ptr->getNumeredRowDofsPtr())
560 "Incremental-optimization problem has no numbered row DOFs");
561
562 const auto field_bit =
564 const auto &dofs =
565 problem_ptr->getNumeredRowDofsPtr()->get<Unique_mi_tag>();
566 auto dof_it =
567 dofs.lower_bound(FieldEntity::getLoBitNumberUId(field_bit));
568 const auto dof_end =
569 dofs.upper_bound(FieldEntity::getHiBitNumberUId(field_bit));
570 for (; dof_it != dof_end; ++dof_it) {
571 const auto &dof = *dof_it;
572 if (dof->getDofOrder() != 0 ||
573 dof->getDofCoeffIdx() >= plasticLogarithmicStretchCoordinateSize)
574 continue;
575 auto [indices_it, inserted] =
576 control_indices_ptr->try_emplace(dof->getEnt());
577 if (inserted)
578 indices_it->second.fill(-1);
579 auto &index = indices_it->second[dof->getDofCoeffIdx()];
580 if (index >= 0)
582 "Duplicate plastic control coefficient %d on entity %llu",
583 dof->getDofCoeffIdx(),
584 static_cast<unsigned long long>(dof->getEnt()));
585 index = dof->getPetscGlobalDofIdx();
586 }
587
588 for (const auto &[entity, indices] : *control_indices_ptr)
589 for (int coordinate = 0;
591 ++coordinate)
592 if (indices[coordinate] < 0)
594 "Plastic control entity %llu has no global index for "
595 "coefficient %d",
596 static_cast<unsigned long long>(entity), coordinate);
598}
599
600MoFEMErrorCode assembleHelmholtzStateGradient(EshelbianCore &ep,
601 Vec state_gradient) {
603 CHKERR VecZeroEntries(state_gradient);
604 auto fe = boost::make_shared<MechanicalValueEle>(ep.mField);
605 fe->ksp_f = state_gradient;
606 CHKERR ep.setBaseVolumeElementOps(1, false, false, false, fe);
607 CHKERR ep.physicalEquations->pushHelmholtzStateGradient(
608 ep, fe->getOpPtrVector(), ep.dataAtPts);
609
610 TetPolynomialBase::switchCacheBaseOn<HDIV>({fe.get()});
611 const MoFEMErrorCode loop_error =
613 TetPolynomialBase::switchCacheBaseOff<HDIV>({fe.get()});
614 CHKERR loop_error;
615 CHKERR VecAssemblyBegin(state_gradient);
616 CHKERR VecAssemblyEnd(state_gradient);
617 CHKERR VecGhostUpdateBegin(state_gradient, ADD_VALUES, SCATTER_REVERSE);
618 CHKERR VecGhostUpdateEnd(state_gradient, ADD_VALUES, SCATTER_REVERSE);
619 CHKERR VecGhostUpdateBegin(state_gradient, INSERT_VALUES, SCATTER_FORWARD);
620 CHKERR VecGhostUpdateEnd(state_gradient, INSERT_VALUES, SCATTER_FORWARD);
622}
623
624MoFEMErrorCode solveStaticHelmholtzAdjoint(EshelbianCore &ep, TS ts,
625 Vec state_gradient, Vec adjoint) {
627 Vec state = nullptr;
628 CHKERR TSGetSolution(ts, &state);
629 if (!state)
631 "State TS has no solution for the Helmholtz adjoint");
632 auto zero_rate = vectorDuplicate(state);
633 CHKERR VecZeroEntries(zero_rate);
634 PetscReal pseudo_time = 0;
635 CHKERR TSGetTime(ts, &pseudo_time);
636
637 Mat jacobian = nullptr;
638 Mat preconditioner = nullptr;
639 CHKERR TSGetIJacobian(ts, &jacobian, &preconditioner, PETSC_NULLPTR,
640 PETSC_NULLPTR);
641 if (!jacobian || !preconditioner)
643 "State TS has no IJacobian matrices for the static adjoint");
644 // The outer optimization differentiates the rate-free equilibrium map.
645 // shift=0 removes all pseudo-time damping from the sensitivity operator.
646 CHKERR TSComputeIJacobian(ts, pseudo_time, state, zero_rate, 0., jacobian,
647 preconditioner, PETSC_FALSE);
648
649 SNES snes = nullptr;
650 KSP ksp = nullptr;
651 CHKERR TSGetSNES(ts, &snes);
652 CHKERR SNESGetKSP(snes, &ksp);
653 CHKERR KSPSetOperators(ksp, jacobian, preconditioner);
654 CHKERR KSPSetInitialGuessNonzero(ksp, PETSC_FALSE);
655 CHKERR VecZeroEntries(adjoint);
656 CHKERR KSPSolveTranspose(ksp, state_gradient, adjoint);
657 KSPConvergedReason reason;
658 CHKERR KSPGetConvergedReason(ksp, &reason);
659 if (reason <= 0)
661 "Static Helmholtz adjoint diverged with KSP reason %d",
662 static_cast<int>(reason));
663 CHKERR VecGhostUpdateBegin(adjoint, INSERT_VALUES, SCATTER_FORWARD);
664 CHKERR VecGhostUpdateEnd(adjoint, INSERT_VALUES, SCATTER_FORWARD);
665
666#ifndef NDEBUG
667 auto adjoint_residual = vectorDuplicate(state_gradient);
668 CHKERR MatMultTranspose(jacobian, adjoint, adjoint_residual);
669 CHKERR VecAXPY(adjoint_residual, -1., state_gradient);
670 PetscReal state_gradient_norm = 0;
671 PetscReal residual_norm = 0;
672 CHKERR VecNorm(state_gradient, NORM_2, &state_gradient_norm);
673 CHKERR VecNorm(adjoint_residual, NORM_2, &residual_norm);
674 MOFEM_LOG("EP", Sev::verbose)
675 << "Static Helmholtz adjoint residual " << residual_norm
676 << ", material state-gradient norm " << state_gradient_norm;
677#endif
679}
680
681MoFEMErrorCode assemblePlasticAdjointContribution(EshelbianCore &ep,
682 Vec adjoint,
683 Vec gradient) {
685 CHKERR VecZeroEntries(gradient);
686 auto control_indices = boost::shared_ptr<PlasticControlDofIndices>();
687 CHKERR createPlasticControlDofIndices(ep, control_indices);
688 auto adjoint_piola = boost::make_shared<MatrixDouble>();
689 auto adjoint_stretch = ep.dataAtPts->getVarLogStreachPts();
690 auto adjoint_rotation = boost::make_shared<MatrixDouble>();
691 auto adjoint_rotation_gradient = boost::make_shared<MatrixDouble>();
692 auto adjoint_vector = SmartPetscObj<Vec>(adjoint, true);
693
694 auto fe = boost::make_shared<MechanicalValueEle>(ep.mField);
695 // OpCalculateRotationAndSpatialGradient fills the P derivatives consumed
696 // below only in Jacobian context. Set it explicitly instead of relying on
697 // values retained from the preceding static-Jacobian assembly.
698 fe->ts_ctx = TSMethod::CTX_TSSETIJACOBIAN;
699 CHKERR ep.setBaseVolumeElementOps(1, false, false, false, fe);
700 fe->getOpPtrVector().push_back(
702 ep.piolaStress, adjoint_piola, nullptr, adjoint_vector));
703 fe->getOpPtrVector().push_back(
705 ep.bubbleField, adjoint_piola, nullptr, adjoint_vector, MBMAXTYPE));
706 CHKERR ep.physicalEquations->pushMaterialVariation(
707 ep, fe->getOpPtrVector(), ep.dataAtPts, adjoint_vector);
708 fe->getOpPtrVector().push_back(new OpCalculateVectorFieldValues<SPACE_DIM>(
709 ep.rotAxis, adjoint_rotation, adjoint_vector, MBTET));
710 fe->getOpPtrVector().push_back(
712 ep.rotAxis, adjoint_rotation_gradient, adjoint_vector, MBTET));
713 fe->getOpPtrVector().push_back(new OpAssembleReducedHelmholtzGradient(
714 ep.dataAtPts, adjoint_piola, adjoint_stretch, adjoint_rotation,
715 adjoint_rotation_gradient, control_indices, gradient, ep.alphaOmega));
716 fe->exeTestHook = [&ep](FEMethod *method) {
717 return ep.plasticVolumes->find(method->getFEEntityHandle()) !=
718 ep.plasticVolumes->end();
719 };
720
721 TetPolynomialBase::switchCacheBaseOn<HDIV>({fe.get()});
722 const MoFEMErrorCode loop_error =
724 TetPolynomialBase::switchCacheBaseOff<HDIV>({fe.get()});
725 CHKERR loop_error;
726 CHKERR VecAssemblyBegin(gradient);
727 CHKERR VecAssemblyEnd(gradient);
728 CHKERR VecGhostUpdateBegin(gradient, INSERT_VALUES, SCATTER_FORWARD);
729 CHKERR VecGhostUpdateEnd(gradient, INSERT_VALUES, SCATTER_FORWARD);
731}
732
733} // namespace
734
736 Vec gradient) {
738 if (!ts || !gradient)
740 "Reduced Helmholtz gradient requires a TS and output vector");
741 auto state_gradient = createDMVector(ep.dmElastic, RowColData::ROW);
742 auto adjoint = vectorDuplicate(state_gradient);
743 CHKERR assembleHelmholtzStateGradient(ep, state_gradient);
744 CHKERR solveStaticHelmholtzAdjoint(ep, ts, state_gradient, adjoint);
745 CHKERR assemblePlasticAdjointContribution(ep, adjoint, gradient);
747}
748
749} // namespace PlasticIncrementalOptimizationInternal
750
751} // namespace EshelbianPlasticity
Eshelbian plasticity interface.
std::string type
Lie algebra implementation.
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
@ ROW
#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.
PetscErrorCode DMMoFEMGetProblemPtr(DM dm, const MoFEM::Problem **problem_ptr)
Get pointer to problem data structure.
Definition DMMoFEM.cpp:422
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
auto createDMVector(DM dm, RowColData rc=RowColData::COL)
Get smart vector from DM.
Definition DMMoFEM.hpp:1237
@ GAUSS
Gaussian quadrature integration.
#define MOFEM_LOG(channel, severity)
Log.
FTensor::Index< 'i', SPACE_DIM > i
const double n
refractive index of diffusive medium
FTensor::Index< 'l', 3 > l
FTensor::Index< 'j', 3 > j
FTensor::Index< 'k', 3 > k
boost::function< T(const T)> Fun
const FTensor::Tensor2< T, Dim, Dim > Vec
auto getDiffMat(A &&t_val, B &&t_vec, Fun< double > f, Fun< double > d_f, const int nb)
Get the Diff Mat object.
FormsIntegrators< VolUserDataOperator >::Assembly< A >::LinearForm< GAUSS >::OpBaseTimesVector< 1, plasticLogarithmicStretchCoordinateSize, plasticLogarithmicStretchCoordinateSize > OpAssemblePlasticForce
std::map< EntityHandle, std::array< PetscInt, plasticLogarithmicStretchCoordinateSize > > PlasticControlDofIndices
FTensor::Tensor1< double, plasticLogarithmicStretchCoordinateSize > plasticLogarithmicStretchCoordinatesFromTensor(const FTensor::Tensor2_symmetric< T, SPACE_DIM > &t_values)
MoFEMErrorCode assembleReducedHelmholtzGradient(EshelbianCore &ep, TS ts, Vec gradient)
FTensor::Tensor2_symmetric< double, SPACE_DIM > plasticLogarithmicStretchTensorFromCoordinates(const FTensor::Tensor1< T, plasticLogarithmicStretchCoordinateSize > &t_coordinates)
MoFEMErrorCode validateEquilibratedMechanicalValueScope(EshelbianCore &ep)
MoFEMErrorCode evaluateEquilibratedMechanicalValue(EshelbianCore &ep, TS ts, double &value)
MoFEMErrorCode evaluatePlasticConjugateWork(EshelbianCore &ep, const FTensor::Tensor2_symmetric< double, SPACE_DIM > &t_direction, double &conjugate_work)
MoFEMErrorCode addCalculatePlasticLogarithmicStretchFieldValues(boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > &pipeline, const std::string &field_name, boost::shared_ptr< MatrixDouble > tensor_values, const EntityType zero_type, SmartPetscObj< DM > data_dm, SmartPetscObj< Vec > data_vector)
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
implementation of Data Operators for Forces and Sources
Definition Common.hpp:10
SmartPetscObj< Vec > vectorDuplicate(Vec vec)
Create duplicate vector of smart vector.
decltype(GetFTensor1FromMatImpl< Tensor_Dim, S, DL, M >::get(std::declval< M & >(), 0, 0)) GetFTensor1FromMatType
MoFEMErrorCode computeEigenValuesSymmetric(const MatrixDouble &mat, VectorDouble &eig, MatrixDouble &eigen_vec)
compute eigenvalues of a symmetric matrix using lapack dsyev
static auto determinantTensor3by3(T &t)
Calculate the determinant of a 3x3 matrix or a tensor of rank 2.
decltype(GetFTensor2FromMatImpl< Tensor_Dim0, Tensor_Dim1, S, DL, M >::get(std::declval< M & >(), 0, 0)) GetFTensor2FromMatType
MoFEMErrorCode VecSetValues(Vec V, const EntitiesFieldData::EntData &data, const double *ptr, InsertMode iora)
Assemble PETSc vector.
constexpr AssemblyType A
constexpr auto field_name
FTensor::Index< 'm', 3 > m
MoFEM::Interface & mField
boost::shared_ptr< Range > plasticVolumes
const std::string elementVolumeName
const std::string piolaStress
const std::string bubbleField
const std::string plasticFlowField
boost::shared_ptr< PhysicalEquations > physicalEquations
const std::string rotAxis
MoFEMErrorCode setBaseVolumeElementOps(const int tag, const bool do_rhs, const bool do_lhs, const bool calc_rates, boost::shared_ptr< VolumeElementForcesAndSourcesCore > fe, const bool add_bubble=true)
static PetscBool plasticVolume
boost::shared_ptr< DataAtIntegrationPts > dataAtPts
SmartPetscObj< DM > dmElastic
Elastic problem.
SmartPetscObj< DM > dmIncrementalOptimization
Incremental-optimization control problem.
OpAssembleReducedHelmholtzGradient(boost::shared_ptr< DataAtIntegrationPts > data_ptr, boost::shared_ptr< MatrixDouble > adjoint_piola_ptr, boost::shared_ptr< MatrixDouble > adjoint_stretch_ptr, boost::shared_ptr< MatrixDouble > adjoint_rotation_ptr, boost::shared_ptr< MatrixDouble > adjoint_rotation_gradient_ptr, boost::shared_ptr< const PlasticControlDofIndices > control_indices_ptr, Vec gradient, const double alpha_omega)
MoFEMErrorCode doWork(int, EntityType, EntData &) override
Operator for linear form, usually to calculate values on right hand side.
OpCalculatePlasticForce(boost::shared_ptr< DataAtIntegrationPts > data_ptr, boost::shared_ptr< MatrixDouble > coefficient_force_ptr)
MoFEMErrorCode doWork(int, EntityType, EntData &) override
Operator for linear form, usually to calculate values on right hand side.
OpIntegratePlasticConjugateWork(boost::shared_ptr< DataAtIntegrationPts > data_ptr, FTensor::Tensor2_symmetric< double, SPACE_DIM > t_direction_in, boost::shared_ptr< double > conjugate_work_ptr)
MoFEMErrorCode doWork(int side, EntityType type, EntData &data) override
Operator for linear form, usually to calculate values on right hand side.
virtual FieldBitNumber get_field_bit_number(const std::string name) const =0
get field bit number
virtual MPI_Comm & get_comm() const =0
Data on single entity (This is passed as argument to DataOperator::doWork)
Structure for user loop methods on finite elements.
static UId getHiBitNumberUId(const FieldBitNumber bit_number)
static UId getLoBitNumberUId(const FieldBitNumber bit_number)
EntityHandle getFEEntityHandle() const
Return finite element entity handle.
auto getFTensor0IntegrationWeight()
Get integration weights.
double getMeasure() const
get measure of element
@ OPROW
operator doWork function is executed on FE rows
@ OPSPACE
operator do Work is execute on space data
MatrixDouble & getGaussPts()
matrix of integration (Gauss) points for Volume Element
Calculate tenor field using tensor base, i.e. Hdiv/Hcurl.
Calculate tenor field using vectorial base, i.e. Hdiv/Hcurl.
Get field gradients at integration pts for scalar field rank 0, i.e. vector field.
Specialization for MatrixDouble vector field values calculation.
@ CTX_SET_TIME
Time value is set.
keeps basic data about problem
auto & getNumeredRowDofsPtr() const
get access to numeredRowDofsPtr storing DOFs on rows
intrusive_ptr for managing petsc objects
@ CTX_TSSETIJACOBIAN
Setting up implicit Jacobian.