19 const double tolerance,
const char *description) {
21 if (!std::isfinite(value) ||
22 std::abs(value - expected) > tolerance * std::max(1., std::abs(expected)))
24 "%s: expected %.16e, obtained %.16e", description, expected, value);
31 const auto *rule = IntRules::XiaoGimbutas::getTetrahedronRule(
order);
32 if (!rule || rule->numBarycentricCoordinates != 4)
34 "Space atom requires a tetrahedral Xiao-Gimbutas rule");
35 points.resize(3, rule->numPoints,
false);
36 weights.resize(rule->numPoints,
false);
38 for (
unsigned int gg = 0; gg != rule->numPoints; ++gg) {
39 points(0, gg) = rule->points[4 * gg + 1];
40 points(1, gg) = rule->points[4 * gg + 2];
41 points(2, gg) = rule->points[4 * gg + 3];
42 weights[gg] = rule->weights[gg] / 6.;
43 if (!(weights[gg] > 0.) || !std::isfinite(weights[gg]))
45 "Space comparisons require strictly positive quadrature weights");
48 CHKERR checkNear(sum, 1. / 6., 1.e-13,
"reference tetrahedron volume");
57 data.dataOnEntities[MBTET][0].getOrder() =
order;
58 auto context = boost::make_shared<EntPolynomialBaseCtx>(
60 EshelbianPlasticity::CGGUserPolynomialBase user_base(
nullptr,
true);
62 basis = data.dataOnEntities[MBTET][0].getN(
USER_BASE);
65 "Unexpected tetrahedral USER_BASE dimension");
70 const bool constant =
false) {
73 const Coordinates t_constant(.12, -.07, .04, .03, -.05);
74 const Coordinates t_first(.22, .09, -.13, .07, .11);
75 const Coordinates t_second(-.08, .18, .07, -.10, .05);
76 const Coordinates t_third(.12, -.15, .09, .03, -.08);
78 values, basis.size1())();
79 for (
unsigned int gg = 0; gg != basis.size1(); ++gg) {
80 t_d(
a) = t_constant(
a);
82 t_d(
a) += basis(gg, 1) * t_first(
a) + basis(gg, 2) * t_second(
a) +
83 basis(gg, 3) * t_third(
a);
89struct CoefficientState {
93 double minimumGap = 0.;
94 double maximumMismatch = 0.;
107 const int nb_basis = basis.size2();
108 const int nb_gauss = basis.size1();
109 if (coefficients.size() != 5 * nb_basis || weights.size() != nb_gauss)
111 "Inconsistent coefficient-space test data");
112 state.residual.resize(5 * nb_basis,
false);
113 state.residual.clear();
115 state.compliance.resize(5 * nb_basis, 5 * nb_basis,
false);
116 state.compliance.clear();
119 state.minimumGap = std::numeric_limits<double>::infinity();
120 state.maximumMismatch = 0.;
125 kinematics, nb_gauss)();
126 for (
int gg = 0; gg != nb_gauss; ++gg) {
127 Coordinates t_stress, t_d, t_mismatch;
129 auto t_coefficient = getFTensor1FromArray<5, 5>(coefficients);
130 for (
int bb = 0; bb != nb_basis; ++bb) {
131 t_stress(
a) += basis(gg, bb) * t_coefficient(
a);
134 t_d(
a) = t_kinematic(
a);
140 state.gap += weights[gg] * gap;
141 state.minimumGap = std::min(
state.minimumGap, gap);
142 state.maximumMismatch = std::max(
143 state.maximumMismatch, std::sqrt(t_mismatch(
a) * t_mismatch(
a)));
144 auto t_residual = getFTensor1FromArray<5, 5>(
state.residual);
145 for (
int rr = 0; rr != nb_basis; ++rr) {
146 const double alpha = weights[gg] * basis(gg, rr);
147 t_residual(
a) += alpha * t_mismatch(
a);
148 if (tangent && alpha != 0.) {
149 auto t_c = getFTensor2FromArray<5, 5, 5>(
state.compliance, 5 * rr);
150 for (
int cc = 0; cc != nb_basis; ++cc) {
151 t_c(
a, b) += (alpha * basis(gg, cc)) * inverse.
tCompliance(
a, b);
166 CoefficientState &
state) {
168 for (
int iteration = 0; iteration != 30; ++iteration) {
169 CHKERR evaluateCoefficients(parameters, basis, weights, kinematics,
170 coefficients,
state,
true);
171 const double residual_norm = norm_2(
state.residual);
172 if (residual_norm < tolerance)
177 bool accepted =
false;
178 for (
double alpha = 1.; alpha >= 1.e-7; alpha *= .5) {
180 CoefficientState trial_state;
181 CHKERR evaluateCoefficients(parameters, basis, weights, kinematics, trial,
183 if (norm_2(trial_state.residual) <=
184 (1. - 1.e-4 * alpha) * residual_norm) {
185 coefficients.swap(trial);
192 "Stress coefficient Newton line search failed");
195 "Stress coefficient moments did not converge");
202 MatrixDouble matrix(5 * row_basis.size2(), 5 * col_basis.size2());
207 for (
unsigned int rr = 0; rr != row_basis.size2(); ++rr) {
208 auto t_m = getFTensor2FromArray<5, 5, 5>(matrix, 5 * rr);
209 for (
unsigned int cc = 0; cc != col_basis.size2(); ++cc) {
211 for (
unsigned int gg = 0; gg != weights.size(); ++gg)
212 pairing += weights[gg] * row_basis(gg, rr) * col_basis(gg, cc);
213 t_m(
a, b) = pairing * t_identity(
a, b);
221 const char *description) {
226 if (!(eigenvalues[0] > 1.e-12 * eigenvalues[eigenvalues.size() - 1]))
228 "%s is not observable with the selected positive quadrature",
230 const double condition = eigenvalues[eigenvalues.size() - 1] / eigenvalues[0];
232 for (
unsigned int row = 0; row != scaled.size1(); ++row)
233 for (
unsigned int col = 0; col != scaled.size2(); ++col)
234 scaled(row, col) /= std::sqrt(matrix(row, row) * matrix(col, col));
236 CHKERR PetscPrintf(PETSC_COMM_WORLD,
237 "%s (%d coefficients): condition %.6e, "
238 "diagonally scaled condition %.6e\n",
239 description,
static_cast<int>(matrix.size1()), condition,
240 eigenvalues[eigenvalues.size() - 1] / eigenvalues[0]);
247 const double tolerance,
const double newton_tolerance) {
251 CHKERR makeKinematics(constant_basis, constant_kinematics,
true);
253 coefficients.clear();
254 CoefficientState
state;
255 CHKERR solveCoefficients(parameters, constant_basis, weights,
256 constant_kinematics, coefficients, newton_tolerance,
258 CHKERR checkNear(
state.maximumMismatch, 0., tolerance,
"P0 constant copy");
259 CHKERR checkNear(
state.gap, 0., tolerance,
"P0 constant Fenchel gap");
260 const Coordinates t_constant(.12, -.07, .04, .03, -.05);
261 Coordinates t_exact, t_error;
264 auto t_coefficient = getFTensor1FromArray<5, 5>(coefficients);
265 t_error(
a) = t_coefficient(
a) - t_exact(
a);
266 CHKERR checkNear(std::sqrt(t_error(
a) * t_error(
a)), 0., tolerance,
267 "P0 coefficient direct-law recovery");
270 const int nb_gauss = weights.size();
272 independent_basis.clear();
273 for (
int gg = 0; gg != nb_gauss; ++gg)
274 independent_basis(gg, gg) = 1.;
275 coefficients.resize(5 * nb_gauss,
false);
276 coefficients.clear();
277 CHKERR solveCoefficients(parameters, independent_basis, weights, kinematics,
278 coefficients, newton_tolerance,
state);
279 CHKERR checkNear(
state.maximumMismatch, 0., tolerance,
280 "independent quadrature material copies");
281 CHKERR checkNear(
state.gap, 0., tolerance,
"independent-copy Fenchel gap");
283 kinematics, nb_gauss)();
284 auto t_independent = getFTensor1FromArray<5, 5>(coefficients);
285 for (
int gg = 0; gg != nb_gauss; ++gg) {
286 Coordinates t_kinematic;
287 t_kinematic(
a) = t_d(
a);
289 t_error(
a) = t_independent(
a) - t_exact(
a);
290 CHKERR checkNear(std::sqrt(t_error(
a) * t_error(
a)), 0., tolerance,
291 "independent-copy direct-law recovery");
301 const double tolerance) {
303 const auto cross = crossMass(constant_basis, linear_basis, weights);
304 CHKERR checkPositiveDefinite(crossMass(linear_basis, linear_basis, weights),
305 "P1 kinematic mass");
309 lost_mode[5 + 2] = 1.;
310 lost_mode[2] = -
cross(2, 5 + 2) /
cross(2, 2);
312 CHKERR checkNear(norm_2(weak), 0., tolerance,
"underresolved cross-mass mode");
313 const auto mass = crossMass(linear_basis, linear_basis, weights);
315 if (!(inner_prod(lost_mode, mass_mode) > 1.e-3))
317 "The allegedly lost kinematic mode has zero physical norm");
318 for (
unsigned int gg = 0; gg != weights.size(); ++gg) {
319 const double value = linear_basis(gg, 1) +
320 lost_mode[2] * linear_basis(gg, 0);
321 Coordinates t_d(0., 0., value, 0., 0.), t_stress, t_error;
328 CHKERR checkNear(std::sqrt(t_error(
a) * t_error(
a)), 0., tolerance,
329 "material inverse on the unobservable kinematic mode");
331 CHKERR PetscPrintf(PETSC_COMM_WORLD,
332 "Underresolved P0/P1 pairing: rank 5 of 20, "
333 "nonzero deviatoric mode invisible; all inverses valid\n");
340 const VectorDouble &equilibrated_stress,
const double tolerance) {
343 CoefficientState
state;
344 CHKERR evaluateCoefficients(parameters, basis, weights, kinematics, stress,
346 if (!(norm_2(
state.residual) > 1.e-4))
348 "Elimination test requires a nonzero copy residual");
349 const MatrixDouble coupling = crossMass(basis, basis, weights);
354 const int size = stress.size();
356 for (
int ii = 0; ii != size; ++ii)
357 mechanical_residual[ii] = .01 * std::sin(ii + 1.);
361 for (
int rr = 0; rr != size; ++rr) {
362 explicit_step[rr] = -mechanical_residual[rr];
363 explicit_step[size + rr] = -
state.residual[rr];
364 for (
int cc = 0; cc != size; ++cc) {
365 enlarged(rr, cc) = mechanical(rr, cc);
366 enlarged(rr, size + cc) = coupling(rr, cc);
367 enlarged(size + rr, cc) = coupling(cc, rr);
368 enlarged(size + rr, size + cc) = -
state.compliance(rr, cc);
374 for (
int cc = 0; cc != size; ++cc) {
376 for (
int rr = 0; rr != size; ++rr)
377 column[rr] = coupling(cc, rr);
380 for (
int rr = 0; rr != size; ++rr)
381 inverse_coupling(rr, cc) = column[rr];
386 MatrixDouble schur = mechanical + prod(coupling, inverse_coupling);
387 VectorDouble rhs_correction = prod(coupling, inverse_residual);
388 VectorDouble condensed_d = -mechanical_residual - rhs_correction;
391 inverse_residual + prod(inverse_coupling, condensed_d);
393 for (
int ii = 0; ii != size; ++ii) {
394 difference[ii] -= condensed_d[ii];
395 difference[size + ii] -= condensed_t[ii];
397 CHKERR checkNear(norm_2(difference) / std::max(1., norm_2(explicit_step)), 0.,
398 tolerance,
"explicit/coefficient-Schur Newton step");
402 omitted_correction -= condensed_d;
403 if (!(norm_2(omitted_correction) > 1.e-4))
405 "Omitting the nonzero copy-residual correction did not change "
406 "the condensed Newton step");
407 CHKERR PetscPrintf(PETSC_COMM_WORLD,
408 "Coefficient Schur step agrees; copy residual %.6e, "
409 "omitted-correction error %.6e\n",
410 norm_2(
state.residual), norm_2(omitted_correction));
415 const int quadrature_order,
const double tolerance,
416 const double newton_tolerance) {
420 CHKERR makeQuadrature(quadrature_order, points, weights);
421 std::array<MatrixDouble, 3> bases;
424 CHKERR checkPositiveDefinite(crossMass(bases[
order], bases[
order], weights),
425 "nested stress-space mass");
427 for (
unsigned int gg = 0; gg != weights.size(); ++gg)
428 for (
unsigned int bb = 0; bb != bases[
order - 1].size2(); ++bb)
430 tolerance,
"actual USER_BASE nesting");
433 CHKERR makeKinematics(bases[1], kinematics);
434 CHKERR checkExactCases(parameters, bases[0], weights, kinematics, tolerance,
437 double previous_gap = std::numeric_limits<double>::infinity();
439 coefficients.resize(5 * bases[
order].size2(),
false);
440 coefficients.clear();
441 std::copy(previous.begin(), previous.end(), coefficients.begin());
442 CoefficientState
state;
443 CHKERR solveCoefficients(parameters, bases[
order], weights, kinematics,
444 coefficients, newton_tolerance,
state);
446 "assembled stress coefficient compliance");
447 if (
state.minimumGap < -tolerance ||
state.gap < -tolerance ||
448 (
order && !(
state.gap < previous_gap - 1.e-3 * tolerance)))
450 "Nested mesh-stress Fenchel gaps are negative or fail to decrease");
452 linear_solution = coefficients;
453 if (!(
state.maximumMismatch > 1.e-5))
455 "Weak P1 closure unexpectedly imposed pointwise material copies");
457 CHKERR PetscPrintf(PETSC_COMM_WORLD,
458 "Mesh stress P%d: %d coefficients, moment %.6e, "
459 "gap %.12e, maximum copy mismatch %.6e\n",
460 order,
static_cast<int>(coefficients.size()),
462 previous = coefficients;
463 previous_gap =
state.gap;
465 CHKERR checkLostMode(parameters, bases[0], bases[1], weights, tolerance);
466 CHKERR checkCoefficientElimination(parameters, bases[1], weights, kinematics,
467 linear_solution, tolerance);
468 CHKERR PetscPrintf(PETSC_COMM_WORLD,
469 "Auxiliary logarithmic stress space atom passed "
470 "with %d fixed positive quadrature points\n",
471 static_cast<int>(weights.size()));
478 "Check weak auxiliary stress spaces and coefficient Schur elimination.\n";
480int main(
int argc,
char *argv[]) {
489 CHKERR meshsets->setMeshsetFromFile();
491 if (block.size() != 2 || !block.count(
"c10") || !block.count(
"k"))
493 "Space atom requires MAT_NEOHOOKEAN JSON block 1001 with c10,k");
496 PetscInt quadrature_order = 0;
497 PetscReal tolerance = 0., newton_tolerance = 0.;
499 &quadrature_order,
nullptr);
501 &tolerance,
nullptr);
503 "-auxiliary_space_newton_tolerance",
504 &newton_tolerance,
nullptr);
505 if (quadrature_order < 4 || !std::isfinite(tolerance) || tolerance <= 0. ||
506 !std::isfinite(newton_tolerance) || newton_tolerance <= 0. ||
507 newton_tolerance >= tolerance)
509 "Space atom requires positive finite JSON tolerances and "
510 "quadrature order at least four");
511 CHKERR runSpaceAtom(parameters, quadrature_order, tolerance, newton_tolerance);
Eshelbian plasticity interface.
boost::shared_ptr< IncrementalOptimizationContext > context
Neo-Hookean material law in orthonormal logarithmic coordinates.
#define CATCH_ERRORS
Catch errors.
@ USER_BASE
user implemented approximation base
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
@ L2
field with C-1 continuity
@ DISCONTINUOUS
Broken continuity (No effect on L2 space)
#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.
auto cross(const Tensor1_Expr< A, T, 3, i > &a, const Tensor1_Expr< B, U, 3, j > &b, const Index< k, 3 > &)
DataLayoutTraits< DataLayout::GaussByCoeffs > DL
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
implementation of Data Operators for Forces and Sources
PetscErrorCode PetscOptionsGetInt(PetscOptions *, const char pre[], const char name[], PetscInt *ivalue, PetscBool *set)
PetscErrorCode PetscOptionsGetReal(PetscOptions *, const char pre[], const char name[], PetscReal *dval, PetscBool *set)
MoFEMErrorCode solveLinearSystem(MatrixDouble &mat, VectorDouble &f)
solve linear system with lapack dgesv
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
Coordinates tMaterialDeviator
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 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.
FTensor::Tensor1< double, 5 > Coordinates
static MoFEMErrorCode evaluateFenchelGap(const Parameters ¶meters, const Coordinates &t_deviator, const Coordinates &t_stress, const InverseState &inverse, double &gap, double *energy_ptr=nullptr)
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.
data structure for finite element entity
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.