15 OpCheckRotationLayout(
const std::string &field,
16 boost::shared_ptr<PetscInt> visits)
18 doEntities.fill(
false);
19 doEntities[MBTET] =
true;
24 const int dofs =
data.getFieldData().size();
28 if (dofs < 3 || dofs % 3 || points <= 1 ||
data.getN().size2() < dofs / 3)
30 "Incomplete tetrahedral L2 rotation block");
31 const auto &field_dofs =
data.getFieldDofs();
32 for (
int c = 0;
c != 3; ++
c)
33 if (field_dofs[
c]->getDofOrder() != 0 ||
34 field_dofs[
c]->getDofCoeffIdx() !=
c)
36 "First rotation block is not the constant vector mode");
37 const double phi0 =
data.getN()(0, 0);
38 if (!std::isfinite(phi0) || std::abs(phi0) < 1.e-12)
40 "Constant rotation basis has invalid normalisation");
42 for (
int gg = 0; gg != points; ++gg) {
44 if (std::abs(
data.getN()(gg, 0) - phi0) > 1.e-13 ||
47 "First L2 rotation basis is not spatially constant");
54 boost::shared_ptr<PetscInt> visitsPtr;
62 constantPtr(constant), higherPtr(higher), referencePtr(reference),
74 .4 * stateScale, -.3 * stateScale, .2 * stateScale);
75 for (
int gg = 0; gg != points; ++gg) {
77 error(
i) =
a(
i) - expected(
i);
78 if (error(
i) * error(
i) > 1.e-24)
80 "Incorrect constant rotation vector");
81 error(
i) =
t(
i) -
r(
i);
82 if (error(
i) * error(
i) > 1.e-24)
84 "Split total differs from core field evaluation");
86 if (error(
i) * error(
i) > 1.e-24)
88 "Rotation decomposition does not reconstruct the total");
96 MatrixPtr totalPtr, constantPtr, higherPtr, referencePtr;
105 CHKERR VecZeroEntries(vector);
106 PetscInt first, last;
107 CHKERR VecGetOwnershipRange(vector, &first, &last);
110 const double c0[] = {.4, -.3, .2};
111 for (
const auto &dof : *problem->getNumeredRowDofsPtr()) {
112 const auto index = dof->getPetscGlobalDofIdx();
113 if (dof->getName() !=
ep.
rotAxis || index < first || index >= last)
115 const auto component = dof->getDofCoeffIdx();
117 dof->getDofOrder() == 0 ? c0[component] : .001 * (index % 13 - 6);
118 CHKERR VecSetValue(vector, index,
scale * value, INSERT_VALUES);
120 CHKERR VecAssemblyBegin(vector);
121 CHKERR VecAssemblyEnd(vector);
122 CHKERR VecGhostUpdateBegin(vector, INSERT_VALUES, SCATTER_FORWARD);
123 CHKERR VecGhostUpdateEnd(vector, INSERT_VALUES, SCATTER_FORWARD);
127 CHKERR make_vector(1., current);
128 CHKERR make_vector(-.7, previous);
132 auto fe = boost::make_shared<VolumeElementForcesAndSourcesCore>(
ep.
mField);
133 fe->getUserPolynomialBase() =
134 boost::make_shared<CGGUserPolynomialBase>(
nullptr,
true);
138 for (
const auto &
state :
141 auto total = boost::make_shared<MatrixDouble>();
142 auto constant = boost::make_shared<MatrixDouble>();
143 auto higher = boost::make_shared<MatrixDouble>();
144 auto reference = boost::make_shared<MatrixDouble>();
149 fe->getOpPtrVector().push_back(
new OpCheckRotationValues(
150 total, constant, higher, reference,
state.second));
170 aa(
i,
j,
k,
l) * da(
k) * ea(
l) + aq(
i,
j,
k,
l) * da(
k) * eq(
l) +
171 qa(
i,
j,
k,
l) * dq(
k) * ea(
l) + qq(
i,
j,
k,
l) * dq(
k) * eq(
l);
178 using namespace LogarithmicDirectionalDerivatives;
183 const Vector zero(0., 0., 0.);
184 const Direction directions[] = {{
Vector(.3, -.2, .1), zero},
185 {zero,
Vector(-.1, .4, .2)},
187 const Direction bases[] = {
192 const double step = 4.e-6;
193 const auto check = [&](
const auto &exact,
const auto &fd,
194 const char *description) {
197 error(
i,
j) = exact(
i,
j) - fd(
i,
j);
198 if (error(
i,
j) * error(
i,
j) > 1.e-14)
200 "Split rotation %s finite difference failed", description);
203 for (
const auto &base : bases) {
204 const SplitRotation rotation(base.a, base.q);
205 for (
const auto &d : directions) {
206 Vector plus_a, minus_a, plus_q, minus_q;
207 plus_a(
i) = base.a(
i) + step *
d.a(
i);
208 minus_a(
i) = base.a(
i) - step *
d.a(
i);
209 plus_q(
i) = base.q(
i) + step *
d.q(
i);
210 minus_q(
i) = base.q(
i) - step *
d.q(
i);
211 const SplitRotation plus(plus_a, plus_q), minus(minus_a, minus_q);
213 fd(
i,
j) = (plus.value()(
i,
j) - minus.value()(
i,
j)) / (2 * step);
215 for (
const auto &e : directions) {
216 fd(
i,
j) = (plus.first(e.a, e.q)(
i,
j) - minus.first(e.a, e.q)(
i,
j)) /
218 CHKERR check(contractRotationHessian(rotation,
d.a,
d.q, e.a, e.q), fd,
220 for (
const auto &f : directions) {
230 rotation.
fill(
a,
q, result);
232 (contractRotationHessian(plus, e.a, e.q,
f.a,
f.q)(
i,
j) -
233 contractRotationHessian(minus, e.a, e.q,
f.a,
f.q)(
i,
j)) /
235 CHKERR check(result[7], fd,
"third");
237 contractRotationHessian(rotation,
d.a,
d.q, e.a, e.q),
243 const Vector a(0., 0., 6.1),
q(.2, -.1, .08);
244 const Vector shortened(0., 0., 6.1 - 2 * std::numbers::pi);
245 CHKERR check(SplitRotation(
a,
q).value(), SplitRotation(shortened,
q).value(),
251 OpCheckShortenedRotation(std::array<MatrixPtr, 2> constant,
252 std::array<MatrixPtr, 2> higher)
257 using namespace LogarithmicDirectionalDerivatives;
267 for (
int gg = 0; gg != points; ++gg) {
268 Vector old_a, new_a, old_q, new_q;
274 error(
i,
j) = SplitRotation(old_a, old_q).value()(
i,
j) -
275 SplitRotation(new_a, new_q).value()(
i,
j);
276 if (error(
i,
j) * error(
i,
j) > 1.e-25 || new_a.l2() >= std::numbers::pi)
278 "Constant branch update changed the product rotation");
286 std::array<MatrixPtr, 2> constantPtr, higherPtr;
307 "Expected rotation preconditioner at the end of the LHS pipeline");
313 CHKERR VecAXPY(base, -1., exact);
315 CHKERR VecNorm(base, NORM_2, &error);
318 "Rotation preconditioning changed the exact Jacobian: %g", error);
319 CHKERR TSComputeIFunction(ts, 0.,
state, rates, base, PETSC_FALSE);
321 CHKERR VecNorm(base, NORM_2, &error);
324 "Rotation preconditioning changed the residual: %g", error);
327 CHKERR VecAXPY(base, -1., shifted);
328 double shift_norm,
work;
329 CHKERR VecNorm(base, NORM_2, &shift_norm);
331 if (!std::isfinite(shift_norm) || shift_norm < 1e-10 || work >= 0.)
333 "Expected a nonzero positive rotation-gradient preconditioner");
339 CHKERR VecGetSubVector(base, rotation_is, &rotation_sub);
340 CHKERR VecZeroEntries(rotation_sub);
341 CHKERR VecRestoreSubVector(base, rotation_is, &rotation_sub);
342 CHKERR VecNorm(base, NORM_2, &error);
345 "Rotation preconditioner modified another field: %g", error);
346 CHKERR MatAXPY(schur_shifted, -1.,
ep.
S, SAME_NONZERO_PATTERN);
347 CHKERR MatNorm(schur_shifted, NORM_FROBENIUS, &error);
348 if (!std::isfinite(error) || error < 1e-10)
350 "Schur preconditioner did not include the rotation shift");
357 CHKERR VecAXPY(base, -1., shifted);
358 CHKERR VecNorm(base, NORM_2, &error);
361 "Rotation preconditioner changed after identical reassembly: %g",
365 CHKERR VecZeroEntries(constant);
368 PetscInt first, last;
369 CHKERR VecGetOwnershipRange(constant, &first, &last);
370 for (
const auto &dof : *problem->getNumeredRowDofsPtr()) {
371 const auto index = dof->getPetscGlobalDofIdx();
372 if (dof->getName() ==
ep.
rotAxis && dof->getDofOrder() == 0 &&
373 index >= first && index < last)
374 CHKERR VecSetValue(constant, index, 1., INSERT_VALUES);
376 CHKERR VecAssemblyBegin(constant);
377 CHKERR VecAssemblyEnd(constant);
378 CHKERR MatMult(pc_mat, constant, base);
380 CHKERR VecAXPY(base, -1., exact);
381 CHKERR VecNorm(base, NORM_2, &error);
384 "Gradient preconditioner penalised constant L2 rotation: %g",
388 CHKERR MatNestGetSubMat(pc_mat, 1, 1, &a00);
390 CHKERR MatCreateVecs(a00, &x_raw, &b_raw);
394 CHKERR MatMult(a00, x, b);
395 CHKERR MatSolve(a00, b, solution);
397 CHKERR VecNorm(b, NORM_2, &rhs_norm);
398 CHKERR MatMult(a00, solution, x);
399 CHKERR VecAXPY(x, -1., b);
400 CHKERR VecNorm(x, NORM_2, &error);
401 error /= std::max(rhs_norm, std::numeric_limits<double>::min());
402 if (!std::isfinite(error) || error > 1e-10)
404 "Shifted A00 solve does not match its operator: %g", error);
406 <<
"Rotation preconditioner: exact residual/Jacobian preserved, shift "
407 << shift_norm <<
", relative A00 residual " << error;
417 PetscInt first, last;
419 for (
const auto &dof : *problem->getNumeredRowDofsPtr()) {
420 const auto index = dof->getPetscGlobalDofIdx();
421 if (dof->getName() !=
ep.
rotAxis || index < first || index >= last)
423 const double value = dof->getDofOrder() == 0
424 ? (dof->getDofCoeffIdx() == 2 ? 6.1 : 0.)
425 : .003 * (index % 11 - 5);
426 CHKERR VecSetValue(
state, index, value, INSERT_VALUES);
430 CHKERR VecGhostUpdateBegin(
state, INSERT_VALUES, SCATTER_FORWARD);
431 CHKERR VecGhostUpdateEnd(
state, INSERT_VALUES, SCATTER_FORWARD);
438 ep.
dataAtPts = boost::make_shared<DataAtIntegrationPts>();
441 CHKERR TSSetType(ts, TSBEULER);
450 "Pre-step changed H1 incremental kinematics before transfer");
454 "Pre-step changed H1 physical history");
457 PetscBool check_schur = PETSC_FALSE;
459 &check_schur,
nullptr);
460 boost::shared_ptr<EshelbianCore::SetUpSchur> schur;
464 CHKERR TSSetOptionsPrefix(ts,
"elastic_");
465 CHKERR TSSetFromOptions(ts);
469 const auto check_schur_hierarchy = [&]() {
475 PC pc, a00_pc, schur_pc;
476 CHKERR TSGetSNES(ts, &snes);
481 CHKERR VecZeroEntries(rates);
490 CHKERR PCFieldSplitSchurGetSubKSP(pc,
nullptr, &subksp);
491 CHKERR KSPGetPC(subksp[0], &a00_pc);
492 CHKERR KSPGetPC(subksp[1], &schur_pc);
498 "Rotation shortening destroyed the Schur A00 shell PC");
500 CHKERR PCGetDM(schur_pc, &dm);
503 if (problem->
getName() !=
"SUB_SCHUR")
505 "Rotation shortening lost the Schur DM");
508 CHKERR check_schur_hierarchy();
510 CHKERR TSGetSNES(ts, &snes);
511 CHKERR SNESSetLagJacobian(snes, 3);
512 CHKERR SNESSetLagPreconditioner(snes, 4);
515 CHKERR check_schur_hierarchy();
520 "Expected a constant rotation branch change");
523 CHKERR VecAXPY(difference, -1., old);
525 CHKERR VecGetArrayRead(difference, &array);
526 for (
const auto &dof : *problem->getNumeredRowDofsPtr()) {
527 const auto index = dof->getPetscGlobalDofIdx();
528 if (index < first || index >= last)
530 if ((dof->getName() !=
ep.
rotAxis || dof->getDofOrder() != 0) &&
531 array[index - first] != 0.)
533 "Branch update changed a higher mode or another field");
535 CHKERR VecRestoreArrayRead(difference, &array);
542 "Short constant rotation should not be changed twice");
543 CHKERR check_schur_hierarchy();
545 CHKERR SNESGetLagJacobian(snes, &lag);
548 "Rotation shortening changed the configured Jacobian lag");
549 CHKERR SNESGetLagPreconditioner(snes, &lag);
552 "Rotation shortening changed the configured preconditioner lag");
556 "TS pre-step replaced the distinct previous physical state");
566 "Raw coordinate penalty must prevent branch shortening");
569 auto fe = boost::make_shared<VolumeElementForcesAndSourcesCore>(
ep.
mField);
570 fe->getUserPolynomialBase() =
571 boost::make_shared<CGGUserPolynomialBase>(
nullptr,
true);
575 std::array<MatrixPtr, 2>
a,
q;
576 for (
int mode = 0; mode != 2; ++mode) {
577 a[mode] = boost::make_shared<MatrixDouble>();
578 q[mode] = boost::make_shared<MatrixDouble>();
580 ep.
rotAxis, boost::make_shared<MatrixDouble>(),
a[mode],
q[mode],
581 mode ?
state : old));
583 fe->getOpPtrVector().push_back(
new OpCheckShortenedRotation(
a,
q));
592 [&](boost::shared_ptr<FieldEntity> entity) {
594 auto values = entity->getEntFieldData();
597 if (entity->getEntType() == MBVERTEX) {
598 double coordinates[3];
599 const auto handle = entity->getEnt();
601 auto x = getFTensor1FromPtr<3>(coordinates);
602 auto displacement = getFTensor1FromPtr<3>(&
values[0]);
603 displacement(0) = .04 * x(0) + .02 * x(1);
604 displacement(1) = -.03 * x(1) + .01 * x(2);
605 displacement(2) = .02 * x(2);
614 PetscInt first, last;
616 for (
const auto &dof : *problem->getNumeredRowDofsPtr()) {
617 const auto index = dof->getPetscGlobalDofIdx();
618 if (index < first || index >= last)
620 const auto &
name = dof->getName();
623 CHKERR VecSetValue(
state, index, .01 * (index % 13 - 6), INSERT_VALUES);
627 CHKERR VecGhostUpdateBegin(
state, INSERT_VALUES, SCATTER_FORWARD);
628 CHKERR VecGhostUpdateEnd(
state, INSERT_VALUES, SCATTER_FORWARD);
631 CHKERR VecZeroEntries(rates);
632 boost::shared_ptr<VolumeElementForcesAndSourcesCore> rhs, lhs;
636 state, rates, rates, 1., 1., {});
638 state, rates, rates, 1., 1., {});
645 CHKERR VecCopy(input, trial);
646 CHKERR VecGhostUpdateBegin(trial, INSERT_VALUES, SCATTER_FORWARD);
647 CHKERR VecGhostUpdateEnd(trial, INSERT_VALUES, SCATTER_FORWARD);
649 trial, rates, rates, 1., 1., {});
650 CHKERR VecCopy(value, output);
658 for (
const auto &dof : *problem->getNumeredRowDofsPtr()) {
659 const auto index = dof->getPetscGlobalDofIdx();
660 if (index >= first && index < last && dof->getName() != field)
661 values[index - first] = 0.;
664 CHKERR tester->checkVectorCentralFiniteDifference(
667 PetscReal error_norm, action_norm;
668 CHKERR VecNorm(error, NORM_INFINITY, &error_norm);
669 CHKERR VecNorm(action, NORM_INFINITY, &action_norm);
670 if (!std::isfinite(error_norm) || error_norm > 2.e-8 + 2.e-6 * action_norm)
672 "H1 split Jacobian for %s: error %g, action %g", field.c_str(),
673 error_norm, action_norm);
675 field.c_str(), error_norm);
683 if (field->getSpace() !=
L2 || field->getApproxBase() !=
USER_BASE ||
684 field->getNbOfCoeffs() != 3)
686 "Rotation split requires three-component USER_BASE L2");
687 auto fe = boost::make_shared<VolumeElementForcesAndSourcesCore>(
ep.
mField);
688 fe->getUserPolynomialBase() =
689 boost::make_shared<CGGUserPolynomialBase>(
nullptr,
true);
693 auto visits = boost::make_shared<PetscInt>(0);
694 fe->getOpPtrVector().push_back(
new OpCheckRotationLayout(
ep.
rotAxis, visits));
696 PetscInt global_visits;
697 CHKERR MPI_Allreduce(visits.get(), &global_visits, 1, MPIU_INT, MPI_SUM,
701 "No rotation layout evaluations executed");
702 CHKERR checkRotationVectors(ep);
703 CHKERR checkSplitRotationDerivatives();
704 CHKERR checkConstantBranchUpdate(ep);
705 PetscBool check_h1 = PETSC_FALSE;
709 CHKERR checkH1RotationJacobian(ep);
711 "Rotation constant-mode layout verified on %d elements\n",
712 static_cast<int>(global_visits));
717int main(
int argc,
char *argv[]) {
719 "Verify L2 constant-higher rotation split.\n");
720 auto log = logging::core::get();
721 for (
const auto *
name : {
"EP",
"EPSELF",
"EPSYNC"}) {
Shared mesh and problem setup for auxiliary formulation atoms.
Mixed directional derivatives of matrix exponentials for the reduced Hessian of the logarithmic plast...
boost::shared_ptr< DataAtIntegrationPts > data
boost::shared_ptr< MatrixDouble > direction
Elastic TS pre/post-step registration and H1 transfer lifecycle.
SmartPetscObj< Vec > work
SmartPetscObj< Vec > residual
SmartPetscObj< Vec > gradient
SmartPetscObj< Mat > jacobian
SmartPetscObj< Vec > values
SmartPetscObj< Mat > preconditioner
#define FTENSOR_INDEXES(DIM,...)
#define FTENSOR_INDEX(DIM, I)
#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
#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.
PetscErrorCode DMMoFEMGetProblemPtr(DM dm, const MoFEM::Problem **problem_ptr)
Get pointer to problem data structure.
PetscErrorCode DMoFEMMeshToLocalVector(DM dm, Vec l, InsertMode mode, ScatterMode scatter_mode, RowColData rc=RowColData::COL)
set local (or ghosted) vector values on mesh for partition only
MoFEMErrorCode DMRegister_MGViaApproxOrders(const char sname[])
Register DM for Multi-Grid via approximation orders.
PetscErrorCode DMoFEMLoopFiniteElements(DM dm, const char fe_name[], MoFEM::FEMethod *method, CacheTupleWeakPtr cache_ptr=CacheTupleSharedPtr())
Executes FEMethod for finite elements in DM.
PetscErrorCode DMMoFEMGetFieldIS(DM dm, RowColData rc, const char field_name[], IS *is)
get field is in the problem
auto createDMVector(DM dm, RowColData rc=RowColData::COL)
Get smart vector from DM.
virtual const Field * get_field_structure(const std::string &name, enum MoFEMTypes bh=MF_EXIST) const =0
get field structure
static LoggerType & setLog(const std::string channel)
Set ans resset chanel logger.
#define MOFEM_LOG(channel, severity)
Log.
FTensor::Index< 'i', SPACE_DIM > i
const double c
speed of light (cm/ns)
FTensor::Index< 'l', 3 > l
FTensor::Index< 'j', 3 > j
FTensor::Index< 'k', 3 > k
const FTensor::Tensor2< T, Dim, Dim > Vec
FTensor::Tensor2< double, 3, 3 > Tensor
FTensor::Tensor1< double, 3 > Vector
FTensor::Tensor2< FTensor::CursorPtr< double *, 9 >, 3, 3 > View
MoFEMErrorCode runAuxiliaryLogarithmicStressTest(const std::function< MoFEMErrorCode(EshelbianCore &)> &test)
boost::shared_ptr< MatrixDouble > MatrixPtr
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
implementation of Data Operators for Forces and Sources
PetscErrorCode PetscOptionsGetBool(PetscOptions *, const char pre[], const char name[], PetscBool *bval, PetscBool *set)
SmartPetscObj< Vec > vectorDuplicate(Vec vec)
Create duplicate vector of smart vector.
auto createTS(MPI_Comm comm)
decltype(GetFTensor1FromMatImpl< Tensor_Dim, S, DL, M >::get(std::declval< M & >(), 0, 0)) GetFTensor1FromMatType
PetscObject getPetscObject(T obj)
SmartPetscObj< Mat > matDuplicate(Mat mat, MatDuplicateOption op)
constexpr double t
plate stiffness
static boost::shared_ptr< SetUpSchur > createSetUpSchur(MoFEM::Interface &m_field, EshelbianCore *ep_core_ptr)
MoFEMErrorCode setElasticElementOps(const int tag)
MoFEM::Interface & mField
const std::string materialH1Positions
const std::string elementVolumeName
static enum RotSelector gradApproximator
const std::string spatialH1Disp
const std::string piolaStress
MoFEMErrorCode setElasticElementToTs(DM dm)
MoFEMErrorCode setVolumeElementOps(const int tag, const bool add_elastic, const bool add_material, boost::shared_ptr< VolumeElementForcesAndSourcesCore > &fe_rhs, boost::shared_ptr< VolumeElementForcesAndSourcesCore > &fe_lhs)
boost::shared_ptr< VolumeElementForcesAndSourcesCore > elasticFeLhs
const std::string rotAxis
double alphaOmegaPrec
Rotation-gradient shift of the Schur preconditioner.
boost::shared_ptr< DataAtIntegrationPts > dataAtPts
SmartPetscObj< Vec > solTSStep
SmartPetscObj< DM > dmElastic
Elastic problem.
const std::string stretchTensor
Tensor first(const Vector &da, const Vector &dq) const
auto secondTensor(const int row_mode, const int col_mode) const
void fill(const Matrix< N > &a, const Matrix< N > &q, Matrix< N > &result) const
static MoFEMErrorCode setPreStep(EshelbianCore *ep_ptr, TS ts, bool h1_update=false)
Add operators pushing bases from local to physical configuration.
virtual moab::Interface & get_moab()=0
virtual MPI_Comm & get_comm() const =0
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.
virtual MoFEMErrorCode doWork(int row_side, int col_side, EntityType row_type, EntityType col_type, EntitiesFieldData::EntData &row_data, EntitiesFieldData::EntData &col_data)
Operator for bi-linear form, usually to calculate values on left hand side.
Data on single entity (This is passed as argument to DataOperator::doWork)
MatrixDouble & getGaussPts()
matrix of integration (Gauss) points for Volume Element
static boost::shared_ptr< SinkType > createSink(boost::shared_ptr< std::ostream > stream_ptr, std::string comm_filter)
Create a sink object.
static boost::shared_ptr< std::ostream > getStrmWorld()
Get the strm world object.
Specialization for MatrixDouble vector field values calculation.
Calculate directional derivative of the right hand side and compare it with tangent matrix derivative...
std::function< MoFEMErrorCode(Vec, Vec)> VectorFunction
keeps basic data about problem
intrusive_ptr for managing petsc objects
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.