14constexpr double c10 = 1.7;
15constexpr double bulk = 8.5;
16constexpr double deltaTime = .5;
22 "Get direct material test field indices");
26MoFEMErrorCode getFieldNorm(Vec vector, IS field, PetscReal &norm) {
29 CHKERR VecGetSubVector(vector, field, &subvector);
30 CHKERR VecNorm(subvector, NORM_INFINITY, &norm);
31 CHKERR VecRestoreSubVector(vector, field, &subvector);
41 const std::array<double, 6>
h{{.12, .035, -.021, -.045, .027, .018}};
42 const std::array<double, 3> rotation{{.14, -.11, .07}};
43 for (
const auto &dof : *problem->getNumeredRowDofsPtr()) {
44 const auto index = dof->getPetscGlobalDofIdx();
45 if (index < first || index >= last)
47 double value = .01 * std::sin(.37 * (index + 1));
49 if (dof->getDofOrder() == 0)
50 value =
h.at(dof->getDofCoeffIdx());
52 value *= .2 / (1 + dof->getDofOrder());
53 }
else if (dof->getName() == ep.
rotAxis && dof->getDofOrder() == 0) {
54 value = rotation.at(dof->getDofCoeffIdx());
56 CHKERR VecSetValue(
state, index, value, INSERT_VALUES);
60 CHKERR VecGhostUpdateBegin(
state, INSERT_VALUES, SCATTER_FORWARD);
61 CHKERR VecGhostUpdateEnd(
state, INSERT_VALUES, SCATTER_FORWARD);
66 double noncoaxial = 0.;
67 double rateGradient = 0.;
68 double energyError = 0.;
72struct OpAuditState : VolumeElement::UserDataOperator {
73 OpAuditState(boost::shared_ptr<DataAtIntegrationPts> data,
74 boost::shared_ptr<Audit> audit)
81 const int points = getGaussPts().size2();
84 "Direct material atom requires multiple Gauss points");
85 auto t_h = dataPtr->getFTensorLogStretch(points);
86 auto t_p = dataPtr->getFTensorAdjointPdstretch(points);
87 auto t_gradient = dataPtr->getFTensorGradLogStretchDot(points);
90 for (
int gg = 0; gg != points; ++gg) {
91 t_symmetric_p(
i,
j) = (t_p(
i,
j) || t_p(
j,
i)) / 2.;
93 t_h(
i,
k) * t_symmetric_p(
k,
j) - t_symmetric_p(
i,
k) * t_h(
k,
j);
94 auditPtr->noncoaxial =
95 std::max(auditPtr->noncoaxial,
96 std::sqrt(t_commutator(
i,
j) * t_commutator(
i,
j)));
97 auditPtr->rateGradient =
98 std::max(auditPtr->rateGradient,
99 std::sqrt(t_gradient(
L,
i) * t_gradient(
L,
i)));
104 auditPtr->points += points;
107 boost::shared_ptr<DataAtIntegrationPts> dataPtr;
108 boost::shared_ptr<Audit> auditPtr;
111struct OpReferenceStress : VolumeElement::UserDataOperator {
112 OpReferenceStress(boost::shared_ptr<DataAtIntegrationPts> data,
113 MatrixPtr stress, boost::shared_ptr<Audit> audit)
115 stressPtr(stress), auditPtr(audit) {}
122 const auto t_packed_basis = FTensor::SymmLTensor<double, 3>();
123 const int points = getGaussPts().size2();
124 auto t_h = dataPtr->getFTensorLogStretch(points);
128 *stressPtr, points)();
131 for (
int gg = 0; gg != points; ++gg) {
132 const double theta = t_h(
i,
i);
133 t_argument(
i,
j) = 2. * t_h(
i,
j) - (2. * theta / 3.) * t_identity(
i,
j);
134 const double argument_norm =
135 std::sqrt(t_argument(
i,
j) * t_argument(
i,
j));
136 if (!(argument_norm < .75))
138 "Test state exceeds matrix exponential reference bound");
141 t_exponential(
i,
j) = t_identity(
i,
j);
142 t_term(
i,
j) = t_identity(
i,
j);
144 t_product(
i,
j) = t_term(
i,
k) * t_argument(
k,
j);
146 t_exponential(
i,
j) += t_term(
i,
j);
148 const double trace_exponential = t_exponential(
i,
i);
149 const double jacobian = std::exp(theta);
150 t_material_stress(
i,
j) =
152 (t_exponential(
i,
j) -
153 (trace_exponential / 3.) * t_identity(
i,
j)) +
154 (bulk * jacobian * (jacobian - 1.)) * t_identity(
i,
j);
155 t_stress(
L) = t_packed_basis(
i,
j,
L) * t_material_stress(
i,
j);
156 const double energy = c10 * (trace_exponential - 3.) +
157 .5 * bulk * (jacobian - 1.) * (jacobian - 1.);
158 const double error = std::abs(t_energy - energy);
159 if (!std::isfinite(error))
161 "Nonfinite direct material energy");
162 auditPtr->energyError = std::max(auditPtr->energyError, error);
169 boost::shared_ptr<DataAtIntegrationPts> dataPtr;
171 boost::shared_ptr<Audit> auditPtr;
179 auto blocks = boost::make_shared<ExternalStrainVec>();
180 blocks->emplace_back(
"EXTERNALSTRAIN_FIRST", std::vector<double>{.07, 2.},
182 blocks->emplace_back(
"EXTERNALSTRAIN_SECOND", std::vector<double>{-.01, 5.},
184 blocks->emplace_back(
"EXTERNALSTRAIN_OTHER", std::vector<double>{1., 20.},
186 const auto first_scale = [](
double time) {
return 1. + 2. * time; };
187 const auto second_scale = [](
double time) {
return time - .3; };
188 std::map<std::string, boost::shared_ptr<ScalingMethod>> scaling{
189 {
"EXTERNALSTRAIN_FIRST",
190 boost::make_shared<TimeScale>(
"",
false, first_scale)},
191 {
"EXTERNALSTRAIN_SECOND",
192 boost::make_shared<TimeScale>(
"",
false, second_scale)}};
194 auto production = boost::make_shared<VolumeElement>(ep.
mField);
196 production->getOpPtrVector().push_back(
199 auto reference = boost::make_shared<VolumeElement>(ep.
mField);
201 auto pressure = boost::make_shared<double>(0.);
204 reference->getOpPtrVector().push_back(
205 new OpReferenceLoad(ep.
stretchTensor, [pressure](
double,
double,
double) {
206 return FTensor::Tensor1<double, 6>{-*pressure, 0., 0.,
207 -*pressure, 0., -*pressure};
210 for (
const double time : {.2, .7}) {
212 *pressure = 3. * (2. * .07 * first_scale(load_time) +
213 5. * -.01 * second_scale(load_time));
216 state, zero, zero, time, deltaTime, {});
219 state, zero, zero, time, deltaTime, {});
220 PetscReal norm, error;
221 CHKERR VecNorm(expected, NORM_INFINITY, &norm);
222 CHKERR VecAXPY(assembled, -1., expected);
223 CHKERR VecNorm(assembled, NORM_INFINITY, &error);
224 if (!(norm > 0.) || !std::isfinite(error) ||
225 error > 1.e-12 * std::max(1., norm))
227 "External-strain residual error %g at time %g (norm %g)", error,
230 "Direct external strain: time %.2f, pressure %.6f, "
231 "assembled error %.3e\n",
232 time, *pressure, error);
242 "Direct atom requires the ordinary six-coefficient field");
249 CHKERR VecZeroEntries(zero);
251 CHKERR VecGhostUpdateBegin(ep.
solTSStep, INSERT_VALUES, SCATTER_FORWARD);
252 CHKERR VecGhostUpdateEnd(ep.
solTSStep, INSERT_VALUES, SCATTER_FORWARD);
253 boost::shared_ptr<VolumeElement> rhs, lhs;
256 auto audit = boost::make_shared<Audit>();
257 rhs->getOpPtrVector().push_back(
new OpAuditState(ep.
dataAtPts, audit));
260 state, rates, zero, 1., deltaTime, {});
262 state, rates, zero, 1., deltaTime, {});
266 std::map<std::string, SmartPetscObj<IS>> indices;
267 for (
const auto &field : fields) {
268 auto field_is = getFieldIS(ep, field);
270 CHKERR ISGetSize(field_is, &size);
273 "Direct test field %s is empty", field.c_str());
274 indices.emplace(field, field_is);
282 CHKERR VecZeroEntries(mixed);
283 const OperatorsTester::VectorFunction evaluate = [&](
Vec input,
Vec output) {
285 CHKERR VecCopy(input, trial);
286 CHKERR VecGhostUpdateBegin(trial, INSERT_VALUES, SCATTER_FORWARD);
287 CHKERR VecGhostUpdateEnd(trial, INSERT_VALUES, SCATTER_FORWARD);
288 CHKERR VecCopy(trial, trial_rates);
291 trial_rates, zero, 1., deltaTime, {});
292 CHKERR VecCopy(value, output);
295 auto check_direction = [&](
const std::string &name) {
297 CHKERR tester->checkVectorCentralFiniteDifference(
298 state, direction, residual, jacobian, 2.e-6, evaluate, error);
299 CHKERR MatMult(jacobian, direction, action);
300 PetscReal maximum = 0.;
301 for (
const auto &field : fields) {
302 PetscReal row_error, row_action;
303 CHKERR getFieldNorm(error, indices.at(field), row_error);
304 CHKERR getFieldNorm(action, indices.at(field), row_action);
305 const double tolerance = 2.e-8 + 2.e-6 * row_action;
306 if (!std::isfinite(row_error) || row_error > tolerance)
308 "Direct Jacobian row %s, direction %s: error %g exceeds %g",
309 field.c_str(), name.c_str(), row_error, tolerance);
310 maximum = std::max(maximum, row_error);
313 "Direct Jacobian direction %s: error %.3e\n",
314 name.c_str(), maximum);
319 PetscInt first, last;
321 for (
const auto &field : fields) {
323 for (
int component = 0; component != components; ++component) {
324 CHKERR VecZeroEntries(direction);
325 for (
const auto &dof : *problem->getNumeredRowDofsPtr()) {
326 const auto index = dof->getPetscGlobalDofIdx();
327 if (index < first || index >= last || dof->getName() != field ||
328 (components == 6 && dof->getDofCoeffIdx() != component))
330 CHKERR VecSetValue(direction, index, std::sin(.71 * (index + 1)) + .3,
333 CHKERR VecAssemblyBegin(direction);
334 CHKERR VecAssemblyEnd(direction);
336 CHKERR VecNormalize(direction, &norm);
339 "Empty direct material direction");
340 CHKERR VecGhostUpdateBegin(direction, INSERT_VALUES, SCATTER_FORWARD);
341 CHKERR VecGhostUpdateEnd(direction, INSERT_VALUES, SCATTER_FORWARD);
342 CHKERR VecAXPY(mixed, 1., direction);
343 CHKERR check_direction(field +
":" + std::to_string(component));
346 CHKERR VecCopy(mixed, direction);
347 CHKERR VecNormalize(direction,
nullptr);
348 CHKERR VecGhostUpdateBegin(direction, INSERT_VALUES, SCATTER_FORWARD);
349 CHKERR VecGhostUpdateEnd(direction, INSERT_VALUES, SCATTER_FORWARD);
350 CHKERR check_direction(
"mixed");
357 CHKERR VecGetSubVector(trial, indices.at(field), &subvector);
358 CHKERR VecZeroEntries(subvector);
359 CHKERR VecRestoreSubVector(trial, indices.at(field), &subvector);
361 CHKERR VecGhostUpdateBegin(trial, INSERT_VALUES, SCATTER_FORWARD);
362 CHKERR VecGhostUpdateEnd(trial, INSERT_VALUES, SCATTER_FORWARD);
364 trial, zero, zero, 1., deltaTime, {});
365 auto reference = boost::make_shared<VolumeElement>(ep.
mField);
367 reference->getOpPtrVector().push_back(
370 auto reference_stress = boost::make_shared<MatrixDouble>();
371 reference->getOpPtrVector().push_back(
372 new OpReferenceStress(ep.
dataAtPts, reference_stress, audit));
375 reference->getOpPtrVector().push_back(
376 new OpReferenceResidual(ep.
stretchTensor, reference_stress));
379 zero, zero, 1., deltaTime, {});
380 CHKERR VecAXPY(independent, -1., direct);
381 PetscReal stress_error, stress_norm;
384 if (!std::isfinite(stress_error) ||
385 stress_error > 1.e-11 * std::max(1., stress_norm))
387 "Independent direct material residual error %g, norm %g",
388 stress_error, stress_norm);
389 std::array<double, 3> local{audit->noncoaxial, audit->rateGradient,
393 CHKERR MPI_Allreduce(local.data(), global.data(), 3, MPI_DOUBLE, MPI_MAX,
395 CHKERR MPI_Allreduce(&audit->points, &points, 1, MPIU_INT, MPI_SUM,
397 if (!points || !(global[0] > 1.e-7) || !(global[1] > 1.e-7) ||
398 !std::isfinite(global[2]) || global[2] > 1.e-12)
400 "Direct reference coverage failed: noncoaxial %g, rate gradient "
401 "%g, energy error %g",
402 global[0], global[1], global[2]);
404 "Direct logarithmic material passed: stress error %.3e, "
405 "energy error %.3e, noncoaxial %.3e, rate gradient %.3e\n",
406 stress_error, global[2], global[0], global[1]);
414 "Check direct logarithmic Neo-Hookean material equations.\n";
416int main(
int argc,
char *argv[]) {
418 auto core_log = logging::core::get();
Shared mesh and problem setup for auxiliary formulation atoms.
#define FTENSOR_INDEXES(DIM,...)
#define FTENSOR_INDEX(DIM, I)
#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.
PetscErrorCode DMMoFEMGetProblemPtr(DM dm, const MoFEM::Problem **problem_ptr)
Get pointer to problem data structure.
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.
static LoggerType & setLog(const std::string channel)
Set ans resset chanel logger.
FTensor::Index< 'i', SPACE_DIM > i
FTensor::Index< 'j', 3 > j
FTensor::Index< 'k', 3 > k
const FTensor::Tensor2< T, Dim, Dim > Vec
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
SmartPetscObj< Vec > vectorDuplicate(Vec vec)
Create duplicate vector of smart vector.
decltype(GetFTensor1FromMatImpl< Tensor_Dim, S, DL, M >::get(std::declval< M & >(), 0, 0)) GetFTensor1FromMatType
static auto getFTensor0FromVec(V &data)
Get tensor rank 0 (scalar) form data vector.
MoFEM::Interface & mField
const std::string spatialL2Disp
const std::string elementVolumeName
const std::string piolaStress
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)
static PetscBool physicalTimeFlg
const std::string bubbleField
static double currentPhysicalTime
boost::shared_ptr< PhysicalEquations > physicalEquations
const std::string rotAxis
boost::shared_ptr< ForcesAndSourcesCore > contactTreeRhs
Make a contact tree.
MoFEMErrorCode setBaseVolumeElementOps(const int tag, const bool do_rhs, const bool do_lhs, const bool calc_rates, boost::shared_ptr< VolumeElementForcesAndSourcesCore > fe, const bool add_bubble=true)
MoFEMErrorCode setContactElementRhsOps(boost::shared_ptr< ForcesAndSourcesCore > &fe_contact_tree)
boost::shared_ptr< DataAtIntegrationPts > dataAtPts
const std::string hybridSpatialDisp
SmartPetscObj< Vec > solTSStep
SmartPetscObj< DM > dmElastic
Elastic problem.
const std::string stretchTensor
@ AUXILIARY_LOGARITHMIC_STRESS
Auxiliary logarithmic stress formulation.
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.
Data on single entity (This is passed as argument to DataOperator::doWork)
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.
static boost::shared_ptr< std::ostream > getStrmSync()
Get the strm sync object.
static boost::shared_ptr< std::ostream > getStrmSelf()
Get the strm self object.
Calculate directional derivative of the right hand side and compare it with tangent matrix derivative...
keeps basic data about problem
intrusive_ptr for managing petsc objects
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.
Volume finite element base.