v0.16.3
Loading...
Searching...
No Matches
auxiliary_logarithmic_stress_jacobian_atom.cpp
Go to the documentation of this file.
1/**
2 * @file auxiliary_logarithmic_stress_jacobian_atom.cpp
3 * @brief Check the production coupled auxiliary residual and Jacobian.
4 */
5
6#include <MoFEM.hpp>
7using namespace MoFEM;
10using namespace EshelbianPlasticity;
11
12namespace {
13
14using VolumeElement = VolumeElementForcesAndSourcesCore;
16
17SmartPetscObj<IS> getFieldIS(EshelbianCore &ep, const std::string &name) {
18 IS raw_is;
20 DMMoFEMGetFieldIS(ep.dmElastic, RowColData::ROW, name.c_str(), &raw_is),
21 "Get test field indices");
22 return SmartPetscObj<IS>(raw_is);
23}
24
25MoFEMErrorCode setState(EshelbianCore &ep, Vec state) {
27 CHKERR VecZeroEntries(state);
28 const Problem *problem;
30 PetscInt first, last;
31 CHKERR VecGetOwnershipRange(state, &first, &last);
32 const std::array<double, 5> deviator{{.12, -.08, .06, -.04, .09}};
33 const std::array<double, 5> stress{{-.21, .12, .31, .19, -.11}};
34 const std::array<double, 3> rotation{{.14, -.11, .07}};
35 for (const auto &dof : *problem->getNumeredRowDofsPtr()) {
36 const auto index = dof->getPetscGlobalDofIdx();
37 if (index < first || index >= last)
38 continue;
39 const auto &name = dof->getName();
40 const auto component = dof->getDofCoeffIdx();
41 double value = .01 * std::sin(.37 * (index + 1));
42 if (name == ep.logDeviator || name == ep.logJacobian ||
43 name == ep.auxiliaryLogStress || name == ep.rotAxis) {
44 if (dof->getDofOrder() == 0) {
45 if (name == ep.logDeviator)
46 value = deviator.at(component);
47 else if (name == ep.logJacobian)
48 value = .09;
49 else if (name == ep.auxiliaryLogStress)
50 value = stress.at(component);
51 else
52 value = rotation.at(component);
53 } else {
54 value *= .2 / (1 + dof->getDofOrder());
55 }
56 }
57 CHKERR VecSetValue(state, index, value, INSERT_VALUES);
58 }
59 CHKERR VecAssemblyBegin(state);
60 CHKERR VecAssemblyEnd(state);
61 CHKERR VecGhostUpdateBegin(state, INSERT_VALUES, SCATTER_FORWARD);
62 CHKERR VecGhostUpdateEnd(state, INSERT_VALUES, SCATTER_FORWARD);
64}
65
68 if (!ep.plasticVolume)
70 double history_norm = .2;
71 CHKERR PetscOptionsGetReal(nullptr, nullptr,
72 "-auxiliary_plastic_history_norm", &history_norm,
73 nullptr);
74 if (!std::isfinite(history_norm) || history_norm <= 0)
76 "Plastic Jacobian fixture requires positive history norm");
77 const FTensor::Tensor1<double, 5> t_history(.13, -.29, .17, .31, -.11);
78 FTensor::Index<'A', 5> A;
79 const double scale = history_norm / std::sqrt(t_history(A) * t_history(A));
80 auto set_history = [&](boost::shared_ptr<FieldEntity> field_entity) {
82 auto values = field_entity->getEntFieldData();
83 if (values.size() != 5)
85 "Plastic Jacobian fixture requires five P0 history coordinates");
86 auto t_values = getFTensor1FromPtr<5>(&values[0]);
87 t_values(A) = scale * t_history(A);
89 };
90 CHKERR ep.mField.getInterface<FieldBlas>()->fieldLambdaOnEntities(
91 set_history, ep.plasticHField, ep.plasticVolumes.get());
93}
94
95struct GaussAudit {
96 PetscInt elements = 0;
97 double noncoaxial = 0;
98 double variation = 0;
99 double plasticHistory = 0;
100 double plasticStretch = 0;
101 double plasticNoncoaxial = 0;
102};
103
104struct OpAuditGaussState : public VolumeElement::UserDataOperator {
105 OpAuditGaussState(boost::shared_ptr<DataAtIntegrationPts> data,
106 boost::shared_ptr<GaussAudit> audit,
107 const Material::Parameters parameters, const double alpha_u)
108 : VolumeElement::UserDataOperator(NOSPACE, OPSPACE), dataPtr(data),
109 auditPtr(audit), parameters(parameters), alphaU(alpha_u) {}
110
111 MoFEMErrorCode doWork(int, EntityType, EntData &) override {
113 if (getFEMethod()->snes) {
114 PetscBool domain_error;
115 CHKERR SNESGetFunctionDomainError(getFEMethod()->snes, &domain_error);
116 if (domain_error)
118 }
119 const int points = getGaussPts().size2();
120 if (points <= 1)
121 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
122 "Coupled Jacobian test requires multiple Gauss points");
123 if (alphaU != 0)
124 CHKERR checkMaterialRate(points);
125 auto t_d = MatrixSizeHelper<GetFTensor1FromMatType<5, -1, DL>, DL>::get(
126 *dataPtr->auxiliaryData->logDeviator, points)();
127 auto t_stress =
129 *dataPtr->auxiliaryData->stress, points)();
130 auto t_h_p = dataPtr->getFTensorPlasticH(points);
131 auto t_f_p = dataPtr->getFTensorPlasticF(points);
132 FTensor::Index<'A', 5> A;
133 FTENSOR_INDEXES(3, i, j, k);
134 FTensor::Tensor1<double, 5> t_first, t_difference;
135 t_first(A) = t_d(A);
136 for (int gg = 0; gg != points; ++gg) {
137 const auto t_d_tensor = Tensor2SymmetricDeviatorBasis::getTensor(t_d);
138 const auto t_stress_tensor =
139 Tensor2SymmetricDeviatorBasis::getTensor(t_stress);
141 t_commutator(i, j) = t_d_tensor(i, k) * t_stress_tensor(k, j) -
142 t_stress_tensor(i, k) * t_d_tensor(k, j);
143 auditPtr->noncoaxial =
144 std::max(auditPtr->noncoaxial,
145 std::sqrt(t_commutator(i, j) * t_commutator(i, j)));
146 t_difference(A) = t_d(A) - t_first(A);
147 auditPtr->variation = std::max(
148 auditPtr->variation, std::sqrt(t_difference(A) * t_difference(A)));
149 if (std::abs(t_h_p(i, i)) > 1.e-12 ||
150 std::abs(determinantTensor3by3(t_f_p) - 1.) > 1.e-12)
151 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
152 "Plastic history must remain trace-free and isochoric");
153 auditPtr->plasticHistory = std::max(auditPtr->plasticHistory,
154 std::sqrt(t_h_p(i, j) * t_h_p(i, j)));
155 const auto t_identity = FTensor::Kronecker_Delta<double>();
156 FTensor::Tensor2<double, 3, 3> t_plastic_difference;
157 t_plastic_difference(i, j) = t_f_p(i, j) - t_identity(i, j);
158 auditPtr->plasticStretch = std::max(
159 auditPtr->plasticStretch,
160 std::sqrt(t_plastic_difference(i, j) * t_plastic_difference(i, j)));
161 t_commutator(i, j) =
162 t_h_p(i, k) * t_d_tensor(k, j) - t_d_tensor(i, k) * t_h_p(k, j);
163 const double history_deviator_commutator =
164 std::sqrt(t_commutator(i, j) * t_commutator(i, j));
165 t_commutator(i, j) = t_h_p(i, k) * t_stress_tensor(k, j) -
166 t_stress_tensor(i, k) * t_h_p(k, j);
167 auditPtr->plasticNoncoaxial = std::max(
168 auditPtr->plasticNoncoaxial,
169 std::min(history_deviator_commutator,
170 std::sqrt(t_commutator(i, j) * t_commutator(i, j))));
171 ++t_d;
172 ++t_stress;
173 ++t_h_p;
174 ++t_f_p;
175 }
176 ++auditPtr->elements;
178 }
179
180 MoFEMErrorCode checkMaterialRate(const int points) {
182 const auto &fields = *dataPtr->auxiliaryData;
183 const auto &material = *dataPtr->auxiliaryMaterialData;
184 using CoordinateView = GetFTensor1FromMatType<5, -1, DL>;
185 auto get_coordinates = [&](const auto &values) {
186 return MatrixSizeHelper<CoordinateView, DL>::get(*values, points)();
187 };
188 auto t_d = get_coordinates(fields.logDeviator);
189 auto t_rate = get_coordinates(fields.logDeviatorDot);
190 auto t_stress = get_coordinates(fields.stress);
191 auto t_elastic_stress = get_coordinates(material.elasticStress);
192 auto t_dm = get_coordinates(material.materialDeviator);
193 auto t_energy =
195 *material.energy, points)();
196 VectorDouble mixed_energy;
197 CHKERR evaluateAuxiliaryMixedStoredEnergy(fields, material, mixed_energy);
198 auto t_mixed = getFTensor0FromVec(mixed_energy);
199 FTensor::Index<'A', 5> A;
200 for (int gg = 0; gg != points; ++gg) {
201 Material::Coordinates t_material_deviator, t_forward_stress, t_error;
202 t_material_deviator(A) = t_dm(A);
203 double material_energy;
204 CHKERR Material::evaluateDeviator(parameters, t_material_deviator,
205 material_energy, &t_forward_stress);
206 t_error(A) = t_stress(A) - alphaU * t_rate(A) - t_forward_stress(A);
207 const double constitutive_error = std::sqrt(t_error(A) * t_error(A));
208 t_error(A) = t_elastic_stress(A) - t_forward_stress(A);
209 const double elastic_error = std::sqrt(t_error(A) * t_error(A));
210 const double expected_energy =
211 material_energy + t_forward_stress(A) * (t_d(A) - t_dm(A)) +
213 const double energy_error = std::abs(t_mixed - expected_energy);
214 if (!std::isfinite(constitutive_error) || constitutive_error > 1.e-10 ||
215 !std::isfinite(elastic_error) || elastic_error > 1.e-10 ||
216 !std::isfinite(energy_error) || energy_error > 1.e-10)
217 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
218 "Auxiliary rate material check: constitutive error %g, "
219 "elastic stress error %g, stored energy error %g",
220 constitutive_error, elastic_error, energy_error);
221 ++t_d;
222 ++t_rate;
223 ++t_stress;
224 ++t_elastic_stress;
225 ++t_dm;
226 ++t_energy;
227 ++t_mixed;
228 }
230 }
231
232 boost::shared_ptr<DataAtIntegrationPts> dataPtr;
233 boost::shared_ptr<GaussAudit> auditPtr;
234 Material::Parameters parameters;
235 double alphaU;
236};
237
238MoFEMErrorCode getFieldNorm(Vec vector, IS field, PetscReal &norm) {
240 Vec subvector;
241 CHKERR VecGetSubVector(vector, field, &subvector);
242 CHKERR VecNorm(subvector, NORM_INFINITY, &norm);
243 CHKERR VecRestoreSubVector(vector, field, &subvector);
245}
246
247MoFEMErrorCode zeroField(Vec vector, IS field) {
249 Vec subvector;
250 CHKERR VecGetSubVector(vector, field, &subvector);
251 CHKERR VecZeroEntries(subvector);
252 CHKERR VecRestoreSubVector(vector, field, &subvector);
253 CHKERR VecGhostUpdateBegin(vector, INSERT_VALUES, SCATTER_FORWARD);
254 CHKERR VecGhostUpdateEnd(vector, INSERT_VALUES, SCATTER_FORWARD);
256}
257
258MoFEMErrorCode checkCrossBlock(EshelbianCore &ep, Mat jacobian,
259 const std::string &row,
260 const std::string &column,
261 const bool symmetric = true) {
263 auto row_is = getFieldIS(ep, row);
264 auto column_is = getFieldIS(ep, column);
265 Mat raw_forward, raw_reverse, raw_transpose;
266 CHKERR MatCreateSubMatrix(jacobian, row_is, column_is, MAT_INITIAL_MATRIX,
267 &raw_forward);
268 SmartPetscObj<Mat> forward(raw_forward);
269 CHKERR MatCreateSubMatrix(jacobian, column_is, row_is, MAT_INITIAL_MATRIX,
270 &raw_reverse);
271 SmartPetscObj<Mat> reverse(raw_reverse);
272 CHKERR MatTranspose(reverse, MAT_INITIAL_MATRIX, &raw_transpose);
273 SmartPetscObj<Mat> transpose(raw_transpose);
274 PetscReal norm, error;
275 CHKERR MatNorm(forward, NORM_INFINITY, &norm);
276 CHKERR MatAXPY(forward, -1., transpose, DIFFERENT_NONZERO_PATTERN);
277 CHKERR MatNorm(forward, NORM_INFINITY, &error);
278 if (!std::isfinite(norm) || norm <= 1.e-13 || !std::isfinite(error) ||
279 (symmetric ? error > 1.e-12 * std::max(1., norm)
280 : error <= 1.e-12 * std::max(1., norm)))
281 SETERRQ(ep.mField.get_comm(), MOFEM_ATOM_TEST_INVALID,
282 "Cross block %s/%s: norm %g, transpose difference %g, symmetric %d",
283 row.c_str(), column.c_str(), norm, error,
284 static_cast<int>(symmetric));
286}
287
288MoFEMErrorCode checkDomainRecovery(EshelbianCore &ep,
289 boost::shared_ptr<VolumeElement> rhs,
290 Vec state, Vec rates, Vec accelerations,
291 const double dt) {
293 const Problem *problem;
295 TsCtx ts_context(ep.mField, problem->getName());
296 ts_context.getLoopsIFunction().emplace_back(ep.elementVolumeName, rhs);
297 auto ts = createTS(ep.mField.get_comm());
298 CHKERR TSSetTimeStep(ts, dt);
299 CHKERR TSSetI2Function(ts, nullptr, TsSetI2Function, &ts_context);
300 SNES snes;
301 CHKERR TSGetSNES(ts, &snes);
302 struct ResidualContext {
303 TS ts;
304 Vec rates, accelerations;
305 } residual_context{ts, rates, accelerations};
306 auto input = vectorDuplicate(state);
307 auto residual = vectorDuplicate(state);
308 auto reference = vectorDuplicate(state);
309 // Include PETSc's SNES input lock and MoFEM's TS assembly lifecycle, which
310 // OperatorsTester alone does not exercise. I2Function also covers rates.
311 CHKERR SNESSetFunction(
312 snes, residual,
313 [](SNES, Vec x, Vec f, void *ctx) -> PetscErrorCode {
314 auto &data = *static_cast<ResidualContext *>(ctx);
315 return TSComputeI2Function(data.ts, 1., x, data.rates,
316 data.accelerations, f);
317 },
318 &residual_context);
319 CHKERR VecCopy(state, input);
320 CHKERR SNESComputeFunction(snes, input, reference);
321 PetscReal reference_norm;
322 CHKERR VecNorm(reference, NORM_2, &reference_norm);
323 if (!std::isfinite(reference_norm))
325 "Domain-recovery reference residual is not finite");
326
327 PetscInt first, last;
328 CHKERR VecGetOwnershipRange(input, &first, &last);
329 PetscInt injected = 0;
330 if (ep.mField.get_comm_rank() == 0) {
331 for (const auto &dof : *problem->getNumeredRowDofsPtr()) {
332 const auto index = dof->getPetscGlobalDofIdx();
333 if (index >= first && index < last && dof->getName() == ep.logJacobian &&
334 dof->getDofOrder() == 0) {
335 // exp(theta) is finite, but the volumetric energy exp(2 theta)
336 // overflows. Only one owned cell is outside the material domain.
337 CHKERR VecSetValue(input, index, 400., INSERT_VALUES);
338 injected = 1;
339 break;
340 }
341 }
342 }
343 PetscInt total_injected;
344 CHKERR MPI_Allreduce(&injected, &total_injected, 1, MPIU_INT, MPI_SUM,
345 ep.mField.get_comm());
346 if (total_injected != 1)
348 "Domain-recovery fixture requires one owned logarithmic volume");
349 CHKERR VecAssemblyBegin(input);
350 CHKERR VecAssemblyEnd(input);
351 CHKERR SNESComputeFunction(snes, input, residual);
352 PetscBool domain_error;
353 CHKERR SNESGetFunctionDomainError(snes, &domain_error);
354 PetscInt local_domain = domain_error ? 1 : 0, domains;
355 CHKERR MPI_Allreduce(&local_domain, &domains, 1, MPIU_INT, MPI_SUM,
356 ep.mField.get_comm());
357 PetscReal rejected_norm;
358 CHKERR VecNorm(residual, NORM_2, &rejected_norm);
359 if (!domains || std::isfinite(rejected_norm))
361 "Nonrepresentable volume must flag the SNES residual domain");
362 for (Vec vector : {input.get(), residual.get()}) {
363 PetscInt lock;
364 CHKERR VecLockGet(vector, &lock);
365 if (lock)
367 "Rejected SNES residual left a vector locked");
368 }
369
370 CHKERR VecCopy(state, input);
371 CHKERR SNESComputeFunction(snes, input, residual);
372 CHKERR SNESGetFunctionDomainError(snes, &domain_error);
373 local_domain = domain_error ? 1 : 0;
374 CHKERR MPI_Allreduce(&local_domain, &domains, 1, MPIU_INT, MPI_SUM,
375 ep.mField.get_comm());
376 CHKERR VecAXPY(residual, -1., reference);
377 PetscReal error;
378 CHKERR VecNorm(residual, NORM_2, &error);
379 if (domains || !std::isfinite(error) ||
380 error > 1.e-12 * std::max(1., reference_norm))
382 "SNES residual did not recover after domain rejection: error %g",
383 error);
384 CHKERR PetscPrintf(ep.mField.get_comm(),
385 "Auxiliary residual domain recovery passed: error %.3e\n",
386 error);
388}
389
390MoFEMErrorCode runJacobianAtom(EshelbianCore &ep) {
393 auto state = createDMVector(ep.dmElastic);
394 auto rates = createDMVector(ep.dmElastic);
395 auto accelerations = createDMVector(ep.dmElastic);
396 CHKERR setState(ep, state);
397 // OperatorsTester takes increments and scales them by dt and dt squared.
398 // Nonzero histories exercise the shared mechanical rate-data producers.
399 constexpr double dt = .4;
400 CHKERR VecCopy(state, rates);
401 CHKERR VecScale(rates, .3);
402 CHKERR VecCopy(state, accelerations);
403 CHKERR VecScale(accelerations, -.2);
404 CHKERR VecCopy(state, ep.solTSStep);
405 CHKERR VecGhostUpdateBegin(ep.solTSStep, INSERT_VALUES, SCATTER_FORWARD);
406 CHKERR VecGhostUpdateEnd(ep.solTSStep, INSERT_VALUES, SCATTER_FORWARD);
407 boost::shared_ptr<VolumeElement> rhs, lhs;
409 CHKERR ep.setVolumeElementOps(1, true, false, rhs, lhs);
410 auto audit = boost::make_shared<GaussAudit>();
411 Material::Parameters parameters{};
412 CHKERR PetscOptionsGetReal(nullptr, nullptr, "-neo_hookean_c10",
413 &parameters.c10, nullptr);
414 CHKERR PetscOptionsGetReal(nullptr, nullptr, "-neo_hookean_K",
415 &parameters.bulkModulus, nullptr);
417 rhs->getOpPtrVector().push_back(
418 new OpAuditGaussState(ep.dataAtPts, audit, parameters, ep.alphaU));
419 auto *tester = ep.mField.getInterface<OperatorsTester>();
420 auto jacobian = tester->assembleMat(ep.dmElastic, ep.elementVolumeName, lhs,
421 state, rates, accelerations, 1., dt, {});
422 auto residual = tester->assembleVec(ep.dmElastic, ep.elementVolumeName, rhs,
423 state, rates, accelerations, 1., dt, {});
424
425 std::vector<std::string> fields{ep.logDeviator, ep.logJacobian,
427 ep.bubbleField, ep.rotAxis,
429 std::map<std::string, SmartPetscObj<IS>> field_indices;
430 for (const auto &name : fields) {
431 auto indices = getFieldIS(ep, name);
432 PetscInt size;
433 CHKERR ISGetSize(indices, &size);
434 if (!size)
436 "Missing coupled test field %s", name.c_str());
437 field_indices.emplace(name, indices);
438 }
439
440 auto zero_rates = createDMVector(ep.dmElastic);
441 CHKERR VecZeroEntries(zero_rates);
442 auto rate_residual =
443 tester->assembleVec(ep.dmElastic, ep.elementVolumeName, rhs, state,
444 zero_rates, zero_rates, 1., dt, {});
445 CHKERR VecAYPX(rate_residual, -1., residual);
446 for (const auto &[field, active] :
447 {std::pair{ep.spatialL2Disp, ep.alphaW != 0 || ep.alphaRho != 0},
448 std::pair{ep.rotAxis,
449 ep.alphaViscousR != 0 || ep.alphaViscousOmega != 0},
450 std::pair{ep.auxiliaryLogStress, ep.alphaU != 0},
451 std::pair{ep.logDeviator, false}, std::pair{ep.logJacobian, false}}) {
452 PetscReal norm;
453 CHKERR getFieldNorm(rate_residual, field_indices.at(field), norm);
454 if (!std::isfinite(norm) || (active ? norm <= 1.e-12 : norm > 1.e-12))
456 "Rate residual %s: norm %g, active %d", field.c_str(), norm,
457 static_cast<int>(active));
458 }
459
460 if (ep.alphaU != 0) {
461 auto zero_deviator_rates = vectorDuplicate(rates);
462 CHKERR VecCopy(rates, zero_deviator_rates);
463 CHKERR zeroField(zero_deviator_rates, field_indices.at(ep.logDeviator));
464 auto zero_deviator_residual =
465 tester->assembleVec(ep.dmElastic, ep.elementVolumeName, rhs, state,
466 zero_deviator_rates, accelerations, 1., dt, {});
467 auto deviator_rate_effect = vectorDuplicate(residual);
468 CHKERR VecWAXPY(deviator_rate_effect, -1., zero_deviator_residual,
469 residual);
470 for (const auto &field : fields) {
471 PetscReal norm;
472 CHKERR getFieldNorm(deviator_rate_effect, field_indices.at(field), norm);
473 const bool active = field == ep.auxiliaryLogStress;
474 if (!std::isfinite(norm) || (active ? norm <= 1.e-12 : norm > 1.e-12))
476 "Deviator rate must affect only Td: row %s, norm %g",
477 field.c_str(), norm);
478 }
479
480 // All other rates, including log J, stay nonzero. Removing alpha_u must
481 // give the identical residual once the D rate vanishes.
482 const auto alpha_u = ep.alphaU;
483 ep.alphaU = 0;
484 boost::shared_ptr<VolumeElement> elastic_rhs, elastic_lhs;
485 CHKERR ep.setVolumeElementOps(1, true, false, elastic_rhs, elastic_lhs);
486 ep.alphaU = alpha_u;
487 auto elastic_residual =
488 tester->assembleVec(ep.dmElastic, ep.elementVolumeName, elastic_rhs,
489 state, rates, accelerations, 1., dt, {});
490 CHKERR VecAXPY(elastic_residual, -1., zero_deviator_residual);
491 PetscReal error;
492 CHKERR VecNorm(elastic_residual, NORM_INFINITY, &error);
493 if (!std::isfinite(error) || error > 1.e-12)
495 "Zero D rate must recover alpha_u=0 residual: error %g", error);
496 CHKERR PetscPrintf(ep.mField.get_comm(),
497 "Auxiliary deviator rate isolation and zero-rate "
498 "recovery passed: error %.3e\n",
499 error);
500 }
501
502 auto trial = vectorDuplicate(state);
503 auto trial_rates = vectorDuplicate(state);
504 auto trial_accelerations = vectorDuplicate(state);
505 const OperatorsTester::VectorFunction evaluate = [&](Vec input, Vec output) {
507 CHKERR VecCopy(input, trial);
508 CHKERR VecGhostUpdateBegin(trial, INSERT_VALUES, SCATTER_FORWARD);
509 CHKERR VecGhostUpdateEnd(trial, INSERT_VALUES, SCATTER_FORWARD);
510 // Perturb both increments consistently with the assembled TS shifts.
511 CHKERR VecWAXPY(trial_rates, -1., state, trial);
512 CHKERR VecCopy(trial_rates, trial_accelerations);
513 CHKERR VecAXPY(trial_rates, 1., rates);
514 CHKERR VecAXPY(trial_accelerations, 1., accelerations);
515 auto value =
516 tester->assembleVec(ep.dmElastic, ep.elementVolumeName, rhs, trial,
517 trial_rates, trial_accelerations, 1., dt, {});
518 CHKERR VecCopy(value, output);
520 };
521 auto direction = vectorDuplicate(state);
522 auto mixed = vectorDuplicate(state);
523 auto error = vectorDuplicate(residual);
524 auto action = vectorDuplicate(residual);
525 CHKERR VecZeroEntries(mixed);
526 auto check_direction = [&](const std::string &name) {
528 CHKERR tester->checkVectorCentralFiniteDifference(
529 state, direction, residual, jacobian, 2.e-6, evaluate, error);
530 CHKERR MatMult(jacobian, direction, action);
531 PetscReal max_error = 0;
532 for (const auto &row : fields) {
533 PetscReal row_error, row_action;
534 CHKERR getFieldNorm(error, field_indices.at(row), row_error);
535 CHKERR getFieldNorm(action, field_indices.at(row), row_action);
536 const double tolerance = 2.e-8 + 2.e-6 * row_action;
537 if (!std::isfinite(row_error) || row_error > tolerance)
539 "Jacobian row %s, direction %s: FD error %g exceeds %g "
540 "(Jacobian action %g)",
541 row.c_str(), name.c_str(), row_error, tolerance, row_action);
542 max_error = std::max(max_error, row_error);
543 }
544 CHKERR PetscPrintf(ep.mField.get_comm(),
545 "Auxiliary coupled Jacobian direction %s: error %.3e\n",
546 name.c_str(), max_error);
548 };
549 for (const auto &name : fields) {
550 CHKERR VecZeroEntries(direction);
551 Vec subvector;
552 auto indices = field_indices.at(name);
553 CHKERR VecGetSubVector(direction, indices, &subvector);
554 PetscInt first, last;
555 CHKERR VecGetOwnershipRange(subvector, &first, &last);
556 PetscScalar *values;
557 CHKERR VecGetArray(subvector, &values);
558 for (PetscInt index = first; index != last; ++index)
559 values[index - first] = std::sin(.71 * (index + 1)) + .3;
560 CHKERR VecRestoreArray(subvector, &values);
561 CHKERR VecRestoreSubVector(direction, indices, &subvector);
562 PetscReal norm;
563 CHKERR VecNormalize(direction, &norm);
564 if (!(norm > 0.))
566 "Zero test direction for %s", name.c_str());
567 CHKERR VecGhostUpdateBegin(direction, INSERT_VALUES, SCATTER_FORWARD);
568 CHKERR VecGhostUpdateEnd(direction, INSERT_VALUES, SCATTER_FORWARD);
569 CHKERR VecAXPY(mixed, 1., direction);
570 CHKERR check_direction(name);
571 }
572 CHKERR VecCopy(mixed, direction);
573 CHKERR VecNormalize(direction, nullptr);
574 CHKERR VecGhostUpdateBegin(direction, INSERT_VALUES, SCATTER_FORWARD);
575 CHKERR VecGhostUpdateEnd(direction, INSERT_VALUES, SCATTER_FORWARD);
576 CHKERR check_direction("mixed");
577
578 for (const auto &material : {ep.logDeviator, ep.logJacobian})
579 for (const auto &mechanical : {ep.piolaStress, ep.bubbleField, ep.rotAxis})
580 CHKERR checkCrossBlock(ep, jacobian, material, mechanical);
581 CHKERR checkCrossBlock(ep, jacobian, ep.logDeviator, ep.logJacobian);
582 CHKERR checkCrossBlock(ep, jacobian, ep.logDeviator, ep.auxiliaryLogStress,
583 ep.alphaU == 0);
584
585 // At zero total Piola stress there is no DD material Hessian: f(D) has
586 // already been replaced by Td:D-f*(Td), and only stress work contributes DD.
587 CHKERR VecCopy(state, trial);
588 CHKERR zeroField(trial, field_indices.at(ep.piolaStress));
589 CHKERR zeroField(trial, field_indices.at(ep.bubbleField));
590 auto zero_stress_jacobian =
591 tester->assembleMat(ep.dmElastic, ep.elementVolumeName, lhs, trial, rates,
592 accelerations, 1., dt, {});
593 Mat raw_dd;
594 CHKERR MatCreateSubMatrix(
595 zero_stress_jacobian, field_indices.at(ep.logDeviator),
596 field_indices.at(ep.logDeviator), MAT_INITIAL_MATRIX, &raw_dd);
597 SmartPetscObj<Mat> dd(raw_dd);
598 PetscReal dd_norm;
599 CHKERR MatNorm(dd, NORM_INFINITY, &dd_norm);
600 if (!std::isfinite(dd_norm) || dd_norm > 1.e-13)
602 "Zero-stress DD block must vanish; norm %g", dd_norm);
603
604 PetscInt elements;
605 double noncoaxial, variation;
606 CHKERR MPI_Allreduce(&audit->elements, &elements, 1, MPIU_INT, MPI_SUM,
607 ep.mField.get_comm());
608 CHKERR MPI_Allreduce(&audit->noncoaxial, &noncoaxial, 1, MPI_DOUBLE, MPI_MAX,
609 ep.mField.get_comm());
610 CHKERR MPI_Allreduce(&audit->variation, &variation, 1, MPI_DOUBLE, MPI_MAX,
611 ep.mField.get_comm());
612 if (!elements || !(noncoaxial > 1.e-4) || !(variation > 1.e-7))
614 "Insufficient Gauss-state coverage: elements %d, commutator %g, "
615 "variation %g",
616 static_cast<int>(elements), noncoaxial, variation);
617 if (ep.plasticVolume) {
618 const std::array<double, 3> local{
619 audit->plasticHistory, audit->plasticStretch, audit->plasticNoncoaxial};
620 std::array<double, 3> global;
621 CHKERR MPI_Allreduce(local.data(), global.data(), 3, MPI_DOUBLE, MPI_MAX,
622 ep.mField.get_comm());
623 if (global[0] < 1.e-3 || global[1] < 1.e-3 || global[2] < 1.e-4)
625 "Insufficient plastic state coverage: Hp norm %g, Fp-I norm %g, "
626 "minimum Hp/D and Hp/Td commutator %g",
627 global[0], global[1], global[2]);
628 CHKERR PetscPrintf(ep.mField.get_comm(),
629 "Auxiliary plastic Jacobian: Hp norm %.3e, "
630 "Fp-I norm %.3e, commutator %.3e\n",
631 global[0], global[1], global[2]);
632 }
633 CHKERR checkDomainRecovery(ep, rhs, state, rates, accelerations, dt);
634 CHKERR PetscPrintf(ep.mField.get_comm(),
635 "Auxiliary coupled Jacobian atom passed: "
636 "commutator %.3e, Gauss variation %.3e\n",
637 noncoaxial, variation);
639}
640
641} // namespace
642
643static char help[] = "Verify the full auxiliary logarithmic stress Jacobian.\n";
644
645int main(int argc, char *argv[]) {
646 MoFEM::Core::Initialize(&argc, &argv, nullptr, help);
647 auto core_log = logging::core::get();
648 core_log->add_sink(LogManager::createSink(LogManager::getStrmWorld(), "EP"));
649 LogManager::setLog("EP");
650 core_log->add_sink(
652 LogManager::setLog("EPSELF");
653 core_log->add_sink(
655 LogManager::setLog("EPSYNC");
656 try {
658 }
661 return 0;
662}
Material and stress-work blocks for the independent D/theta/Td fields.
Shared mesh and problem setup for auxiliary formulation atoms.
const double alphaU
#define FTENSOR_INDEXES(DIM,...)
int main()
Kronecker Delta class.
@ ROW
#define CATCH_ERRORS
Catch errors.
#define CHK_THROW_MESSAGE(err, msg)
Check and throw MoFEM exception.
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
@ NOSPACE
Definition definitions.h:83
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
@ MOFEM_ATOM_TEST_INVALID
Definition definitions.h:40
#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.
Definition DMMoFEM.cpp:422
PetscErrorCode DMMoFEMGetFieldIS(DM dm, RowColData rc, const char field_name[], IS *is)
get field is in the problem
Definition DMMoFEM.cpp:1507
auto createDMVector(DM dm, RowColData rc=RowColData::COL)
Get smart vector from DM.
Definition DMMoFEM.hpp:1237
static LoggerType & setLog(const std::string channel)
Set ans resset chanel logger.
FTensor::Index< 'i', SPACE_DIM > i
double dt
FTensor::Index< 'j', 3 > j
FTensor::Index< 'k', 3 > k
const FTensor::Tensor2< T, Dim, Dim > Vec
MoFEMErrorCode setPlasticHistory(EshelbianCore &ep, const PlasticHistory &history, const FTensor::Tensor2_symmetric< double, SPACE_DIM > &t_direction, const double scale)
MoFEMErrorCode runAuxiliaryLogarithmicStressTest(const std::function< MoFEMErrorCode(EshelbianCore &)> &test)
MoFEMErrorCode evaluateAuxiliaryMixedStoredEnergy(const AuxiliaryLogarithmicStressData &fields, const AuxiliaryLogarithmicStressMaterialData &material, VectorDouble &mixed_energy)
const Tensor2_symmetric_Expr< const ddTensor0< T, Dim, i, j >, typename promote< T, double >::V, Dim, i, j > dd(const Tensor0< T * > &a, const Index< i, Dim > index1, const Index< j, Dim > index2, const Tensor1< int, Dim > &d_ijk, const Tensor1< double, Dim > &d_xyz)
Definition ddTensor0.hpp:33
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
implementation of Data Operators for Forces and Sources
Definition Common.hpp:10
PetscErrorCode PetscOptionsGetReal(PetscOptions *, const char pre[], const char name[], PetscReal *dval, PetscBool *set)
PetscErrorCode TsSetI2Function(TS ts, PetscReal t, Vec u, Vec u_t, Vec u_tt, Vec F, void *ctx)
Calculation the right hand side for second order PDE in time.
Definition TsCtx.cpp:620
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
static auto getFTensor0FromVec(V &data)
Get tensor rank 0 (scalar) form data vector.
static auto determinantTensor3by3(T &t)
Calculate the determinant of a 3x3 matrix or a tensor of rank 2.
auto deviator(FTensor::Tensor2_symmetric< T, DIM > &t_stress, double trace, FTensor::Tensor2_symmetric< double, DIM > &t_alpha, FTensor::Number< DIM >)
constexpr AssemblyType A
MoFEM::Interface & mField
const std::string spatialL2Disp
boost::shared_ptr< Range > plasticVolumes
const std::string elementVolumeName
const std::string logDeviator
const std::string plasticHField
const std::string piolaStress
const std::string logJacobian
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)
const std::string bubbleField
const std::string auxiliaryLogStress
const std::string rotAxis
boost::shared_ptr< ForcesAndSourcesCore > contactTreeRhs
Make a contact tree.
static PetscBool plasticVolume
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.
static MoFEMErrorCode validateParameters(const Parameters &parameters)
Check finite, strictly positive C10, K and representable mu = 2*C10.
static MoFEMErrorCode evaluateDeviator(const Parameters &parameters, const Coordinates &t_deviator, double &energy, Coordinates *stress_ptr=nullptr, Tangent *hessian_ptr=nullptr)
Evaluate f(D), optionally its five-component gradient and Hessian.
virtual MPI_Comm & get_comm() const =0
virtual int get_comm_rank() const =0
static MoFEMErrorCode Initialize(int *argc, char ***args, const char file[], const char help[])
Initializes the MoFEM database PETSc, MOAB and MPI.
Definition Core.cpp:68
static MoFEMErrorCode Finalize()
Checks for options to be called at the conclusion of the program.
Definition Core.cpp:123
Data on single entity (This is passed as argument to DataOperator::doWork)
Basic algebra on fields.
Definition FieldBlas.hpp:21
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...
SmartPetscObj< Mat > assembleMat(SmartPetscObj< DM > dm, std::string fe_name, boost::shared_ptr< FEMethod > pipeline, SmartPetscObj< Vec > x, SmartPetscObj< Vec > delta_x, SmartPetscObj< Vec > delta2_x, double time, double delta_t, CacheTupleWeakPtr cache_ptr)
Assemble the left hand side vector.
keeps basic data about problem
intrusive_ptr for managing petsc objects
Interface for Time Stepping (TS) solver.
Definition TsCtx.hpp:17
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.
double scale
Definition plastic.cpp:123