v0.16.3
Loading...
Searching...
No Matches
auxiliary_logarithmic_stress_layout_atom.cpp
Go to the documentation of this file.
1/**
2 * @file auxiliary_logarithmic_stress_layout_atom.cpp
3 * @brief Verify auxiliary material fields, distributed layouts and evaluation.
4 */
5
6#include <MoFEM.hpp>
7using namespace MoFEM;
10using namespace EshelbianPlasticity;
11
12namespace {
13
14using Coordinates = FTensor::Tensor1<double, 5>;
15using VolumeElement = VolumeElementForcesAndSourcesCore;
16using MatrixPtr = boost::shared_ptr<MatrixDouble>;
17
18MoFEMErrorCode checkNear(const double value, const double expected,
19 const char *description) {
21 if (!std::isfinite(value) ||
22 std::abs(value - expected) > 1.e-11 * std::max(1., std::abs(expected)))
23 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
24 "%s: expected %.16e, obtained %.16e", description, expected, value);
26}
27
28MoFEMErrorCode getCellScale(moab::Interface &moab, const EntityHandle entity,
29 double &scale) {
31 const EntityHandle *connectivity;
32 int count;
33 CHKERR moab.get_connectivity(entity, connectivity, count, true);
34 std::vector<double> coordinates(3 * count);
35 CHKERR moab.get_coords(connectivity, count, coordinates.data());
36 scale = 1.;
37 for (const double coordinate : coordinates)
38 scale += 0.001 * coordinate / count;
40}
41
42MoFEMErrorCode checkFieldLayout(EshelbianCore &ep) {
44 const auto expected_features = PhysicalEquations::Features{}.set(
46 if (ep.physicalEquations->getFeatures() != expected_features ||
49 "Auxiliary mode must register D/theta/Td without the old u field");
50 const std::vector<std::string> names{ep.logDeviator, ep.logJacobian,
52 if (ep.physicalEquations->getMaterialFields(ep) != names)
54 "Unexpected auxiliary material-field group");
55 const auto *finite_element =
57 const int order =
59 const PetscInt basis_count = (order + 1) * (order + 2) * (order + 3) / 6;
60 const Problem *problem;
62 int rank;
63 CHKERR MPI_Comm_rank(ep.mField.get_comm(), &rank);
64 // Count active owned volume elements, excluding broken-space mesh copies.
65 PetscInt local_tets = 0, global_tets;
66 for (const auto &element : *problem->getNumeredFiniteElementsPtr())
67 if (element->getName() == ep.elementVolumeName &&
68 element->getPart() == rank && element->getEntType() == MBTET)
69 ++local_tets;
70 CHKERR MPI_Allreduce(&local_tets, &global_tets, 1, MPIU_INT, MPI_SUM,
71 ep.mField.get_comm());
72 if (!global_tets)
74 "Layout atom requires tetrahedra");
75 for (const auto &name : names) {
76 const int components = name == ep.logJacobian ? 1 : 5;
77 const auto *field = ep.mField.get_field_structure(name);
78 if (field->getNbOfCoeffs() != components || field->getSpace() != L2 ||
79 field->getApproxBase() != USER_BASE)
81 "Field %s must have %d USER_BASE L2 components", name.c_str(),
82 components);
83 for (const auto mask : {finite_element->getBitFieldIdRow(),
84 finite_element->getBitFieldIdCol(),
85 finite_element->getBitFieldIdData()})
86 if ((mask & field->getId()) != field->getId())
88 "Field %s missing from volume FE row, column or data",
89 name.c_str());
90 for (const auto entry :
91 {std::make_pair(ep.dmElastic.get(), RowColData::ROW),
92 std::make_pair(ep.dmElastic.get(), RowColData::COL),
93 std::make_pair(ep.dmMaterial.get(), RowColData::COL)}) {
94 IS raw_is;
95 CHKERR DMMoFEMGetFieldIS(entry.first, entry.second, name.c_str(),
96 &raw_is);
97 SmartPetscObj<IS> field_is(raw_is);
98 PetscInt size;
99 CHKERR ISGetSize(field_is, &size);
100 if (size != global_tets * components * basis_count)
102 "Field %s in %s/%s has %d DOFs, expected %d", name.c_str(),
103 entry.first == ep.dmElastic.get() ? "dmElastic" : "dmMaterial",
104 entry.second == RowColData::ROW ? "ROW" : "COL",
105 static_cast<int>(size),
106 static_cast<int>(global_tets * components * basis_count));
107 }
108 }
109 for (const auto &dof : *problem->getNumeredRowDofsPtr()) {
110 if (std::find(names.begin(), names.end(), dof->getName()) == names.end())
111 continue;
112 if (dof->getEntType() != MBTET ||
113 dof->getFieldEntityPtr()->getMaxOrder() != order)
115 "Material DOF has unexpected entity or approximation order");
116 }
117 CHKERR PetscPrintf(ep.mField.get_comm(),
118 "Auxiliary layout: %d tetrahedra, order %d, "
119 "%d scalar basis functions per field\n",
120 static_cast<int>(global_tets), order,
121 static_cast<int>(basis_count));
123}
124
125double getCoefficient(const EshelbianCore &ep, const std::string &name,
126 const int component) {
127 if (name == ep.logDeviator)
128 return 0.02 * (component + 1);
129 if (name == ep.logJacobian)
130 return 0.18;
131 return -0.07 * (component + 1);
132}
133
134MoFEMErrorCode setMaterialVector(EshelbianCore &ep, Vec vector,
135 const double state_scale) {
137 CHKERR VecZeroEntries(vector);
138 PetscInt first, last;
139 CHKERR VecGetOwnershipRange(vector, &first, &last);
140 const Problem *problem;
142 const auto names = ep.physicalEquations->getMaterialFields(ep);
143 for (const auto &dof : *problem->getNumeredRowDofsPtr()) {
144 const auto index = dof->getPetscGlobalDofIdx();
145 if (index < first || index >= last || dof->getDofOrder() != 0 ||
146 std::find(names.begin(), names.end(), dof->getName()) == names.end())
147 continue;
148 double cell_scale;
149 CHKERR getCellScale(ep.mField.get_moab(), dof->getEnt(), cell_scale);
150 CHKERR VecSetValue(
151 vector, index,
152 state_scale * cell_scale *
153 getCoefficient(ep, dof->getName(), dof->getDofCoeffIdx()),
154 INSERT_VALUES);
155 }
156 CHKERR VecAssemblyBegin(vector);
157 CHKERR VecAssemblyEnd(vector);
158 CHKERR VecGhostUpdateBegin(vector, INSERT_VALUES, SCATTER_FORWARD);
159 CHKERR VecGhostUpdateEnd(vector, INSERT_VALUES, SCATTER_FORWARD);
161}
162
163struct OpCheckMaterialFields : public VolumeElement::UserDataOperator {
164 OpCheckMaterialFields(EshelbianCore &ep,
165 boost::shared_ptr<AuxiliaryLogarithmicStressData> data,
166 MatrixPtr reconstructed, const double state_scale,
167 boost::shared_ptr<PetscInt> visited,
168 const bool compatible_state)
169 : VolumeElement::UserDataOperator(NOSPACE, OPSPACE), eP(ep),
170 dataPtr(std::move(data)), reconstructedPtr(std::move(reconstructed)),
171 stateScale(state_scale), visitedPtr(std::move(visited)),
172 compatibleState(compatible_state) {}
173
174 MoFEMErrorCode doWork(int, EntityType, EntData &) override {
176 FTensor::Index<'A', 5> A;
177 FTensor::Index<'i', 3> i;
178 FTensor::Index<'j', 3> j;
179 const int points = getGaussPts().size2();
180 if (points <= 1)
181 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
182 "Layout test requires multiple integration points");
183 auto t_d = MatrixSizeHelper<GetFTensor1FromMatType<5, -1, DL>, DL>::get(
184 *dataPtr->logDeviator, points)();
185 auto t_theta = MatrixSizeHelper<GetFTensor1FromMatType<1, -1, DL>, DL>::get(
186 *dataPtr->logJacobian, points)();
187 auto t_stress =
189 *dataPtr->stress, points)();
190 auto t_h =
192 *reconstructedPtr, points)();
193 double cell_scale = 1.;
194 if (!compatibleState)
195 CHKERR getCellScale(eP.mField.get_moab(), getFEEntityHandle(),
196 cell_scale);
197 const double scale = stateScale * cell_scale;
198 Coordinates t_expected_d, t_expected_stress;
199 for (int aa = 0; aa != 5; ++aa) {
200 t_expected_d(aa) = scale * getCoefficient(eP, eP.logDeviator, aa);
201 t_expected_stress(aa) =
202 scale * getCoefficient(eP, eP.auxiliaryLogStress, aa);
203 }
204 if (compatibleState) {
205 double energy;
207 {1.7, 8.5}, t_expected_d, energy, &t_expected_stress);
208 }
209 for (int gg = 0; gg != points; ++gg) {
210 Coordinates t_error;
211 t_error(A) = t_d(A) - t_expected_d(A);
212 CHKERR checkNear(std::sqrt(t_error(A) * t_error(A)), 0., "evaluated D");
213 t_error(A) = t_stress(A) - t_expected_stress(A);
214 CHKERR checkNear(std::sqrt(t_error(A) * t_error(A)), 0., "evaluated Td");
215 CHKERR checkNear(t_theta(0), 0.18 * scale, "evaluated theta");
216 CHKERR checkNear(t_h(i, i), t_theta(0), "reconstructed trace");
217 CHKERR checkNear(t_h(i, j) * t_h(i, j),
218 t_d(A) * t_d(A) + t_theta(0) * t_theta(0) / 3.,
219 "reconstructed Frobenius norm");
220 const auto t_recovered = Tensor2SymmetricDeviatorBasis::getCoordinates(t_h);
221 t_error(A) = t_recovered(A) - t_d(A);
222 CHKERR checkNear(std::sqrt(t_error(A) * t_error(A)), 0.,
223 "reconstructed deviator");
224 if (compatibleState) {
225 Coordinates t_material_stress;
226 t_material_stress(A) = t_stress(A);
229 {1.7, 8.5}, t_material_stress, inverse);
230 t_error(A) = inverse.tMaterialDeviator(A) - t_d(A);
231 CHKERR checkNear(std::sqrt(t_error(A) * t_error(A)), 0.,
232 "constant initialized material copy");
233 }
234 ++t_d;
235 ++t_theta;
236 ++t_stress;
237 ++t_h;
238 }
239 ++*visitedPtr;
241 }
242
243 EshelbianCore &eP;
244 boost::shared_ptr<AuxiliaryLogarithmicStressData> dataPtr;
245 MatrixPtr reconstructedPtr;
246 double stateScale;
247 boost::shared_ptr<PetscInt> visitedPtr;
248 bool compatibleState;
249};
250
251MoFEMErrorCode checkStateEvaluation(EshelbianCore &ep,
252 SmartPetscObj<Vec> current,
253 SmartPetscObj<Vec> previous,
254 const double current_scale,
255 const double previous_scale,
256 const bool compatible_state = false) {
258 if (compatible_state) {
259 CHKERR DMoFEMMeshToLocalVector(ep.dmElastic, current, INSERT_VALUES,
260 SCATTER_FORWARD);
261 CHKERR VecCopy(current, previous);
262 CHKERR VecGhostUpdateBegin(previous, INSERT_VALUES, SCATTER_FORWARD);
263 CHKERR VecGhostUpdateEnd(previous, INSERT_VALUES, SCATTER_FORWARD);
264 } else {
265 CHKERR setMaterialVector(ep, current, current_scale);
266 CHKERR setMaterialVector(ep, previous, previous_scale);
267 }
268 CHKERR DMoFEMMeshToLocalVector(ep.dmElastic, current, INSERT_VALUES,
269 SCATTER_REVERSE);
270 auto round_trip = createDMVector(ep.dmElastic);
271 CHKERR VecZeroEntries(round_trip);
272 CHKERR DMoFEMMeshToLocalVector(ep.dmElastic, round_trip, INSERT_VALUES,
273 SCATTER_FORWARD);
274 CHKERR VecAXPY(round_trip, -1., current);
275 PetscReal error;
276 CHKERR VecNorm(round_trip, NORM_INFINITY, &error);
277 CHKERR checkNear(error, 0., "current vector-mesh-vector transfer");
278
279 auto fe = boost::make_shared<VolumeElement>(ep.mField);
280 fe->getUserPolynomialBase() =
281 boost::make_shared<CGGUserPolynomialBase>(nullptr, true);
282 fe->getRuleHook = [](int, int, int) { return 4; };
284 fe->getOpPtrVector(), {L2}, ep.materialH1Positions);
285 auto visited = boost::make_shared<PetscInt>(0);
286 for (const bool previous_state : {false, true}) {
287 auto data = boost::make_shared<AuxiliaryLogarithmicStressData>();
288 auto reconstructed = boost::make_shared<MatrixDouble>();
290 ep, fe->getOpPtrVector(), data, reconstructed,
291 previous_state ? previous : SmartPetscObj<Vec>());
292 fe->getOpPtrVector().push_back(new OpCheckMaterialFields(
293 ep, data, reconstructed,
294 previous_state ? previous_scale : current_scale, visited,
295 compatible_state));
296 }
298 PetscInt global_visited;
299 CHKERR MPI_Allreduce(visited.get(), &global_visited, 1, MPIU_INT, MPI_SUM,
300 ep.mField.get_comm());
301 if (!global_visited)
303 "No auxiliary field evaluations were executed");
305}
306
307/** Set the fixture's constant material state, including local ghost copies. */
308MoFEMErrorCode setConstantMaterialState(EshelbianCore &ep,
309 const Coordinates &t_deviator,
310 const double theta) {
312 Coordinates t_stress;
313 double energy;
315 {1.7, 8.5}, t_deviator, energy, &t_stress);
316 auto field_blas = ep.mField.getInterface<FieldBlas>();
317 auto set_field = [&]<int Dim>(const std::string &field,
318 const FTensor::Tensor1<double, Dim> &t_values) {
320 CHKERR field_blas->setField(0., field);
321 auto set_constant = [&](boost::shared_ptr<FieldEntity> entity_ptr) {
323 auto data = entity_ptr->getEntFieldData();
324 if (data.size() < Dim)
325 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
326 "Field %s has no constant mode", field.c_str());
327 FTensor::Index<'i', Dim> i;
328 auto t_dof = getFTensor1FromPtr<Dim>(&data[0]);
329 t_dof(i) = t_values(i);
331 };
332 CHKERR field_blas->fieldLambdaOnEntities(set_constant, field);
334 };
335 CHKERR set_field(ep.logDeviator, t_deviator);
336 const FTensor::Tensor1<double, 1> t_theta(theta);
337 CHKERR set_field(ep.logJacobian, t_theta);
338 CHKERR set_field(ep.auxiliaryLogStress, t_stress);
340}
341
342MoFEMErrorCode runLayoutAtom(EshelbianCore &ep) {
344 CHKERR checkFieldLayout(ep);
345 auto current = createDMVector(ep.dmElastic);
346 auto previous = createDMVector(ep.dmElastic);
347 FTensor::Index<'A', 5> A;
348 Coordinates t_initial;
349 t_initial(A) = 0.;
350 CHKERR setConstantMaterialState(ep, t_initial, 0.);
351 CHKERR checkStateEvaluation(ep, current, previous, 0., 0., true);
352 for (const auto &name : ep.physicalEquations->getMaterialFields(ep))
353 CHKERR ep.mField.getInterface<FieldBlas>()->setField(0.4, name);
354 for (int aa = 0; aa != 5; ++aa)
355 t_initial(aa) = getCoefficient(ep, ep.logDeviator, aa);
356 CHKERR setConstantMaterialState(ep, t_initial, 0.18);
357 CHKERR checkStateEvaluation(ep, current, previous, 1., 1., true);
358 CHKERR checkStateEvaluation(ep, current, previous, 1., -0.5);
359 CHKERR checkStateEvaluation(ep, current, previous, -0.25, 1.5);
360 CHKERR PetscPrintf(PETSC_COMM_WORLD,
361 "Auxiliary logarithmic stress layout atom passed\n");
363}
364
365} // namespace
366
367static char help[] = "Verify the auxiliary logarithmic stress field layout.\n";
368
369int main(int argc, char *argv[]) {
370 MoFEM::Core::Initialize(&argc, &argv, nullptr, help);
371 auto core_log = logging::core::get();
372 core_log->add_sink(LogManager::createSink(LogManager::getStrmWorld(), "EP"));
373 LogManager::setLog("EP");
374 core_log->add_sink(
376 LogManager::setLog("EPSELF");
377 core_log->add_sink(
379 LogManager::setLog("EPSYNC");
380 try {
382 }
385 return 0;
386}
Shared mesh and problem setup for auxiliary formulation atoms.
Evaluation of independent logarithmic material fields.
int main()
RowColData
RowColData.
@ COL
@ ROW
#define CATCH_ERRORS
Catch errors.
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base .
Definition definitions.h:60
@ USER_BASE
user implemented approximation base
Definition definitions.h:68
@ L2
field with C-1 continuity
Definition definitions.h:88
@ 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.
constexpr int order
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
PetscErrorCode DMoFEMLoopFiniteElements(DM dm, const char fe_name[], MoFEM::FEMethod *method, CacheTupleWeakPtr cache_ptr=CacheTupleSharedPtr())
Executes FEMethod for finite elements in DM.
Definition DMMoFEM.cpp:576
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
virtual const Field * get_field_structure(const std::string &name, enum MoFEMTypes bh=MF_EXIST) const =0
get field structure
virtual bool check_field(const std::string &name) const =0
check if field is in database
static LoggerType & setLog(const std::string channel)
Set ans resset chanel logger.
FTensor::Index< 'i', SPACE_DIM > i
FTensor::Index< 'j', 3 > j
const FTensor::Tensor2< T, Dim, Dim > Vec
MoFEMErrorCode runAuxiliaryLogarithmicStressTest(const std::function< MoFEMErrorCode(EshelbianCore &)> &test)
boost::shared_ptr< MatrixDouble > MatrixPtr
MoFEMErrorCode pushAuxiliaryLogarithmicFields(const EshelbianCore &ep, boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > &pipeline, boost::shared_ptr< AuxiliaryLogarithmicStressData > values, boost::shared_ptr< MatrixDouble > reconstructed_log_stretch, SmartPetscObj< Vec > state=nullptr)
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
implementation of Data Operators for Forces and Sources
Definition Common.hpp:10
decltype(GetFTensor2SymmetricFromMatImpl< Tensor_Dim, S, DL, M >::get(std::declval< M & >(), 0, 0)) GetFTensor2SymmetricFromMatType
decltype(GetFTensor1FromMatImpl< Tensor_Dim, S, DL, M >::get(std::declval< M & >(), 0, 0)) GetFTensor1FromMatType
constexpr AssemblyType A
MoFEM::Interface & mField
const std::string materialH1Positions
const std::string elementVolumeName
static FieldApproximationBase brokenHdivBase
const std::string logDeviator
const std::string logJacobian
SmartPetscObj< DM > dmMaterial
Material problem.
const std::string auxiliaryLogStress
boost::shared_ptr< PhysicalEquations > physicalEquations
SmartPetscObj< DM > dmElastic
Elastic problem.
const std::string stretchTensor
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 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.
@ AUXILIARY_LOGARITHMIC_STRESS
Auxiliary logarithmic stress formulation.
Add operators pushing bases from local to physical configuration.
virtual const FiniteElement * get_finite_element_structure(const std::string &name, enum MoFEMTypes bh=MF_EXIST) const =0
get finite element structure
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.
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
MoFEMErrorCode setField(const double val, const EntityType type, const std::string field_name)
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.
keeps basic data about problem
intrusive_ptr for managing petsc objects
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.
double scale
Definition plastic.cpp:123