v0.16.0
Loading...
Searching...
No Matches
plastic.cpp
Go to the documentation of this file.
1/**
2 * \file plastic.cpp
3 * \example mofem/tutorials/adv-0_plasticity/plastic.cpp
4 *
5 * Plasticity in 2d and 3d
6 *
7 */
8
9/* The above code is a preprocessor directive in C++ that checks if the macro
10"EXECUTABLE_DIMENSION" has been defined. If it has not been defined, it replaces
11the " */
12#ifndef EXECUTABLE_DIMENSION
13 #define EXECUTABLE_DIMENSION 3
14#endif
15
16// #undef ADD_CONTACT
17
18#include <MoFEM.hpp>
19#include <MatrixFunction.hpp>
20#include <IntegrationRules.hpp>
21
22using namespace MoFEM;
23
24template <int DIM> struct ElementsAndOps;
25
26template <> struct ElementsAndOps<2> {
30 static constexpr FieldSpace CONTACT_SPACE = HCURL;
31};
32
33template <> struct ElementsAndOps<3> {
37 static constexpr FieldSpace CONTACT_SPACE = HDIV;
38};
39
40constexpr int SPACE_DIM =
41 EXECUTABLE_DIMENSION; //< Space dimension of problem, mesh
42constexpr auto size_symm = (SPACE_DIM * (SPACE_DIM + 1)) / 2;
43
44constexpr AssemblyType AT =
45 (SCHUR_ASSEMBLE) ? AssemblyType::BLOCK_SCHUR
46 : AssemblyType::PETSC; //< selected assembly type
48 IntegrationType::GAUSS; //< selected integration type
49
52[[maybe_unused]] constexpr FieldSpace CONTACT_SPACE =
54
57using DomainEleOp = DomainEle::UserDataOperator;
59using BoundaryEleOp = BoundaryEle::UserDataOperator;
64
65inline double iso_hardening_exp(double tau, double b_iso) {
66 return std::exp(
67 std::max(static_cast<double>(std::numeric_limits<float>::min_exponent10),
68 -b_iso * tau));
69}
70
71/**
72 * Isotropic hardening
73 */
74inline double iso_hardening(double tau, double H, double Qinf, double b_iso,
75 double sigmaY) {
76 return H * tau + Qinf * (1. - iso_hardening_exp(tau, b_iso)) + sigmaY;
77}
78
79inline double iso_hardening_dtau(double tau, double H, double Qinf,
80 double b_iso) {
81 auto r = [&](auto tau) {
82 return H + Qinf * b_iso * iso_hardening_exp(tau, b_iso);
83 };
84 constexpr double eps = 1e-12;
85 return std::max(r(tau), eps * r(0));
86}
87
88/**
89 * Kinematic hardening
90 */
91template <typename T, int DIM>
92inline auto
94 double C1_k) {
95 FTensor::Index<'i', DIM> i;
96 FTensor::Index<'j', DIM> j;
98 if (C1_k < std::numeric_limits<double>::epsilon()) {
99 t_alpha(i, j) = 0;
100 return t_alpha;
101 }
102 t_alpha(i, j) = C1_k * t_plastic_strain(i, j);
103 return t_alpha;
104}
105
106template <int DIM>
108 FTensor::Index<'i', DIM> i;
109 FTensor::Index<'j', DIM> j;
110 FTensor::Index<'k', DIM> k;
111 FTensor::Index<'l', DIM> l;
114 t_diff(i, j, k, l) = C1_k * (t_kd(i, k) ^ t_kd(j, l)) / 4.;
115 return t_diff;
116}
117
118PetscBool is_large_strains = PETSC_TRUE; ///< Large strains
119PetscBool set_timer = PETSC_FALSE; ///< Set timer
120PetscBool do_eval_field = PETSC_FALSE; ///< Evaluate field
121
122int atom_test = 0; ///< Atom test
123
124double scale = 1.;
125
126double young_modulus = 206913; ///< Young modulus
127double poisson_ratio = 0.29; ///< Poisson ratio
128double sigmaY = 450; ///< Yield stress
129double H = 129; ///< Hardening
130double visH = 0; ///< Viscous hardening
131double zeta = 5e-2; ///< Viscous hardening
132double Qinf = 265; ///< Saturation yield stress
133double b_iso = 16.93; ///< Saturation exponent
134double C1_k = 0; ///< Kinematic hardening
135
136double cn0 = 1;
137double cn1 = 1;
138
139int order = 2; ///< Order displacement
140int tau_order = order - 2; ///< Order of tau files
141int ep_order = order - 1; ///< Order of ep files
142int geom_order = 2; ///< Order if fixed.
143
144PetscBool is_quasi_static = PETSC_TRUE;
145double rho = 0.0;
146double alpha_damping = 0;
147
148#include <HenckyOps.hpp>
149#include <PlasticOps.hpp>
150#include <PlasticNaturalBCs.hpp>
151
152#ifdef ADD_CONTACT
153 #ifdef ENABLE_PYTHON_BINDING
154 #include <boost/python.hpp>
155 #include <boost/python/def.hpp>
156 #include <boost/python/numpy.hpp>
157namespace bp = boost::python;
158namespace np = boost::python::numpy;
159 #endif
160
161namespace ContactOps {
162
163double cn_contact = 0.1;
164
165}; // namespace ContactOps
166
167 #include <ContactOps.hpp>
168#endif // ADD_CONTACT
169
179
180using namespace PlasticOps;
181using namespace HenckyOps;
182
183namespace PlasticOps {
184
185template <int FE_DIM, int PROBLEM_DIM, int SPACE_DIM> struct AddHOOps;
186
187template <> struct AddHOOps<2, 3, 3> {
188 AddHOOps() = delete;
189 static MoFEMErrorCode
190 add(boost::ptr_deque<ForcesAndSourcesCore::UserDataOperator> &pipeline,
191 std::vector<FieldSpace> space, std::string geom_field_name);
192};
193
194template <> struct AddHOOps<1, 2, 2> {
195 AddHOOps() = delete;
196 static MoFEMErrorCode
197 add(boost::ptr_deque<ForcesAndSourcesCore::UserDataOperator> &pipeline,
198 std::vector<FieldSpace> space, std::string geom_field_name);
199};
200
201template <> struct AddHOOps<3, 3, 3> {
202 AddHOOps() = delete;
203 static MoFEMErrorCode
204 add(boost::ptr_deque<ForcesAndSourcesCore::UserDataOperator> &pipeline,
205 std::vector<FieldSpace> space, std::string geom_field_name);
206};
207
208template <> struct AddHOOps<2, 2, 2> {
209 AddHOOps() = delete;
210 static MoFEMErrorCode
211 add(boost::ptr_deque<ForcesAndSourcesCore::UserDataOperator> &pipeline,
212 std::vector<FieldSpace> space, std::string geom_field_name);
213};
214
215} // namespace PlasticOps
216
217struct Example {
218
219 Example(MoFEM::Interface &m_field) : mField(m_field) {}
220
222
223 enum { VOL, COUNT };
224 static inline std::array<double, 2> meshVolumeAndCount = {0, 0};
225
226private:
228
235
236 std::tuple<SmartPetscObj<Vec>, SmartPetscObj<VecScatter>> uXScatter;
237 std::tuple<SmartPetscObj<Vec>, SmartPetscObj<VecScatter>> uYScatter;
238 std::tuple<SmartPetscObj<Vec>, SmartPetscObj<VecScatter>> uZScatter;
239
242 double getScale(const double time) {
243 return scale * MoFEM::TimeScale::getScale(time);
244 };
245 };
246
247#ifdef ADD_CONTACT
248 #ifdef ENABLE_PYTHON_BINDING
249 boost::shared_ptr<ContactOps::SDFPython> sdfPythonPtr;
250 #endif
251#endif // ADD_CONTACT
252};
253
254//! [Run problem]
259 CHKERR bC();
260 CHKERR OPs();
261 PetscBool test_ops = PETSC_FALSE;
262 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-test_operators", &test_ops,
263 PETSC_NULLPTR);
264 if (test_ops == PETSC_FALSE) {
265 CHKERR tsSolve();
266 } else {
268 }
270}
271//! [Run problem]
272
273//! [Set up problem]
277
278 Range domain_ents;
279 CHKERR mField.get_moab().get_entities_by_dimension(0, SPACE_DIM, domain_ents,
280 true);
281 auto get_ents_by_dim = [&](const auto dim) {
282 if (dim == SPACE_DIM) {
283 return domain_ents;
284 } else {
285 Range ents;
286 if (dim == 0)
287 CHKERR mField.get_moab().get_connectivity(domain_ents, ents, true);
288 else
289 CHKERR mField.get_moab().get_entities_by_dimension(0, dim, ents, true);
290 return ents;
291 }
292 };
293
294 auto get_base = [&]() {
295 auto domain_ents = get_ents_by_dim(SPACE_DIM);
296 if (domain_ents.empty())
297 CHK_THROW_MESSAGE(MOFEM_NOT_FOUND, "Empty mesh");
298 const auto type = type_from_handle(domain_ents[0]);
299 switch (type) {
300 case MBQUAD:
302 case MBHEX:
304 case MBTRI:
306 case MBTET:
308 default:
309 CHK_THROW_MESSAGE(MOFEM_NOT_FOUND, "Element type not handled");
310 }
311 return NOBASE;
312 };
313
314 const auto base = get_base();
315 MOFEM_LOG("PLASTICITY", Sev::inform)
316 << "Base " << ApproximationBaseNames[base];
317
318 CHKERR simple->addDomainField("U", H1, base, SPACE_DIM);
319 CHKERR simple->addDomainField("EP", L2, base, size_symm);
320 CHKERR simple->addDomainField("TAU", L2, base, 1);
321 CHKERR simple->addBoundaryField("U", H1, base, SPACE_DIM);
322
323 CHKERR simple->addDataField("GEOMETRY", H1, base, SPACE_DIM);
324
325 PetscBool order_edge = PETSC_FALSE;
326 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-order_edge", &order_edge,
327 PETSC_NULLPTR);
328 PetscBool order_face = PETSC_FALSE;
329 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-order_face", &order_face,
330 PETSC_NULLPTR);
331 PetscBool order_volume = PETSC_FALSE;
332 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-order_volume", &order_volume,
333 PETSC_NULLPTR);
334
336
337 MOFEM_LOG("PLASTICITY", Sev::inform) << "Order edge " << order_edge
338 ? "true"
339 : "false";
340 MOFEM_LOG("PLASTICITY", Sev::inform) << "Order face " << order_face
341 ? "true"
342 : "false";
343 MOFEM_LOG("PLASTICITY", Sev::inform) << "Order volume " << order_volume
344 ? "true"
345 : "false";
346
347 auto ents = get_ents_by_dim(0);
348 if (order_edge)
349 ents.merge(get_ents_by_dim(1));
350 if (order_face)
351 ents.merge(get_ents_by_dim(2));
352 if (order_volume)
353 ents.merge(get_ents_by_dim(3));
354 CHKERR simple->setFieldOrder("U", order, &ents);
355 } else {
356 CHKERR simple->setFieldOrder("U", order);
357 }
358 CHKERR simple->setFieldOrder("EP", ep_order);
359 CHKERR simple->setFieldOrder("TAU", tau_order);
360
361 CHKERR simple->setFieldOrder("GEOMETRY", geom_order);
362
363#ifdef ADD_CONTACT
364 CHKERR simple->addDomainField("SIGMA", CONTACT_SPACE, DEMKOWICZ_JACOBI_BASE,
365 SPACE_DIM);
366 CHKERR simple->addBoundaryField("SIGMA", CONTACT_SPACE, DEMKOWICZ_JACOBI_BASE,
367 SPACE_DIM);
368
369 auto get_skin = [&]() {
370 Range body_ents;
371 CHKERR mField.get_moab().get_entities_by_dimension(0, SPACE_DIM, body_ents);
372 Skinner skin(&mField.get_moab());
373 Range skin_ents;
374 CHKERR skin.find_skin(0, body_ents, false, skin_ents);
375 return skin_ents;
376 };
377
378 auto filter_blocks = [&](auto skin) {
379 bool is_contact_block = true;
380 Range contact_range;
381 for (auto m :
382 mField.getInterface<MeshsetsManager>()->getCubitMeshsetPtr(std::regex(
383
384 (boost::format("%s(.*)") % "CONTACT").str()
385
386 ))
387
388 ) {
389 is_contact_block =
390 true; ///< blocs interation is collective, so that is set irrespective
391 ///< if there are entities in given rank or not in the block
392 MOFEM_LOG("CONTACT", Sev::inform)
393 << "Find contact block set: " << m->getName();
394 auto meshset = m->getMeshset();
395 Range contact_meshset_range;
396 CHKERR mField.get_moab().get_entities_by_dimension(
397 meshset, SPACE_DIM - 1, contact_meshset_range, true);
398
399 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
400 contact_meshset_range);
401 contact_range.merge(contact_meshset_range);
402 }
403 if (is_contact_block) {
404 MOFEM_LOG("SYNC", Sev::inform)
405 << "Nb entities in contact surface: " << contact_range.size();
407 skin = intersect(skin, contact_range);
408 }
409 return skin;
410 };
411
412 auto filter_true_skin = [&](auto skin) {
413 Range boundary_ents;
414 ParallelComm *pcomm =
415 ParallelComm::get_pcomm(&mField.get_moab(), MYPCOMM_INDEX);
416 CHKERR pcomm->filter_pstatus(skin, PSTATUS_SHARED | PSTATUS_MULTISHARED,
417 PSTATUS_NOT, -1, &boundary_ents);
418 return boundary_ents;
419 };
420
421 auto boundary_ents = filter_true_skin(filter_blocks(get_skin()));
422 CHKERR simple->setFieldOrder("SIGMA", 0);
423 CHKERR simple->setFieldOrder("SIGMA", order - 1, &boundary_ents);
424#endif
425
426 CHKERR simple->setUp();
427 CHKERR simple->addFieldToEmptyFieldBlocks("U", "TAU");
428
429 auto project_ho_geometry = [&]() {
430 Projection10NodeCoordsOnField ent_method(mField, "GEOMETRY");
431 return mField.loop_dofs("GEOMETRY", ent_method);
432 };
433 PetscBool project_geometry = PETSC_TRUE;
434 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-project_geometry",
435 &project_geometry, PETSC_NULLPTR);
436 if (project_geometry) {
437 CHKERR project_ho_geometry();
438 }
439
440 auto get_volume = [&]() {
441 using VolOp = DomainEle::UserDataOperator;
442 auto *op_ptr = new VolOp(NOSPACE, VolOp::OPSPACE);
443 std::array<double, 2> volume_and_count;
444 op_ptr->doWorkRhsHook = [&](DataOperator *base_op_ptr, int side,
445 EntityType type,
448 auto op_ptr = static_cast<VolOp *>(base_op_ptr);
449 volume_and_count[VOL] += op_ptr->getMeasure();
450 volume_and_count[COUNT] += 1;
451 // in necessary at integration over Gauss points.
453 };
454 volume_and_count = {0, 0};
455 auto fe = boost::make_shared<DomainEle>(mField);
456 fe->getOpPtrVector().push_back(op_ptr);
457
458 auto dm = simple->getDM();
460 DMoFEMLoopFiniteElements(dm, simple->getDomainFEName(), fe),
461 "cac volume");
462 std::array<double, 2> tot_volume_and_count;
463 MPI_Allreduce(volume_and_count.data(), tot_volume_and_count.data(),
464 volume_and_count.size(), MPI_DOUBLE, MPI_SUM,
465 mField.get_comm());
466 return tot_volume_and_count;
467 };
468
469 meshVolumeAndCount = get_volume();
470 MOFEM_LOG("PLASTICITY", Sev::inform)
471 << "Mesh volume " << meshVolumeAndCount[VOL] << " nb. of elements "
473
475}
476//! [Set up problem]
477
478//! [Create common data]
481
482 auto get_command_line_parameters = [&]() {
484
485 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-scale", &scale, PETSC_NULLPTR);
486 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-young_modulus",
487 &young_modulus, PETSC_NULLPTR);
488 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-poisson_ratio",
489 &poisson_ratio, PETSC_NULLPTR);
490 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-hardening", &H, PETSC_NULLPTR);
491 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-hardening_viscous", &visH,
492 PETSC_NULLPTR);
493 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-yield_stress", &sigmaY,
494 PETSC_NULLPTR);
495 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-cn0", &cn0, PETSC_NULLPTR);
496 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-cn1", &cn1, PETSC_NULLPTR);
497 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-zeta", &zeta, PETSC_NULLPTR);
498 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-Qinf", &Qinf, PETSC_NULLPTR);
499 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-b_iso", &b_iso, PETSC_NULLPTR);
500 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-C1_k", &C1_k, PETSC_NULLPTR);
501 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-large_strains",
502 &is_large_strains, PETSC_NULLPTR);
503 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-set_timer", &set_timer,
504 PETSC_NULLPTR);
505 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-atom_test", &atom_test,
506 PETSC_NULLPTR);
507
508 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-order", &order, PETSC_NULLPTR);
509 PetscBool tau_order_is_set; ///< true if tau order is set
510 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-tau_order", &tau_order,
511 &tau_order_is_set);
512 PetscBool ep_order_is_set; ///< true if tau order is set
513 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-ep_order", &ep_order,
514 &ep_order_is_set);
515 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-geom_order", &geom_order,
516 PETSC_NULLPTR);
517
518 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-rho", &rho, PETSC_NULLPTR);
519 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-alpha_damping",
520 &alpha_damping, PETSC_NULLPTR);
521
522 MOFEM_LOG("PLASTICITY", Sev::inform) << "Young modulus " << young_modulus;
523 MOFEM_LOG("PLASTICITY", Sev::inform) << "Poisson ratio " << poisson_ratio;
524 MOFEM_LOG("PLASTICITY", Sev::inform) << "Yield stress " << sigmaY;
525 MOFEM_LOG("PLASTICITY", Sev::inform) << "Hardening " << H;
526 MOFEM_LOG("PLASTICITY", Sev::inform) << "Viscous hardening " << visH;
527 MOFEM_LOG("PLASTICITY", Sev::inform) << "Saturation yield stress " << Qinf;
528 MOFEM_LOG("PLASTICITY", Sev::inform) << "Saturation exponent " << b_iso;
529 MOFEM_LOG("PLASTICITY", Sev::inform) << "Kinematic hardening " << C1_k;
530 MOFEM_LOG("PLASTICITY", Sev::inform) << "cn0 " << cn0;
531 MOFEM_LOG("PLASTICITY", Sev::inform) << "cn1 " << cn1;
532 MOFEM_LOG("PLASTICITY", Sev::inform) << "zeta " << zeta;
533
534 if (tau_order_is_set == PETSC_FALSE)
535 tau_order = order - 2;
536 if (ep_order_is_set == PETSC_FALSE)
537 ep_order = order - 1;
538
539 MOFEM_LOG("PLASTICITY", Sev::inform) << "Approximation order " << order;
540 MOFEM_LOG("PLASTICITY", Sev::inform)
541 << "Ep approximation order " << ep_order;
542 MOFEM_LOG("PLASTICITY", Sev::inform)
543 << "Tau approximation order " << tau_order;
544 MOFEM_LOG("PLASTICITY", Sev::inform)
545 << "Geometry approximation order " << geom_order;
546
547 MOFEM_LOG("PLASTICITY", Sev::inform) << "Density " << rho;
548 MOFEM_LOG("PLASTICITY", Sev::inform) << "alpha_damping " << alpha_damping;
549
550 PetscBool is_scale = PETSC_TRUE;
551 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-is_scale", &is_scale,
552 PETSC_NULLPTR);
553 if (is_scale) {
555 }
556
557 MOFEM_LOG("PLASTICITY", Sev::inform) << "Scale " << scale;
558
559#ifdef ADD_CONTACT
560 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-cn_contact",
561 &ContactOps::cn_contact, PETSC_NULLPTR);
562 MOFEM_LOG("CONTACT", Sev::inform)
563 << "cn_contact " << ContactOps::cn_contact;
564#endif // ADD_CONTACT
565
566 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-quasi_static",
567 &is_quasi_static, PETSC_NULLPTR);
568 MOFEM_LOG("PLASTICITY", Sev::inform)
569 << "Is quasi static: " << (is_quasi_static ? "true" : "false");
570
572 };
573
574 CHKERR get_command_line_parameters();
575
576#ifdef ADD_CONTACT
577 #ifdef ENABLE_PYTHON_BINDING
578 auto file_exists = [](std::string myfile) {
579 std::ifstream file(myfile.c_str());
580 if (file) {
581 return true;
582 }
583 return false;
584 };
585 char sdf_file_name[255] = "sdf.py";
586 CHKERR PetscOptionsGetString(PETSC_NULLPTR, PETSC_NULLPTR, "-sdf_file",
587 sdf_file_name, 255, PETSC_NULLPTR);
588
589 if (file_exists(sdf_file_name)) {
590 MOFEM_LOG("CONTACT", Sev::inform) << sdf_file_name << " file found";
591 sdfPythonPtr = boost::make_shared<ContactOps::SDFPython>();
592 CHKERR sdfPythonPtr->sdfInit(sdf_file_name);
593 ContactOps::sdfPythonWeakPtr = sdfPythonPtr;
594 } else {
595 MOFEM_LOG("CONTACT", Sev::warning) << sdf_file_name << " file NOT found";
596 }
597 #endif
598#endif // ADD_CONTACT
599
601}
602//! [Create common data]
603
604//! [Boundary condition]
607
609 auto bc_mng = mField.getInterface<BcManager>();
610
611 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "REMOVE_X",
612 "U", 0, 0);
613 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "REMOVE_Y",
614 "U", 1, 1);
615 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "REMOVE_Z",
616 "U", 2, 2);
617 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(),
618 "REMOVE_ALL", "U", 0, 3);
619
620#ifdef ADD_CONTACT
621 for (auto b : {"FIX_X", "REMOVE_X"})
622 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), b,
623 "SIGMA", 0, 0, false, true);
624 for (auto b : {"FIX_Y", "REMOVE_Y"})
625 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), b,
626 "SIGMA", 1, 1, false, true);
627 for (auto b : {"FIX_Z", "REMOVE_Z"})
628 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), b,
629 "SIGMA", 2, 2, false, true);
630 for (auto b : {"FIX_ALL", "REMOVE_ALL"})
631 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), b,
632 "SIGMA", 0, 3, false, true);
633 CHKERR bc_mng->removeBlockDOFsOnEntities(
634 simple->getProblemName(), "NO_CONTACT", "SIGMA", 0, 3, false, true);
635#endif
636
637 CHKERR bc_mng->pushMarkDOFsOnEntities<DisplacementCubitBcData>(
638 simple->getProblemName(), "U");
639
640 auto &bc_map = bc_mng->getBcMapByBlockName();
641 for (auto bc : bc_map)
642 MOFEM_LOG("PLASTICITY", Sev::verbose) << "Marker " << bc.first;
643
645}
646//! [Boundary condition]
647
648//! [Push operators to pipeline]
651 auto pip_mng = mField.getInterface<PipelineManager>();
652
653 auto integration_rule_bc = [](int, int, int ao) { return 2 * ao; };
654
655 auto vol_rule = [](int, int, int ao) { return 2 * ao + geom_order - 1; };
656
657 auto add_boundary_ops_lhs_mechanical = [&](auto &pip) {
659
661 pip, {HDIV}, "GEOMETRY");
662 pip.push_back(new OpSetHOWeightsOnSubDim<SPACE_DIM>());
663
664 // Add Natural BCs to LHS
666 pip, mField, "U", Sev::inform);
667
668#ifdef ADD_CONTACT
670 CHKERR
671 ContactOps::opFactoryBoundaryLhs<SPACE_DIM, AT, GAUSS, BoundaryEleOp>(
672 pip, "SIGMA", "U");
673 CHKERR
674 ContactOps::opFactoryBoundaryToDomainLhs<SPACE_DIM, AT, IT, DomainEle>(
675 mField, pip, simple->getDomainFEName(), "SIGMA", "U", "GEOMETRY",
676 vol_rule);
677#endif // ADD_CONTACT
678
680 };
681
682 auto add_boundary_ops_rhs_mechanical = [&](auto &pip) {
684
686 pip, {HDIV}, "GEOMETRY");
687 pip.push_back(new OpSetHOWeightsOnSubDim<SPACE_DIM>());
688
689 // Add Natural BCs to RHS
691 pip, mField, "U", {boost::make_shared<ScaledTimeScale>()}, Sev::inform);
692
693#ifdef ADD_CONTACT
694 CHKERR ContactOps::opFactoryBoundaryRhs<SPACE_DIM, AT, IT, BoundaryEleOp>(
695 pip, "SIGMA", "U");
696#endif // ADD_CONTACT
697
699 };
700
701 auto add_domain_ops_lhs = [this](auto &pip) {
704 pip, {H1, HDIV}, "GEOMETRY");
705
706 if (is_quasi_static == PETSC_FALSE) {
707
708 //! [Only used for dynamics]
711 //! [Only used for dynamics]
712
713 auto get_inertia_and_mass_damping = [this](const double, const double,
714 const double) {
715 auto *pip = mField.getInterface<PipelineManager>();
716 auto &fe_domain_lhs = pip->getDomainLhsFE();
717 return (rho / scale) * fe_domain_lhs->ts_aa +
718 (alpha_damping / scale) * fe_domain_lhs->ts_a;
719 };
720 pip.push_back(new OpMass("U", "U", get_inertia_and_mass_damping));
721 }
722
723 CHKERR PlasticOps::opFactoryDomainLhs<SPACE_DIM, AT, IT, DomainEleOp>(
724 mField, "MAT_PLASTIC", pip, "U", "EP", "TAU");
725
727 };
728
729 auto add_domain_ops_rhs = [this](auto &pip) {
731
733 pip, {H1, HDIV}, "GEOMETRY");
734
736 pip, mField, "U",
737 {boost::make_shared<ScaledTimeScale>("body_force_hist.txt")},
738 Sev::inform);
739
740 // only in case of dynamics
741 if (is_quasi_static == PETSC_FALSE) {
742
743 //! [Only used for dynamics]
746 //! [Only used for dynamics]
747
748 auto mat_acceleration = boost::make_shared<MatrixDouble>();
750 "U", mat_acceleration));
751 pip.push_back(
752 new OpInertiaForce("U", mat_acceleration, [](double, double, double) {
753 return rho / scale;
754 }));
755 if (alpha_damping > 0) {
756 auto mat_velocity = boost::make_shared<MatrixDouble>();
757 pip.push_back(
758 new OpCalculateVectorFieldValuesDot<SPACE_DIM>("U", mat_velocity));
759 pip.push_back(
760 new OpInertiaForce("U", mat_velocity, [](double, double, double) {
761 return alpha_damping / scale;
762 }));
763 }
764 }
765
766 CHKERR PlasticOps::opFactoryDomainRhs<SPACE_DIM, AT, IT, DomainEleOp>(
767 mField, "MAT_PLASTIC", pip, "U", "EP", "TAU");
768
769#ifdef ADD_CONTACT
770 CHKERR ContactOps::opFactoryDomainRhs<SPACE_DIM, AT, IT, DomainEleOp>(
771 pip, "SIGMA", "U");
772#endif // ADD_CONTACT
773
775 };
776
777 CHKERR add_domain_ops_lhs(pip_mng->getOpDomainLhsPipeline());
778 CHKERR add_domain_ops_rhs(pip_mng->getOpDomainRhsPipeline());
779
780 // Boundary
781 CHKERR add_boundary_ops_lhs_mechanical(pip_mng->getOpBoundaryLhsPipeline());
782 CHKERR add_boundary_ops_rhs_mechanical(pip_mng->getOpBoundaryRhsPipeline());
783
784 CHKERR pip_mng->setDomainRhsIntegrationRule(vol_rule);
785 CHKERR pip_mng->setDomainLhsIntegrationRule(vol_rule);
786
787 CHKERR pip_mng->setBoundaryLhsIntegrationRule(integration_rule_bc);
788 CHKERR pip_mng->setBoundaryRhsIntegrationRule(integration_rule_bc);
789
790 auto create_reaction_pipeline = [&](auto &pip) {
793 pip, {H1}, "GEOMETRY");
794 CHKERR PlasticOps::opFactoryDomainReactions<SPACE_DIM, AT, IT, DomainEleOp>(
795 mField, "MAT_PLASTIC", pip, "U", "EP", "TAU");
797 };
798
799 CHKERR pip_mng->setEvaluationIntegrationRule(vol_rule);
800 CHKERR create_reaction_pipeline(pip_mng->getOpEvaluationPipeline());
801 auto &reaction_fe = pip_mng->getEvaluationFE();
802 reaction_fe->postProcessHook =
804
806}
807//! [Push operators to pipeline]
808
809//! [Solve]
810struct SetUpSchur {
811
812 /**
813 * @brief Create data structure for handling Schur complement
814 *
815 * @param m_field
816 * @param sub_dm Schur complement sub dm
817 * @param field_split_it IS of Schur block
818 * @param ao_map AO map from sub dm to main problem
819 * @return boost::shared_ptr<SetUpSchur>
820 */
821 static boost::shared_ptr<SetUpSchur> createSetUpSchur(
822
823 MoFEM::Interface &m_field, SmartPetscObj<DM> sub_dm,
824 SmartPetscObj<IS> field_split_it, SmartPetscObj<AO> ao_map
825
826 );
827 virtual MoFEMErrorCode setUp(TS solver) = 0;
828
829protected:
830 SetUpSchur() = default;
831};
832
835
838 ISManager *is_manager = mField.getInterface<ISManager>();
839
840 auto snes_ctx_ptr = getDMSnesCtx(simple->getDM());
841
842 auto set_section_monitor = [&](auto solver) {
844 SNES snes;
845 CHKERR TSGetSNES(solver, &snes);
846 CHKERR SNESMonitorSet(snes,
847 (MoFEMErrorCode(*)(SNES, PetscInt, PetscReal,
849 (void *)(snes_ctx_ptr.get()), nullptr);
851 };
852
853 auto create_post_process_elements = [&]() {
854 auto push_vol_ops = [this](auto &pip) {
856 pip, {H1, HDIV}, "GEOMETRY");
857
858 auto [common_plastic_ptr, common_hencky_ptr] =
859 PlasticOps::createCommonPlasticOps<SPACE_DIM, IT, DomainEleOp>(
860 mField, "MAT_PLASTIC", pip, "U", "EP", "TAU", 1., Sev::inform);
861
862 if (common_hencky_ptr) {
863 if (common_plastic_ptr->mGradPtr != common_hencky_ptr->matGradPtr)
864 CHK_THROW_MESSAGE(MOFEM_DATA_INCONSISTENCY, "Wrong pointer for grad");
865 }
866
867 return std::make_pair(common_plastic_ptr, common_hencky_ptr);
868 };
869
870 auto push_vol_post_proc_ops = [this](auto &pp_fe, auto &&p) {
872
873 auto &pip = pp_fe->getOpPtrVector();
874
875 auto [common_plastic_ptr, common_hencky_ptr] = p;
876
878
879 auto x_ptr = boost::make_shared<MatrixDouble>();
880 pip.push_back(
881 new OpCalculateVectorFieldValues<SPACE_DIM>("GEOMETRY", x_ptr));
882 auto u_ptr = boost::make_shared<MatrixDouble>();
883 pip.push_back(new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_ptr));
884
885 if (is_large_strains) {
886
887 pip.push_back(
888
889 new OpPPMap(
890
891 pp_fe->getPostProcMesh(), pp_fe->getMapGaussPts(),
892
893 {{"PLASTIC_SURFACE",
894 common_plastic_ptr->getPlasticSurfacePtr()},
895 {"PLASTIC_MULTIPLIER",
896 common_plastic_ptr->getPlasticTauPtr()}},
897
898 {{"U", u_ptr}, {"GEOMETRY", x_ptr}},
899
900 {{"GRAD", common_hencky_ptr->matGradPtr},
901 {"FIRST_PIOLA", common_hencky_ptr->getMatFirstPiolaStress()}},
902
903 {{"HENCKY_STRAIN", common_hencky_ptr->getMatLogC()},
904 {"PLASTIC_STRAIN", common_plastic_ptr->getPlasticStrainPtr()},
905 {"PLASTIC_FLOW", common_plastic_ptr->getPlasticFlowPtr()}}
906
907 )
908
909 );
910
911 } else {
912
913 pip.push_back(
914
915 new OpPPMap(
916
917 pp_fe->getPostProcMesh(), pp_fe->getMapGaussPts(),
918
919 {{"PLASTIC_SURFACE",
920 common_plastic_ptr->getPlasticSurfacePtr()},
921 {"PLASTIC_MULTIPLIER",
922 common_plastic_ptr->getPlasticTauPtr()}},
923
924 {{"U", u_ptr}, {"GEOMETRY", x_ptr}},
925
926 {},
927
928 {{"STRAIN", common_plastic_ptr->mStrainPtr},
929 {"STRESS", common_plastic_ptr->mStressPtr},
930 {"PLASTIC_STRAIN", common_plastic_ptr->getPlasticStrainPtr()},
931 {"PLASTIC_FLOW", common_plastic_ptr->getPlasticFlowPtr()}}
932
933 )
934
935 );
936 }
937
939 };
940
941 PetscBool post_proc_vol;
942 PetscBool post_proc_skin;
943
944 if constexpr (SPACE_DIM == 2) {
945 post_proc_vol = PETSC_TRUE;
946 post_proc_skin = PETSC_FALSE;
947 } else {
948 post_proc_vol = PETSC_FALSE;
949 post_proc_skin = PETSC_TRUE;
950 }
951 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-post_proc_vol", &post_proc_vol,
952 PETSC_NULLPTR);
953 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-post_proc_skin",
954 &post_proc_skin, PETSC_NULLPTR);
955
956 auto vol_post_proc = [this, push_vol_post_proc_ops, push_vol_ops,
957 post_proc_vol]() {
958 if (post_proc_vol == PETSC_FALSE)
959 return boost::shared_ptr<PostProcEle>();
960 auto pp_fe = boost::make_shared<PostProcEle>(mField);
962 push_vol_post_proc_ops(pp_fe, push_vol_ops(pp_fe->getOpPtrVector())),
963 "push_vol_post_proc_ops");
964 return pp_fe;
965 };
966
967 auto skin_post_proc = [this, push_vol_post_proc_ops, push_vol_ops,
968 post_proc_skin]() {
969 if (post_proc_skin == PETSC_FALSE)
970 return boost::shared_ptr<SkinPostProcEle>();
971
972 auto simple = mField.getInterface<Simple>();
973 auto pp_fe = boost::make_shared<SkinPostProcEle>(mField);
974 auto op_side = new OpLoopSide<SideEle>(mField, simple->getDomainFEName(),
975 SPACE_DIM, Sev::verbose);
976 pp_fe->getOpPtrVector().push_back(op_side);
977 CHK_MOAB_THROW(push_vol_post_proc_ops(
978 pp_fe, push_vol_ops(op_side->getOpPtrVector())),
979 "push_vol_post_proc_ops");
980 return pp_fe;
981 };
982
983 return std::make_pair(vol_post_proc(), skin_post_proc());
984 };
985
986 auto scatter_create = [&](auto D, auto coeff) {
988 CHKERR is_manager->isCreateProblemFieldAndRank(simple->getProblemName(),
989 ROW, "U", coeff, coeff, is);
990 int loc_size;
991 CHKERR ISGetLocalSize(is, &loc_size);
992 Vec v;
993 CHKERR VecCreateMPI(mField.get_comm(), loc_size, PETSC_DETERMINE, &v);
994 VecScatter scatter;
995 CHKERR VecScatterCreate(D, is, v, PETSC_NULLPTR, &scatter);
996 return std::make_tuple(SmartPetscObj<Vec>(v),
998 };
999
1000 boost::shared_ptr<SetPtsData> field_eval_data;
1001 boost::shared_ptr<MatrixDouble> u_field_ptr;
1002
1003 std::array<double, 3> field_eval_coords{0.0, 0.0, 0.0};
1004 int coords_dim = 3;
1005 CHKERR PetscOptionsGetRealArray(NULL, NULL, "-field_eval_coords",
1006 field_eval_coords.data(), &coords_dim,
1007 &do_eval_field);
1008
1009 boost::shared_ptr<std::map<std::string, boost::shared_ptr<VectorDouble>>>
1010 scalar_field_ptrs = boost::make_shared<
1011 std::map<std::string, boost::shared_ptr<VectorDouble>>>();
1012 boost::shared_ptr<std::map<std::string, boost::shared_ptr<MatrixDouble>>>
1013 vector_field_ptrs = boost::make_shared<
1014 std::map<std::string, boost::shared_ptr<MatrixDouble>>>();
1015 boost::shared_ptr<std::map<std::string, boost::shared_ptr<MatrixDouble>>>
1016 sym_tensor_field_ptrs = boost::make_shared<
1017 std::map<std::string, boost::shared_ptr<MatrixDouble>>>();
1018 boost::shared_ptr<std::map<std::string, boost::shared_ptr<MatrixDouble>>>
1019 tensor_field_ptrs = boost::make_shared<
1020 std::map<std::string, boost::shared_ptr<MatrixDouble>>>();
1021
1022 if (do_eval_field) {
1023 auto u_field_ptr = boost::make_shared<MatrixDouble>();
1024 field_eval_data =
1025 mField.getInterface<FieldEvaluatorInterface>()->getData<DomainEle>();
1026
1027 CHKERR mField.getInterface<FieldEvaluatorInterface>()->buildTree<SPACE_DIM>(
1028 field_eval_data, simple->getDomainFEName());
1029
1030 field_eval_data->setEvalPoints(field_eval_coords.data(), 1);
1031 auto no_rule = [](int, int, int) { return -1; };
1032 auto field_eval_fe_ptr = field_eval_data->feMethodPtr;
1033 field_eval_fe_ptr->getRuleHook = no_rule;
1034
1036 field_eval_fe_ptr->getOpPtrVector(), {H1, HDIV}, "GEOMETRY");
1037
1038 auto [common_plastic_ptr, common_hencky_ptr] =
1039 PlasticOps::createCommonPlasticOps<SPACE_DIM, IT, DomainEleOp>(
1040 mField, "MAT_PLASTIC", field_eval_fe_ptr->getOpPtrVector(), "U",
1041 "EP", "TAU", 1., Sev::inform);
1042
1043 field_eval_fe_ptr->getOpPtrVector().push_back(
1044 new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_field_ptr));
1045
1046 if ((common_plastic_ptr) && (common_hencky_ptr) && (scalar_field_ptrs)) {
1047 if (is_large_strains) {
1048 scalar_field_ptrs->insert(
1049 {"PLASTIC_SURFACE", common_plastic_ptr->getPlasticSurfacePtr()});
1050 scalar_field_ptrs->insert(
1051 {"PLASTIC_MULTIPLIER", common_plastic_ptr->getPlasticTauPtr()});
1052 vector_field_ptrs->insert({"U", u_field_ptr});
1053 sym_tensor_field_ptrs->insert(
1054 {"PLASTIC_STRAIN", common_plastic_ptr->getPlasticStrainPtr()});
1055 sym_tensor_field_ptrs->insert(
1056 {"PLASTIC_FLOW", common_plastic_ptr->getPlasticFlowPtr()});
1057 sym_tensor_field_ptrs->insert(
1058 {"HENCKY_STRAIN", common_hencky_ptr->getMatLogC()});
1059 tensor_field_ptrs->insert({"GRAD", common_hencky_ptr->matGradPtr});
1060 tensor_field_ptrs->insert(
1061 {"FIRST_PIOLA", common_hencky_ptr->getMatFirstPiolaStress()});
1062 } else {
1063 scalar_field_ptrs->insert(
1064 {"PLASTIC_SURFACE", common_plastic_ptr->getPlasticSurfacePtr()});
1065 scalar_field_ptrs->insert(
1066 {"PLASTIC_MULTIPLIER", common_plastic_ptr->getPlasticTauPtr()});
1067 vector_field_ptrs->insert({"U", u_field_ptr});
1068 sym_tensor_field_ptrs->insert(
1069 {"STRAIN", common_plastic_ptr->mStrainPtr});
1070 sym_tensor_field_ptrs->insert(
1071 {"STRESS", common_plastic_ptr->mStressPtr});
1072 sym_tensor_field_ptrs->insert(
1073 {"PLASTIC_STRAIN", common_plastic_ptr->getPlasticStrainPtr()});
1074 sym_tensor_field_ptrs->insert(
1075 {"PLASTIC_FLOW", common_plastic_ptr->getPlasticFlowPtr()});
1076 }
1077 }
1078 }
1079
1080 auto test_monitor_ptr = boost::make_shared<FEMethod>();
1081
1082 auto set_time_monitor = [&](auto dm, auto solver) {
1084 boost::shared_ptr<Monitor<SPACE_DIM>> monitor_ptr(new Monitor<SPACE_DIM>(
1085 dm, create_post_process_elements(), uXScatter, uYScatter, uZScatter,
1086 field_eval_coords, field_eval_data, scalar_field_ptrs,
1087 vector_field_ptrs, sym_tensor_field_ptrs, tensor_field_ptrs));
1088 boost::shared_ptr<ForcesAndSourcesCore> null;
1089
1090 test_monitor_ptr->postProcessHook = [&]() {
1092
1093 if (atom_test && fabs(test_monitor_ptr->ts_t - 0.5) < 1e-12 &&
1094 test_monitor_ptr->ts_step == 25) {
1095
1096 if (scalar_field_ptrs->at("PLASTIC_MULTIPLIER")->size()) {
1097 auto t_tau =
1098 getFTensor0FromVec(*scalar_field_ptrs->at("PLASTIC_MULTIPLIER"));
1099 MOFEM_LOG("PlasticSync", Sev::inform) << "Eval point tau: " << t_tau;
1100
1101 if (atom_test == 1 && fabs(t_tau - 0.688861) > 1e-5) {
1102 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
1103 "atom test %d failed: wrong plastic multiplier value",
1104 atom_test);
1105 }
1106 }
1107
1108 if (vector_field_ptrs->at("U")->size1()) {
1110 auto t_disp =
1111 getFTensor1FromMat<SPACE_DIM>(*vector_field_ptrs->at("U"));
1112 MOFEM_LOG("PlasticSync", Sev::inform) << "Eval point U: " << t_disp;
1113
1114 if (atom_test == 1 && fabs(t_disp(0) - 0.25 / 2.) > 1e-5 ||
1115 fabs(t_disp(1) + 0.0526736) > 1e-5) {
1116 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
1117 "atom test %d failed: wrong displacement value",
1118 atom_test);
1119 }
1120 }
1121
1122 if (sym_tensor_field_ptrs->at("PLASTIC_STRAIN")->size1()) {
1123 auto t_plastic_strain = getFTensor2SymmetricFromMat<SPACE_DIM>(
1124 *sym_tensor_field_ptrs->at("PLASTIC_STRAIN"));
1125 MOFEM_LOG("PlasticSync", Sev::inform)
1126 << "Eval point EP: " << t_plastic_strain;
1127
1128 if (atom_test == 1 &&
1129 fabs(t_plastic_strain(0, 0) - 0.221943) > 1e-5 ||
1130 fabs(t_plastic_strain(0, 1)) > 1e-5 ||
1131 fabs(t_plastic_strain(1, 1) + 0.110971) > 1e-5) {
1132 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
1133 "atom test %d failed: wrong plastic strain value",
1134 atom_test);
1135 }
1136 }
1137
1138 if (tensor_field_ptrs->at("FIRST_PIOLA")->size1()) {
1139 auto t_piola_stress = getFTensor2FromMat<SPACE_DIM, SPACE_DIM>(
1140 *tensor_field_ptrs->at("FIRST_PIOLA"));
1141 MOFEM_LOG("PlasticSync", Sev::inform)
1142 << "Eval point Piola stress: " << t_piola_stress;
1143
1144 if (atom_test == 1 && fabs((t_piola_stress(0, 0) - 198.775) /
1145 t_piola_stress(0, 0)) > 1e-5 ||
1146 fabs(t_piola_stress(0, 1)) + fabs(t_piola_stress(1, 0)) +
1147 fabs(t_piola_stress(1, 1)) >
1148 1e-5) {
1149 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
1150 "atom test %d failed: wrong Piola stress value",
1151 atom_test);
1152 }
1153 }
1154 }
1155
1156 MOFEM_LOG_SYNCHRONISE(mField.get_comm());
1158 };
1159
1160 CHKERR DMMoFEMTSSetMonitor(dm, solver, simple->getDomainFEName(),
1161 monitor_ptr, null, test_monitor_ptr);
1162
1164 };
1165
1166 auto set_schur_pc = [&](auto solver,
1167 boost::shared_ptr<SetUpSchur> &schur_ptr) {
1169
1170 auto name_prb = simple->getProblemName();
1171
1172 // create sub dm for Schur complement
1173 auto create_schur_dm = [&](SmartPetscObj<DM> base_dm,
1174 SmartPetscObj<DM> &dm_sub) {
1176 dm_sub = createDM(mField.get_comm(), "DMMOFEM");
1177 CHKERR DMMoFEMCreateSubDM(dm_sub, base_dm, "SCHUR");
1178 CHKERR DMMoFEMSetSquareProblem(dm_sub, PETSC_TRUE);
1179 CHKERR DMMoFEMAddElement(dm_sub, simple->getDomainFEName());
1180 CHKERR DMMoFEMAddElement(dm_sub, simple->getBoundaryFEName());
1181 for (auto f : {"U"}) {
1184 }
1185 CHKERR DMSetUp(dm_sub);
1186
1188 };
1189
1190 auto create_block_dm = [&](SmartPetscObj<DM> base_dm,
1191 SmartPetscObj<DM> &dm_sub) {
1193 dm_sub = createDM(mField.get_comm(), "DMMOFEM");
1194 CHKERR DMMoFEMCreateSubDM(dm_sub, base_dm, "BLOCK");
1195 CHKERR DMMoFEMSetSquareProblem(dm_sub, PETSC_TRUE);
1196 CHKERR DMMoFEMAddElement(dm_sub, simple->getDomainFEName());
1197 CHKERR DMMoFEMAddElement(dm_sub, simple->getBoundaryFEName());
1198#ifdef ADD_CONTACT
1199 for (auto f : {"SIGMA", "EP", "TAU"}) {
1202 }
1203#else
1204 for (auto f : {"EP", "TAU"}) {
1207 }
1208#endif
1209 CHKERR DMSetUp(dm_sub);
1211 };
1212
1213 // Create nested (sub BC) Schur DM
1214 if constexpr (AT == AssemblyType::BLOCK_SCHUR) {
1215
1216 SmartPetscObj<DM> dm_schur;
1217 CHKERR create_schur_dm(simple->getDM(), dm_schur);
1218 SmartPetscObj<DM> dm_block;
1219 CHKERR create_block_dm(simple->getDM(), dm_block);
1220
1221#ifdef ADD_CONTACT
1222
1223 auto get_nested_mat_data = [&](auto schur_dm, auto block_dm) {
1224 auto block_mat_data = createBlockMatStructure(
1225 simple->getDM(),
1226
1227 {
1228
1229 {simple->getDomainFEName(),
1230
1231 {{"U", "U"},
1232 {"SIGMA", "SIGMA"},
1233 {"U", "SIGMA"},
1234 {"SIGMA", "U"},
1235 {"EP", "EP"},
1236 {"TAU", "TAU"},
1237 {"U", "EP"},
1238 {"EP", "U"},
1239 {"EP", "TAU"},
1240 {"TAU", "EP"},
1241 {"TAU", "U"}
1242
1243 }},
1244
1245 {simple->getBoundaryFEName(),
1246
1247 {{"SIGMA", "SIGMA"}, {"U", "SIGMA"}, {"SIGMA", "U"}
1248
1249 }}
1250
1251 }
1252
1253 );
1254
1256
1257 {dm_schur, dm_block}, block_mat_data,
1258
1259 {"SIGMA", "EP", "TAU"}, {nullptr, nullptr, nullptr}, true
1260
1261 );
1262 };
1263
1264#else
1265
1266 auto get_nested_mat_data = [&](auto schur_dm, auto block_dm) {
1267 auto block_mat_data =
1269
1270 {{simple->getDomainFEName(),
1271
1272 {{"U", "U"},
1273 {"EP", "EP"},
1274 {"TAU", "TAU"},
1275 {"U", "EP"},
1276 {"EP", "U"},
1277 {"EP", "TAU"},
1278 {"TAU", "U"},
1279 {"TAU", "EP"}
1280
1281 }}}
1282
1283 );
1284
1286
1287 {dm_schur, dm_block}, block_mat_data,
1288
1289 {"EP", "TAU"}, {nullptr, nullptr}, false
1290
1291 );
1292 };
1293
1294#endif
1295
1296 auto nested_mat_data = get_nested_mat_data(dm_schur, dm_block);
1297 CHKERR DMMoFEMSetNestSchurData(simple->getDM(), nested_mat_data);
1298
1299 auto block_is = getDMSubData(dm_block)->getSmartRowIs();
1300 auto ao_schur = getDMSubData(dm_schur)->getSmartRowMap();
1301
1302 // Indices has to be map fro very to level, while assembling Schur
1303 // complement.
1304 schur_ptr =
1305 SetUpSchur::createSetUpSchur(mField, dm_schur, block_is, ao_schur);
1306 CHKERR schur_ptr->setUp(solver);
1307 }
1308
1310 };
1311
1312 auto dm = simple->getDM();
1313 auto D = createDMVector(dm);
1314 auto DD = vectorDuplicate(D);
1315 CHKERR VecSetDM(D, PETSC_NULLPTR);
1316 CHKERR VecSetDM(DD, PETSC_NULLPTR);
1317 uXScatter = scatter_create(D, 0);
1318 uYScatter = scatter_create(D, 1);
1319 if constexpr (SPACE_DIM == 3)
1320 uZScatter = scatter_create(D, 2);
1321
1322 auto create_solver = [pip_mng]() {
1323 if (is_quasi_static == PETSC_TRUE)
1324 return pip_mng->createTSIM();
1325 else
1326 return pip_mng->createTSIM2();
1327 };
1328
1329 auto solver = create_solver();
1330
1331 auto active_pre_lhs = []() {
1333 std::fill(PlasticOps::CommonData::activityData.begin(),
1336 };
1337
1338 auto active_post_lhs = [&]() {
1340 auto get_iter = [&]() {
1341 SNES snes;
1342 CHK_THROW_MESSAGE(TSGetSNES(solver, &snes), "Can not get SNES");
1343 int iter;
1344 CHK_THROW_MESSAGE(SNESGetIterationNumber(snes, &iter),
1345 "Can not get iter");
1346 return iter;
1347 };
1348
1349 auto iter = get_iter();
1350 if (iter >= 0) {
1351
1352 std::array<int, 5> activity_data;
1353 std::fill(activity_data.begin(), activity_data.end(), 0);
1354 MPI_Allreduce(PlasticOps::CommonData::activityData.data(),
1355 activity_data.data(), activity_data.size(), MPI_INT,
1356 MPI_SUM, mField.get_comm());
1357
1358 int &active_points = activity_data[0];
1359 int &avtive_full_elems = activity_data[1];
1360 int &avtive_elems = activity_data[2];
1361 int &nb_points = activity_data[3];
1362 int &nb_elements = activity_data[4];
1363
1364 if (nb_points) {
1365
1366 double proc_nb_points =
1367 100 * static_cast<double>(active_points) / nb_points;
1368 double proc_nb_active =
1369 100 * static_cast<double>(avtive_elems) / nb_elements;
1370 double proc_nb_full_active = 100;
1371 if (avtive_elems)
1372 proc_nb_full_active =
1373 100 * static_cast<double>(avtive_full_elems) / avtive_elems;
1374
1375 MOFEM_LOG_C("PLASTICITY", Sev::inform,
1376 "Iter %d nb pts %d nb active pts %d (%3.3f\%) nb active "
1377 "elements %d "
1378 "(%3.3f\%) nb full active elems %d (%3.3f\%)",
1379 iter, nb_points, active_points, proc_nb_points,
1380 avtive_elems, proc_nb_active, avtive_full_elems,
1381 proc_nb_full_active, iter);
1382 }
1383 }
1384
1386 };
1387
1388 auto add_active_dofs_elem = [&](auto dm) {
1390 auto fe_pre_proc = boost::make_shared<FEMethod>();
1391 fe_pre_proc->preProcessHook = active_pre_lhs;
1392 auto fe_post_proc = boost::make_shared<FEMethod>();
1393 fe_post_proc->postProcessHook = active_post_lhs;
1394 auto ts_ctx_ptr = getDMTsCtx(dm);
1395 ts_ctx_ptr->getPreProcessIJacobian().push_front(fe_pre_proc);
1396 ts_ctx_ptr->getPostProcessIJacobian().push_back(fe_post_proc);
1398 };
1399
1400 auto set_essential_bc = [&](auto dm, auto solver) {
1402 // This is low level pushing finite elements (pipelines) to solver
1403
1404 auto pre_proc_ptr = boost::make_shared<FEMethod>();
1405 auto post_proc_rhs_ptr = boost::make_shared<FEMethod>();
1406 auto post_proc_lhs_ptr = boost::make_shared<FEMethod>();
1407 auto ts_ctx_ptr = getDMTsCtx(dm);
1408 ts_ctx_ptr->getPreProcessIFunction().push_front(pre_proc_ptr);
1409 ts_ctx_ptr->getPreProcessIJacobian().push_front(pre_proc_ptr);
1410 ts_ctx_ptr->getPostProcessIFunction().push_back(post_proc_rhs_ptr);
1411 ts_ctx_ptr->getPostProcessIJacobian().push_back(post_proc_lhs_ptr);
1412
1413 // Add boundary condition scaling
1414 auto disp_time_scale = boost::make_shared<TimeScale>();
1415
1416 auto get_bc_hook_rhs = [&]() {
1418 mField, pre_proc_ptr, {disp_time_scale}, false);
1419 };
1420 pre_proc_ptr->preProcessHook = get_bc_hook_rhs();
1421
1422 auto waak_post_proc_rhs_ptr = boost::weak_ptr<FEMethod>(
1423 post_proc_rhs_ptr); // fe method passed to lambda, have to be weak ptr to avoid circular shared ptr reference
1424 auto get_post_proc_hook_rhs = [this, waak_post_proc_rhs_ptr]() {
1427 mField, waak_post_proc_rhs_ptr.lock(), nullptr, Sev::verbose)();
1429 mField, waak_post_proc_rhs_ptr.lock(), 1.)();
1431 };
1432 auto get_post_proc_hook_lhs = [&]() {
1434 mField, post_proc_lhs_ptr, 1.);
1435 };
1436
1437 post_proc_rhs_ptr->postProcessHook = get_post_proc_hook_rhs;
1438 post_proc_lhs_ptr->postProcessHook = get_post_proc_hook_lhs();
1439
1441 };
1442
1443 auto B = createDMMatrix(dm);
1444 if (is_quasi_static == PETSC_FALSE) {
1445 CHKERR TSSetIJacobian(solver, B, B, PETSC_NULLPTR, PETSC_NULLPTR);
1446 } else {
1447 CHKERR TSSetI2Jacobian(solver, B, B, PETSC_NULLPTR, PETSC_NULLPTR);
1448 }
1449 if (is_quasi_static == PETSC_TRUE) {
1450 CHKERR TSSetSolution(solver, D);
1451 } else {
1452 CHKERR TS2SetSolution(solver, D, DD);
1453 }
1454 CHKERR set_section_monitor(solver);
1455 CHKERR set_time_monitor(dm, solver);
1456 CHKERR TSSetFromOptions(solver);
1457
1458 CHKERR add_active_dofs_elem(dm);
1459 boost::shared_ptr<SetUpSchur> schur_ptr;
1460 CHKERR set_schur_pc(solver, schur_ptr);
1461 CHKERR set_essential_bc(dm, solver);
1462
1463 MOFEM_LOG_CHANNEL("TIMER");
1464 MOFEM_LOG_TAG("TIMER", "timer");
1465 if (set_timer)
1466 BOOST_LOG_SCOPED_THREAD_ATTR("Timeline", attrs::timer());
1467 MOFEM_LOG("TIMER", Sev::verbose) << "TSSetUp";
1468 CHKERR TSSetUp(solver);
1469 MOFEM_LOG("TIMER", Sev::verbose) << "TSSetUp <= done";
1470 MOFEM_LOG("TIMER", Sev::verbose) << "TSSolve";
1471 CHKERR TSSolve(solver, NULL);
1472 MOFEM_LOG("TIMER", Sev::verbose) << "TSSolve <= done";
1473
1474 if (mField.get_comm_rank() == 0) {
1475 auto ts_ctx_ptr = getDMTsCtx(dm);
1477 "ts_manager_graph.dot");
1478 }
1479
1481}
1482//! [Solve]
1483
1484//! [TestOperators]
1487
1488 // get operators tester
1489 auto simple = mField.getInterface<Simple>();
1490 auto opt = mField.getInterface<OperatorsTester>(); // get interface to
1491 // OperatorsTester
1492 auto pip = mField.getInterface<PipelineManager>(); // get interface to
1493 // pipeline manager
1494
1495 constexpr double eps = 1e-9;
1496
1497 auto x = opt->setRandomFields(simple->getDM(), {
1498
1499 {"U", {-1e-4, 1e-4}},
1500
1501 {"EP", {-1e-4, 1e-4}},
1502
1503 {"TAU", {0, 1e-4}}
1504
1505 });
1506
1507 auto dot_x_plastic_active =
1508 opt->setRandomFields(simple->getDM(), {
1509
1510 {"U", {-1, 1}},
1511
1512 {"EP", {-1, 1}},
1513
1514 {"TAU", {0.1, 0.5}}
1515
1516 });
1517 auto diff_x_plastic_active =
1518 opt->setRandomFields(simple->getDM(), {
1519
1520 {"U", {-1, 1}},
1521
1522 {"EP", {-1, 1}},
1523
1524 {"TAU", {-1, 1}}
1525
1526 });
1527
1528 auto dot_x_elastic =
1529 opt->setRandomFields(simple->getDM(), {
1530
1531 {"U", {-1, 1}},
1532
1533 {"EP", {-1, 1}},
1534
1535 {"TAU", {-1, -0.1}}
1536
1537 });
1538 auto diff_x_elastic =
1539 opt->setRandomFields(simple->getDM(), {
1540
1541 {"U", {-1, 1}},
1542
1543 {"EP", {-1, 1}},
1544
1545 {"TAU", {-1, 1}}
1546
1547 });
1548
1549 auto test_domain_ops = [&](auto fe_name, auto lhs_pipeline, auto rhs_pipeline,
1550 auto dot_x, auto diff_x) {
1552
1553 auto diff_res = opt->checkCentralFiniteDifference(
1554 simple->getDM(), fe_name, rhs_pipeline, lhs_pipeline, x, dot_x,
1555 SmartPetscObj<Vec>(), diff_x, 0, 0.5, eps);
1556
1557 // Calculate norm of difference between directional derivative calculated
1558 // from finite difference, and tangent matrix.
1559 double fnorm;
1560 CHKERR VecNorm(diff_res, NORM_2, &fnorm);
1561 MOFEM_LOG_C("PLASTICITY", Sev::inform,
1562 "Test consistency of tangent matrix %3.4e", fnorm);
1563
1564 constexpr double err = 1e-5;
1565 if (fnorm > err)
1566 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
1567 "Norm of directional derivative too large err = %3.4e", fnorm);
1568
1570 };
1571
1572 MOFEM_LOG("PLASTICITY", Sev::inform) << "Elastic active";
1573 CHKERR test_domain_ops(simple->getDomainFEName(), pip->getDomainLhsFE(),
1574 pip->getDomainRhsFE(), dot_x_elastic, diff_x_elastic);
1575
1576 MOFEM_LOG("PLASTICITY", Sev::inform) << "Plastic active";
1577 CHKERR test_domain_ops(simple->getDomainFEName(), pip->getDomainLhsFE(),
1578 pip->getDomainRhsFE(), dot_x_plastic_active,
1579 diff_x_plastic_active);
1580
1582};
1583
1584//! [TestOperators]
1585
1586static char help[] = "...\n\n";
1587
1588int main(int argc, char *argv[]) {
1589
1590#ifdef ADD_CONTACT
1591 #ifdef ENABLE_PYTHON_BINDING
1592 Py_Initialize();
1593 np::initialize();
1594 #endif
1595#endif // ADD_CONTACT
1596
1597 // Initialisation of MoFEM/PETSc and MOAB data structures
1598 const char param_file[] = "param_file.petsc";
1599 MoFEM::Core::Initialize(&argc, &argv, param_file, help);
1600
1601 // Add logging channel for example
1602 auto core_log = logging::core::get();
1603 core_log->add_sink(
1605 core_log->add_sink(
1607 LogManager::setLog("PLASTICITY");
1608 MOFEM_LOG_TAG("PLASTICITY", "Plasticity");
1609
1610#ifdef ADD_CONTACT
1611 core_log->add_sink(
1613 LogManager::setLog("CONTACT");
1614 MOFEM_LOG_TAG("CONTACT", "Contact");
1615#endif // ADD_CONTACT
1616
1617 core_log->add_sink(
1619 LogManager::setLog("PlasticSync");
1620 MOFEM_LOG_TAG("PlasticSync", "PlasticSync");
1621
1622 try {
1623
1624 //! [Register MoFEM discrete manager in PETSc]
1625 DMType dm_name = "DMMOFEM";
1626 CHKERR DMRegister_MoFEM(dm_name);
1627 //! [Register MoFEM discrete manager in PETSc
1628
1629 //! [Create MoAB]
1630 moab::Core mb_instance; ///< mesh database
1631 moab::Interface &moab = mb_instance; ///< mesh database interface
1632 //! [Create MoAB]
1633
1634 //! [Create MoFEM]
1635 MoFEM::Core core(moab); ///< finite element database
1636 MoFEM::Interface &m_field = core; ///< finite element database interface
1637 //! [Create MoFEM]
1638
1639 //! [Load mesh]
1640 Simple *simple = m_field.getInterface<Simple>();
1642 CHKERR simple->loadFile();
1643 //! [Load mesh]
1644
1645 //! [Example]
1646 Example ex(m_field);
1647 CHKERR ex.runProblem();
1648 //! [Example]
1649 }
1651
1653
1654#ifdef ADD_CONTACT
1655 #ifdef ENABLE_PYTHON_BINDING
1656 if (Py_FinalizeEx() < 0) {
1657 exit(120);
1658 }
1659 #endif
1660#endif // ADD_CONTACT
1661
1662 return 0;
1663}
1664
1665struct SetUpSchurImpl : public SetUpSchur {
1666
1668 SmartPetscObj<IS> field_split_is, SmartPetscObj<AO> ao_up)
1669 : SetUpSchur(), mField(m_field), subDM(sub_dm),
1670 fieldSplitIS(field_split_is), aoSchur(ao_up) {
1671 if (S) {
1673 "Is expected that schur matrix is not "
1674 "allocated. This is "
1675 "possible only is if PC is set up twice");
1676 }
1677 }
1678 virtual ~SetUpSchurImpl() { S.reset(); }
1679
1680 MoFEMErrorCode setUp(TS solver);
1683
1684private:
1686
1688 SmartPetscObj<DM> subDM; ///< field split sub dm
1689 SmartPetscObj<IS> fieldSplitIS; ///< IS for split Schur block
1690 SmartPetscObj<AO> aoSchur; ///> main DM to subDM
1691};
1692
1695 auto simple = mField.getInterface<Simple>();
1696 auto pip_mng = mField.getInterface<PipelineManager>();
1697
1698 SNES snes;
1699 CHKERR TSGetSNES(solver, &snes);
1700 KSP ksp;
1701 CHKERR SNESGetKSP(snes, &ksp);
1702 CHKERR KSPSetFromOptions(ksp);
1703
1704 PC pc;
1705 CHKERR KSPGetPC(ksp, &pc);
1706 PetscBool is_pcfs = PETSC_FALSE;
1707 PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &is_pcfs);
1708 if (is_pcfs) {
1709 if (S) {
1711 "Is expected that schur matrix is not "
1712 "allocated. This is "
1713 "possible only is if PC is set up twice");
1714 }
1715
1717 CHKERR MatSetBlockSize(S, SPACE_DIM);
1718
1719 // Set DM to use shell block matrix
1720 DM solver_dm;
1721 CHKERR TSGetDM(solver, &solver_dm);
1722 CHKERR DMSetMatType(solver_dm, MATSHELL);
1723
1724 auto ts_ctx_ptr = getDMTsCtx(solver_dm);
1725 auto A = createDMBlockMat(simple->getDM());
1726 auto P = createDMNestSchurMat(simple->getDM());
1727
1728 if (is_quasi_static == PETSC_TRUE) {
1729 auto swap_assemble = [](TS ts, PetscReal t, Vec u, Vec u_t, PetscReal a,
1730 Mat A, Mat B, void *ctx) {
1731 return TsSetIJacobian(ts, t, u, u_t, a, B, A, ctx);
1732 };
1733 CHKERR TSSetIJacobian(solver, A, P, swap_assemble, ts_ctx_ptr.get());
1734 } else {
1735 auto swap_assemble = [](TS ts, PetscReal t, Vec u, Vec u_t, Vec utt,
1736 PetscReal a, PetscReal aa, Mat A, Mat B,
1737 void *ctx) {
1738 return TsSetI2Jacobian(ts, t, u, u_t, utt, a, aa, B, A, ctx);
1739 };
1740 CHKERR TSSetI2Jacobian(solver, A, P, swap_assemble, ts_ctx_ptr.get());
1741 }
1742 CHKERR KSPSetOperators(ksp, A, P);
1743
1744 auto set_ops = [&]() {
1746 auto pip_mng = mField.getInterface<PipelineManager>();
1747
1748#ifndef ADD_CONTACT
1749 // Boundary
1750 pip_mng->getOpBoundaryLhsPipeline().push_front(
1752 pip_mng->getOpBoundaryLhsPipeline().push_back(createOpSchurAssembleEnd(
1753
1754 {"EP", "TAU"}, {nullptr, nullptr}, aoSchur, S, false, false
1755
1756 ));
1757 // Domain
1758 pip_mng->getOpDomainLhsPipeline().push_front(
1760 pip_mng->getOpDomainLhsPipeline().push_back(createOpSchurAssembleEnd(
1761
1762 {"EP", "TAU"}, {nullptr, nullptr}, aoSchur, S, false, false
1763
1764 ));
1765#else
1766
1767 double eps_stab = 1e-4;
1768 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-eps_stab", &eps_stab,
1769 PETSC_NULLPTR);
1770
1773 using OpMassStab = B::OpMass<3, SPACE_DIM * SPACE_DIM>;
1774
1775 // Boundary
1776 pip_mng->getOpBoundaryLhsPipeline().push_front(
1778 pip_mng->getOpBoundaryLhsPipeline().push_back(
1779 new OpMassStab("SIGMA", "SIGMA", [eps_stab](double, double, double) {
1780 return eps_stab;
1781 }));
1782 pip_mng->getOpBoundaryLhsPipeline().push_back(createOpSchurAssembleEnd(
1783
1784 {"SIGMA", "EP", "TAU"}, {nullptr, nullptr, nullptr}, aoSchur, S,
1785 false, false
1786
1787 ));
1788 // Domain
1789 pip_mng->getOpDomainLhsPipeline().push_front(
1791 pip_mng->getOpDomainLhsPipeline().push_back(createOpSchurAssembleEnd(
1792
1793 {"SIGMA", "EP", "TAU"}, {nullptr, nullptr, nullptr}, aoSchur, S,
1794 false, false
1795
1796 ));
1797#endif // ADD_CONTACT
1799 };
1800
1801 auto set_assemble_elems = [&]() {
1803 auto schur_asmb_pre_proc = boost::make_shared<FEMethod>();
1804 schur_asmb_pre_proc->preProcessHook = [this]() {
1806 CHKERR MatZeroEntries(S);
1807 MOFEM_LOG("TIMER", Sev::verbose) << "Lhs Assemble Begin";
1809 };
1810 auto schur_asmb_post_proc = boost::make_shared<FEMethod>();
1811 auto weak_schur_asmb_post_proc = boost::weak_ptr<FEMethod>(
1812 schur_asmb_post_proc); // fe method passed to lambda, have to be weak ptr to avoid circular shared ptr reference
1813
1814 schur_asmb_post_proc->postProcessHook = [this,
1815 weak_schur_asmb_post_proc]() {
1817 MOFEM_LOG("TIMER", Sev::verbose) << "Lhs Assemble End";
1818
1819 // Apply essential constrains to Schur complement
1820 CHKERR MatAssemblyBegin(S, MAT_FINAL_ASSEMBLY);
1821 CHKERR MatAssemblyEnd(S, MAT_FINAL_ASSEMBLY);
1823 mField, weak_schur_asmb_post_proc.lock(), 1, S, aoSchur)();
1824
1826 };
1827 auto ts_ctx_ptr = getDMTsCtx(simple->getDM());
1828 ts_ctx_ptr->getPreProcessIJacobian().push_front(schur_asmb_pre_proc);
1829 ts_ctx_ptr->getPostProcessIJacobian().push_front(schur_asmb_post_proc);
1831 };
1832
1833 auto set_pc = [&]() {
1835 CHKERR PCFieldSplitSetIS(pc, NULL, fieldSplitIS);
1836 CHKERR PCFieldSplitSetSchurPre(pc, PC_FIELDSPLIT_SCHUR_PRE_USER, S);
1838 };
1839
1840 auto set_diagonal_pc = [&]() {
1842 KSP *subksp;
1843 CHKERR PCFieldSplitSchurGetSubKSP(pc, PETSC_NULLPTR, &subksp);
1844 auto get_pc = [](auto ksp) {
1845 PC pc_raw;
1846 CHKERR KSPGetPC(ksp, &pc_raw);
1847 return SmartPetscObj<PC>(pc_raw,
1848 true); // bump reference
1849 };
1850 CHKERR setSchurA00MatSolvePC(get_pc(subksp[0]));
1851 CHKERR PetscFree(subksp);
1853 };
1854
1855 CHKERR set_ops();
1856 CHKERR set_pc();
1857 CHKERR set_assemble_elems();
1858
1859 CHKERR TSSetUp(solver);
1860 CHKERR KSPSetUp(ksp);
1861 CHKERR set_diagonal_pc();
1862
1863 } else {
1864 pip_mng->getOpBoundaryLhsPipeline().push_front(
1866 pip_mng->getOpBoundaryLhsPipeline().push_back(
1867 createOpSchurAssembleEnd({}, {}));
1868 pip_mng->getOpDomainLhsPipeline().push_front(createOpSchurAssembleBegin());
1869 pip_mng->getOpDomainLhsPipeline().push_back(
1870 createOpSchurAssembleEnd({}, {}));
1871 }
1872
1873 // fieldSplitIS.reset();
1874 // aoSchur.reset();
1876}
1877
1878boost::shared_ptr<SetUpSchur>
1880 SmartPetscObj<DM> sub_dm, SmartPetscObj<IS> is_sub,
1881 SmartPetscObj<AO> ao_up) {
1882 return boost::shared_ptr<SetUpSchur>(
1883 new SetUpSchurImpl(m_field, sub_dm, is_sub, ao_up));
1884}
1885
1886namespace PlasticOps {
1887
1889 boost::ptr_deque<ForcesAndSourcesCore::UserDataOperator> &pipeline,
1890 std::vector<FieldSpace> spaces, std::string geom_field_name) {
1892 CHKERR MoFEM::AddHOOps<2, 3, 3>::add(pipeline, spaces, geom_field_name);
1894}
1895
1897 boost::ptr_deque<ForcesAndSourcesCore::UserDataOperator> &pipeline,
1898 std::vector<FieldSpace> spaces, std::string geom_field_name) {
1900 CHKERR MoFEM::AddHOOps<1, 2, 2>::add(pipeline, spaces, geom_field_name);
1902}
1903
1904template <int FE_DIM, int PROBLEM_DIM, int SPACE_DIM>
1906scaleL2(boost::ptr_deque<ForcesAndSourcesCore::UserDataOperator> &pipeline,
1907 std::string geom_field_name) {
1909
1910 auto jac_ptr = boost::make_shared<MatrixDouble>();
1911 auto det_ptr = boost::make_shared<VectorDouble>();
1913 geom_field_name, jac_ptr));
1914 pipeline.push_back(new OpInvertMatrix<SPACE_DIM>(jac_ptr, det_ptr, nullptr));
1915
1916 auto scale_ptr = boost::make_shared<double>(1.);
1918 Example::meshVolumeAndCount[1]; // average volume of elements
1920 auto op_scale = new OP(NOSPACE, OP::OPSPACE);
1921 op_scale->doWorkRhsHook = [scale_ptr, det_ptr,
1922 scale](DataOperator *base_op_ptr, int, EntityType,
1924 *scale_ptr = scale / det_ptr->size(); // distribute average element size
1925 // over integration points
1926 return 0;
1927 };
1928 pipeline.push_back(op_scale);
1929
1932 pipeline.push_back(
1933 new OpScaleBaseBySpaceInverseOfMeasure(L2, base, det_ptr, scale_ptr));
1934 }
1935
1937}
1938
1940 boost::ptr_deque<ForcesAndSourcesCore::UserDataOperator> &pipeline,
1941 std::vector<FieldSpace> spaces, std::string geom_field_name) {
1943 constexpr bool scale_l2 = false;
1944 if (scale_l2) {
1945 CHKERR scaleL2<3, 3, 3>(pipeline, geom_field_name);
1946 }
1947 CHKERR MoFEM::AddHOOps<3, 3, 3>::add(pipeline, spaces, geom_field_name,
1948 nullptr, nullptr, nullptr);
1950}
1951
1953 boost::ptr_deque<ForcesAndSourcesCore::UserDataOperator> &pipeline,
1954 std::vector<FieldSpace> spaces, std::string geom_field_name) {
1956 constexpr bool scale_l2 = false;
1957 if (scale_l2) {
1958 CHKERR scaleL2<2, 2, 2>(pipeline, geom_field_name);
1959 }
1960 CHKERR MoFEM::AddHOOps<2, 2, 2>::add(pipeline, spaces, geom_field_name,
1961 nullptr, nullptr, nullptr);
1963}
1964
1965} // namespace PlasticOps
static auto filter_true_skin(MoFEM::Interface &m_field, Range &&skin)
std::string type
#define MOFEM_LOG_SYNCHRONISE(comm)
Synchronise "SYNC" channel.
#define MOFEM_LOG_C(channel, severity, format,...)
void simple(double P1[], double P2[], double P3[], double c[], const int N)
Definition acoustic.cpp:69
int main()
constexpr double a
ElementsAndOps< SPACE_DIM >::DomainEle DomainEle
ElementsAndOps< SPACE_DIM >::BoundaryEle BoundaryEle
Kronecker Delta class symmetric.
@ ROW
#define CATCH_ERRORS
Catch errors.
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base .
Definition definitions.h:60
@ AINSWORTH_LOBATTO_BASE
Definition definitions.h:62
@ NOBASE
Definition definitions.h:59
@ DEMKOWICZ_JACOBI_BASE
Definition definitions.h:66
#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()
FieldSpace
approximation spaces
Definition definitions.h:82
@ L2
field with C-1 continuity
Definition definitions.h:88
@ H1
continuous field
Definition definitions.h:85
@ NOSPACE
Definition definitions.h:83
@ HCURL
field with continuous tangents
Definition definitions.h:86
@ HDIV
field with continuous normal traction
Definition definitions.h:87
#define MYPCOMM_INDEX
default communicator number PCOMM
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
#define CHK_MOAB_THROW(err, msg)
Check error code of MoAB function and throw MoFEM exception.
@ MOFEM_NOT_FOUND
Definition definitions.h:33
@ MOFEM_ATOM_TEST_INVALID
Definition definitions.h:40
@ MOFEM_DATA_INCONSISTENCY
Definition definitions.h:31
static const char *const ApproximationBaseNames[]
Definition definitions.h:72
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
#define MoFEMFunctionBeginHot
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
constexpr int order
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::LinearForm< GAUSS >::OpBaseTimesVector< 1, SPACE_DIM, SPACE_DIM > OpInertiaForce
constexpr auto t_kd
PetscErrorCode DMMoFEMCreateSubDM(DM subdm, DM dm, const char problem_name[])
Must be called by user to set Sub DM MoFEM data structures.
Definition DMMoFEM.cpp:215
PetscErrorCode DMMoFEMAddElement(DM dm, std::string fe_name)
add element to dm
Definition DMMoFEM.cpp:488
PetscErrorCode DMMoFEMSetSquareProblem(DM dm, PetscBool square_problem)
set squared problem
Definition DMMoFEM.cpp:450
PetscErrorCode DMMoFEMAddSubFieldRow(DM dm, const char field_name[])
Definition DMMoFEM.cpp:238
PetscErrorCode DMRegister_MoFEM(const char sname[])
Register MoFEM problem.
Definition DMMoFEM.cpp:43
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
auto createDMVector(DM dm, RowColData rc=RowColData::COL)
Get smart vector from DM.
Definition DMMoFEM.hpp:1237
PetscErrorCode DMMoFEMAddSubFieldCol(DM dm, const char field_name[])
Definition DMMoFEM.cpp:280
auto createDMMatrix(DM dm)
Get smart matrix from DM.
Definition DMMoFEM.hpp:1194
IntegrationType
Form integrator integration types.
AssemblyType
[Storage and set boundary conditions]
@ GAUSS
Gaussian quadrature integration.
@ PETSC
Standard PETSc assembly.
@ BLOCK_PRECONDITIONER_SCHUR
Block preconditioner Schur assembly.
static LoggerType & setLog(const std::string channel)
Set ans resset chanel logger.
#define MOFEM_LOG(channel, severity)
Log.
#define MOFEM_LOG_TAG(channel, tag)
Tag channel.
#define MOFEM_LOG_CHANNEL(channel)
Set and reset channel.
virtual MoFEMErrorCode loop_dofs(const Problem *problem_ptr, const std::string &field_name, RowColData rc, DofMethod &method, int lower_rank, int upper_rank, int verb=DEFAULT_VERBOSITY)=0
Make a loop over dofs.
FTensor::Index< 'i', SPACE_DIM > i
double D
const double v
phase velocity of light in medium (cm/ns)
FTensor::Index< 'l', 3 > l
FTensor::Index< 'j', 3 > j
FTensor::Index< 'k', 3 > k
double cn_contact
Definition contact.cpp:97
const FTensor::Tensor2< T, Dim, Dim > Vec
const double eps
Definition HenckyOps.hpp:13
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
implementation of Data Operators for Forces and Sources
Definition Common.hpp:10
auto type_from_handle(const EntityHandle h)
get type from entity handle
PetscErrorCode DMMoFEMTSSetMonitor(DM dm, TS ts, const std::string fe_name, boost::shared_ptr< MoFEM::FEMethod > method, boost::shared_ptr< MoFEM::BasicMethod > pre_only, boost::shared_ptr< MoFEM::BasicMethod > post_only)
Set Monitor To TS solver.
Definition DMMoFEM.cpp:1046
PetscErrorCode TsSetIJacobian(TS ts, PetscReal t, Vec u, Vec u_t, PetscReal a, Mat A, Mat B, void *ctx)
Set function evaluating jacobian in TS solver.
Definition TsCtx.cpp:169
auto getDMTsCtx(DM dm)
Get TS context data structure used by DM.
Definition DMMoFEM.hpp:1279
OpSchurAssembleBase * createOpSchurAssembleEnd(std::vector< std::string > fields_name, std::vector< boost::shared_ptr< Range > > field_ents, SmartPetscObj< AO > ao, SmartPetscObj< Mat > schur, bool sym_schur, bool symm_op)
Construct a new Op Schur Assemble End object.
Definition Schur.cpp:2675
PetscErrorCode PetscOptionsGetInt(PetscOptions *, const char pre[], const char name[], PetscInt *ivalue, PetscBool *set)
MoFEMErrorCode MoFEMSNESMonitorFields(SNES snes, PetscInt its, PetscReal fgnorm, SnesCtx *ctx)
Sens monitor printing residual field by field.
Definition SnesCtx.cpp:600
MoFEMErrorCode setSchurA00MatSolvePC(SmartPetscObj< PC > pc)
Set PC for A00 block.
Definition Schur.cpp:2717
PetscErrorCode PetscOptionsGetBool(PetscOptions *, const char pre[], const char name[], PetscBool *bval, PetscBool *set)
PetscErrorCode PetscOptionsGetScalar(PetscOptions *, const char pre[], const char name[], PetscScalar *dval, PetscBool *set)
SmartPetscObj< Vec > vectorDuplicate(Vec vec)
Create duplicate vector of smart vector.
PetscErrorCode PetscOptionsGetRealArray(PetscOptions *, const char pre[], const char name[], PetscReal dval[], PetscInt *nmax, PetscBool *set)
auto getDMSubData(DM dm)
Get sub problem data structure.
Definition DMMoFEM.hpp:1295
PetscErrorCode TsSetI2Jacobian(TS ts, PetscReal t, Vec u, Vec u_t, Vec u_tt, PetscReal a, PetscReal aa, Mat A, Mat B, void *ctx)
Calculation Jacobian for second order PDE in time.
Definition TsCtx.cpp:519
boost::shared_ptr< BlockStructure > createBlockMatStructure(DM dm, SchurFEOpsFEandFields schur_fe_op_vec)
Create a Mat Diag Blocks object.
Definition Schur.cpp:1082
boost::shared_ptr< NestSchurData > createSchurNestedMatrixStruture(std::pair< SmartPetscObj< DM >, SmartPetscObj< DM > > dms, boost::shared_ptr< BlockStructure > block_mat_data_ptr, std::vector< std::string > fields_names, std::vector< boost::shared_ptr< Range > > field_ents, bool add_preconditioner_block)
Get the Schur Nest Mat Array object.
Definition Schur.cpp:2433
PetscErrorCode PetscOptionsGetString(PetscOptions *, const char pre[], const char name[], char str[], size_t size, PetscBool *set)
MoFEMErrorCode DMMoFEMSetNestSchurData(DM dm, boost::shared_ptr< NestSchurData >)
Definition DMMoFEM.cpp:1555
static auto getFTensor0FromVec(V &data)
Get tensor rank 0 (scalar) form data vector.
auto getDMSnesCtx(DM dm)
Get SNES context data structure used by DM.
Definition DMMoFEM.hpp:1265
auto createDMNestSchurMat(DM dm)
Definition DMMoFEM.hpp:1221
auto createDM(MPI_Comm comm, const std::string dm_type_name)
Creates smart DM object.
OpSchurAssembleBase * createOpSchurAssembleBegin()
Definition Schur.cpp:2670
auto createDMBlockMat(DM dm)
Definition DMMoFEM.hpp:1214
MoFEMErrorCode scaleL2(boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > &pipeline, std::string geom_field_name)
Definition plastic.cpp:1906
OpPostProcMapInMoab< SPACE_DIM, SPACE_DIM > OpPPMap
constexpr double t
plate stiffness
Definition plate.cpp:58
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::BiLinearForm< GAUSS >::OpMass< 1, SPACE_DIM > OpMass
[Only used with Hooke equation (linear material model)]
Definition seepage.cpp:56
FTensor::Index< 'm', 3 > m
PipelineManager::ElementsAndOpsByDim< 2 >::FaceSideEle SideEle
Definition plastic.cpp:29
PipelineManager::ElementsAndOpsByDim< 3 >::FaceSideEle SideEle
Definition plastic.cpp:36
[Operators_definition]
double getScale(const double time)
Get scaling at given time.
Definition plastic.cpp:242
[Example]
Definition plastic.cpp:217
static std::array< double, 2 > meshVolumeAndCount
Definition plastic.cpp:224
MoFEMErrorCode testOperators()
[Solve]
Definition plastic.cpp:1485
MoFEMErrorCode tsSolve()
Definition plastic.cpp:833
FieldApproximationBase base
Choice of finite element basis functions.
Definition plot_base.cpp:68
std::tuple< SmartPetscObj< Vec >, SmartPetscObj< VecScatter > > uYScatter
Definition plastic.cpp:237
MoFEMErrorCode createCommonData()
[Set up problem]
Definition plastic.cpp:479
Example(MoFEM::Interface &m_field)
Definition plastic.cpp:219
MoFEMErrorCode OPs()
[Boundary condition]
Definition plastic.cpp:649
MoFEMErrorCode runProblem()
[Run problem]
Definition plastic.cpp:255
MoFEM::Interface & mField
Reference to MoFEM interface.
Definition plastic.cpp:227
std::tuple< SmartPetscObj< Vec >, SmartPetscObj< VecScatter > > uZScatter
Definition plastic.cpp:238
MoFEMErrorCode setupProblem()
[Run problem]
Definition plastic.cpp:274
MoFEMErrorCode bC()
[Create common data]
Definition plastic.cpp:605
std::tuple< SmartPetscObj< Vec >, SmartPetscObj< VecScatter > > uXScatter
Definition plastic.cpp:236
Add operators pushing bases from local to physical configuration.
Boundary condition manager for finite element problem setup.
Managing BitRefLevels.
virtual moab::Interface & get_moab()=0
virtual MPI_Comm & get_comm() const =0
Core (interface) class.
Definition Core.hpp:83
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
base operator to do operations at Gauss Pt. level
Deprecated interface functions.
Definition of the displacement bc data structure.
Definition BCData.hpp:72
Data on single entity (This is passed as argument to DataOperator::doWork)
Class (Function) to enforce essential constrains on the left hand side diagonal.
Definition Essential.hpp:33
Class (Function) to enforce essential constrains on the right hand side diagonal.
Definition Essential.hpp:41
Class (Function) to calculate residual side diagonal.
Definition Essential.hpp:49
Class (Function) to enforce essential constrains.
Definition Essential.hpp:25
Field evaluator interface.
SetIntegrationPtsMethodData SetPtsData
double getMeasure() const
get measure of element
@ OPSPACE
operator do Work is execute on space data
Section manager is used to create indexes and sections.
Definition ISManager.hpp:23
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.
Interface for managing meshsets containing materials and boundary conditions.
Assembly methods.
Definition Natural.hpp:65
Get field gradients at integration pts for scalar field rank 0, i.e. vector field.
Approximate field values for given petsc vector.
Specialization for MatrixDouble vector field values calculation.
Operator for inverting matrices at integration points.
Element used to execute operators on side of the element.
Post post-proc data at points from hash maps.
Scale base functions by inverses of measure of element.
Calculate directional derivative of the right hand side and compare it with tangent matrix derivative...
static MoFEMErrorCode writeTSGraphGraphviz(TsCtx *ts_ctx, std::string file_name)
TS graph to Graphviz file.
Template struct for dimension-specific finite element types.
PipelineManager interface.
MoFEM::VolumeElementForcesAndSourcesCore VolEle
boost::shared_ptr< FEMethod > & getDomainLhsFE()
Get domain left-hand side finite element.
MoFEM::FaceElementForcesAndSourcesCore FaceEle
MoFEM::EdgeElementForcesAndSourcesCore EdgeEle
Projection of edge entities with one mid-node on hierarchical basis.
Simple interface for fast problem set-up.
Definition Simple.hpp:27
MoFEMErrorCode getOptions()
get options
Definition Simple.cpp:180
intrusive_ptr for managing petsc objects
Force scale operator for reading two columns.
double getScale(const double time)
Get scaling at a given time.
TimeScale(std::string file_name="", bool error_if_file_not_given=false, ScalingFun def_scaling_fun=[](double time) { return time;})
TimeScale constructor.
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.
static std::array< int, 5 > activityData
SmartPetscObj< DM > subDM
field split sub dm
Definition plastic.cpp:1688
SmartPetscObj< Mat > S
SmartPetscObj< AO > aoSchur
Definition plastic.cpp:1690
SmartPetscObj< IS > fieldSplitIS
IS for split Schur block.
Definition plastic.cpp:1689
SetUpSchurImpl(MoFEM::Interface &m_field, SmartPetscObj< DM > sub_dm, SmartPetscObj< IS > field_split_is, SmartPetscObj< AO > ao_up)
Definition plastic.cpp:1667
MoFEMErrorCode setUp(SmartPetscObj< KSP >)
virtual ~SetUpSchurImpl()
Definition plastic.cpp:1678
MoFEMErrorCode postProc()
MoFEMErrorCode preProc()
MoFEM::Interface & mField
[Push operators to pipeline]
SetUpSchur()=default
static boost::shared_ptr< SetUpSchur > createSetUpSchur(MoFEM::Interface &m_field)
virtual MoFEMErrorCode setUp(TS solver)=0
constexpr AssemblyType AT
VolEle::UserDataOperator VolOp
PetscBool order_face
PetscBool order_edge
PetscBool order_volume
double young_modulus
Young modulus.
Definition plastic.cpp:126
constexpr AssemblyType AT
Definition plastic.cpp:44
double C1_k
Kinematic hardening.
Definition plastic.cpp:134
double Qinf
Saturation yield stress.
Definition plastic.cpp:132
constexpr IntegrationType IT
Definition plastic.cpp:47
static char help[]
[TestOperators]
Definition plastic.cpp:1586
double rho
Definition plastic.cpp:145
int atom_test
Atom test.
Definition plastic.cpp:122
#define EXECUTABLE_DIMENSION
Definition plastic.cpp:13
PetscBool do_eval_field
Evaluate field.
Definition plastic.cpp:120
PetscBool is_quasi_static
Definition plastic.cpp:144
double alpha_damping
Definition plastic.cpp:146
constexpr int SPACE_DIM
Definition plastic.cpp:40
double visH
Viscous hardening.
Definition plastic.cpp:130
double poisson_ratio
Poisson ratio.
Definition plastic.cpp:127
auto kinematic_hardening(FTensor::Tensor2_symmetric< T, DIM > &t_plastic_strain, double C1_k)
Definition plastic.cpp:93
PetscBool set_timer
Set timer.
Definition plastic.cpp:119
double iso_hardening_dtau(double tau, double H, double Qinf, double b_iso)
Definition plastic.cpp:79
double scale
Definition plastic.cpp:124
constexpr auto size_symm
Definition plastic.cpp:42
double zeta
Viscous hardening.
Definition plastic.cpp:131
double H
Hardening.
Definition plastic.cpp:129
int tau_order
Order of tau files.
Definition plastic.cpp:140
double iso_hardening_exp(double tau, double b_iso)
Definition plastic.cpp:65
double cn0
Definition plastic.cpp:136
int order
Order displacement.
Definition plastic.cpp:139
double b_iso
Saturation exponent.
Definition plastic.cpp:133
PetscBool is_large_strains
Large strains.
Definition plastic.cpp:118
int geom_order
Order if fixed.
Definition plastic.cpp:142
double sigmaY
Yield stress.
Definition plastic.cpp:128
double iso_hardening(double tau, double H, double Qinf, double b_iso, double sigmaY)
Definition plastic.cpp:74
auto kinematic_hardening_dplastic_strain(double C1_k)
Definition plastic.cpp:107
ElementsAndOps< SPACE_DIM >::SideEle SideEle
Definition plastic.cpp:62
int ep_order
Order of ep files.
Definition plastic.cpp:141
double cn1
Definition plastic.cpp:137
constexpr FieldSpace CONTACT_SPACE
Definition plastic.cpp:52
#define SCHUR_ASSEMBLE
Definition contact.cpp:18
constexpr int SPACE_DIM
[Define dimension]
Definition elastic.cpp:18
constexpr AssemblyType A
[Define dimension]
Definition elastic.cpp:21
constexpr int SPACE_DIM