v0.16.0
Loading...
Searching...
No Matches
Classes | Public Member Functions | Public Attributes | Private Member Functions | Static Private Member Functions | Private Attributes | List of all members
EshelbianPlasticity::HMHStorakers::StressToStrech Struct Reference

Recover the right stretch from a symmetric Biot stress. More...

Collaboration diagram for EshelbianPlasticity::HMHStorakers::StressToStrech:
[legend]

Classes

struct  ScalarEquationState
 

Public Member Functions

 StressToStrech (const MaterialParameters &parameters)
 
template<typename T >
MoFEMErrorCode stressToSpectralForm (T &t_stress)
 Diagonalise sym(stress) and calculate b_i = t_i - 2 mu_1.
 
template<typename T >
MoFEMErrorCode stressToSpectralForm (T &t_stress, const double q)
 
MoFEMErrorCode calculatePrincipalStretches (const double y, ScalarEquationState &state) const
 Evaluate u_i(y), phi(y), and the exact Newton derivative.
 
MoFEMErrorCode solveScalarEquation ()
 Solve phi(y)=0 with safeguarded Newton–Brent iterations.
 
MoFEMErrorCode solveScalarEquation (const double initial_y)
 
template<typename T >
MoFEMErrorCode spectralFormToStrech (T &t_stretch) const
 Reconstruct U = Q diag(u_i) Q^T in the working basis.
 
template<typename T >
MoFEMErrorCode calculateStiffness (T &t_stiffness) const
 Calculate C = dT/dU in the working/reference coordinates.
 
template<typename T >
MoFEMErrorCode calculateCompliance (T &t_compliance) const
 Calculate S = dU/dT in the working/reference coordinates.
 
template<typename TStiffness , typename TCompliance >
MoFEMErrorCode calculateBiotTangent (TStiffness &t_stiffness, TCompliance &t_compliance) const
 Calculate stiffness and compliance in reference coordinates.
 
template<typename TStress , typename TStretch >
MoFEMErrorCode calculate (TStress &t_stress, TStretch &t_stretch)
 
template<typename TStress , typename TStretch >
MoFEMErrorCode calculate (TStress &t_stress, TStretch &t_stretch, const double q)
 
template<typename TStress , typename TStretch , typename TStiffness , typename TCompliance >
MoFEMErrorCode calculate (TStress &t_stress, TStretch &t_stretch, TStiffness &t_stiffness, TCompliance &t_compliance)
 Calculate U(T), dT/dU, and dU/dT in reference coordinates.
 
template<typename TStress , typename TStretch , typename TStiffness , typename TCompliance >
MoFEMErrorCode calculate (TStress &t_stress, TStretch &t_stretch, TStiffness &t_stiffness, TCompliance &t_compliance, const double q)
 
const ScalarEquationStategetScalarEquationState () const
 
double getJacobian () const
 
const FTensor::Tensor1< double, SPACE_DIM > & getPrincipalStress () const
 
const FTensor::Tensor1< double, SPACE_DIM > & getShiftedPrincipalStress () const
 
const FTensor::Tensor2< double, SPACE_DIM, SPACE_DIM > & getEigenVectors () const
 

Public Attributes

int maxIterations = 100
 
int maxBracketIterations = 64
 
double absoluteTolerance = 1e-12
 
double relativeTolerance = 1e-12
 

Private Member Functions

std::pair< double, doublegetSafeYBounds () const
 
bool hasConverged (const ScalarEquationState &state, const double lower_y, const double upper_y) const
 

Static Private Member Functions

static double logSumExp (const double first, const double second)
 

Private Attributes

MaterialParameters materialParameters
 
double mu1
 
double mu2
 
double externalPressure = 0
 
FTensor::Tensor1< double, SPACE_DIMtPrincipalStress
 
FTensor::Tensor2< double, SPACE_DIM, SPACE_DIMtEigenVectors
 
FTensor::Tensor1< double, SPACE_DIMtB
 
ScalarEquationState scalarState
 
int nbUniqueEigenvalues = 0
 
bool hasSpectralForm = false
 
bool hasScalarSolution = false
 

Detailed Description

Recover the right stretch from a symmetric Biot stress.

This class inverts the Storakers constitutive equation

\[ \mathbf{T} = 2\mu_1\mathbf{I} + \mu_2\mathbf{U} - (\gamma+q)\mathbf{U}^{-1}, \qquad \mu_1 = (1-\eta)\mu, \quad \mu_2 = \eta\mu, \]

by diagonalising \(\mathbf{T}=\mathbf{Q}\operatorname{diag}(t_i)\mathbf{Q}^T\). For a trial \(y=\log z\), where \(z=J^{-\beta}\), it evaluates

\[ \gamma = 2\mu_1 z + \mu_2 z^2, \qquad \gamma_{\mathrm{eff}}=\gamma+q, \qquad u_i(y) = \frac{b_i+\sqrt{b_i^2+4\mu_2\gamma_{\mathrm{eff}}}} {2\mu_2}, \qquad b_i=t_i-2\mu_1. \]

The positive-tangent \(+\) root is used. If \(\gamma_{\mathrm{eff}}<0\), it is admissible only while \(b_i>0\) and \(b_i^2+4\mu_2\gamma_{\mathrm{eff}}>0\) for every principal value.

The only nonlinear unknown is obtained with safeguarded Newton–Brent iterations from

\[ \phi(y)=\frac{y}{\beta}+\sum_i\log u_i(y)=0. \]

Finally, \(\mathbf{U}=\mathbf{Q}\operatorname{diag}(u_i)\mathbf{Q}^T\) and \(J=\exp(-y/\beta)\). The spelling "Strech" is retained to match the existing material interface.

Definition at line 343 of file HMHStorakers.cpp.

Constructor & Destructor Documentation

◆ StressToStrech()

EshelbianPlasticity::HMHStorakers::StressToStrech::StressToStrech ( const MaterialParameters parameters)
inlineexplicit

Definition at line 361 of file HMHStorakers.cpp.

362 : materialParameters(parameters),
363 mu1((1 - parameters.eta) * parameters.mu),
364 mu2(parameters.eta * parameters.mu) {
365 CHK_THROW_MESSAGE(validateParameters(parameters, "StressToStrech"),
366 "invalid Storakers parameters");
367 }
#define CHK_THROW_MESSAGE(err, msg)
Check and throw MoFEM exception.
static MoFEMErrorCode validateParameters(const MaterialParameters &parameters, const char *source)

Member Function Documentation

◆ calculate() [1/4]

template<typename TStress , typename TStretch >
MoFEMErrorCode EshelbianPlasticity::HMHStorakers::StressToStrech::calculate ( TStress &  t_stress,
TStretch &  t_stretch 
)
inline

Definition at line 936 of file HMHStorakers.cpp.

936 {
937 return calculate(t_stress, t_stretch, 0.);
938 }
MoFEMErrorCode calculate(TStress &t_stress, TStretch &t_stretch)

◆ calculate() [2/4]

template<typename TStress , typename TStretch >
MoFEMErrorCode EshelbianPlasticity::HMHStorakers::StressToStrech::calculate ( TStress &  t_stress,
TStretch &  t_stretch,
const double  q 
)
inline

Definition at line 941 of file HMHStorakers.cpp.

942 {
944 CHKERR stressToSpectralForm(t_stress, q);
946 CHKERR spectralFormToStrech(t_stretch);
948 }
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
MoFEMErrorCode stressToSpectralForm(T &t_stress)
Diagonalise sym(stress) and calculate b_i = t_i - 2 mu_1.
MoFEMErrorCode solveScalarEquation()
Solve phi(y)=0 with safeguarded Newton–Brent iterations.
MoFEMErrorCode spectralFormToStrech(T &t_stretch) const
Reconstruct U = Q diag(u_i) Q^T in the working basis.

◆ calculate() [3/4]

template<typename TStress , typename TStretch , typename TStiffness , typename TCompliance >
MoFEMErrorCode EshelbianPlasticity::HMHStorakers::StressToStrech::calculate ( TStress &  t_stress,
TStretch &  t_stretch,
TStiffness &  t_stiffness,
TCompliance &  t_compliance 
)
inline

Calculate U(T), dT/dU, and dU/dT in reference coordinates.

Definition at line 955 of file HMHStorakers.cpp.

957 {
958 return calculate(t_stress, t_stretch, t_stiffness, t_compliance, 0.);
959 }

◆ calculate() [4/4]

template<typename TStress , typename TStretch , typename TStiffness , typename TCompliance >
MoFEMErrorCode EshelbianPlasticity::HMHStorakers::StressToStrech::calculate ( TStress &  t_stress,
TStretch &  t_stretch,
TStiffness &  t_stiffness,
TCompliance &  t_compliance,
const double  q 
)
inline

Definition at line 963 of file HMHStorakers.cpp.

965 {
967 CHKERR calculate(t_stress, t_stretch, q);
968 CHKERR calculateBiotTangent(t_stiffness, t_compliance);
970 }
MoFEMErrorCode calculateBiotTangent(TStiffness &t_stiffness, TCompliance &t_compliance) const
Calculate stiffness and compliance in reference coordinates.

◆ calculateBiotTangent()

template<typename TStiffness , typename TCompliance >
MoFEMErrorCode EshelbianPlasticity::HMHStorakers::StressToStrech::calculateBiotTangent ( TStiffness &  t_stiffness,
TCompliance &  t_compliance 
) const
inline

Calculate stiffness and compliance in reference coordinates.

The output arguments can be owning Ddg tensors or MoFEM Ddg views over matD and matInvD storage.

Definition at line 927 of file HMHStorakers.cpp.

928 {
930 CHKERR calculateStiffness(t_stiffness);
931 CHKERR calculateCompliance(t_compliance);
933 }
MoFEMErrorCode calculateCompliance(T &t_compliance) const
Calculate S = dU/dT in the working/reference coordinates.
MoFEMErrorCode calculateStiffness(T &t_stiffness) const
Calculate C = dT/dU in the working/reference coordinates.

◆ calculateCompliance()

template<typename T >
MoFEMErrorCode EshelbianPlasticity::HMHStorakers::StressToStrech::calculateCompliance ( T &  t_compliance) const
inline

Calculate S = dU/dT in the working/reference coordinates.

getDiffMat applied to the inverse principal stress law gives L^{-1} already rotated from the principal basis. The second term is the exact Sherman–Morrison correction.

Definition at line 839 of file HMHStorakers.cpp.

839 {
841
842 if (!hasScalarSolution) {
843 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
844 "Call solveScalarEquation before calculateCompliance");
845 }
846
848 const int gamma_sign = scalarState.gammaEffectiveSign;
849 const double log_abs_gamma = scalarState.logAbsGammaEffective;
850 auto inverse_state = [this, gamma_sign,
851 log_abs_gamma](const double stress) {
852 const double b = stress - 2 * mu1;
853 double log_s;
854 if (gamma_sign > 0) {
855 const double log_gamma_term =
856 std::log(2.) +
857 0.5 * (std::log(mu2) + log_abs_gamma);
858 const double gamma_term = std::exp(log_gamma_term);
859 const double s = std::hypot(b, gamma_term);
860 log_s = std::log(s);
861 if (b < 0) {
862 const double log_denominator =
863 logSumExp(log_s, std::log(-b));
864 const double log_u =
865 std::log(2.) + log_abs_gamma - log_denominator;
866 return std::pair{std::exp(log_u), s};
867 }
868 } else if (gamma_sign == 0) {
869 log_s = std::log(b);
870 } else {
871 const double log_b = std::log(b);
872 const double log_ratio = std::log(4.) + std::log(mu2) +
873 log_abs_gamma - 2 * log_b;
874 log_s = log_b + 0.5 * std::log(-std::expm1(log_ratio));
875 }
876
877 const double log_b = std::log(b);
878 const double log_u =
879 logSumExp(log_b, log_s) - std::log(2.) - std::log(mu2);
880 return std::pair{std::exp(log_u), std::exp(log_s)};
881 };
882 auto inverse_stress_law = [inverse_state](const double stress) {
883 return inverse_state(stress).first;
884 };
885 auto inverse_stress_law_derivative =
886 [inverse_state](const double stress) {
887 const auto [u, s] = inverse_state(stress);
888 return u / s;
889 };
890 auto t_inverse_l = EigenMatrix::getDiffMat(
891 tPrincipalStress, tEigenVectors, inverse_stress_law,
892 inverse_stress_law_derivative, nbUniqueEigenvalues);
893
894 auto inverse_discriminant = [](const double s) { return 1 / s; };
896 inverse_discriminant);
897
898 const double alpha = materialParameters.beta * scalarState.gammaY;
899 FTensor::Tensor1<double, SPACE_DIM> t_inverse_stretch_dot_y_terms;
900 for (int aa = 0; aa != SPACE_DIM; ++aa) {
901 t_inverse_stretch_dot_y_terms(aa) =
902 1 / (scalarState.tU(aa) * scalarState.tS(aa));
903 }
904 constexpr auto t_one = FTensor::One<>();
905 const double inverse_stretch_dot_y =
906 t_inverse_stretch_dot_y_terms(i) * t_one(i);
907 const double denominator = 1 + alpha * inverse_stretch_dot_y;
908 if (!std::isfinite(denominator) || denominator <= 0) {
909 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
910 "Invalid Storakers compliance denominator");
911 }
912 const double correction = alpha / denominator;
913
914 t_compliance(i, j, k, l) =
915 t_inverse_l(i, j, k, l) - correction * t_y(i, j) * t_y(k, l);
916
918 }
#define FTENSOR_INDEXES(DIM,...)
constexpr int SPACE_DIM
Stateless vector whose components are all equal to one.
Definition One.hpp:22
@ MOFEM_DATA_INCONSISTENCY
Definition definitions.h:31
@ MOFEM_INVALID_DATA
Definition definitions.h:36
FTensor::Index< 'i', SPACE_DIM > i
FTensor::Index< 'l', 3 > l
FTensor::Index< 'j', 3 > j
FTensor::Index< 'k', 3 > k
auto getMat(A &&t_val, B &&t_vec, Fun< double > f)
Get the Mat object.
auto getDiffMat(A &&t_val, B &&t_vec, Fun< double > f, Fun< double > d_f, const int nb)
Get the Diff Mat object.
static double logSumExp(const double first, const double second)
FTensor::Tensor2< double, SPACE_DIM, SPACE_DIM > tEigenVectors
FTensor::Tensor1< double, SPACE_DIM > tPrincipalStress

◆ calculatePrincipalStretches()

MoFEMErrorCode EshelbianPlasticity::HMHStorakers::StressToStrech::calculatePrincipalStretches ( const double  y,
ScalarEquationState state 
) const
inline

Evaluate u_i(y), phi(y), and the exact Newton derivative.

Definition at line 415 of file HMHStorakers.cpp.

416 {
418
419 if (!hasSpectralForm) {
420 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
421 "Call stressToSpectralForm before evaluating the scalar "
422 "equation");
423 }
424 if (!std::isfinite(y)) {
425 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
426 "Non-finite Storakers scalar iterate");
427 }
428
429 state = {};
430 state.y = y;
432 constexpr auto t_one = FTensor::One<>();
433 const double log_minimum =
434 std::log(std::numeric_limits<double>::min());
435 const double log_maximum =
436 std::log(std::numeric_limits<double>::max());
437 const double negative_infinity =
438 -std::numeric_limits<double>::infinity();
439 const double log_linear_gamma =
440 mu1 > 0 ? std::log(2 * mu1) + y : negative_infinity;
441 const double log_quadratic_gamma = std::log(mu2) + 2 * y;
442 const double log_gamma =
443 logSumExp(log_linear_gamma, log_quadratic_gamma);
444 const double log_gamma_y = logSumExp(
445 log_linear_gamma, std::log(2 * mu2) + 2 * y);
446
447 int gamma_effective_sign = 1;
448 double log_abs_gamma_effective = log_gamma;
449 if (externalPressure > 0) {
450 log_abs_gamma_effective =
451 logSumExp(log_gamma, std::log(externalPressure));
452 } else if (externalPressure < 0) {
453 const double log_minus_q = std::log(-externalPressure);
454 if (log_gamma > log_minus_q) {
455 log_abs_gamma_effective =
456 log_gamma +
457 std::log(-std::expm1(log_minus_q - log_gamma));
458 } else if (log_gamma < log_minus_q) {
459 gamma_effective_sign = -1;
460 log_abs_gamma_effective =
461 log_minus_q +
462 std::log(-std::expm1(log_gamma - log_minus_q));
463 } else {
464 gamma_effective_sign = 0;
465 log_abs_gamma_effective = negative_infinity;
466 }
467 }
468
469 if (y > log_maximum || log_gamma > log_maximum ||
470 log_abs_gamma_effective > log_maximum ||
471 log_gamma_y > log_maximum) {
472 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
473 "Storakers scalar iterate is outside the floating-point "
474 "range");
475 }
476
477 state.z = y >= log_minimum ? std::exp(y) : 0;
478 state.gamma = log_gamma >= log_minimum ? std::exp(log_gamma) : 0;
479 state.gammaY =
480 log_gamma_y >= log_minimum ? std::exp(log_gamma_y) : 0;
481 state.q = externalPressure;
482 state.gammaEffectiveSign = gamma_effective_sign;
483 state.logAbsGammaEffective = log_abs_gamma_effective;
484 if (gamma_effective_sign &&
485 log_abs_gamma_effective >= log_minimum) {
486 state.gammaEffective =
487 gamma_effective_sign * std::exp(log_abs_gamma_effective);
488 }
489
490 const double log_two_mu2 = std::log(2.) + std::log(mu2);
491 double positive_gamma_term = 0;
492 if (gamma_effective_sign > 0) {
493 const double log_gamma_term =
494 std::log(2.) +
495 0.5 * (std::log(mu2) + log_abs_gamma_effective);
496 if (log_gamma_term > log_maximum) {
497 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
498 "Storakers principal-stretch discriminant is outside the "
499 "floating-point range");
500 }
501 positive_gamma_term =
502 log_gamma_term >= log_minimum ? std::exp(log_gamma_term) : 0;
503 }
504
505 double log_derivative_sum = negative_infinity;
506 for (int ii = 0; ii != SPACE_DIM; ++ii) {
507 double log_s = negative_infinity;
508 if (gamma_effective_sign > 0) {
509 state.tS(ii) = std::hypot(tB(ii), positive_gamma_term);
510 log_s = std::log(state.tS(ii));
511 } else if (gamma_effective_sign == 0) {
512 if (tB(ii) <= 0) {
513 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
514 "No positive stable Storakers stretch at gamma_eff=0");
515 }
516 state.tS(ii) = tB(ii);
517 log_s = std::log(tB(ii));
518 } else {
519 if (tB(ii) <= 0) {
520 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
521 "Negative Storakers gamma_eff requires positive shifted "
522 "principal stresses");
523 }
524 const double log_b = std::log(tB(ii));
525 const double log_negative_term =
526 std::log(4.) + std::log(mu2) + log_abs_gamma_effective;
527 const double log_b_squared = 2 * log_b;
528 if (!(log_negative_term < log_b_squared)) {
529 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
530 "Storakers state is outside the stable principal-stretch "
531 "branch");
532 }
533 log_s =
534 log_b +
535 0.5 * std::log(-std::expm1(log_negative_term -
536 log_b_squared));
537 state.tS(ii) = log_s >= log_minimum ? std::exp(log_s) : 0;
538 }
539 if (!std::isfinite(state.tS(ii)) || state.tS(ii) <= 0) {
540 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
541 "Invalid Storakers principal-stretch discriminant");
542 }
543
544 if (tB(ii) >= 0) {
545 const double log_b =
546 tB(ii) > 0 ? std::log(tB(ii)) : negative_infinity;
547 state.tLogU(ii) =
548 logSumExp(log_b, log_s) - log_two_mu2;
549 } else {
550 const double log_denominator =
551 logSumExp(log_s, std::log(-tB(ii)));
552 state.tLogU(ii) =
553 std::log(2.) + log_abs_gamma_effective - log_denominator;
554 }
555
556 if (!std::isfinite(state.tLogU(ii)) ||
557 state.tLogU(ii) < log_minimum ||
558 state.tLogU(ii) > log_maximum) {
559 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
560 "Invalid Storakers principal stretch");
561 }
562 state.tU(ii) = std::exp(state.tLogU(ii));
563
564 const double log_derivative_term =
565 -state.tLogU(ii) - log_s;
566 log_derivative_sum =
567 logSumExp(log_derivative_sum, log_derivative_term);
568 }
569
570 state.phi =
571 y / materialParameters.beta + state.tLogU(i) * t_one(i);
572 const double log_volumetric_derivative =
573 log_gamma_y + log_derivative_sum;
574 if (log_volumetric_derivative > log_maximum) {
575 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
576 "Invalid Storakers scalar derivative term");
577 }
578 const double volumetric_derivative =
579 log_volumetric_derivative >= log_minimum
580 ? std::exp(log_volumetric_derivative)
581 : 0;
582 state.dPhi = 1 / materialParameters.beta + volumetric_derivative;
583 if (!std::isfinite(state.phi) || !std::isfinite(state.dPhi) ||
584 state.dPhi <= 0) {
585 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
586 "Invalid Storakers scalar residual or derivative");
587 }
588
590 }
#define FTENSOR_INDEX(DIM, I)
FTensor::Tensor1< double, SPACE_DIM > tB

◆ calculateStiffness()

template<typename T >
MoFEMErrorCode EshelbianPlasticity::HMHStorakers::StressToStrech::calculateStiffness ( T &  t_stiffness) const
inline

Calculate C = dT/dU in the working/reference coordinates.

EigenMatrix::getDiffMat evaluates the derivative at fixed gamma_eff=gamma+q and rotates it from the principal basis with the stored eigenvectors. The rank-one term adds the variation of J, z and material gamma; prescribed q has zero derivative.

Definition at line 799 of file HMHStorakers.cpp.

799 {
801
802 if (!hasScalarSolution) {
803 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
804 "Call solveScalarEquation before calculateStiffness");
805 }
806
808 const double gamma = scalarState.gammaEffective;
809 auto principal_stress = [this, gamma](const double u) {
810 return 2 * mu1 + mu2 * u - gamma / u;
811 };
812 auto principal_stiffness = [this, gamma](const double u) {
813 return mu2 + (gamma / u) / u;
814 };
815 auto t_frozen_gamma_stiffness = EigenMatrix::getDiffMat(
816 scalarState.tU, tEigenVectors, principal_stress,
817 principal_stiffness, nbUniqueEigenvalues);
818
819 auto inverse_stretch = [](const double u) { return 1 / u; };
820 auto t_inverse_stretch = EigenMatrix::getMat(
821 scalarState.tU, tEigenVectors, inverse_stretch);
822 const double alpha = materialParameters.beta * scalarState.gammaY;
823
824 t_stiffness(i, j, k, l) =
825 t_frozen_gamma_stiffness(i, j, k, l) +
826 alpha * t_inverse_stretch(i, j) * t_inverse_stretch(k, l);
827
829 }

◆ getEigenVectors()

const FTensor::Tensor2< double, SPACE_DIM, SPACE_DIM > & EshelbianPlasticity::HMHStorakers::StressToStrech::getEigenVectors ( ) const
inline

Definition at line 990 of file HMHStorakers.cpp.

990 {
991 return tEigenVectors;
992 }

◆ getJacobian()

double EshelbianPlasticity::HMHStorakers::StressToStrech::getJacobian ( ) const
inline

◆ getPrincipalStress()

const FTensor::Tensor1< double, SPACE_DIM > & EshelbianPlasticity::HMHStorakers::StressToStrech::getPrincipalStress ( ) const
inline

Definition at line 980 of file HMHStorakers.cpp.

980 {
981 return tPrincipalStress;
982 }

◆ getSafeYBounds()

std::pair< double, double > EshelbianPlasticity::HMHStorakers::StressToStrech::getSafeYBounds ( ) const
inlineprivate

Definition at line 1012 of file HMHStorakers.cpp.

1012 {
1013 const double safety_margin = std::log(16.);
1014 const double log_maximum =
1015 std::log(std::numeric_limits<double>::max()) - safety_margin;
1016
1017 // gamma, gammaY, and z may safely underflow to zero because the scalar
1018 // residual is evaluated from their logarithms. The lower limit instead
1019 // keeps J = exp(-y/beta) representable.
1020 double lower_y = -materialParameters.beta * log_maximum;
1021 if (externalPressure < 0) {
1022 const double negative_infinity =
1023 -std::numeric_limits<double>::infinity();
1024 const double log_minus_q = std::log(-externalPressure);
1025 bool all_shifted_stresses_positive = true;
1026 double minimum_shifted_stress = std::numeric_limits<double>::max();
1027 for (int ii = 0; ii != SPACE_DIM; ++ii) {
1028 if (tB(ii) <= 0) {
1029 all_shifted_stresses_positive = false;
1030 break;
1031 }
1032 minimum_shifted_stress =
1033 std::min(minimum_shifted_stress, tB(ii));
1034 }
1035
1036 double log_required_gamma = log_minus_q;
1037 if (all_shifted_stresses_positive) {
1038 const double log_spinodal_magnitude =
1039 2 * std::log(minimum_shifted_stress) -
1040 std::log(4.) - std::log(mu2);
1041 if (log_spinodal_magnitude > log_minus_q) {
1042 log_required_gamma = negative_infinity;
1043 } else if (log_spinodal_magnitude == log_minus_q) {
1044 log_required_gamma =
1045 log_minus_q +
1046 std::log(64 * std::numeric_limits<double>::epsilon());
1047 } else {
1048 log_required_gamma =
1049 log_minus_q +
1050 std::log(-std::expm1(log_spinodal_magnitude - log_minus_q));
1051 }
1052 }
1053
1054 if (std::isfinite(log_required_gamma)) {
1055 const double log_mu1 =
1056 mu1 > 0 ? std::log(mu1) : negative_infinity;
1057 const double log_sqrt_discriminant =
1058 0.5 * logSumExp(2 * log_mu1,
1059 std::log(mu2) + log_required_gamma);
1060 const double log_denominator =
1061 logSumExp(log_mu1, log_sqrt_discriminant);
1062 const double boundary_y =
1063 log_required_gamma - log_denominator;
1064 const double boundary_margin =
1065 64 * std::numeric_limits<double>::epsilon() *
1066 std::max(1., std::abs(boundary_y));
1067 lower_y = std::max(lower_y, boundary_y + boundary_margin);
1068 }
1069 }
1070
1071 double upper_y = log_maximum;
1072 const int active_terms = mu1 > 0 ? 2 : 1;
1073 const double log_term_maximum =
1074 log_maximum - std::log(static_cast<double>(active_terms));
1075
1076 // Bound gammaY, whose quadratic coefficient is the largest coefficient
1077 // used by gamma and gammaY.
1078 if (mu1 > 0) {
1079 upper_y = std::min(
1080 upper_y, log_term_maximum - std::log(2 * mu1));
1081 }
1082 upper_y = std::min(
1083 upper_y,
1084 0.5 * (log_term_maximum - std::log(2 * mu2)));
1085
1086 // Also reserve enough range for 2*sqrt(mu2*gamma), which enters the
1087 // principal-stretch discriminant.
1088 const double log_gamma_effective_limit = std::min(
1089 log_maximum,
1090 2 * (log_maximum - std::log(2.)) - std::log(mu2));
1091 double log_gamma_limit = log_gamma_effective_limit;
1092 if (externalPressure > 0) {
1093 const double log_q = std::log(externalPressure);
1094 if (log_q >= log_gamma_effective_limit) {
1095 return {1., 0.};
1096 }
1097 log_gamma_limit =
1098 log_gamma_effective_limit +
1099 std::log(-std::expm1(log_q - log_gamma_effective_limit));
1100 }
1101 const double log_gamma_term_limit =
1102 log_gamma_limit - std::log(static_cast<double>(active_terms));
1103 if (mu1 > 0) {
1104 upper_y = std::min(
1105 upper_y, log_gamma_term_limit - std::log(2 * mu1));
1106 }
1107 upper_y = std::min(
1108 upper_y,
1109 0.5 * (log_gamma_term_limit - std::log(mu2)));
1110
1111 return {lower_y, upper_y};
1112 }

◆ getScalarEquationState()

const ScalarEquationState & EshelbianPlasticity::HMHStorakers::StressToStrech::getScalarEquationState ( ) const
inline

Definition at line 972 of file HMHStorakers.cpp.

972 {
973 return scalarState;
974 }

◆ getShiftedPrincipalStress()

const FTensor::Tensor1< double, SPACE_DIM > & EshelbianPlasticity::HMHStorakers::StressToStrech::getShiftedPrincipalStress ( ) const
inline

Definition at line 985 of file HMHStorakers.cpp.

985 {
986 return tB;
987 }

◆ hasConverged()

bool EshelbianPlasticity::HMHStorakers::StressToStrech::hasConverged ( const ScalarEquationState state,
const double  lower_y,
const double  upper_y 
) const
inlineprivate

Definition at line 1114 of file HMHStorakers.cpp.

1115 {
1116 const double y_scale = std::max(1., std::abs(state.y));
1117 const double y_tolerance =
1119 return std::abs(state.phi) <= absoluteTolerance ||
1120 std::abs(upper_y - lower_y) <= y_tolerance;
1121 }

◆ logSumExp()

static double EshelbianPlasticity::HMHStorakers::StressToStrech::logSumExp ( const double  first,
const double  second 
)
inlinestaticprivate

Definition at line 1000 of file HMHStorakers.cpp.

1000 {
1001 if (first == -std::numeric_limits<double>::infinity()) {
1002 return second;
1003 }
1004 if (second == -std::numeric_limits<double>::infinity()) {
1005 return first;
1006 }
1007 const double maximum = std::max(first, second);
1008 const double minimum = std::min(first, second);
1009 return maximum + std::log1p(std::exp(minimum - maximum));
1010 }

◆ solveScalarEquation() [1/2]

MoFEMErrorCode EshelbianPlasticity::HMHStorakers::StressToStrech::solveScalarEquation ( )
inline

Solve phi(y)=0 with safeguarded Newton–Brent iterations.

The last converged value is used as the initial guess, which allows one instance to be reused over a sequence of nearby quadrature-point states.

Definition at line 598 of file HMHStorakers.cpp.

598 {
600 const auto [safe_lower_y, safe_upper_y] = getSafeYBounds();
601 if (!(safe_lower_y < safe_upper_y)) {
602 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
603 "No admissible Storakers scalar interval for q=%.16g",
605 }
607 std::clamp(scalarState.y, safe_lower_y, safe_upper_y));
609 }
std::pair< double, double > getSafeYBounds() const

◆ solveScalarEquation() [2/2]

MoFEMErrorCode EshelbianPlasticity::HMHStorakers::StressToStrech::solveScalarEquation ( const double  initial_y)
inline

Definition at line 611 of file HMHStorakers.cpp.

611 {
613
614 if (!hasSpectralForm) {
615 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
616 "Call stressToSpectralForm before solveScalarEquation");
617 }
618
619 const auto [safe_lower_y, safe_upper_y] = getSafeYBounds();
620 if (!(safe_lower_y < safe_upper_y)) {
621 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
622 "No admissible Storakers scalar interval for q=%.16g",
624 }
625 if (!std::isfinite(initial_y) || initial_y < safe_lower_y ||
626 initial_y > safe_upper_y) {
627 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
628 "Initial Storakers scalar iterate %.16g is outside the safe "
629 "interval [%.16g, %.16g]",
630 initial_y, safe_lower_y, safe_upper_y);
631 }
632
633 ScalarEquationState initial;
635 if (std::abs(initial.phi) <= absoluteTolerance) {
637 hasScalarSolution = true;
639 }
640
641 double lower_y = initial_y;
642 double upper_y = initial_y;
643 ScalarEquationState lower = initial;
644 ScalarEquationState upper = initial;
645 double bracket_step = 1;
646 bool bracketed = false;
647 double bracket_endpoint_y = initial_y;
648 constexpr double bracket_growth_factor = 1.5;
649
650 for (int iteration = 0; iteration < maxBracketIterations; ++iteration) {
651 const bool search_lower = initial.phi > 0;
652 const double available_distance =
653 search_lower ? bracket_endpoint_y - safe_lower_y
654 : safe_upper_y - bracket_endpoint_y;
655 if (available_distance <= 0) {
656 break;
657 }
658
659 const double increment = std::min(bracket_step, available_distance);
660 const double candidate_y =
661 bracket_endpoint_y + (search_lower ? -increment : increment);
662 if (candidate_y == bracket_endpoint_y) {
663 break;
664 }
665
666 ScalarEquationState candidate;
667 CHKERR calculatePrincipalStretches(candidate_y, candidate);
668 if (initial.phi > 0) {
669 lower_y = candidate_y;
670 lower = candidate;
671 upper_y = initial_y;
672 upper = initial;
673 bracketed = lower.phi <= 0;
674 } else {
675 lower_y = initial_y;
676 lower = initial;
677 upper_y = candidate_y;
678 upper = candidate;
679 bracketed = upper.phi >= 0;
680 }
681 if (bracketed) {
682 break;
683 }
684 bracket_endpoint_y = candidate_y;
685 bracket_step *= bracket_growth_factor;
686 }
687
688 if (!bracketed) {
689 SETERRQ(PETSC_COMM_SELF, MOFEM_OPERATION_UNSUCCESSFUL,
690 "Could not bracket the Storakers scalar root inside the safe "
691 "interval [%.16g, %.16g]",
692 safe_lower_y, safe_upper_y);
693 }
694
695 double current_y =
696 std::abs(lower.phi) < std::abs(upper.phi) ? lower_y : upper_y;
697 ScalarEquationState current =
698 std::abs(lower.phi) < std::abs(upper.phi) ? lower : upper;
699 double history_y = std::numeric_limits<double>::quiet_NaN();
700 double history_phi = std::numeric_limits<double>::quiet_NaN();
701
702 for (int iteration = 0; iteration < maxIterations; ++iteration) {
703 if (hasConverged(current, lower_y, upper_y)) {
704 scalarState = current;
705 hasScalarSolution = true;
707 }
708
709 const double width = upper_y - lower_y;
710 const double guard = 0.05 * width;
711 auto is_safely_bracketed = [&](const double candidate) {
712 return std::isfinite(candidate) && candidate > lower_y + guard &&
713 candidate < upper_y - guard;
714 };
715
716 // First use the exact derivative from Section 3.2.
717 double candidate_y = current_y - current.phi / current.dPhi;
718 bool accepted = is_safely_bracketed(candidate_y) &&
719 std::abs(candidate_y - current_y) <= 0.5 * width;
720
721 // Brent inverse quadratic interpolation, when three distinct residual
722 // values are available.
723 if (!accepted && std::isfinite(history_phi) && lower.phi != upper.phi &&
724 lower.phi != history_phi && upper.phi != history_phi) {
725 candidate_y =
726 lower_y * upper.phi * history_phi /
727 ((lower.phi - upper.phi) * (lower.phi - history_phi)) +
728 upper_y * lower.phi * history_phi /
729 ((upper.phi - lower.phi) * (upper.phi - history_phi)) +
730 history_y * lower.phi * upper.phi /
731 ((history_phi - lower.phi) * (history_phi - upper.phi));
732 accepted = is_safely_bracketed(candidate_y);
733 }
734
735 // Brent secant interpolation, followed by the bisection safeguard.
736 if (!accepted && lower.phi != upper.phi) {
737 candidate_y = upper_y - upper.phi * (upper_y - lower_y) /
738 (upper.phi - lower.phi);
739 accepted = is_safely_bracketed(candidate_y);
740 }
741 if (!accepted) {
742 candidate_y = 0.5 * (lower_y + upper_y);
743 }
744
745 ScalarEquationState candidate;
746 CHKERR calculatePrincipalStretches(candidate_y, candidate);
747 history_y = current_y;
748 history_phi = current.phi;
749
750 if (candidate.phi <= 0) {
751 lower_y = candidate_y;
752 lower = candidate;
753 } else {
754 upper_y = candidate_y;
755 upper = candidate;
756 }
757
758 current_y = candidate_y;
759 current = candidate;
760 }
761
762 SETERRQ(PETSC_COMM_SELF, MOFEM_OPERATION_UNSUCCESSFUL,
763 "Storakers Newton--Brent solver did not converge in %d "
764 "iterations",
767 }
void initial(double P1[], double P2[], double P3[], double c[], const int N)
Definition acoustic.cpp:9
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
@ MOFEM_OPERATION_UNSUCCESSFUL
Definition definitions.h:34
MoFEMErrorCode calculatePrincipalStretches(const double y, ScalarEquationState &state) const
Evaluate u_i(y), phi(y), and the exact Newton derivative.
bool hasConverged(const ScalarEquationState &state, const double lower_y, const double upper_y) const
double width
Width of Gaussian distribution.

◆ spectralFormToStrech()

template<typename T >
MoFEMErrorCode EshelbianPlasticity::HMHStorakers::StressToStrech::spectralFormToStrech ( T &  t_stretch) const
inline

Reconstruct U = Q diag(u_i) Q^T in the working basis.

Definition at line 773 of file HMHStorakers.cpp.

773 {
775
776 if (!hasScalarSolution) {
777 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
778 "Call solveScalarEquation before spectralFormToStrech");
779 }
780
782 auto identity = [](const double u) { return u; };
783 auto t_reconstructed_stretch =
785 t_stretch(i, j) = t_reconstructed_stretch(i, j);
786
788 }

◆ stressToSpectralForm() [1/2]

template<typename T >
MoFEMErrorCode EshelbianPlasticity::HMHStorakers::StressToStrech::stressToSpectralForm ( T &  t_stress)
inline

Diagonalise sym(stress) and calculate b_i = t_i - 2 mu_1.

Definition at line 372 of file HMHStorakers.cpp.

372 {
373 return stressToSpectralForm(t_stress, 0.);
374 }

◆ stressToSpectralForm() [2/2]

template<typename T >
MoFEMErrorCode EshelbianPlasticity::HMHStorakers::StressToStrech::stressToSpectralForm ( T &  t_stress,
const double  q 
)
inline

Definition at line 377 of file HMHStorakers.cpp.

377 {
379
380 if (!std::isfinite(q)) {
381 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
382 "Storakers external pressure q must be finite");
383 }
385
387 tEigenVectors(i, j) =
388 0.5 * (t_stress(i, j) + t_stress(j, i));
389
390 for (int ii = 0; ii != SPACE_DIM; ++ii) {
391 for (int jj = 0; jj != SPACE_DIM; ++jj) {
392 if (!std::isfinite(tEigenVectors(ii, jj))) {
393 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
394 "Storakers Biot stress contains a non-finite value");
395 }
396 }
397 }
398
400 nbUniqueEigenvalues = getUniqNb<SPACE_DIM>(tPrincipalStress);
402 CHKERR sortEigenVals<SPACE_DIM>(tPrincipalStress, tEigenVectors);
403 }
404 tB(i) = tPrincipalStress(i) - 2 * mu1;
405
406 hasSpectralForm = true;
407 hasScalarSolution = false;
409 }
MoFEMErrorCode computeEigenValuesSymmetric(const MatrixDouble &mat, VectorDouble &eig, MatrixDouble &eigen_vec)
compute eigenvalues of a symmetric matrix using lapack dsyev

Member Data Documentation

◆ absoluteTolerance

double EshelbianPlasticity::HMHStorakers::StressToStrech::absoluteTolerance = 1e-12

Definition at line 996 of file HMHStorakers.cpp.

◆ externalPressure

double EshelbianPlasticity::HMHStorakers::StressToStrech::externalPressure = 0
private

Definition at line 1126 of file HMHStorakers.cpp.

◆ hasScalarSolution

bool EshelbianPlasticity::HMHStorakers::StressToStrech::hasScalarSolution = false
private

Definition at line 1133 of file HMHStorakers.cpp.

◆ hasSpectralForm

bool EshelbianPlasticity::HMHStorakers::StressToStrech::hasSpectralForm = false
private

Definition at line 1132 of file HMHStorakers.cpp.

◆ materialParameters

MaterialParameters EshelbianPlasticity::HMHStorakers::StressToStrech::materialParameters
private

Definition at line 1123 of file HMHStorakers.cpp.

◆ maxBracketIterations

int EshelbianPlasticity::HMHStorakers::StressToStrech::maxBracketIterations = 64

Definition at line 995 of file HMHStorakers.cpp.

◆ maxIterations

int EshelbianPlasticity::HMHStorakers::StressToStrech::maxIterations = 100

Definition at line 994 of file HMHStorakers.cpp.

◆ mu1

double EshelbianPlasticity::HMHStorakers::StressToStrech::mu1
private

Definition at line 1124 of file HMHStorakers.cpp.

◆ mu2

double EshelbianPlasticity::HMHStorakers::StressToStrech::mu2
private

Definition at line 1125 of file HMHStorakers.cpp.

◆ nbUniqueEigenvalues

int EshelbianPlasticity::HMHStorakers::StressToStrech::nbUniqueEigenvalues = 0
private

Definition at line 1131 of file HMHStorakers.cpp.

◆ relativeTolerance

double EshelbianPlasticity::HMHStorakers::StressToStrech::relativeTolerance = 1e-12

Definition at line 997 of file HMHStorakers.cpp.

◆ scalarState

ScalarEquationState EshelbianPlasticity::HMHStorakers::StressToStrech::scalarState
private

Definition at line 1130 of file HMHStorakers.cpp.

◆ tB

FTensor::Tensor1<double, SPACE_DIM> EshelbianPlasticity::HMHStorakers::StressToStrech::tB
private

Definition at line 1129 of file HMHStorakers.cpp.

◆ tEigenVectors

FTensor::Tensor2<double, SPACE_DIM, SPACE_DIM> EshelbianPlasticity::HMHStorakers::StressToStrech::tEigenVectors
private

Definition at line 1128 of file HMHStorakers.cpp.

◆ tPrincipalStress

FTensor::Tensor1<double, SPACE_DIM> EshelbianPlasticity::HMHStorakers::StressToStrech::tPrincipalStress
private

Definition at line 1127 of file HMHStorakers.cpp.


The documentation for this struct was generated from the following file: