13MoFEMErrorCode checkNear(
const double actual,
const double expected,
14 const double tolerance,
const char *label) {
16 if (!std::isfinite(actual) ||
17 std::abs(actual - expected) >
18 tolerance * std::max(1., std::abs(expected)))
20 "%s: expected %.16e, obtained %.16e", label, expected, actual);
26 const double tolerance,
const char *label) {
30 for (
int aa = 0; aa != 5; ++aa)
31 scale = std::max(
scale, std::abs(expected(aa)));
33 t_error(
A) = (actual(
A) - expected(
A)) /
scale;
34 CHKERR checkNear(std::sqrt(t_error(
A) * t_error(
A)), 0., tolerance, label);
39 const double tolerance,
45 t_error(
A,
B) = t_matrix(
A,
B) - t_matrix(
B,
A);
46 CHKERR checkNear(std::sqrt(t_error(
A,
B) * t_error(
A,
B)), 0.,
48 std::max(1., std::sqrt(t_matrix(
A,
B) * t_matrix(
A,
B))),
51 t_eigen_vectors(
A,
B) = t_matrix(
A,
B);
54 for (
int aa = 0; aa != 5; ++aa)
55 if (!std::isfinite(t_eigen_values(aa)) || t_eigen_values(aa) <= 0.)
57 "%s: eigenvalue %d is %.16e", label, aa, t_eigen_values(aa));
62 const double tolerance) {
75 CHKERR checkNear(energy, 0., tolerance,
"reference deviatoric energy");
76 CHKERR checkCoordinates(t_stress, t_zero, tolerance,
"reference stress");
82 "reference conjugate energy");
85 t_error(
A,
B) = t_hessian(
A,
B) - 4. * parameters.
c10 * t_delta(
A,
B);
86 CHKERR checkNear(std::sqrt(t_error(
A,
B) * t_error(
A,
B)), 0., tolerance,
90 CHKERR checkNear(std::sqrt(t_error(
A,
B) * t_error(
A,
B)), 0., tolerance,
91 "reference compliance");
95 CHKERR checkNear(volume.
jacobian, 1., tolerance,
"reference Jacobian");
96 CHKERR checkNear(volume.
energy, 0., tolerance,
"reference volume energy");
98 "reference volume derivative");
100 "reference volume Hessian");
103 tolerance,
"unprojected compressed volume Hessian");
107 {parameters.
c10, std::numeric_limits<double>::denorm_min()}, 709.7,
110 "large finite volume energy");
112 tolerance,
"large finite volume Hessian");
114 for (
int aa = 0; aa != 5; ++aa) {
116 t_coordinate(
A) = 0.;
117 t_coordinate(aa) = 1.;
119 CHKERR checkNear(t_basis(
i,
i), 0., tolerance,
"basis trace");
120 CHKERR checkNear(t_basis(
i,
j) * t_basis(
i,
j), 1., tolerance,
121 "basis Frobenius norm");
123 tolerance,
"basis coordinate round trip");
124 for (
int bb = 0; bb != aa; ++bb) {
125 t_coordinate(
A) = 0.;
126 t_coordinate(bb) = 1.;
128 CHKERR checkNear(t_basis(
i,
j) * t_other_basis(
i,
j), 0., tolerance,
129 "orthogonal tensor coordinates");
132 const FTensor::Tensor2<double, 3, 3> t_full(2., 3., 1., -1., -1., 4., 5., 0.,
134 const auto t_projected =
135 MoFEM::Tensor2SymmetricDeviatorBasis::getCoordinates(t_full);
136 const double sqrt_two = std::sqrt(2.);
138 sqrt_two, 3. * sqrt_two,
140 CHKERR checkCoordinates(t_projected, t_expected, tolerance,
141 "full tensor symmetric deviatoric projection");
142 CHKERR checkNear(t_projected(
A) * t_projected(
A), 34., tolerance,
143 "full tensor projected Frobenius norm");
149 const double fd_step,
150 const double tolerance) {
166 "inverse round trip");
168 "inverse material energy");
170 t_stress(
A) * t_deviator(
A), tolerance,
"Fenchel identity");
174 CHKERR checkNear(gap, 0., tolerance,
"zero gap at the material copy");
175 CHKERR checkPositiveSymmetric(t_hessian, tolerance,
"deviatoric Hessian");
180 t_inverse_error(
A,
B) =
182 CHKERR checkNear(std::sqrt(t_inverse_error(
A,
B) * t_inverse_error(
A,
B)), 0.,
183 tolerance,
"Hessian-compliance product");
186 const double direction_norm = std::sqrt(t_direction(
B) * t_direction(
B));
187 t_direction(
A) = t_direction(
A) / direction_norm;
191 t_commutator(
i,
j) = t_d(
i,
k) * t_v(
k,
j) - t_v(
i,
k) * t_d(
k,
j);
192 if (std::sqrt(t_deviator(
A) * t_deviator(
A)) > 0.01 &&
193 std::sqrt(t_commutator(
i,
j) * t_commutator(
i,
j)) < 1.e-3)
195 "Material derivative test direction must be noncoaxial");
198 t_plus(
A) = t_deviator(
A) + fd_step * t_direction(
A);
199 t_minus(
A) = t_deviator(
A) - fd_step * t_direction(
A);
200 double energy_plus, energy_minus;
205 CHKERR checkNear((energy_plus - energy_minus) / (2. * fd_step),
206 t_stress(
A) * t_direction(
A), tolerance,
207 "energy directional derivative");
209 t_fd(
A) = (t_stress_plus(
A) - t_stress_minus(
A)) / (2. * fd_step);
210 t_exact(
A) = t_hessian(
A,
B) * t_direction(
B);
211 CHKERR checkCoordinates(t_fd, t_exact, tolerance,
212 "forward stress directional derivative");
214 t_plus(
A) = t_stress(
A) + fd_step * t_direction(
A);
215 t_minus(
A) = t_stress(
A) - fd_step * t_direction(
A);
223 CHKERR checkCoordinates(t_fd, t_exact, tolerance,
224 "inverse noncoaxial directional derivative");
228 t_deviator(
A) * t_direction(
A), tolerance,
229 "conjugate energy directional derivative");
230 t_plus(
A) = t_deviator(
A) + 0.2 * t_direction(
A);
235 "Distinct material copies must have a positive Fenchel gap");
240 const double fd_step,
241 const double tolerance) {
248 for (
const auto &diagonal : {std::array<double, 3>{0., 0., 0.},
250 {0.12, 0.120000001, -0.240000001},
251 {0.3, -0.12, -0.18}}) {
253 t_diagonal(
i,
j) = 0.;
254 for (
int aa = 0; aa != 3; ++aa)
255 t_diagonal(aa, aa) = diagonal[aa];
257 CHKERR checkMaterialState(parameters, t_coordinates, fd_step, tolerance);
259 t_rotated_left(
i,
j) = t_rotation(
i,
k) * t_diagonal(
k,
j);
261 t_rotated(
i,
j) = (t_rotated_left(
i,
k) * t_rotation(
j,
k) ||
262 t_rotated_left(
j,
k) * t_rotation(
i,
k)) /
265 CHKERR checkMaterialState(parameters, t_rotated_coordinates, fd_step,
269 double energy, rotated_energy;
273 rotated_energy, &t_rotated_stress);
274 CHKERR checkNear(rotated_energy, energy, tolerance,
275 "rotation-invariant energy");
277 t_rotated_left(
i,
j) = t_rotation(
i,
k) * t_s(
k,
j);
278 t_rotated(
i,
j) = (t_rotated_left(
i,
k) * t_rotation(
j,
k) ||
279 t_rotated_left(
j,
k) * t_rotation(
i,
k)) /
281 CHKERR checkCoordinates(t_rotated_stress,
283 "rotated material stress");
289 const double fd_step,
290 const double tolerance) {
295 std::array<double, 3> diagonal;
297 std::array<double, 3> piola;
299 const std::array<Reference, 3> references{
302 {3.63220735658965, 3.63220735658965, 3.63220735658965}},
305 {3.03780092210880, 1.14937771717195, 1.74058832297094}},
306 {{-0.3, 0.12, -0.02},
308 {-3.68584071124042, 0.0674874416521112, -1.15285500880558}}}};
309 for (
const auto &reference : references) {
312 for (
int aa = 0; aa != 3; ++aa)
313 t_h(aa, aa) = reference.diagonal[aa];
314 const double theta = t_h(
i,
i);
318 t_error(
i,
j) = t_reconstructed(
i,
j) - t_h(
i,
j);
319 CHKERR checkNear(std::sqrt(t_error(
i,
j) * t_error(
i,
j)), 0., tolerance,
320 "reconstructed logarithmic stretch");
329 CHKERR checkNear(energy + volume.
energy, reference.energy, tolerance,
330 "independent forward energy");
332 for (
int aa = 0; aa != 3; ++aa)
334 std::exp(reference.diagonal[aa]),
335 reference.piola[aa], tolerance,
336 "independent principal Piola stress");
338 (volume_plus.
energy - volume_minus.
energy) / (2. * fd_step),
349 const double tolerance) {
353 for (
const double scale : {1.e4, 1.e8, 1.e100, 1.e200}) {
355 t_stress(
A) =
scale * t_direction(
A);
361 energy, &t_recovered);
362 CHKERR checkCoordinates(t_recovered, t_stress, tolerance,
363 "large finite stress round trip");
365 "large finite stress inverse residual");
368 "large stress Fenchel identity");
374 const double tolerance) {
382 const double norm_squared = t_deviator(
A) * t_deviator(
A);
383 const double mu = 2. * parameters.
c10;
384 CHKERR checkNear(energy / (
mu * norm_squared), 1., tolerance,
385 "small-deviator relative energy");
386 t_error(
A) = t_stress(
A) / (2. *
mu) - t_deviator(
A);
387 CHKERR checkNear(std::sqrt((t_error(
A) * t_error(
A)) / norm_squared), 0.,
388 tolerance,
"small-deviator relative stress");
399 CHKERR checkNear(energy / 8.56694110570638e307, 1., tolerance,
400 "finite energy despite large exponential term");
403 CHKERR checkNear(energy / 1.e-92, 1., tolerance,
404 "finite energy despite tiny squared strain");
409 CHKERR checkNear(t_stress(0) / 1.7163010440184161e308, 1., tolerance,
410 "finite projected principal stress");
411 CHKERR checkNear(t_stress(1) / 9.909068697744685e307, 1., tolerance,
412 "finite projected second stress coordinate");
417 const double tolerance) {
423 double previous_condition = 0.;
424 for (
const double amplitude : {0., 1., 2.}) {
426 t_diagonal(
i,
j) = 0.;
427 t_diagonal(0, 0) = -amplitude;
428 t_diagonal(1, 1) = -amplitude;
429 t_diagonal(2, 2) = 2. * amplitude;
438 "conditioned inverse round trip");
440 std::exp(2. * amplitude) / (4. * parameters.
c10),
441 tolerance,
"repeated-plane shear compliance");
446 const double condition = t_eigen_values(4) / t_eigen_values(0);
447 if (!std::isfinite(condition) || condition <= previous_condition)
449 "Expected increasing compliance condition, got %.16e", condition);
450 CHKERR PetscPrintf(PETSC_COMM_WORLD,
451 "Auxiliary inverse a=%.1f: compliance condition %.8e\n",
452 amplitude, condition);
453 previous_condition = condition;
460 const double infinity = std::numeric_limits<double>::infinity();
461 const double nan = std::numeric_limits<double>::quiet_NaN();
464 {parameters.
c10, 0.},
465 {parameters.
c10, -1.},
467 {parameters.
c10, infinity}}) {
468 CHKERR PetscPushErrorHandler(PetscReturnErrorHandler,
nullptr);
470 CHKERR PetscPopErrorHandler();
473 "Invalid material parameters were accepted");
479 CHKERR PetscPushErrorHandler(PetscReturnErrorHandler,
nullptr);
480 const auto inverse_error =
482 const auto forward_error =
484 const auto volume_error =
486 CHKERR PetscPopErrorHandler();
487 if (!inverse_error || !forward_error || !volume_error)
489 "Non-finite material input was accepted");
496 "Neo-Hookean auxiliary logarithmic stress material atom.\n"
497 "Use -json_config neohookean_auxiliary_log_stress_atom.json.\n";
499int main(
int argc,
char *argv[]) {
508 CHKERR meshsets_manager->addMeshset(
BLOCKSET, 1001,
"MAT_NEOHOOKEAN");
509 CHKERR meshsets_manager->setMeshsetFromFile();
512 if (block.size() != 2 || !block.count(
"c10") || !block.count(
"k"))
514 "Atom requires MAT_NEOHOOKEAN JSON block 1001 with c10,k");
517 CHKERR checkNear(parameters.c10, 1.7, 1.e-14,
"reference C10");
518 CHKERR checkNear(parameters.bulkModulus, 8.5, 1.e-14,
"reference K");
519 PetscReal fd_step = 0., tolerance = 0.;
523 &tolerance,
nullptr);
524 if (!std::isfinite(fd_step) || fd_step <= 0. || !std::isfinite(tolerance) ||
527 "Atom requires positive finite JSON finite-difference settings");
528 CHKERR checkReference(parameters, tolerance);
529 CHKERR checkReference({parameters.c10, 0.1}, tolerance);
530 CHKERR checkSpectralStates(parameters, fd_step, tolerance);
531 CHKERR checkForwardReferences(parameters, fd_step, tolerance);
532 CHKERR checkLargeStress(parameters, tolerance);
533 CHKERR checkSmallDeviator(parameters, tolerance);
534 CHKERR checkEnergyScaling(tolerance);
535 CHKERR checkConditioning(parameters, tolerance);
536 CHKERR checkInvalidInputs(parameters);
539 "Neo-Hookean auxiliary logarithmic stress atom passed\n");
Neo-Hookean material law in orthonormal logarithmic coordinates.
#define CATCH_ERRORS
Catch errors.
#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.
FTensor::Index< 'i', SPACE_DIM > i
FTensor::Index< 'j', 3 > j
FTensor::Index< 'k', 3 > k
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
implementation of Data Operators for Forces and Sources
PetscErrorCode PetscOptionsGetReal(PetscOptions *, const char pre[], const char name[], PetscReal *dval, PetscBool *set)
MoFEMErrorCode computeEigenValuesSymmetric(const MatrixDouble &mat, VectorDouble &eig, MatrixDouble &eigen_vec)
compute eigenvalues of a symmetric matrix using lapack dsyev
Coordinates tMaterialDeviator
double inverseResidual
Sum of principal logarithms before projection.
double firstDerivative
d[g(exp(theta))]/d theta
double secondDerivative
d2[g(exp(theta))]/d theta2
static MoFEMErrorCode evaluateInverse(const Parameters ¶meters, const Coordinates &t_stress, InverseState &state)
Recover Dm(Td), its compliance and conjugate energy; no state is cached.
static MoFEMErrorCode validateParameters(const Parameters ¶meters)
Check finite, strictly positive C10, K and representable mu = 2*C10.
static SymmetricTensor getTensor(const Coordinates &t_coordinates, double theta=0.)
Reconstruct H = D + theta*I/3 from the fixed five-coordinate basis.
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 MoFEMErrorCode evaluateFenchelGap(const Parameters ¶meters, const Coordinates &t_deviator, const Coordinates &t_stress, const InverseState &inverse, double &gap, double *energy_ptr=nullptr)
static Coordinates getCoordinates(const SymmetricTensor &t_tensor)
Project a symmetric tensor onto the fixed trace-free basis.
static MoFEMErrorCode evaluateVolume(const Parameters ¶meters, double theta, VolumeState &state)
Evaluate g(J) = K*(J-1)^2/2 and its logarithmic-volume derivatives.
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.
std::map< std::string, double > getParamsFromBlockset(const std::string &type_name, int meshset_id) const
Interface for managing meshsets containing materials and boundary conditions.
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.