221 {
223 try {
224 moab::Core moab_core;
225 moab::Interface &moab = moab_core;
229
232
233
235 0.02,
236 0.03,
237 std::log(0.01),
238 0.1,
239 1e-4};
242 const std::array<const PlasticLocalLawParameters *, 2> parameter_sets{
243 &hardening, &perfect};
244
245 const Point
active{Increment{0.012, -0.004, 0.007, 0.002, -0.009},
246 std::log(0.003)};
247 const Point elastic{Increment{0., 0., 0., 0., 0.}, std::log(0.0005)};
248
249 const std::array<Gradient, 3> directions{
250 Gradient{0.3, -0.7, 0.2, 0.5, -0.4, 0.},
251 Gradient{0., 0., 0., 0., 0., 1.},
252 Gradient{-0.2, 0.4, 0.6, -0.3, 0.1, 0.8}};
253
254
255 CHKERR testing->addTestCommandLine(
"", 1,
"tape value", [&]() {
257 for (const auto *p : parameter_sets) {
258 CHKERR law->setParameters(*p);
259 for (
const auto *pt : {&
active, &elastic}) {
261 CHKERR law->evaluateValue(pt->t_h, pt->psi, terms);
262 const auto direct =
265 "density tape vs direct", terms.
density, direct.density,
266 {1e-15, 1e-13});
268 "density = resistance + proximal", terms.
density,
271 "proximal Bregman term non-negative",
272 std::max(0., -terms.
proximal), 1., {0., 0.});
273 }
274 }
276 });
277
278
279
280 CHKERR testing->addTestCommandLine(
"", 2,
"reconstruction", [&]() {
282 CHKERR law->setParameters(hardening);
286 "slack equals exp(psi)",
288 std::exp(
active.psi), {1e-15, 1e-13});
290 "slack positive", terms.
slack > 0 ? 0. : 1., 1., {0., 0.});
291 const double exact_norm =
294 "ell_eps >= ell",
296 {0., 0.});
298 "ell_eps^2 = ell^2 + eps^2",
300 exact_norm * exact_norm +
301 hardening.regularisationEpsilon * hardening.regularisationEpsilon,
302 {1e-15, 1e-13});
303 CHKERR law->evaluateValue(elastic.t_h, elastic.psi, terms);
306 hardening.regularisationEpsilon, {1e-15, 1e-13});
309 hardening.yieldStress +
310 hardening.hardeningModulus *
311 (hardening.committedKappa + hardening.regularisationEpsilon +
312 std::exp(elastic.psi)),
313 {1e-15, 1e-13});
315 });
316
317
318
319 CHKERR testing->addTestCommandLine(
"", 3,
"gradient", [&]() {
321 for (const auto *p : parameter_sets) {
322 CHKERR law->setParameters(*p);
323 for (
const auto *pt : {&
active, &elastic}) {
324 Gradient t_g;
325 CHKERR law->evaluateGradient(pt->t_h, pt->psi, t_g);
326 const auto t_closed = closedFormGradient(pt->t_h, pt->psi, *p);
328 "gradient tape vs closed form", maxAbsDifference(t_g, t_closed),
329 std::max(maxAbs(t_g), maxAbs(t_closed)), {1e-16, 1e-12});
330 for (const auto &t_v : directions) {
331 double assembled = 0;
332 for (
int a = 0;
a != nbActive; ++
a)
333 assembled += t_g(
a) * t_v(
a);
334 for (const double step : {1e-5, 1e-6}) {
335 Point plus, minus;
336 perturb(*pt, t_v, step, plus);
337 perturb(*pt, t_v, -step, minus);
339 CHKERR law->evaluateValue(plus.t_h, plus.psi, terms_plus);
340 CHKERR law->evaluateValue(minus.t_h, minus.psi, terms_minus);
341 const double fd =
343
344 const double tolerance = step == 1e-5 ? 1e-5 : 1e-7;
346 "gradient centred difference", std::abs(fd - assembled),
347 std::max(std::abs(fd), std::abs(assembled)),
348 {1e-12, tolerance});
349 }
350 }
351 }
352 }
354 });
355
356
357
358
359 CHKERR testing->addTestCommandLine(
"", 4,
"perfect plasticity", [&]() {
361 CHKERR law->setParameters(perfect);
364 Gradient t_g_star, t_g_other;
365 CHKERR law->evaluateGradient(
active.t_h, psi_star, t_g_star);
368 "latent gradient vanishes at the explicit root",
369 std::abs(t_g_star(nbCoords)),
370 std::exp(psi_star) * perfect.
yieldStress, {1e-16, 1e-12});
371 double tensor_difference = 0, tensor_scale = 0;
372 for (
int l = 0;
l != nbCoords; ++
l) {
373 tensor_difference =
374 std::max(tensor_difference, std::abs(t_g_star(
l) - t_g_other(
l)));
375 tensor_scale = std::max(tensor_scale, std::abs(t_g_other(
l)));
376 }
378 "tensor gradient independent of psi", tensor_difference, tensor_scale,
379 {1e-16, 1e-14});
380
381 Gradient t_g_above;
382 CHKERR law->evaluateGradient(
active.t_h, psi_star + 1., t_g_above);
384 "latent gradient positive above the root",
385 t_g_above(nbCoords) > 0 ? 0. : 1., 1., {0., 0.});
387 });
388
389
390
391 CHKERR testing->addTestCommandLine(
"", 5,
"hardening coupling", [&]() {
393 CHKERR law->setParameters(hardening);
394 const double psi_open =
active.psi;
395 const double psi_closed = std::log(1e-7);
396 Gradient t_g_open, t_g_closed;
397 CHKERR law->evaluateGradient(
active.t_h, psi_open, t_g_open);
398 CHKERR law->evaluateGradient(
active.t_h, psi_closed, t_g_closed);
399 const auto terms =
401 const double factor = hardening.hardeningModulus *
402 (std::exp(psi_open) - std::exp(psi_closed));
403 double error = 0,
scale = 0;
404 for (
int l = 0;
l != nbCoords; ++
l) {
405 const double predicted = factor *
408 error = std::max(error,
409 std::abs((t_g_open(
l) - t_g_closed(
l)) - predicted));
411 }
413 "tensor gradient shift equals A_h delta(e^psi) G", error,
scale,
414 {1e-16, 1e-12});
416 });
417
418
419 CHKERR testing->addTestCommandLine(
"", 6,
"parameter validation", [&]() {
422 CHKERR PetscPushErrorHandler(PetscIgnoreErrorHandler,
nullptr);
423 const auto ierr = law->setParameters(bad);
424 CHKERR PetscPopErrorHandler();
425 return ierr != 0 ? 0. : 1.;
426 };
427 auto bad_eps = hardening;
428 bad_eps.regularisationEpsilon = 0;
430 "epsilon zero rejected", rejects(bad_eps), 1., {0., 0.});
431 auto bad_alpha = hardening;
432 bad_alpha.proximalCoefficient = 0;
434 "zero proximal coefficient rejected", rejects(bad_alpha), 1.,
435 {0., 0.});
436 auto bad_hardening = hardening;
437 bad_hardening.hardeningModulus = -1;
439 "negative hardening rejected", rejects(bad_hardening), 1., {0., 0.});
440
441 CHKERR law->setParameters(hardening);
443 "valid parameters restored",
444 law->getParameters().regularisationEpsilon,
445 hardening.regularisationEpsilon, {0., 0.});
447 });
448
449
450
451 CHKERR testing->addTestCommandLine(
"", 7,
"hessian action", [&]() {
453 for (const auto *p : parameter_sets) {
454 CHKERR law->setParameters(*p);
455 for (
const auto *pt : {&
active, &elastic}) {
456 for (const auto &t_v : directions) {
457 HessianAction t_action;
458 CHKERR law->evaluateHessianAction(pt->t_h, pt->psi, t_v, t_action);
459 const auto t_closed =
460 closedFormHessianAction(pt->t_h, pt->psi, t_v, *p);
462 "Hessian action tape vs closed form",
463 maxAbsDifference(t_action, t_closed),
464 std::max(maxAbs(t_action), maxAbs(t_closed)), {1e-12, 1e-11});
465
466
467
468
469 const double step = pt == &elastic ? 1e-8 : 1e-7;
470 Point plus, minus;
471 perturb(*pt, t_v, step, plus);
472 perturb(*pt, t_v, -step, minus);
473 Gradient t_gradient_plus, t_gradient_minus;
474 CHKERR law->evaluateGradient(plus.t_h, plus.psi, t_gradient_plus);
475 CHKERR law->evaluateGradient(minus.t_h, minus.psi,
476 t_gradient_minus);
477 HessianAction t_difference;
478 for (
int a = 0;
a != nbActive; ++
a)
480 (t_gradient_plus(
a) - t_gradient_minus(
a)) / (2. * step);
482 "Hessian action centred gradient difference",
483 maxAbsDifference(t_action, t_difference),
484 std::max(maxAbs(t_action), maxAbs(t_difference)), {1e-8, 2e-7});
485 }
486 }
487 }
488
489 CHKERR law->setParameters(perfect);
490 HessianAction t_perfect_cross;
492 t_perfect_cross);
493 double tensor_cross_norm = 0;
494 for (
int l = 0;
l != nbCoords; ++
l)
495 tensor_cross_norm =
496 std::max(tensor_cross_norm, std::abs(t_perfect_cross(
l)));
498 "perfect-plastic tensor-latent Hessian coupling vanishes",
499 tensor_cross_norm, std::abs(t_perfect_cross(nbCoords)),
500 {1e-16, 1e-13});
501
502 CHKERR law->setParameters(hardening);
503 HessianAction t_origin_action;
504 CHKERR law->evaluateHessianAction(elastic.t_h, elastic.psi, directions[0],
505 t_origin_action);
506 const auto origin_terms =
508 double origin_error = 0;
509 double origin_scale = 0;
510 for (
int l = 0;
l != nbCoords; ++
l) {
511 const double expected = origin_terms.resistanceForce *
514 hardening.regularisationEpsilon;
515 origin_error =
516 std::max(origin_error, std::abs(t_origin_action(
l) - expected));
517 origin_scale = std::max(origin_scale, std::abs(expected));
518 }
520 "regularised tensor curvature at the origin", origin_error,
521 origin_scale, {1e-10, 1e-12});
523 });
524
525
526
528 "", 8, "plastic exponential directional actions", [&]() {
530 Increment t_u_coordinates;
531 Increment t_v_coordinates;
532 for (
int l = 0;
l != nbCoords; ++
l) {
533 t_u_coordinates(
l) = directions[0](
l);
534 t_v_coordinates(
l) = directions[2](
l);
535 }
536 const auto t_h =
538 const auto t_u =
540 const auto t_v =
542 SymmetricTensor t_s{0.7, -0.2, 0.1, 0.5, 0.3, -0.4};
543 PlasticExponentialDirectionalData
data;
544 CHKERR evaluatePlasticExponentialDirectionalData(t_h, t_u,
data);
545
546 constexpr double step = 2e-6;
547 SymmetricTensor t_plus_h;
548 SymmetricTensor t_minus_h;
550 for (
int j = 0;
j <=
i; ++
j) {
551 t_plus_h(
i,
j) = t_h(
i,
j) + step * t_u(
i,
j);
552 t_minus_h(
i,
j) = t_h(
i,
j) - step * t_u(
i,
j);
553 }
554 PlasticExponentialDirectionalData plus_data;
555 PlasticExponentialDirectionalData minus_data;
556 CHKERR evaluatePlasticExponentialDirectionalData(t_plus_h, t_v,
557 plus_data);
558 CHKERR evaluatePlasticExponentialDirectionalData(t_minus_h, t_v,
559 minus_data);
560
561 SymmetricTensor t_first_difference_f;
562 SymmetricTensor t_first_difference_inverse;
564 for (
int j = 0;
j <=
i; ++
j) {
565 t_first_difference_f(
i,
j) =
566 (plus_data.plasticF(
i,
j) - minus_data.plasticF(
i,
j)) /
567 (2. * step);
568 t_first_difference_inverse(
i,
j) =
569 (plus_data.inversePlasticF(
i,
j) -
570 minus_data.inversePlasticF(
i,
j)) /
571 (2. * step);
572 }
574 "D exp(H)[U]",
575 maxAbsDifference(
data.directionPlasticF, t_first_difference_f),
576 std::max(maxAbs(
data.directionPlasticF),
577 maxAbs(t_first_difference_f)),
578 {1e-10, 2e-8});
580 "D exp(-H)[U]",
581 maxAbsDifference(
data.directionInversePlasticF,
582 t_first_difference_inverse),
583 std::max(maxAbs(
data.directionInversePlasticF),
584 maxAbs(t_first_difference_inverse)),
585 {1e-10, 2e-8});
586
587 double exact_second_contraction = 0;
588 CHKERR evaluatePlasticExponentialSecondContraction(
589 t_h, t_u, t_v, t_s, exact_second_contraction);
590 double difference_second_contraction = 0;
593 difference_second_contraction +=
595 (plus_data.directionPlasticF(
i,
j) -
596 minus_data.directionPlasticF(
i,
j)) /
597 (2. * step);
599 "S:D2 exp(H)[U,V]",
600 std::abs(exact_second_contraction -
601 difference_second_contraction),
602 std::max(std::abs(exact_second_contraction),
603 std::abs(difference_second_contraction)),
604 {1e-10, 3e-8});
606 });
607
609 "", 9, "local elastic logarithmic sensitivity", [&]() {
614 const auto function = [](
const SymmetricTensor &tensor,
619 vectors(
m,
n) = tensor(
m,
n);
621 "Diagonalise local sensitivity test tensor");
623 };
625 return std::exp(x);
626 };
628 return std::exp(-x);
629 };
631 return .5 * std::log(x);
632 };
633 const std::array<SymmetricTensor, 4> elastic_logs{
634 {{0., 0., 0., 0., 0., 0.},
635 {.12, 0., 0., .12, 0., -.08},
636 {.12, 0., 0., .12 + 1e-12, 0., -.08},
637 {.18, .07, -.04, -.09, .03, .02}}};
638 const std::array<SymmetricTensor, 3> plastic_logs{
639 {{0., 0., 0., 0., 0., 0.},
640 {.1, 0., 0., .1, 0., -.2},
641 {.21, -.09, .04, -.13, .06, -.08}}};
642 double worst_error = 0.;
643 for (const auto &he : elastic_logs) {
644 const auto ue =
function(he, exp_f);
645 for (const auto &hp : plastic_logs) {
648 const auto fp =
function(hp, exp_f);
650 anchor(
i,
j) = ue(
i,
k) * fp(
k,
j);
651 for (
const auto &
source : {directions[0], directions[2]}) {
653 for (
int n = 0;
n != 5; ++
n)
655 const auto tv =
657 exact(
a) = map(
a, b) *
v(b);
658 for (const double step : {2e-5, 2e-6}) {
659 const auto evaluate = [&](double shift) {
660 SymmetricTensor trial_hp,
c;
661 trial_hp(
i,
j) = hp(
i,
j) + shift * tv(
i,
j);
668 };
669 const auto plus = evaluate(step), minus = evaluate(-step);
670 SymmetricTensor derivative;
671 derivative(
i,
j) = (plus(
i,
j) - minus(
i,
j)) / (2. * step);
672 const auto reference =
674 derivative);
675 double error = 0.;
676 for (
int n = 0;
n != 5; ++
n)
677 error = std::max(error, std::abs(exact(
n) - reference(
n)));
678 worst_error = std::max(worst_error, error);
680 "Direct Ue sensitivity vs fixed-F differences", error,
683 "Isochoric elastic logarithmic sensitivity",
684 std::abs(derivative(
i,
i)), 1., {2e-8, 2e-8});
685 }
686 }
687 }
692 double energy = 0.;
694 nullptr, &tangent);
695 for (
int n = 0;
n != 5; ++
n) {
696 constexpr double step = 2e-6;
697 Increment unit, plus, minus, gp, gm,
action;
700 plus(
a) = coordinates(
a) + step * unit(
a);
701 minus(
a) = coordinates(
a) - step * unit(
a);
704 action(
a) = tangent(
a, b) * unit(b);
705 double error = 0.;
706 for (int col = 0; col != 5; ++col)
707 error =
708 std::max(error, std::abs(
action(col) - (gp(col) - gm(col)) /
709 (2. * step)));
711 "Pure logarithmic material tangent", error,
713 }
714 }
715 SymmetricTensor zero{0., 0., 0., 0., 0., 0.};
716 SymmetricTensor identity{1., 0., 0., 1., 0., 1.};
719 map);
720 for (int row = 0; row != 5; ++row)
721 for (int col = 0; col != 5; ++col)
722 if (std::abs(map(row, col) + (row == col ? 1. : 0.)) > 1e-12)
724 "Identity elastic sensitivity is not minus identity");
726 double energy = 0.;
729 energy, nullptr, &tangent);
732 tangent_map(
a, b) = tangent(
a, d) * map(d, b);
733 estimate(
a, b) = map(d,
a) * tangent_map(d, b);
734 for (int row = 0; row != 5; ++row)
735 for (int col = 0; col != 5; ++col)
736 if (std::abs(estimate(row, col) - (row == col ? 6.8 : 0.)) >
737 1e-11)
739 "Identity local material estimate is not 2*mu*I");
741 << "Local stretch sensitivity maximum FD error " << worst_error;
743 });
744
746 }
749 return 0;
750}
SmartPetscObj< Mat > metric
boost::shared_ptr< DataAtIntegrationPts > data
PetscErrorCode(* function)(TS, PetscReal, Vec, Vec, Vec, void *)
SmartPetscObj< Vec > values
SmartPetscObj< Mat > inverse
#define FTENSOR_INDEXES(DIM,...)
#define CATCH_ERRORS
Catch errors.
#define CHK_THROW_MESSAGE(err, msg)
Check and throw MoFEM exception.
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
@ MOFEM_ATOM_TEST_INVALID
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
#define MOFEM_LOG(channel, severity)
Log.
FTensor::Index< 'i', SPACE_DIM > i
const double c
speed of light (cm/ns)
const double v
phase velocity of light in medium (cm/ns)
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
auto getMat(A &&t_val, B &&t_vec, Fun< double > f)
Get the Mat object.
PlasticLocalLawTermsT< T > evaluatePlasticLocalLawTerms(const FTensor::Tensor1< T, plasticLogarithmicStretchCoordinateSize > &t_increment, const T &latent, const PlasticLocalLawParametersT< S > &p)
constexpr double plasticEquivalentIncrementScale
MoFEMErrorCode evaluateLocalElasticLogarithmicSensitivity(const FTensor::Tensor2_symmetric< double, 3 > &plastic_h, const FTensor::Tensor2_symmetric< double, 3 > &elastic_stretch, FTensor::Tensor2< double, 5, 5 > &sensitivity)
constexpr double plasticEquivalentIncrementScaleSquared
double plasticCoordinateNorm(const FTensor::Tensor1< T, plasticLogarithmicStretchCoordinateSize > &t_values)
boost::shared_ptr< PlasticLocalLaw > createPlasticLocalLaw(boost::shared_ptr< MatOps::MatOpsData > mat_ops_data_ptr=nullptr)
FTensor::Tensor1< double, plasticLogarithmicStretchCoordinateSize > plasticLogarithmicStretchCoordinatesFromTensor(const FTensor::Tensor2_symmetric< T, SPACE_DIM > &t_values)
FTensor::Tensor2_symmetric< double, SPACE_DIM > plasticLogarithmicStretchTensorFromCoordinates(const FTensor::Tensor1< T, plasticLogarithmicStretchCoordinateSize > &t_coordinates)
static MoFEMErrorCodeGeneric< PetscErrorCode > ierr
MoFEMErrorCode computeEigenValuesSymmetric(const MatrixDouble &mat, VectorDouble &eig, MatrixDouble &eigen_vec)
compute eigenvalues of a symmetric matrix using lapack dsyev
FTensor::Index< 'm', 3 > m
static MoFEMErrorCode evaluateDeviator(const Parameters ¶meters, const Coordinates &t_deviator, double &energy, Coordinates *stress_ptr=nullptr, Tangent *hessian_ptr=nullptr)
Evaluate f(D), optionally its five-component gradient and Hessian.
static Coordinates getCoordinates(const SymmetricTensor &t_tensor)
Project a symmetric tensor onto the fixed trace-free basis.
S latentCentre
psi^k, the fixed proximal centre
S proximalCoefficient
alpha_k = c_star / omega_k > 0
S hardeningModulus
A_h >= 0.
T resistanceForce
f_r, the KKT multiplier candidate
T proximal
alpha_k Bregman term, non-negative
T slack
exp(psi) = eta - ell_eps > 0
T regularisedMagnitude
ell_eps(Delta H^p)
T density
r(eta) + proximal
static MoFEMErrorCode Initialize(int *argc, char ***args, const char file[], const char help[])
Initializes the MoFEM database PETSc, MOAB and MPI.
static MoFEMErrorCode Finalize()
Checks for options to be called at the conclusion of the program.
Deprecated interface functions.
MoFEMErrorCode checkValue(const std::string &check_name, PetscReal actual, PetscReal expected, Tolerance tolerance, Sev error_severity=Sev::error, Sev success_severity=Sev::inform) const
MoFEMErrorCode checkError(const std::string &check_name, PetscReal error, PetscReal scale, Tolerance tolerance, Sev error_severity=Sev::error, Sev success_severity=Sev::inform) const
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.