v0.16.3
Loading...
Searching...
No Matches
auxiliary_logarithmic_stress_output_atom.cpp
Go to the documentation of this file.
1/**
2 * @file auxiliary_logarithmic_stress_output_atom.cpp
3 * @brief Check production output meanings and diagnostic state preservation.
4 */
5
6#include <MoFEM.hpp>
7using namespace MoFEM;
9#include <MatrixFunction.hpp>
11using namespace EshelbianPlasticity;
12
13#include <array>
14#include <cmath>
15
16namespace {
17
19using Coordinates = Material::Coordinates;
20
21MoFEMErrorCode checkNear(const double actual, const double expected,
22 const char *name, const double tolerance = 2.e-6) {
24 if (!std::isfinite(actual) ||
25 std::abs(actual - expected) >
26 tolerance * std::max(1., std::abs(expected)))
27 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
28 "%s: expected %.16e, obtained %.16e", name, expected, actual);
30}
31
32MoFEMErrorCode setState(EshelbianCore &ep, Vec state, const Coordinates &t_d,
33 const double theta, const Coordinates &t_stress) {
35 CHKERR VecZeroEntries(state);
36 const Problem *problem = nullptr;
38 PetscInt first, last;
39 CHKERR VecGetOwnershipRange(state, &first, &last);
40 const std::array<double, 3> rotation{.14, -.11, .07};
41 for (const auto &dof : *problem->getNumeredRowDofsPtr()) {
42 const auto index = dof->getPetscGlobalDofIdx();
43 if (index < first || index >= last || dof->getDofOrder() != 0)
44 continue;
45 const auto &name = dof->getName();
46 const auto component = dof->getDofCoeffIdx();
47 double value = 0.;
48 if (name == ep.logDeviator)
49 value = t_d(component);
50 else if (name == ep.logJacobian)
51 value = theta;
52 else if (name == ep.auxiliaryLogStress)
53 value = t_stress(component);
54 else if (name == ep.rotAxis)
55 value = rotation.at(component);
56 CHKERR VecSetValue(state, index, value, INSERT_VALUES);
57 }
58 CHKERR VecAssemblyBegin(state);
59 CHKERR VecAssemblyEnd(state);
60 CHKERR VecGhostUpdateBegin(state, INSERT_VALUES, SCATTER_FORWARD);
61 CHKERR VecGhostUpdateEnd(state, INSERT_VALUES, SCATTER_FORWARD);
63}
64
65MoFEMErrorCode readTag(moab::Interface &mesh, const EntityHandle vertex,
66 const std::string &name, const int size,
67 double *values) {
69 Tag tag;
70 CHKERR mesh.tag_get_handle(name.c_str(), tag);
71 int length;
72 CHKERR mesh.tag_get_length(tag, length);
73 if (length != size)
74 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
75 "Output tag %s has length %d instead of %d", name.c_str(), length,
76 size);
77 CHKERR mesh.tag_get_data(tag, &vertex, 1, values);
79}
80
81MoFEMErrorCode checkTensor(moab::Interface &mesh, const EntityHandle vertex,
82 const std::string &name,
83 const Material::SymmetricTensor &t_expected) {
85 std::array<double, 9> values;
86 CHKERR readTag(mesh, vertex, name, values.size(), values.data());
87 auto t_actual = getFTensor2FromPtr<3, 3>(values.data());
88 FTENSOR_INDEXES(3, i, j);
90 t_error(i, j) = t_actual(i, j) - t_expected(i, j);
91 CHKERR checkNear(std::sqrt(t_error(i, j) * t_error(i, j)), 0., name.c_str());
93}
94
95MoFEMErrorCode checkVectorUnchanged(Vec before, Vec after,
96 const char *description) {
98 auto difference = vectorDuplicate(after);
99 CHKERR VecWAXPY(difference, -1., before, after);
100 PetscReal norm;
101 CHKERR VecNorm(difference, NORM_INFINITY, &norm);
102 CHKERR checkNear(norm, 0., description, 0.);
104}
105
106MoFEMErrorCode checkOutput(const std::string &file, const Coordinates &t_d,
107 const double theta, const Coordinates &t_stress,
108 const bool variation) {
110 const Material::Parameters parameters{1.7, 8.5};
113 double deviatoric_energy, gap;
114 CHKERR Material::evaluateDeviator(parameters, t_d, deviatoric_energy);
115 CHKERR Material::evaluateVolume(parameters, theta, volume);
116 CHKERR Material::evaluateInverse(parameters, t_stress, inverse);
117 CHKERR Material::evaluateFenchelGap(parameters, t_d, t_stress, inverse, gap);
118 FTensor::Index<'a', 5> a;
119 FTENSOR_INDEXES(3, i, j, k);
120 Coordinates t_copy_error;
121 t_copy_error(a) = t_d(a) - inverse.tMaterialDeviator(a);
122 const double copy_error = std::sqrt(t_copy_error(a) * t_copy_error(a));
123 const double physical_energy = deviatoric_energy + volume.energy;
124 const double mixed_energy =
125 t_stress(a) * t_d(a) - inverse.conjugateEnergy + volume.energy;
126 if (gap <= .01 || copy_error <= .01)
127 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
128 "Output test requires distinct material and kinematic copies");
129 const auto t_d_tensor = Material::getTensor(t_d);
130 const auto t_stress_tensor = Material::getTensor(t_stress);
132 t_commutator(i, j) = t_d_tensor(i, k) * t_stress_tensor(k, j) -
133 t_stress_tensor(i, k) * t_d_tensor(k, j);
134 if (std::sqrt(t_commutator(i, j) * t_commutator(i, j)) <= .01)
135 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
136 "Output test requires noncoaxial D and Td");
137 const auto t_log_stretch = Material::getTensor(t_d, theta);
138 FTensor::Tensor1<double, 3> t_eigenvalues;
139 FTensor::Tensor2<double, 3, 3> t_eigenvectors;
140 t_eigenvectors(i, j) = t_log_stretch(i, j);
141 CHKERR computeEigenValuesSymmetric(t_eigenvectors, t_eigenvalues);
142 const Material::SymmetricTensor t_stretch =
143 EigenMatrix::getMat(t_eigenvalues, t_eigenvectors,
144 [](double value) { return std::exp(value); });
145
146 moab::Core output;
147 CHKERR output.load_file(file.c_str());
148 for (const auto *name : {"FenchelGap", "PointwiseCopyMismatch"}) {
149 Tag tag;
150 if (output.tag_get_handle(name, tag) != MB_TAG_NOT_FOUND)
151 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
152 "Unexpected material diagnostic output tag %s", name);
153 }
154 for (const auto *prefix :
155 {"D_", "Td_", "D_m_", "VarD_", "VarTd_", "ResD_", "ResTd_"})
156 for (int c = 0; c != 5; ++c) {
157 const std::string name = prefix + std::to_string(c);
158 Tag tag;
159 if (output.tag_get_handle(name.c_str(), tag) != MB_TAG_NOT_FOUND)
160 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
161 "Unexpected scalar coordinate output tag %s", name.c_str());
162 }
163 Range vertices;
164 CHKERR output.get_entities_by_type(0, MBVERTEX, vertices);
165 if (vertices.empty())
166 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
167 "Production output %s contains no vertices", file.c_str());
168 for (const auto vertex : vertices) {
169 CHKERR checkTensor(output, vertex, "D", t_d_tensor);
170 CHKERR checkTensor(output, vertex, "Td", t_stress_tensor);
171 CHKERR checkTensor(output, vertex, "D_m",
173 CHKERR checkTensor(output, vertex, "LogSpatialStretch", t_log_stretch);
174 CHKERR checkTensor(output, vertex, "SpatialStretch", t_stretch);
175 const std::array<std::pair<const char *, double>, 6> scalar_values{
176 {{"theta", theta},
177 {"J", volume.jacobian},
178 {"PhysicalEnergy", physical_energy},
179 {"MixedStoredEnergy", mixed_energy},
180 {"Vartheta", .25 * theta},
181 {"Restheta", -.75 * theta}}};
182 double saved_physical = 0., saved_mixed = 0.;
183 for (const auto &[name, expected] : scalar_values) {
184 if (std::string(name) == "Vartheta" && !variation)
185 continue;
186 double actual;
187 CHKERR readTag(output, vertex, name, 1, &actual);
188 CHKERR checkNear(actual, expected, name);
189 if (std::string(name) == "PhysicalEnergy")
190 saved_physical = actual;
191 else if (std::string(name) == "MixedStoredEnergy")
192 saved_mixed = actual;
193 }
194 CHKERR checkNear(saved_physical - saved_mixed, gap,
195 "PhysicalEnergy - MixedStoredEnergy = FenchelGap", 6.e-6);
196 Coordinates t_residual;
197 t_residual(a) = -.75 * t_d(a);
198 CHKERR checkTensor(output, vertex, "ResD", Material::getTensor(t_residual));
199 t_residual(a) = -.75 * t_stress(a);
200 CHKERR checkTensor(output, vertex, "ResTd",
201 Material::getTensor(t_residual));
202 if (variation) {
203 Coordinates t_variation;
204 t_variation(a) = .25 * t_d(a);
205 CHKERR checkTensor(output, vertex, "VarD",
206 Material::getTensor(t_variation));
207 CHKERR checkTensor(output, vertex, "VarLogSpatialStretch",
208 Material::getTensor(t_variation, .25 * theta));
209 t_variation(a) = .25 * t_stress(a);
210 CHKERR checkTensor(output, vertex, "VarTd",
211 Material::getTensor(t_variation));
212 }
213 }
214 CHKERR PetscPrintf(PETSC_COMM_WORLD,
215 "Checked %d production output vertices in %s; "
216 "gap %.6e, pointwise copy mismatch %.6e\n",
217 static_cast<int>(vertices.size()), file.c_str(), gap,
218 copy_error);
220}
221
222MoFEMErrorCode runOutputAtom(EshelbianCore &ep) {
224 if (ep.mField.get_comm_size() != 1)
226 "The output inspection atom runs on one rank");
228 const Coordinates t_d(.12, -.08, .06, -.04, .09);
229 const Coordinates t_stress(-.8, .4, .5, .3, -.7);
230 const double theta = .13;
231 auto state = createDMVector(ep.dmElastic);
232 CHKERR setState(ep, state, t_d, theta, t_stress);
234 SCATTER_REVERSE);
235 auto variation = vectorDuplicate(state);
236 CHKERR VecCopy(state, variation);
237 CHKERR VecScale(variation, .25);
238 CHKERR VecGhostUpdateBegin(variation, INSERT_VALUES, SCATTER_FORWARD);
239 CHKERR VecGhostUpdateEnd(variation, INSERT_VALUES, SCATTER_FORWARD);
240 auto residual = vectorDuplicate(state);
241 CHKERR VecCopy(state, residual);
242 CHKERR VecScale(residual, -.75);
243 CHKERR VecGhostUpdateBegin(residual, INSERT_VALUES, SCATTER_FORWARD);
244 CHKERR VecGhostUpdateEnd(residual, INSERT_VALUES, SCATTER_FORWARD);
245 CHKERR VecCopy(state, ep.solTSStep);
246 CHKERR VecScale(ep.solTSStep, -.5);
247 CHKERR VecGhostUpdateBegin(ep.solTSStep, INSERT_VALUES, SCATTER_FORWARD);
248 CHKERR VecGhostUpdateEnd(ep.solTSStep, INSERT_VALUES, SCATTER_FORWARD);
249 auto previous = vectorDuplicate(ep.solTSStep);
250 CHKERR VecCopy(ep.solTSStep, previous);
251 auto mesh_before = createDMVector(ep.dM);
252 auto mesh_after = vectorDuplicate(mesh_before);
253 CHKERR DMoFEMMeshToLocalVector(ep.dM, mesh_before, INSERT_VALUES,
254 SCATTER_FORWARD);
255
256 // Leave nonzero rate data in the shared material scratch. Mesh-only output
257 // must evaluate the zero-rate inverse, independent of the preceding solve.
258 boost::shared_ptr<VolumeElementForcesAndSourcesCore> rhs, lhs;
259 CHKERR ep.setVolumeElementOps(1, true, false, rhs, lhs);
260 ep.mField.getInterface<OperatorsTester>()->assembleVec(
261 ep.dmElastic, ep.elementVolumeName, rhs, state, variation, nullptr, 1.,
262 .4, {});
263
264 const std::string skin_file = "auxiliary_output_skin.h5m";
265 CHKERR ep.postProcessResults(1, skin_file, residual, variation);
266 CHKERR DMoFEMMeshToLocalVector(ep.dM, mesh_after, INSERT_VALUES,
267 SCATTER_FORWARD);
268 CHKERR checkVectorUnchanged(mesh_before, mesh_after,
269 "Skin output changed mesh coefficients");
270 CHKERR checkVectorUnchanged(previous, ep.solTSStep,
271 "Skin output changed previous coefficients");
272 CHKERR checkOutput(skin_file, t_d, theta, t_stress, true);
273
274 const std::string skeleton_file = "auxiliary_output_skeleton.h5m";
275 CHKERR ep.postProcessSkeletonResults(1, skeleton_file, residual);
276 CHKERR DMoFEMMeshToLocalVector(ep.dM, mesh_after, INSERT_VALUES,
277 SCATTER_FORWARD);
278 CHKERR checkVectorUnchanged(mesh_before, mesh_after,
279 "Skeleton output changed mesh coefficients");
280 CHKERR checkVectorUnchanged(previous, ep.solTSStep,
281 "Skeleton output changed previous coefficients");
282 CHKERR checkOutput(skeleton_file, t_d, theta, t_stress, false);
283 CHKERR PetscPrintf(ep.mField.get_comm(),
284 "Auxiliary logarithmic stress output atom passed\n");
286}
287
288} // namespace
289
290static char help[] = "Check production auxiliary material diagnostic output.\n";
291
292int main(int argc, char *argv[]) {
293 MoFEM::Core::Initialize(&argc, &argv, nullptr, help);
294 auto core_log = logging::core::get();
295 core_log->add_sink(LogManager::createSink(LogManager::getStrmWorld(), "EP"));
296 LogManager::setLog("EP");
297 core_log->add_sink(
299 LogManager::setLog("EPSELF");
300 core_log->add_sink(
302 LogManager::setLog("EPSYNC");
303 try {
305 }
308 return 0;
309}
Shared mesh and problem setup for auxiliary formulation atoms.
Neo-Hookean material law in orthonormal logarithmic coordinates.
#define FTENSOR_INDEXES(DIM,...)
int main()
constexpr double a
#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
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 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
Definition DMMoFEM.cpp:514
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
const double c
speed of light (cm/ns)
FTensor::Index< 'j', 3 > j
FTensor::Index< 'k', 3 > k
auto getMat(A &&t_val, B &&t_vec, Fun< double > f)
Get the Mat object.
MoFEMErrorCode runAuxiliaryLogarithmicStressTest(const std::function< MoFEMErrorCode(EshelbianCore &)> &test)
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
implementation of Data Operators for Forces and Sources
Definition Common.hpp:10
SmartPetscObj< Vec > vectorDuplicate(Vec vec)
Create duplicate vector of smart vector.
MoFEMErrorCode computeEigenValuesSymmetric(const MatrixDouble &mat, VectorDouble &eig, MatrixDouble &eigen_vec)
compute eigenvalues of a symmetric matrix using lapack dsyev
MoFEMErrorCode setElasticElementOps(const int tag)
MoFEM::Interface & mField
MoFEMErrorCode postProcessSkeletonResults(const int tag, const std::string file, Vec f_residual=PETSC_NULLPTR, std::vector< Tag > tags_to_transfer={}, TS ts=PETSC_NULLPTR)
SmartPetscObj< DM > dM
Coupled problem all fields.
const std::string elementVolumeName
MoFEMErrorCode postProcessResults(const int tag, const std::string file, Vec f_residual=PETSC_NULLPTR, Vec var_vec=PETSC_NULLPTR, Vec gradient=PETSC_NULLPTR, std::vector< Tag > tags_to_transfer={}, TS ts=PETSC_NULLPTR)
const std::string logDeviator
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 auxiliaryLogStress
const std::string rotAxis
SmartPetscObj< Vec > solTSStep
SmartPetscObj< DM > dmElastic
Elastic problem.
static MoFEMErrorCode evaluateInverse(const Parameters &parameters, const Coordinates &t_stress, InverseState &state)
Recover Dm(Td), its compliance and conjugate energy; no state is cached.
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 &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.
static MoFEMErrorCode evaluateFenchelGap(const Parameters &parameters, const Coordinates &t_deviator, const Coordinates &t_stress, const InverseState &inverse, double &gap, double *energy_ptr=nullptr)
static MoFEMErrorCode evaluateVolume(const Parameters &parameters, double theta, VolumeState &state)
Evaluate g(J) = K*(J-1)^2/2 and its logarithmic-volume derivatives.
virtual int get_comm_size() const =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.
Definition Core.cpp:68
static MoFEMErrorCode Finalize()
Checks for options to be called at the conclusion of the program.
Definition Core.cpp:123
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
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.