v0.15.0
Loading...
Searching...
No Matches
thermoplastic.cpp
Go to the documentation of this file.
1/**
2 * \file thermoplastic.cpp
3 * \example thermoplastic.cpp
4 *
5 * Thermoplasticity 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#include <cstdlib>
22extern "C" {
23#include <phg-quadrule/quad.h>
24}
25
26using namespace MoFEM;
27
28template <int DIM> struct ElementsAndOps;
29
30template <> struct ElementsAndOps<2> {
36 static constexpr FieldSpace CONTACT_SPACE = HCURL;
37};
38
39template <> struct ElementsAndOps<3> {
45 static constexpr FieldSpace CONTACT_SPACE = HDIV;
46};
47
48constexpr int SPACE_DIM =
49 EXECUTABLE_DIMENSION; //< Space dimension of problem, mesh
50constexpr auto size_symm = (SPACE_DIM * (SPACE_DIM + 1)) / 2;
51
52constexpr bool IS_LARGE_STRAINS =
53 FINITE_DEFORMATION_FLAG; //< Flag to turn off/on geometric nonlinearities
54
55constexpr AssemblyType AT =
56 (SCHUR_ASSEMBLE) ? AssemblyType::BLOCK_SCHUR
57 : AssemblyType::PETSC; //< selected assembly type
59 IntegrationType::GAUSS; //< selected integration type
60
64
68using DomainEleOp = DomainEle::UserDataOperator;
70using BoundaryEleOp = BoundaryEle::UserDataOperator;
75
77
78using ScalerFunTwoArgs = boost::function<double(const double, const double)>;
80 boost::function<double(const double, const double, const double)>;
81
82inline double H_thermal(double H, double omega_h, double temp_0, double temp) {
83 return H * (1. - omega_h * (temp - temp_0));
84}
85
86inline double dH_thermal_dtemp(double H, double omega_h) {
87 return -H * omega_h;
88}
89
90inline double y_0_thermal(double sigmaY, double omega_0, double temp_0,
91 double temp) {
92 return sigmaY * (1. - omega_0 * (temp - temp_0));
93}
94
95inline double dy_0_thermal_dtemp(double sigmaY, double omega_0) {
96 return -sigmaY * omega_0;
97}
98
99inline double Qinf_thermal(double Qinf, double omega_h, double temp_0,
100 double temp) {
101 return Qinf * (1. - omega_h * (temp - temp_0));
102}
103
104inline double dQinf_thermal_dtemp(double Qinf, double omega_h) {
105 return -Qinf * omega_h;
106}
107
108inline double iso_hardening_exp(double tau, double b_iso) {
109 return std::exp(-b_iso * tau);
110}
111
112double exp_C = -6.284;
113double exp_D = -1.024;
114
115inline double temp_hat(double temp) {
116 double JC_ref_temp = 0.;
117 double JC_melt_temp = 1650.;
118
119 return (temp - JC_ref_temp) / (JC_melt_temp - JC_ref_temp);
120}
121
122inline double exp_softening(double temp_hat) {
123 return std::exp(exp_C * pow(temp_hat, 2) + exp_D * temp_hat);
124}
125
126/**
127 * Isotropic hardening
128 */
129inline double iso_hardening(double tau, double H, double omega_0, double Qinf,
130 double omega_h, double b_iso, double sigmaY,
131 double temp_0, double temp) {
132 return (sigmaY + H * tau + Qinf * (1. - iso_hardening_exp(tau, b_iso))) *
134}
135
136inline double iso_hardening_dtau(double tau, double H, double omega_0,
137 double Qinf, double omega_h, double b_iso,
138 double sigmaY, double temp_0, double temp) {
139 return (H + Qinf * b_iso * iso_hardening_exp(tau, b_iso)) *
141}
142
143inline double iso_hardening_dtemp(double tau, double H, double omega_0,
144 double Qinf, double omega_h, double b_iso,
145 double sigmaY, double temp_0, double temp) {
146 double JC_ref_temp = 0.;
147 double JC_melt_temp = 1650.;
148 double T_hat = temp_hat(temp);
149
150 return (sigmaY + H * tau + Qinf * (1. - iso_hardening_exp(tau, b_iso))) *
151 (exp_D + 2 * T_hat * exp_C) *
152 std::exp(exp_D * T_hat + pow(T_hat, 2) * exp_C) /
153 (JC_melt_temp - JC_ref_temp);
154}
155
156/**
157 * Kinematic hardening
158 */
159template <typename T, int DIM>
160inline auto
162 double C1_k) {
163 FTensor::Index<'i', DIM> i;
164 FTensor::Index<'j', DIM> j;
166 if (C1_k < std::numeric_limits<double>::epsilon()) {
167 t_alpha(i, j) = 0;
168 return t_alpha;
169 }
170 t_alpha(i, j) = C1_k * t_plastic_strain(i, j);
171 return t_alpha;
172}
173
174template <int DIM>
176 FTensor::Index<'i', DIM> i;
177 FTensor::Index<'j', DIM> j;
178 FTensor::Index<'k', DIM> k;
179 FTensor::Index<'l', DIM> l;
182 t_diff(i, j, k, l) = C1_k * (t_kd(i, k) ^ t_kd(j, l)) / 4.;
183 return t_diff;
184}
185
187 IS_LARGE_STRAINS; // PETSC_TRUE; ///< Large strains
188PetscBool set_timer = PETSC_FALSE; ///< Set timer
189PetscBool do_eval_field = PETSC_FALSE; ///< Evaluate field
190char restart_file[255];
191PetscBool restart_flg = PETSC_TRUE;
192double restart_time = 0;
194PetscBool is_distributed_mesh = PETSC_TRUE;
195
196double scale = 1.;
202
203double young_modulus = 115000; ///< Young modulus
204double poisson_ratio = 0.31; ///< Poisson ratio
205double sigmaY = 936.2; ///< Yield stress
206double H = 584.3; ///< Hardening
207double visH = 0; ///< Viscous hardening
208double zeta = 5e-2; ///< regularisation parameter
209double Qinf = 174.2; ///< Saturation yield stress
210double b_iso = 63.69; ///< Saturation exponent
211double C1_k = 0; ///< Kinematic hardening
212
213double cn0 = 1;
214double cn1 = 1;
215
216double default_ref_temp = 20.0;
218const char *const ICTypes[] = {"uniform", "gaussian", "linear",
219 "ICType", "IC_", nullptr};
220// CHANGE this from PetscBool to ICType
222double init_temp = 20.0;
223double peak_temp = 1000.0;
224double width = 10.0; ///< Width of Gaussian distribution
227 11.4; // Force / (time temperature ) or Power /
228 // (length temperature) // Time unit is hour. force unit kN
229double default_heat_capacity = 2.332; // length^2/(time^2 temperature) //
230 // length is millimeter time is hour
231
232double omega_0 = 2e-3; ///< flow stress softening
233double omega_h = 2e-3; ///< hardening softening
235 0.9; ///< fraction of plastic dissipation converted to heat
236double temp_0 = 20; ///< reference temperature for thermal softening
237
238int order = 2; ///< Order displacement
239int tau_order = order - 2; ///< Order of tau field
240int ep_order = order - 1; ///< Order of ep field
241int flux_order = order; ///< Order of tau field
242int T_order = order - 1; ///< Order of ep field
243int geom_order = 2; ///< Order if fixed.
244
245int atom_test = 0;
246
247PetscBool order_edge = PETSC_FALSE;
248PetscBool order_face = PETSC_FALSE;
249PetscBool order_volume = PETSC_FALSE;
250
251PetscBool is_quasi_static = PETSC_TRUE;
252double rho = 0.0;
253double alpha_damping = 0;
254double init_dt = 0.05;
255double min_dt = 1e-12;
256double qual_tol = 0;
257double qual_thresh = 0.1;
260
270
277
278auto Gaussian_distribution = [](double init_temp, double peak_temp, double x,
279 double y, double z) {
280 double s =
281 width /
282 std::sqrt(-2. * std::log(0.01 * peak_temp / (peak_temp - init_temp)));
283 return (peak_temp - init_temp) * exp(-pow(y, 2) / (2. * pow(s, 2))) +
284 init_temp;
285};
286
287auto linear_distribution = [](double init_temp, double peak_temp, double x,
288 double y, double z) {
289 return ((peak_temp - init_temp) / width) * y + (peak_temp + init_temp) / 2.0;
290};
291
292auto uniform_distribution = [](double init_temp, double peak_temp, double x,
293 double y, double z) { return init_temp; };
294
295/**
296 * @brief Initialisation function for temperature field
297 */
298auto init_T = [](double init_temp, double peak_temp, double x, double y,
299 double z) {
300 switch (ic_type) {
301 case IC_GAUSSIAN:
302 return -Gaussian_distribution(init_temp, peak_temp, x, y, z);
303 case IC_LINEAR:
304 return -linear_distribution(init_temp, peak_temp, x, y, z);
305 case IC_UNIFORM:
306 default:
307 return -uniform_distribution(init_temp, peak_temp, x, y, z);
308 }
309};
310
311#include <HenckyOps.hpp>
312#include <PlasticOps.hpp>
313#include <PlasticNaturalBCs.hpp>
314#include <ThermoElasticOps.hpp>
315#include <FiniteThermalOps.hpp>
316#include <ThermoPlasticOps.hpp>
317#include <ThermalOps.hpp>
318
319#include <EdgeFlippingOps.hpp>
320#include <SolutionMapping.hpp>
321
322#include <ThermalConvection.hpp>
323#include <ThermalRadiation.hpp>
324
325#ifdef ADD_CONTACT
326 #ifdef ENABLE_PYTHON_BINDING
327 #include <boost/python.hpp>
328 #include <boost/python/def.hpp>
329 #include <boost/python/numpy.hpp>
330namespace bp = boost::python;
331namespace np = boost::python::numpy;
332 #endif
333
334namespace ContactOps {
335
336double cn_contact = 0.1;
337
338}; // namespace ContactOps
339
340 #include <ContactOps.hpp>
341#endif // ADD_CONTACT
342
343using namespace PlasticOps;
344using namespace HenckyOps;
345using namespace ThermoElasticOps;
346using namespace FiniteThermalOps;
347using namespace ThermalOps;
348
350
352 std::string output_name, int &counter = *(new int(0))) {
354
355 auto create_post_process_elements = [&]() {
357 auto pp_fe = boost::make_shared<PostProcEle>(m_field);
358
359 auto push_vol_post_proc_ops = [&](auto &pp_fe) {
361
362 auto &pip = pp_fe->getOpPtrVector();
363
364 auto TAU_ptr = boost::make_shared<VectorDouble>();
365 pip.push_back(new OpCalculateScalarFieldValues("TAU", TAU_ptr));
366 auto T_ptr = boost::make_shared<VectorDouble>();
367 pip.push_back(new OpCalculateScalarFieldValues("T", T_ptr));
368
369 auto T_grad_ptr = boost::make_shared<MatrixDouble>();
370 pip.push_back(
371 new OpCalculateScalarFieldGradient<SPACE_DIM>("T", T_grad_ptr));
372 auto U_ptr = boost::make_shared<MatrixDouble>();
373 pip.push_back(new OpCalculateVectorFieldValues<SPACE_DIM>("U", U_ptr));
374 auto FLUX_ptr = boost::make_shared<MatrixDouble>();
375 pip.push_back(
376 new OpCalculateHVecVectorField<3, SPACE_DIM>("FLUX", FLUX_ptr));
377
378 auto EP_ptr = boost::make_shared<MatrixDouble>();
379 pip.push_back(
381
383
384 pip.push_back(
385
386 new OpPPMap(
387
388 pp_fe->getPostProcMesh(), pp_fe->getMapGaussPts(),
389
390 {{"TAU", TAU_ptr}, {"T", T_ptr}},
391
392 {{"U", U_ptr}, {"FLUX", FLUX_ptr}, {"T_GRAD", T_grad_ptr}},
393
394 {},
395
396 {{"EP", EP_ptr}}
397
398 )
399
400 );
401
403 };
404
405 CHKERR push_vol_post_proc_ops(pp_fe);
406
407 if (m_field.get_comm_size() == 1) {
408
409 CHKERR DMoFEMLoopFiniteElements(dm, "dFE", pp_fe);
410 CHKERR pp_fe->writeFile("out_" + std::to_string(counter) + "_" +
411 output_name + ".h5m");
412 } else {
413
415 m_field.get_comm_size());
416 auto &post_proc_moab = pp_fe->getPostProcMesh();
417 auto file_name = "out_" + std::to_string(counter) + "_" + output_name +
418 "_" + std::to_string(m_field.get_comm_rank()) + ".vtk";
419 MOFEM_LOG("WORLD", Sev::inform)
420 << "Writing file " << file_name << std::endl;
421 CHKERR post_proc_moab.write_file(file_name.c_str(), "VTK");
422 }
423 counter++;
424
426 };
427
428 CHKERR create_post_process_elements();
429
431}
432
434 Vec sol, std::string output_name) {
436
437 auto smart_sol = SmartPetscObj<Vec>(sol, true);
438
439 auto create_post_process_elements = [&]() {
441 auto pp_fe = boost::make_shared<PostProcEle>(m_field);
442
443 auto push_vol_post_proc_ops = [&](auto &pp_fe) {
445
446 auto &pip = pp_fe->getOpPtrVector();
447
448 auto TAU_ptr = boost::make_shared<VectorDouble>();
449 pip.push_back(
450 new OpCalculateScalarFieldValues("TAU", TAU_ptr, smart_sol));
451 auto T_ptr = boost::make_shared<VectorDouble>();
452 pip.push_back(new OpCalculateScalarFieldValues("T", T_ptr, smart_sol));
453
454 auto U_ptr = boost::make_shared<MatrixDouble>();
455 pip.push_back(
456 new OpCalculateVectorFieldValues<SPACE_DIM>("U", U_ptr, smart_sol));
457 auto FLUX_ptr = boost::make_shared<MatrixDouble>();
459 "FLUX", FLUX_ptr, smart_sol));
460
461 auto EP_ptr = boost::make_shared<MatrixDouble>();
463 "EP", EP_ptr, smart_sol));
464
466
467 pip.push_back(
468
469 new OpPPMap(
470
471 pp_fe->getPostProcMesh(), pp_fe->getMapGaussPts(),
472
473 {{"TAU", TAU_ptr}, {"T", T_ptr}},
474
475 {{"U", U_ptr}, {"FLUX", FLUX_ptr}},
476
477 {},
478
479 {{"EP", EP_ptr}}
480
481 )
482
483 );
484
486 };
487
488 CHKERR push_vol_post_proc_ops(pp_fe);
489
490 CHKERR DMoFEMLoopFiniteElements(dm, "dFE", pp_fe);
491 CHKERR pp_fe->writeFile("out_" + output_name + ".h5m");
492
494 };
495
496 CHKERR create_post_process_elements();
497
499}
500
502 const std::string &out_put_string,
503 const auto &out_put_quantity) {
505 auto rank = m_field.get_comm_rank();
506 auto size = m_field.get_comm_size();
507
508 // Loop through all processes and print one by one
509 for (int i = 0; i < size; ++i) {
510 // If it is this process's turn, print the data
511 if (i == rank) {
512 std::cout << "Proc " << rank << " " + out_put_string + " "
513 << out_put_quantity << std::endl;
514 }
515 // All processes wait here until the current one has finished
516 // printing
517 CHKERR PetscBarrier(NULL);
518 }
520};
521
531
532//! [Body and heat source]
540//! [Body and heat source]
541
542//! [Natural boundary conditions]
548//! [Natural boundary conditions]
549
550//! [Essential boundary conditions (Least square approach)]
552 IT>::OpEssentialRhs<HeatFluxCubitBcData, 3, SPACE_DIM>;
555//! [Essential boundary conditions (Least square approach)]
556
561
562auto save_range = [](moab::Interface &moab, const std::string name,
563 const Range r) {
565 auto out_meshset = get_temp_meshset_ptr(moab);
566 CHKERR moab.add_entities(*out_meshset, r);
567 CHKERR moab.write_file(name.c_str(), "VTK", "", out_meshset->get_ptr(), 1);
569};
570
571auto get_string_from_vector = [](auto vec) {
572 std::string output_string = "";
573 for (auto el : vec) {
574 output_string += std::to_string(el) + " ";
575 }
576 return output_string;
577};
578
579struct Example;
580
581/**
582 * @brief Set of functions called by PETSc solver used to refine and update
583 * mesh.
584 *
585 * @note Currently theta method is only handled by this code.
586 *
587 */
588struct TSPrePostProc {
589
590 TSPrePostProc() = default;
591 virtual ~TSPrePostProc() = default;
592
593 /**
594 * @brief Used to setup TS solver
595 *
596 * @param ts
597 * @return MoFEMErrorCode
598 */
600
602
603private:
604 /**
605 * @brief Pre process time step
606 *
607 * Refine mesh and update fields
608 *
609 * @param ts
610 * @return MoFEMErrorCode
611 */
613
614 /**
615 * @brief Post process time step.
616 *
617 * Currently that function do not make anything major
618 *
619 * @param ts
620 * @return MoFEMErrorCode
621 */
623
625};
626
627static boost::weak_ptr<TSPrePostProc> tsPrePostProc;
628
629struct ResizeCtx {
631 // any flags / lists indicating which elements flipped or were added
632 PetscBool mesh_changed; // set by your code that flips elements
633 std::multimap<double, EntityHandle> el_q_map;
635 std::vector<EntityHandle> new_connectivity;
637 boost::weak_ptr<TSPrePostProc> ptr;
638 // store whatever mapping info you need
639};
640
641static std::unordered_map<TS, ResizeCtx *> ts_to_rctx;
642
644
647 int order_row, int order_col,
648 int order_data) {
650
651 constexpr int numNodes = 3;
652 constexpr int numEdges = 3;
653
654 auto &m_field = fe_raw_ptr->mField;
655 auto fe_ptr = static_cast<Fe *>(fe_raw_ptr);
656 auto fe_handle = fe_ptr->getFEEntityHandle();
657
658 auto set_base_quadrature = [&]() {
660 int rule = 2 * (order_data + 1);
661 if (rule < QUAD_2D_TABLE_SIZE) {
662 if (QUAD_2D_TABLE[rule]->dim != 2) {
663 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "wrong dimension");
664 }
665 if (QUAD_2D_TABLE[rule]->order < rule) {
666 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
667 "wrong order %d != %d", QUAD_2D_TABLE[rule]->order, rule);
668 }
669 const size_t nb_gauss_pts = QUAD_2D_TABLE[rule]->npoints;
670 fe_ptr->gaussPts.resize(3, nb_gauss_pts, false);
671 cblas_dcopy(nb_gauss_pts, &QUAD_2D_TABLE[rule]->points[1], 3,
672 &fe_ptr->gaussPts(0, 0), 1);
673 cblas_dcopy(nb_gauss_pts, &QUAD_2D_TABLE[rule]->points[2], 3,
674 &fe_ptr->gaussPts(1, 0), 1);
675 cblas_dcopy(nb_gauss_pts, QUAD_2D_TABLE[rule]->weights, 1,
676 &fe_ptr->gaussPts(2, 0), 1);
677 auto &data = fe_ptr->dataOnElement[H1];
678 data->dataOnEntities[MBVERTEX][0].getN(NOBASE).resize(nb_gauss_pts, 3,
679 false);
680 double *shape_ptr =
681 &*data->dataOnEntities[MBVERTEX][0].getN(NOBASE).data().begin();
682 cblas_dcopy(3 * nb_gauss_pts, QUAD_2D_TABLE[rule]->points, 1, shape_ptr,
683 1);
684 data->dataOnEntities[MBVERTEX][0].getDiffN(NOBASE).resize(3, 2, false);
685 std::copy(
687 data->dataOnEntities[MBVERTEX][0].getDiffN(NOBASE).data().begin());
688
689 } else {
690 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
691 "rule > quadrature order %d < %d", rule, QUAD_3D_TABLE_SIZE);
692 }
694 };
695
696 CHKERR set_base_quadrature();
697
698 auto set_gauss_pts = [&](auto &ref_gauss_pts) {
700 fe_ptr->gaussPts.swap(ref_gauss_pts);
701 const size_t nb_gauss_pts = fe_ptr->gaussPts.size2();
702 auto &data = fe_ptr->dataOnElement[H1];
703 data->dataOnEntities[MBVERTEX][0].getN(NOBASE).resize(nb_gauss_pts, 3);
704 double *shape_ptr =
705 &*data->dataOnEntities[MBVERTEX][0].getN(NOBASE).data().begin();
706 CHKERR ShapeMBTRI(shape_ptr, &fe_ptr->gaussPts(0, 0),
707 &fe_ptr->gaussPts(1, 0), nb_gauss_pts);
709 };
710
711 auto refine_quadrature = [&]() {
713
714 moab::Core moab_ref;
715 double base_coords[] = {0, 0, 0, 1, 0, 0, 0, 1, 0};
716 EntityHandle nodes[numNodes];
717 for (int nn = 0; nn != numNodes; nn++)
718 CHKERR moab_ref.create_vertex(&base_coords[3 * nn], nodes[nn]);
719 EntityHandle tri;
720 CHKERR moab_ref.create_element(MBTRI, nodes, numNodes, tri);
721 MoFEM::CoreTmp<-1> mofem_ref_core(moab_ref, PETSC_COMM_SELF, -2);
722 MoFEM::Interface &m_field_ref = mofem_ref_core;
723
724 Range ref_tri(tri, tri);
725 Range edges;
726 CHKERR m_field_ref.get_moab().get_adjacencies(ref_tri, 1, true, edges,
727 moab::Interface::UNION);
728 CHKERR m_field_ref.getInterface<BitRefManager>()->setBitRefLevel(
729 ref_tri, BitRefLevel().set(0), false, VERBOSE);
730
731 Range nodes_at_front;
732 for (int nn = 0; nn != numNodes; nn++) {
733 EntityHandle ent;
734 CHKERR moab_ref.side_element(tri, 0, nn, ent);
735 nodes_at_front.insert(ent);
736 }
737
738 EntityHandle meshset;
739 CHKERR moab_ref.create_meshset(MESHSET_SET, meshset);
740 for (int ee = 0; ee != numEdges; ee++) {
741 EntityHandle ent;
742 CHKERR moab_ref.side_element(tri, 1, ee, ent);
743 CHKERR moab_ref.add_entities(meshset, &ent, 1);
744 }
745
746 // refine mesh
747 auto *m_ref = m_field_ref.getInterface<MeshRefinement>();
748 Range ref_edges;
749 CHKERR m_field_ref.getInterface<BitRefManager>()
750 ->getEntitiesByTypeAndRefLevel(BitRefLevel().set(0),
751 BitRefLevel().set(), MBEDGE, ref_edges);
752
753 // Range tris_to_refine;
754 // CHKERR m_field_ref.getInterface<BitRefManager>()
755 // ->getEntitiesByTypeAndRefLevel(
756 // BitRefLevel().set(0), BitRefLevel().set(), MBTRI,
757 // tris_to_refine);
758 CHKERR m_ref->addVerticesInTheMiddleOfEdges(ref_edges,
759 BitRefLevel().set(1));
760 CHKERR m_ref->addVerticesInTheMiddleOfFaces(ref_tri, BitRefLevel().set(1));
761 CHKERR m_ref->refineTris(ref_tri, BitRefLevel().set(1));
762 CHKERR m_field_ref.getInterface<BitRefManager>()
763 ->updateMeshsetByEntitiesChildren(meshset, BitRefLevel().set(1),
764 meshset, MBEDGE, true);
765 CHKERR m_field_ref.getInterface<BitRefManager>()
766 ->updateMeshsetByEntitiesChildren(meshset, BitRefLevel().set(1),
767 meshset, MBTRI, true);
768
769 // get ref coords
770 Range output_ref_tris;
771 CHKERR m_field_ref.getInterface<BitRefManager>()
772 ->getEntitiesByTypeAndRefLevel(
773 BitRefLevel().set(1), BitRefLevel().set(), MBTRI, output_ref_tris);
774
775#ifndef NDEBUG
776 CHKERR save_range(moab_ref, "ref_tris.vtk", output_ref_tris);
777#endif
778
779 MatrixDouble ref_coords(output_ref_tris.size(), 9, false);
780 int tt = 0;
781 for (Range::iterator tit = output_ref_tris.begin();
782 tit != output_ref_tris.end(); tit++, tt++) {
783 int num_nodes;
784 const EntityHandle *conn;
785 CHKERR moab_ref.get_connectivity(*tit, conn, num_nodes, false);
786 CHKERR moab_ref.get_coords(conn, num_nodes, &ref_coords(tt, 0));
787 }
788
789 auto &data = fe_ptr->dataOnElement[H1];
790 const size_t nb_gauss_pts = fe_ptr->gaussPts.size2();
791 MatrixDouble ref_gauss_pts(3, nb_gauss_pts * ref_coords.size1());
792 MatrixDouble &shape_n = data->dataOnEntities[MBVERTEX][0].getN(NOBASE);
793 int gg = 0;
794 for (size_t tt = 0; tt != ref_coords.size1(); tt++) {
795 double *tri_coords = &ref_coords(tt, 0);
797 CHKERR Tools::getTriNormal(tri_coords, &t_normal(0));
798 auto det = t_normal.l2();
799 for (size_t ggg = 0; ggg != nb_gauss_pts; ++ggg, ++gg) {
800 for (int dd = 0; dd != 2; dd++) {
801 ref_gauss_pts(dd, gg) = shape_n(ggg, 0) * tri_coords[3 * 0 + dd] +
802 shape_n(ggg, 1) * tri_coords[3 * 1 + dd] +
803 shape_n(ggg, 2) * tri_coords[3 * 2 + dd];
804 }
805 MOFEM_LOG("REMESHING", Sev::noisy)
806 << ref_gauss_pts(0, gg) << ", " << ref_gauss_pts(1, gg);
807 ref_gauss_pts(2, gg) = fe_ptr->gaussPts(2, ggg) * det;
808 }
809 }
810
811 int num_nodes;
812 const EntityHandle *conn;
813 CHKERR m_field.get_moab().get_connectivity(fe_handle, conn, num_nodes,
814 true);
815 std::bitset<numNodes> all_nodes;
816 for (auto nn = 0; nn != numNodes; ++nn) {
817 all_nodes.set(nn);
818 }
819
820 mapRefCoords[all_nodes.to_ulong()].swap(ref_gauss_pts);
821 CHKERR set_gauss_pts(mapRefCoords[all_nodes.to_ulong()]);
822
824 };
825
826 CHKERR refine_quadrature();
827
829}
830
831extern PetscErrorCode MyTSResizeTransfer(TS, PetscInt, Vec[], Vec[], void *);
832
833struct Example {
834
835 Example(MoFEM::Interface &m_field) : mField(m_field) {}
836
838
840
841private:
842 friend PetscErrorCode ::MyTSResizeTransfer(TS, PetscInt, Vec[], Vec[],
843 void *);
850 getElementQuality(std::multimap<double, EntityHandle> &el_q_map,
851 Range &flipped_els,
852 std::vector<EntityHandle> &new_connectivity,
853 bool &do_refine, Tag &th_spatial_coords);
855 MoFEMErrorCode doEdgeFlips(std::multimap<double, EntityHandle> &el_q_map,
856 Range &flipped_els, Tag &th_spatial_coords,
857 std::vector<EntityHandle> &new_connectivity);
858 MoFEMErrorCode doEdgeSplits(bool &refine, bool add_ents);
861
862 boost::shared_ptr<DomainEle> reactionFe;
863
864 std::tuple<SmartPetscObj<Vec>, SmartPetscObj<VecScatter>> uXScatter;
865 std::tuple<SmartPetscObj<Vec>, SmartPetscObj<VecScatter>> uYScatter;
866 std::tuple<SmartPetscObj<Vec>, SmartPetscObj<VecScatter>> uZScatter;
867
868 boost::shared_ptr<VectorDouble> tempFieldPtr =
869 boost::make_shared<VectorDouble>();
870 boost::shared_ptr<MatrixDouble> fluxFieldPtr =
871 boost::make_shared<MatrixDouble>();
872 boost::shared_ptr<MatrixDouble> dispFieldPtr =
873 boost::make_shared<MatrixDouble>();
874 boost::shared_ptr<MatrixDouble> dispGradPtr =
875 boost::make_shared<MatrixDouble>();
876 boost::shared_ptr<MatrixDouble> strainFieldPtr =
877 boost::make_shared<MatrixDouble>();
878 boost::shared_ptr<MatrixDouble> stressFieldPtr =
879 boost::make_shared<MatrixDouble>();
880 boost::shared_ptr<VectorDouble> plasticMultiplierFieldPtr =
881 boost::make_shared<VectorDouble>();
882 boost::shared_ptr<MatrixDouble> plasticStrainFieldPtr =
883 boost::make_shared<MatrixDouble>();
884
885 struct ScaledTimeScale : public MoFEM::TimeScale {
887 double getScale(const double time) {
888 return scale * MoFEM::TimeScale::getScale(time);
889 };
890 };
891
892#ifdef ADD_CONTACT
893 #ifdef ENABLE_PYTHON_BINDING
894 boost::shared_ptr<ContactOps::SDFPython> sdfPythonPtr;
895 #endif
896#endif // ADD_CONTACT
897
898 template <int DIM, AssemblyType A, IntegrationType I, typename DomainEleOp>
900 MoFEM::Interface &m_field, std::string block_name,
901 std::string thermal_block_name, std::string thermoelastic_block_name,
902 std::string thermoplastic_block_name, Pip &pip, std::string u,
903 std::string ep, std::string tau, std::string temperature) {
905
906 using B = typename FormsIntegrators<DomainEleOp>::template Assembly<
907 A>::template LinearForm<I>;
909 typename B::template OpGradTimesSymTensor<1, DIM, DIM>;
911 typename B::template OpGradTimesTensor<1, DIM, DIM>;
912
914
916
917 auto [common_plastic_ptr, common_hencky_ptr, common_thermal_ptr,
918 common_thermoelastic_ptr, common_thermoplastic_ptr] =
919 createCommonThermoPlasticOps<DIM, I, DomainEleOp>(
920 m_field, block_name, thermal_block_name, thermoelastic_block_name,
921 thermoplastic_block_name, pip, u, ep, tau, temperature, scale,
924
925 auto m_D_ptr = common_hencky_ptr->matDPtr;
926
928 ep, common_plastic_ptr->getPlasticStrainDotPtr()));
929 pip.push_back(new OpCalculateScalarFieldValuesDot(
930 tau, common_plastic_ptr->getPlasticTauDotPtr()));
931 pip.push_back(new OpCalculateScalarFieldValues(
932 temperature, common_thermoplastic_ptr->getTempPtr()));
934 "FLUX", common_thermoplastic_ptr->getHeatFluxPtr()));
935 pip.push_back(new typename P::template OpCalculatePlasticity<DIM, I>(
936 u, common_plastic_ptr, m_D_ptr, common_thermoplastic_ptr));
937
938 pip.push_back(
939 new
940 typename H::template OpCalculateHenckyThermoPlasticStress<DIM, I, 0>(
941 u, common_thermoplastic_ptr->getTempPtr(), common_hencky_ptr,
942 common_thermoelastic_ptr->getCoeffExpansionPtr(),
943 common_thermoelastic_ptr->getRefTempPtr()));
944
945 // Calculate internal forces
946 if (common_hencky_ptr) {
947 pip.push_back(new OpInternalForcePiola(
948 u, common_hencky_ptr->getMatFirstPiolaStress()));
949 } else {
950 pip.push_back(
951 new OpInternalForceCauchy(u, common_plastic_ptr->mStressPtr));
952 }
953
954 auto inelastic_heat_frac_ptr =
955 common_thermoplastic_ptr->getInelasticHeatFractionPtr();
957 [inelastic_heat_frac_ptr](const double, const double, const double) {
958 return (*inelastic_heat_frac_ptr);
959 };
960
961 // TODO: add scenario for when not using Hencky material
964 temperature, common_hencky_ptr->getMatHenckyStress(),
965 common_plastic_ptr->getPlasticStrainDotPtr(), inelastic_heat_fraction));
966
967 pip.push_back(
968 new
969 typename P::template Assembly<A>::template OpCalculateConstraintsRhs<I>(
970 tau, common_plastic_ptr, m_D_ptr));
971 pip.push_back(
972 new
973 typename P::template Assembly<A>::template OpCalculatePlasticFlowRhs<
974 DIM, I>(ep, common_plastic_ptr, m_D_ptr));
975
977 }
978
979 template <int DIM, AssemblyType A, IntegrationType I, typename DomainEleOp>
981 MoFEM::Interface &m_field, std::string block_name,
982 std::string thermal_block_name, std::string thermoelastic_block_name,
983 std::string thermoplastic_block_name, Pip &pip, std::string u,
984 std::string ep, std::string tau, std::string temperature) {
986
987 using namespace HenckyOps;
989
990 using B = typename FormsIntegrators<DomainEleOp>::template Assembly<
991 A>::template BiLinearForm<I>;
992 using OpKPiola = typename B::template OpGradTensorGrad<1, DIM, DIM, 1>;
993 using OpKCauchy = typename B::template OpGradSymTensorGrad<1, DIM, DIM, 0>;
994
996
997 auto [common_plastic_ptr, common_hencky_ptr, common_thermal_ptr,
998 common_thermoelastic_ptr, common_thermoplastic_ptr] =
999 createCommonThermoPlasticOps<DIM, I, DomainEleOp>(
1000 m_field, block_name, thermal_block_name, thermoelastic_block_name,
1001 thermoplastic_block_name, pip, u, ep, tau, temperature, scale,
1003 inelastic_heat_fraction_scaling, Sev::inform);
1004
1005 auto m_D_ptr = common_hencky_ptr->matDPtr;
1006
1008 ep, common_plastic_ptr->getPlasticStrainDotPtr()));
1009 pip.push_back(new OpCalculateScalarFieldValuesDot(
1010 tau, common_plastic_ptr->getPlasticTauDotPtr()));
1011 pip.push_back(new typename P::template OpCalculatePlasticity<DIM, I>(
1012 u, common_plastic_ptr, m_D_ptr, common_thermoplastic_ptr));
1013
1014 if (common_hencky_ptr) {
1015 pip.push_back(new typename H::template OpHenckyTangent<DIM, I, 0>(
1016 u, common_hencky_ptr, m_D_ptr));
1017 pip.push_back(new OpKPiola(u, u, common_hencky_ptr->getMatTangent()));
1018 pip.push_back(
1019 new typename P::template Assembly<A>::
1020 template OpCalculatePlasticInternalForceLhs_LogStrain_dEP<DIM, I>(
1021 u, ep, common_plastic_ptr, common_hencky_ptr, m_D_ptr));
1022 } else {
1023 pip.push_back(new OpKCauchy(u, u, m_D_ptr));
1024 pip.push_back(new typename P::template Assembly<A>::
1025 template OpCalculatePlasticInternalForceLhs_dEP<DIM, I>(
1026 u, ep, common_plastic_ptr, m_D_ptr));
1027 }
1028
1029 if (common_hencky_ptr) {
1030 pip.push_back(
1031 new typename P::template Assembly<A>::
1032 template OpCalculateConstraintsLhs_LogStrain_dU<DIM, I>(
1033 tau, u, common_plastic_ptr, common_hencky_ptr, m_D_ptr));
1034 pip.push_back(
1035 new typename P::template Assembly<A>::
1036 template OpCalculatePlasticFlowLhs_LogStrain_dU<DIM, I>(
1037 ep, u, common_plastic_ptr, common_hencky_ptr, m_D_ptr));
1038 } else {
1039 pip.push_back(new typename P::template Assembly<A>::
1040 template OpCalculateConstraintsLhs_dU<DIM, I>(
1041 tau, u, common_plastic_ptr, m_D_ptr));
1042 pip.push_back(new typename P::template Assembly<A>::
1043 template OpCalculatePlasticFlowLhs_dU<DIM, I>(
1044 ep, u, common_plastic_ptr, m_D_ptr));
1045 }
1046
1047 pip.push_back(new typename P::template Assembly<A>::
1048 template OpCalculatePlasticFlowLhs_dEP<DIM, I>(
1049 ep, ep, common_plastic_ptr, m_D_ptr));
1050 pip.push_back(new typename P::template Assembly<A>::
1051 template OpCalculatePlasticFlowLhs_dTAU<DIM, I>(
1052 ep, tau, common_plastic_ptr, m_D_ptr));
1053 pip.push_back(
1055 ep, temperature, common_thermoplastic_ptr));
1056 pip.push_back(new typename P::template Assembly<A>::
1057 template OpCalculateConstraintsLhs_dEP<DIM, I>(
1058 tau, ep, common_plastic_ptr, m_D_ptr));
1059 pip.push_back(
1060 new typename P::template Assembly<
1061 A>::template OpCalculateConstraintsLhs_dTAU<I>(tau, tau,
1062 common_plastic_ptr));
1063
1064 // TODO: add scenario for when not using Hencky material
1065 pip.push_back(new typename H::template OpCalculateHenckyThermalStressdT<
1066 DIM, I, AssemblyDomainEleOp, 0>(
1067 u, temperature, common_hencky_ptr,
1068 common_thermoelastic_ptr->getCoeffExpansionPtr()));
1069
1070 auto inelastic_heat_frac_ptr =
1071 common_thermoplastic_ptr->getInelasticHeatFractionPtr();
1073 [inelastic_heat_frac_ptr](const double, const double, const double) {
1074 return (*inelastic_heat_frac_ptr);
1075 };
1076
1077 // TODO: add scenario for when not using Hencky material
1080 temperature, temperature, common_hencky_ptr, common_plastic_ptr,
1082 common_thermoelastic_ptr->getCoeffExpansionPtr()));
1083
1084 // TODO: add scenario for when not using Hencky material
1087 temperature, ep, common_hencky_ptr, common_plastic_ptr,
1089
1090 // TODO: add scenario for when not using Hencky material
1093 temperature, u, common_hencky_ptr, common_plastic_ptr,
1095
1097 tau, temperature, common_thermoplastic_ptr));
1098
1100 }
1101
1102 template <int DIM, IntegrationType I, typename DomainEleOp>
1104 MoFEM::Interface &m_field, std::string plastic_block_name,
1105 std::string thermal_block_name, std::string thermoelastic_block_name,
1106 std::string thermoplastic_block_name,
1107 boost::ptr_deque<ForcesAndSourcesCore::UserDataOperator> &pip,
1108 std::string u, std::string ep, std::string tau, std::string temperature,
1112 bool with_rates = true) {
1113
1115
1116 auto common_plastic_ptr = boost::make_shared<PlasticOps::CommonData>();
1117 auto common_thermal_ptr =
1118 boost::make_shared<ThermoElasticOps::BlockedThermalParameters>();
1119 auto common_thermoelastic_ptr =
1120 boost::make_shared<ThermoElasticOps::BlockedThermoElasticParameters>();
1121 auto common_thermoplastic_ptr =
1122 boost::make_shared<ThermoPlasticOps::ThermoPlasticBlockedParameters>();
1123
1124 constexpr auto size_symm = (DIM * (DIM + 1)) / 2;
1125 auto make_d_mat = []() {
1126 return boost::make_shared<MatrixDouble>(size_symm * size_symm, 1);
1127 };
1128
1129 common_plastic_ptr->mDPtr = boost::make_shared<MatrixDouble>();
1130 common_plastic_ptr->mGradPtr = boost::make_shared<MatrixDouble>();
1131 common_plastic_ptr->mStrainPtr = boost::make_shared<MatrixDouble>();
1132 common_plastic_ptr->mStressPtr = boost::make_shared<MatrixDouble>();
1133
1134 auto m_D_ptr = common_plastic_ptr->mDPtr;
1135
1136 CHK_THROW_MESSAGE(PlasticOps::addMatBlockOps<DIM>(
1137 m_field, plastic_block_name, pip, m_D_ptr,
1138 common_plastic_ptr->getParamsPtr(), scale, sev),
1139 "add mat block plastic ops");
1141 m_field, pip, thermal_block_name, common_thermal_ptr,
1146 "add mat block thermal ops");
1148 m_field, pip, thermoelastic_block_name,
1149 common_thermoelastic_ptr, default_coeff_expansion,
1150 default_ref_temp, sev),
1151 "add mat block thermal ops");
1153 m_field, pip, thermoplastic_block_name,
1154 common_thermoplastic_ptr, common_thermal_ptr, sev,
1156 "add mat block thermoplastic ops");
1157 auto common_hencky_ptr =
1158 HenckyOps::commonDataFactory<SPACE_DIM, IT, DomainEleOp>(
1159 mField, pip, "U", "MAT_ELASTIC", Sev::inform, scale);
1160
1161 common_plastic_ptr->mDPtr = common_hencky_ptr->matDPtr;
1162
1163 pip.push_back(new OpCalculateScalarFieldValues(
1164 tau, common_plastic_ptr->getPlasticTauPtr()));
1166 ep, common_plastic_ptr->getPlasticStrainPtr()));
1168 u, common_plastic_ptr->mGradPtr));
1169
1170 pip.push_back(new OpCalculateScalarFieldValues(
1171 temperature, common_thermoplastic_ptr->getTempPtr()));
1173 "FLUX", common_thermoplastic_ptr->getHeatFluxPtr()));
1174
1175 common_plastic_ptr->mGradPtr = common_hencky_ptr->matGradPtr;
1176 common_plastic_ptr->mDPtr = common_hencky_ptr->matDPtr;
1177 common_hencky_ptr->matLogCPlastic =
1178 common_plastic_ptr->getPlasticStrainPtr();
1179 common_plastic_ptr->mStrainPtr = common_hencky_ptr->getMatLogC();
1180 common_plastic_ptr->mStressPtr = common_hencky_ptr->getMatHenckyStress();
1181
1183
1184 pip.push_back(new typename H::template OpCalculateEigenVals<DIM, I>(
1185 u, common_hencky_ptr));
1186 pip.push_back(
1187 new typename H::template OpCalculateLogC<DIM, I>(u, common_hencky_ptr));
1188 pip.push_back(new typename H::template OpCalculateLogC_dC<DIM, I>(
1189 u, common_hencky_ptr));
1190
1191 pip.push_back(
1192 new
1193 typename H::template OpCalculateHenckyThermoPlasticStress<DIM, I, 0>(
1194 u, common_thermoplastic_ptr->getTempPtr(), common_hencky_ptr,
1195 common_thermoelastic_ptr->getCoeffExpansionPtr(),
1196 common_thermoelastic_ptr->getRefTempPtr()));
1197 pip.push_back(new typename H::template OpCalculatePiolaStress<DIM, I, 0>(
1198 u, common_hencky_ptr));
1199
1200 pip.push_back(new typename P::template OpCalculatePlasticSurface<DIM, I>(
1201 u, common_plastic_ptr));
1202
1203 pip.push_back(new typename P::template OpCalculatePlasticHardening<DIM, I>(
1204 u, common_plastic_ptr, common_thermoplastic_ptr));
1205
1206 return std::make_tuple(common_plastic_ptr, common_hencky_ptr,
1207 common_thermal_ptr, common_thermoelastic_ptr,
1208 common_thermoplastic_ptr);
1209 }
1210
1211 friend struct TSPrePostProc;
1212};
1213
1216
1217 if (auto ptr = tsPrePostProc.lock()) {
1218 MOFEM_LOG("THERMOPLASTICITY", Sev::inform) << "Run step pre proc";
1219
1220 auto &m_field = ptr->ExRawPtr->mField;
1221 auto simple = m_field.getInterface<Simple>();
1222
1223 ResizeCtx *ctx = nullptr;
1224 CHKERR TSGetApplicationContext(ts, (void **)&ctx);
1225 if (!ctx)
1226 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "ResizeCtx missing");
1227
1228 if (ctx->mesh_changed == PETSC_TRUE) { // need to be set for new meshsets
1229 ptr->ExRawPtr->mechanicalBC(); // if remeshed
1230 ptr->ExRawPtr->thermalBC();
1231 }
1232
1233 // get vector norm
1234 auto get_norm = [&](auto x) {
1235 double nrm;
1236 CHKERR VecNorm(x, NORM_2, &nrm);
1237 return nrm;
1238 };
1239
1240 auto save_range = [](moab::Interface &moab, const std::string name,
1241 const Range r) {
1243 auto out_meshset = get_temp_meshset_ptr(moab);
1244 CHKERR moab.add_entities(*out_meshset, r);
1245 CHKERR moab.write_file(name.c_str(), "VTK", "", out_meshset->get_ptr(),
1246 1);
1248 };
1249
1250 auto dm = simple->getDM();
1251 auto d_vector = createDMVector(dm);
1252 CHKERR DMoFEMMeshToLocalVector(dm, d_vector, INSERT_VALUES,
1253 SCATTER_FORWARD);
1254 CHKERR VecGhostUpdateBegin(d_vector, INSERT_VALUES, SCATTER_FORWARD);
1255 CHKERR VecGhostUpdateEnd(d_vector, INSERT_VALUES, SCATTER_FORWARD);
1256 CHKERR DMoFEMMeshToGlobalVector(dm, d_vector, INSERT_VALUES,
1257 SCATTER_REVERSE);
1258
1259 Tag th_spatial_coords;
1260 std::multimap<double, EntityHandle> el_q_map;
1261 std::vector<EntityHandle> new_connectivity;
1262 Range flipped_els;
1263 bool do_refine = false;
1264
1265 auto check_element_quality = [&]() {
1267
1268 // Get Range of all elements not to be flipped in the mesh
1269 Range virgin_entities;
1270 CHKERR m_field.getInterface<BitRefManager>()->getEntitiesByRefLevel(
1271 virgin_mesh_bit, BitRefLevel().set(), virgin_entities);
1272
1273 // Calculates the element quality
1274 CHKERR ptr->ExRawPtr->getElementQuality(el_q_map, flipped_els,
1275 new_connectivity, do_refine,
1276 th_spatial_coords);
1277
1279 };
1280
1281 auto solve_equil_sub_problem = [&]() {
1283 if (el_q_map.size() == 0) {
1285 }
1286
1287 auto vol_rule = [](int, int, int ao) { return 2 * ao + geom_order; };
1288
1289 auto simple = m_field.getInterface<Simple>();
1290
1292
1293 auto U_ptr = boost::make_shared<MatrixDouble>();
1294 auto EP_ptr = boost::make_shared<MatrixDouble>();
1295 auto TAU_ptr = boost::make_shared<VectorDouble>();
1296 auto T_ptr = boost::make_shared<VectorDouble>();
1297 // auto FLUX_ptr = boost::make_shared<MatrixDouble>();
1298 // auto T_grad_ptr = boost::make_shared<MatrixDouble>();
1299
1300 auto post_proc = [&](auto dm) {
1302
1303 auto post_proc_fe = boost::make_shared<PostProcEle>(m_field);
1304
1306 post_proc_fe->getOpPtrVector(), {H1, L2, HDIV});
1307
1309
1310 // post_proc_fe->getOpPtrVector().push_back(
1311 // new OpCalculateHVecVectorField<3, SPACE_DIM>("FLUX",
1312 // FLUX_ptr));
1313 post_proc_fe->getOpPtrVector().push_back(
1314 new OpCalculateScalarFieldValues("T", T_ptr));
1315 // post_proc_fe->getOpPtrVector().push_back(
1316 // new OpCalculateScalarFieldGradient<SPACE_DIM>("T",
1317 // T_grad_ptr));
1318 post_proc_fe->getOpPtrVector().push_back(
1320 post_proc_fe->getOpPtrVector().push_back(
1321 new OpCalculateScalarFieldValues("TAU", TAU_ptr));
1322 post_proc_fe->getOpPtrVector().push_back(
1324 EP_ptr));
1325 post_proc_fe->getOpPtrVector().push_back(
1326
1327 new OpPPMap(post_proc_fe->getPostProcMesh(),
1328 post_proc_fe->getMapGaussPts(),
1329
1330 {
1331 {"TAU", TAU_ptr},
1332 {"T", T_ptr},
1333 },
1334
1335 {{"U", U_ptr}},
1336
1337 {},
1338
1339 {{"EP", EP_ptr}}
1340
1341 )
1342
1343 );
1344
1345 CHKERR DMoFEMLoopFiniteElements(dm, "dFE", post_proc_fe);
1346 CHKERR post_proc_fe->writeFile("out_equilibrate.h5m");
1347
1349 };
1350
1351 auto solve_equilibrate_solution = [&]() {
1353
1354 auto set_domain_rhs = [&](auto &pip) {
1356
1358 {H1, HDIV});
1359
1360 using B = typename FormsIntegrators<DomainEleOp>::template Assembly<
1361 AT>::template LinearForm<IT>;
1362 using OpInternalForceCauchy =
1363 typename B::template OpGradTimesSymTensor<1, SPACE_DIM,
1364 SPACE_DIM>;
1365 using OpInternalForcePiola =
1366 typename B::template OpGradTimesTensor<1, SPACE_DIM, SPACE_DIM>;
1367
1369
1370 auto [common_plastic_ptr, common_hencky_ptr, common_thermal_ptr,
1371 common_thermoelastic_ptr, common_thermoplastic_ptr] =
1372 ptr->ExRawPtr
1373 ->createCommonThermoPlasticOps<SPACE_DIM, IT, DomainEleOp>(
1374 m_field, "MAT_PLASTIC", "MAT_THERMAL",
1375 "MAT_THERMOELASTIC", "MAT_THERMOPLASTIC", pip, "U", "EP",
1378 Sev::inform);
1379
1380 auto m_D_ptr = common_plastic_ptr->mDPtr;
1381
1382 pip.push_back(new OpCalculateScalarFieldValues(
1383 "T", common_thermoplastic_ptr->getTempPtr()));
1384 pip.push_back(
1385 new
1386 typename P::template OpCalculatePlasticityWithoutRates<SPACE_DIM,
1387 IT>(
1388 "U", common_plastic_ptr, m_D_ptr, common_thermoplastic_ptr));
1389
1390 // Calculate internal forces
1391 if (common_hencky_ptr) {
1392 pip.push_back(new OpInternalForcePiola(
1393 "U", common_hencky_ptr->getMatFirstPiolaStress()));
1394 } else {
1395 pip.push_back(
1396 new OpInternalForceCauchy("U", common_plastic_ptr->mStressPtr));
1397 }
1398
1400 };
1401
1402 auto set_domain_lhs = [&](auto &pip) {
1404
1406 {H1, L2, HDIV});
1407
1408 using namespace HenckyOps;
1409
1410 using B = typename FormsIntegrators<DomainEleOp>::template Assembly<
1411 AT>::template BiLinearForm<IT>;
1412 using OpKPiola =
1413 typename B::template OpGradTensorGrad<1, SPACE_DIM, SPACE_DIM, 1>;
1414 using OpKCauchy =
1415 typename B::template OpGradSymTensorGrad<1, SPACE_DIM, SPACE_DIM,
1416 0>;
1417
1419
1420 auto [common_plastic_ptr, common_hencky_ptr, common_thermal_ptr,
1421 common_thermoelastic_ptr, common_thermoplastic_ptr] =
1422 ptr->ExRawPtr
1423 ->createCommonThermoPlasticOps<SPACE_DIM, IT, DomainEleOp>(
1424 m_field, "MAT_PLASTIC", "MAT_THERMAL",
1425 "MAT_THERMOELASTIC", "MAT_THERMOPLASTIC", pip, "U", "EP",
1428 Sev::inform);
1429
1430 auto m_D_ptr = common_plastic_ptr->mDPtr;
1431
1432 pip.push_back(
1433 new
1434 typename P::template OpCalculatePlasticityWithoutRates<SPACE_DIM,
1435 IT>(
1436 "U", common_plastic_ptr, m_D_ptr, common_thermoplastic_ptr));
1437
1438 if (common_hencky_ptr) {
1440 pip.push_back(
1441 new typename H::template OpHenckyTangent<SPACE_DIM, IT, 0>(
1442 "U", common_hencky_ptr, m_D_ptr));
1443 pip.push_back(
1444 new OpKPiola("U", "U", common_hencky_ptr->getMatTangent()));
1445 // pip.push_back(
1446 // new typename P::template Assembly<AT>::
1447 // template
1448 // OpCalculatePlasticInternalForceLhs_LogStrain_dEP<
1449 // SPACE_DIM, IT>("U", "EP", common_plastic_ptr,
1450 // common_hencky_ptr, m_D_ptr));
1451 } else {
1452 pip.push_back(new OpKCauchy("U", "U", m_D_ptr));
1453 // pip.push_back(
1454 // new typename P::template Assembly<AT>::
1455 // template
1456 // OpCalculatePlasticInternalForceLhs_dEP<SPACE_DIM,
1457 // IT>(
1458 // "U", "EP", common_plastic_ptr, m_D_ptr));
1459 }
1460
1461 // TODO: add scenario for when not using Hencky material
1462 // pip.push_back(new
1463 // HenckyOps::OpCalculateHenckyThermalStressdT<
1464 // SPACE_DIM, IT, AssemblyDomainEleOp>(
1465 // "U", "T", common_hencky_ptr,
1466 // common_thermal_ptr->getCoeffExpansionPtr()));
1467
1469 };
1470
1471 auto create_sub_dm = [&](SmartPetscObj<DM> base_dm) {
1472 auto dm_sub = createDM(m_field.get_comm(), "DMMOFEM");
1473 CHKERR DMMoFEMCreateSubDM(dm_sub, base_dm, "EQUIL_DM");
1474 CHKERR DMMoFEMSetSquareProblem(dm_sub, PETSC_TRUE);
1475 CHKERR DMMoFEMAddElement(dm_sub, simple->getDomainFEName());
1476 for (auto f : {"U", "EP", "TAU", "T"}) {
1479 }
1480 CHKERR DMSetUp(dm_sub);
1481 return dm_sub;
1482 };
1483
1484 auto sub_dm = create_sub_dm(simple->getDM());
1485
1486 auto fe_rhs = boost::make_shared<DomainEle>(m_field);
1487 auto fe_lhs = boost::make_shared<DomainEle>(m_field);
1488
1489 fe_rhs->getRuleHook = vol_rule;
1490 fe_lhs->getRuleHook = vol_rule;
1491 CHKERR set_domain_rhs(fe_rhs->getOpPtrVector());
1492 CHKERR set_domain_lhs(fe_lhs->getOpPtrVector());
1493
1494 auto bc_mng = m_field.getInterface<BcManager>();
1495
1497 "EQUIL_DM", "U");
1498
1499 auto &bc_map = bc_mng->getBcMapByBlockName();
1500 for (auto bc : bc_map)
1501 MOFEM_LOG("PLASTICITY", Sev::verbose) << "Marker " << bc.first;
1502
1503 auto time_scale = boost::make_shared<TimeScale>(
1504 "", false, [](const double) { return 1; });
1505 auto def_time_scale = [time_scale](const double time) {
1506 return (!time_scale->argFileScale) ? time : 1;
1507 };
1508 auto def_file_name = [time_scale](const std::string &&name) {
1509 return (!time_scale->argFileScale) ? name : "";
1510 };
1511 auto time_displacement_scaling = boost::make_shared<TimeScale>(
1512 def_file_name("displacement_bc_scale.txt"), false, def_time_scale);
1513
1514 auto pre_proc_ptr = boost::make_shared<FEMethod>();
1515 auto post_proc_rhs_ptr = boost::make_shared<FEMethod>();
1516 auto post_proc_lhs_ptr = boost::make_shared<FEMethod>();
1517
1518 PetscReal current_time;
1519 TSGetTime(ts, &current_time);
1520 pre_proc_ptr->ts_t = current_time;
1521
1522 // Set BCs by eliminating degrees of freedom
1523 auto get_bc_hook_rhs = [&]() {
1525 ptr->ExRawPtr->mField, pre_proc_ptr,
1526 {time_scale, time_displacement_scaling});
1527 return hook;
1528 };
1529 auto get_bc_hook_lhs = [&]() {
1531 ptr->ExRawPtr->mField, pre_proc_ptr,
1532 {time_scale, time_displacement_scaling});
1533 return hook;
1534 };
1535
1536 pre_proc_ptr->preProcessHook = get_bc_hook_rhs();
1537 pre_proc_ptr->preProcessHook = get_bc_hook_lhs();
1538
1539 auto get_post_proc_hook_rhs = [&]() {
1542 ptr->ExRawPtr->mField, post_proc_rhs_ptr, nullptr,
1543 Sev::verbose)();
1545 ptr->ExRawPtr->mField, post_proc_rhs_ptr, 1.)();
1547 };
1548 auto get_post_proc_hook_lhs = [&]() {
1550 ptr->ExRawPtr->mField, post_proc_lhs_ptr, 1.);
1551 };
1552 post_proc_rhs_ptr->postProcessHook = get_post_proc_hook_rhs;
1553 post_proc_lhs_ptr->postProcessHook = get_post_proc_hook_lhs();
1554
1555 auto snes_ctx_ptr = getDMSnesCtx(sub_dm);
1556 snes_ctx_ptr->getPreProcComputeRhs().push_front(pre_proc_ptr);
1557 snes_ctx_ptr->getPreProcSetOperators().push_front(pre_proc_ptr);
1558 snes_ctx_ptr->getPostProcComputeRhs().push_back(post_proc_rhs_ptr);
1559 snes_ctx_ptr->getPostProcSetOperators().push_back(post_proc_lhs_ptr);
1560
1561 auto null_fe = boost::shared_ptr<FEMethod>();
1562 // CHKERR DMMoFEMKSPSetComputeOperators(
1563 // sub_dm, simple->getDomainFEName(), fe_lhs, null_fe,
1564 // null_fe);
1565 // CHKERR DMMoFEMKSPSetComputeRHS(sub_dm,
1566 // simple->getDomainFEName(),
1567 // fe_rhs, null_fe, null_fe);
1568 CHKERR DMMoFEMSNESSetFunction(sub_dm, simple->getDomainFEName(), fe_rhs,
1569 null_fe, null_fe);
1570 CHKERR DMMoFEMSNESSetJacobian(sub_dm, simple->getDomainFEName(), fe_lhs,
1571 null_fe, null_fe);
1572
1573 // auto ksp = MoFEM::createKSP(m_field.get_comm());
1574 // CHKERR KSPSetDM(ksp, sub_dm);
1575 // CHKERR KSPSetFromOptions(ksp);
1576
1577 auto D = createDMVector(sub_dm);
1578
1579 auto snes = MoFEM::createSNES(m_field.get_comm());
1580 CHKERR SNESSetDM(snes, sub_dm);
1581 CHKERR SNESSetFromOptions(snes);
1582 CHKERR SNESSetUp(snes);
1583
1584 CHKERR DMoFEMMeshToLocalVector(sub_dm, D, INSERT_VALUES,
1585 SCATTER_FORWARD);
1586 CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
1587 CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
1588 // SmartPetscObj<Vec> global_rhs;
1589 // CHKERR DMCreateGlobalVector_MoFEM(
1590 // sub_dm, global_rhs);
1591 // CHKERR KSPSolve(ksp, PETSC_NULLPTR, D);
1592 CHKERR SNESSolve(snes, PETSC_NULLPTR, D);
1593
1594 CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
1595 CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
1596 CHKERR DMoFEMMeshToLocalVector(sub_dm, D, INSERT_VALUES,
1597 SCATTER_REVERSE);
1598
1600 };
1601
1602 CHKERR solve_equilibrate_solution();
1603 CHKERR post_proc(simple->getDM());
1604
1605 MOFEM_LOG("REMESHING", Sev::inform)
1606 << "Equilibrated solution after mapping";
1607
1609 };
1610
1611 if (ctx->mesh_changed == PETSC_FALSE) // protects for rollback
1612 CHKERR check_element_quality(); // improve element quality
1613 ctx->mesh_changed = PETSC_FALSE; // needs reset if true
1614 if (el_q_map.size() > 0 || do_refine) {
1615 // Now you can safely update the context fields
1616 ctx->ptr = ptr;
1617 ctx->el_q_map = el_q_map;
1618 ctx->flipped_els = flipped_els;
1619 ctx->new_connectivity = new_connectivity;
1620 ctx->th_spatial_coords = th_spatial_coords;
1621 ctx->mesh_changed = PETSC_TRUE;
1622
1623 // Then trigger the resize process
1624 // CHKERR TSResize(ts);
1625 }
1626
1627 // Need barriers, some functions in TS solver need are called
1628 // collectively and requite the same state of variables
1629 CHKERR PetscBarrier((PetscObject)ts);
1630
1631 MOFEM_LOG_CHANNEL("SYNC");
1632 MOFEM_TAG_AND_LOG("SYNC", Sev::verbose, "REMESHING") << "PreProc done";
1633 MOFEM_LOG_SEVERITY_SYNC(m_field.get_comm(), Sev::verbose);
1634 }
1635
1637}
1638
1640 if (auto ptr = tsPrePostProc.lock()) {
1641 auto &m_field = ptr->ExRawPtr->mField;
1642 MOFEM_LOG_CHANNEL("SYNC");
1643 MOFEM_TAG_AND_LOG("SYNC", Sev::verbose, "THERMOPLASTICITY")
1644 << "PostProc done";
1645 MOFEM_LOG_SEVERITY_SYNC(m_field.get_comm(), Sev::verbose);
1646 }
1647 return 0;
1648}
1649
1651
1653
1654 CHKERR TSSetPreStep(ts, tsPreProc);
1655 CHKERR TSSetPostStep(ts, tsPostProc);
1656
1658}
1659
1661 MoFEM::Interface &m_field,
1662 boost::ptr_deque<ForcesAndSourcesCore::UserDataOperator> &pipeline,
1663 std::string thermoplastic_block_name,
1664 boost::shared_ptr<ThermoPlasticOps::ThermoPlasticBlockedParameters>
1665 blockedParamsPtr,
1666 boost::shared_ptr<ThermoElasticOps::BlockedThermalParameters>
1667 &blockedThermalParamsPtr,
1668 Sev sev, ScalerFunThreeArgs inelastic_heat_fraction_scaling_func) {
1670
1671 struct OpMatThermoPlasticBlocks : public DomainEleOp {
1672 OpMatThermoPlasticBlocks(
1673 boost::shared_ptr<double> omega_0_ptr,
1674 boost::shared_ptr<double> omega_h_ptr,
1675 boost::shared_ptr<double> inelastic_heat_fraction_ptr,
1676 boost::shared_ptr<double> temp_0_ptr,
1677 boost::shared_ptr<double> heat_conductivity,
1678 boost::shared_ptr<double> heat_capacity,
1679 boost::shared_ptr<double> heat_conductivity_scaling,
1680 boost::shared_ptr<double> heat_capacity_scaling,
1682 MoFEM::Interface &m_field, Sev sev,
1683 std::vector<const CubitMeshSets *> meshset_vec_ptr)
1684 : DomainEleOp(NOSPACE, DomainEleOp::OPSPACE), omega0Ptr(omega_0_ptr),
1685 omegaHPtr(omega_h_ptr),
1686 inelasticHeatFractionPtr(inelastic_heat_fraction_ptr),
1687 temp0Ptr(temp_0_ptr), heatConductivityPtr(heat_conductivity),
1688 heatCapacityPtr(heat_capacity),
1689 heatConductivityScalingPtr(heat_conductivity_scaling),
1690 heatCapacityScalingPtr(heat_capacity_scaling),
1691 inelasticHeatFractionScaling(inelastic_heat_fraction_scaling) {
1693 extractThermoPlasticBlockData(m_field, meshset_vec_ptr, sev),
1694 "Can not get data from block");
1695 }
1696
1697 MoFEMErrorCode doWork(int side, EntityType type,
1700
1701 auto scale_param = [this](auto parameter, double scaling) {
1702 return parameter * scaling;
1703 };
1704
1705 for (auto &b : blockData) {
1706
1707 if (b.blockEnts.find(getFEEntityHandle()) != b.blockEnts.end()) {
1708 *omega0Ptr = b.omega_0;
1709 *omegaHPtr = b.omega_h;
1710 *inelasticHeatFractionPtr = scale_param(
1711 b.inelastic_heat_fraction,
1712 inelasticHeatFractionScaling(
1714 *heatConductivityPtr / (*heatConductivityScalingPtr),
1715 *heatCapacityPtr / (*heatCapacityScalingPtr)));
1716 *temp0Ptr = b.temp_0;
1718 }
1719 }
1720
1721 *omega0Ptr = omega_0;
1722 *omegaHPtr = omega_h;
1723 *inelasticHeatFractionPtr =
1724 scale_param(inelastic_heat_fraction,
1725 inelasticHeatFractionScaling(
1727 *heatConductivityPtr / (*heatConductivityScalingPtr),
1728 *heatCapacityPtr / (*heatCapacityScalingPtr)));
1729 *temp0Ptr = temp_0;
1730
1732 }
1733
1734 private:
1735 ScalerFunThreeArgs inelasticHeatFractionScaling;
1736 boost::shared_ptr<double> heatConductivityPtr;
1737 boost::shared_ptr<double> heatCapacityPtr;
1738 boost::shared_ptr<double> heatConductivityScalingPtr;
1739 boost::shared_ptr<double> heatCapacityScalingPtr;
1740 struct BlockData {
1741 double omega_0;
1742 double omega_h;
1744 double temp_0;
1745 Range blockEnts;
1746 };
1747
1748 std::vector<BlockData> blockData;
1749
1750 MoFEMErrorCode extractThermoPlasticBlockData(
1751 MoFEM::Interface &m_field,
1752 std::vector<const CubitMeshSets *> meshset_vec_ptr, Sev sev) {
1754
1755 for (auto m : meshset_vec_ptr) {
1756 MOFEM_TAG_AND_LOG("WORLD", sev, "Mat ThermoPlastic Block") << *m;
1757 std::vector<double> block_data;
1758 CHKERR m->getAttributes(block_data);
1759 if (block_data.size() < 3) {
1760 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1761 "Expected that block has four attributes");
1762 }
1763 auto get_block_ents = [&]() {
1764 Range ents;
1765 CHKERR
1766 m_field.get_moab().get_entities_by_handle(m->meshset, ents, true);
1767 return ents;
1768 };
1769
1770 MOFEM_TAG_AND_LOG("WORLD", sev, "Mat ThermoPlastic Block")
1771 << m->getName() << ": omega_0 = " << block_data[0]
1772 << " omega_h = " << block_data[1]
1773 << " inelastic_heat_fraction = " << block_data[2] << " temp_0 "
1774 << block_data[3];
1775
1776 blockData.push_back({block_data[0], block_data[1], block_data[2],
1777 block_data[3], get_block_ents()});
1778 }
1779 MOFEM_LOG_CHANNEL("WORLD");
1781 }
1782
1783 boost::shared_ptr<double> omega0Ptr;
1784 boost::shared_ptr<double> omegaHPtr;
1785 boost::shared_ptr<double> inelasticHeatFractionPtr;
1786 boost::shared_ptr<double> temp0Ptr;
1787 };
1788
1789 pipeline.push_back(new OpMatThermoPlasticBlocks(
1790 blockedParamsPtr->getOmega0Ptr(), blockedParamsPtr->getOmegaHPtr(),
1791 blockedParamsPtr->getInelasticHeatFractionPtr(),
1792 blockedParamsPtr->getTemp0Ptr(),
1793 blockedThermalParamsPtr->getHeatConductivityPtr(),
1794 blockedThermalParamsPtr->getHeatCapacityPtr(),
1795 blockedThermalParamsPtr->getHeatConductivityScalingPtr(),
1796 blockedThermalParamsPtr->getHeatCapacityScalingPtr(),
1797 inelastic_heat_fraction_scaling_func, m_field, sev,
1798
1799 // Get blockset using regular expression
1800 m_field.getInterface<MeshsetsManager>()->getCubitMeshsetPtr(std::regex(
1801
1802 (boost::format("%s(.*)") % thermoplastic_block_name).str()
1803
1804 ))
1805
1806 ));
1807
1809}
1810
1811//! [Get element quality]
1813Example::getElementQuality(std::multimap<double, EntityHandle> &el_q_map,
1814 Range &flipped_els,
1815 std::vector<EntityHandle> &new_connectivity,
1816 bool &do_refine, Tag &th_spatial_coords) {
1818
1819 Range verts;
1820 CHKERR mField.get_moab().get_entities_by_type(0, MBVERTEX, verts);
1821 std::vector<double> coords(verts.size() * 3);
1822 CHKERR mField.get_moab().get_coords(verts, coords.data());
1823 auto t_x = getFTensor1FromPtr<3>(coords.data());
1824
1825 auto save_tag = [&](boost::shared_ptr<FieldEntity> ent_ptr) {
1827 FTENSOR_INDEX(3, i)
1828 auto field_data = ent_ptr->getEntFieldData();
1830 if (SPACE_DIM == 2) {
1831 t_u = {field_data[0], field_data[1], 0.0};
1832 } else {
1833 t_u = {field_data[0], field_data[1], field_data[2]};
1834 }
1835
1836 t_x(i) += t_u(i);
1837 ++t_x;
1839 };
1840
1841 mField.getInterface<FieldBlas>()->fieldLambdaOnEntities(save_tag, "U",
1842 &verts);
1843 double def_coord[3] = {0.0, 0.0, 0.0};
1844 CHKERR mField.get_moab().tag_get_handle(
1845 "SpatialCoord", 3, MB_TYPE_DOUBLE, th_spatial_coords,
1846 MB_TAG_DENSE | MB_TAG_CREAT, def_coord);
1847 CHKERR mField.get_moab().tag_set_data(th_spatial_coords, verts,
1848 coords.data());
1849
1850 // get a map which has the element quality for each tag
1851
1852 Range all_els;
1853 CHKERR mField.get_moab().get_entities_by_dimension(0, SPACE_DIM, all_els,
1854 true);
1855 CHKERR mField.getInterface<BitRefManager>()->filterEntitiesByRefLevel(
1856 virgin_mesh_bit, BitRefLevel().set(), all_els);
1857
1858 std::multimap<double, EntityHandle> candidate_el_q_map;
1859 double spatial_coords[9], material_coords[9];
1860 const EntityHandle *conn;
1861 int num_nodes;
1862 Range::iterator nit = all_els.begin();
1863 for (int gg = 0; nit != all_els.end(); nit++, gg++) {
1864 CHKERR mField.get_moab().get_connectivity(*nit, conn, num_nodes, true);
1865
1866 CHKERR mField.get_moab().get_coords(conn, num_nodes, material_coords);
1867 CHKERR mField.get_moab().tag_get_data(th_spatial_coords, conn, num_nodes,
1868 spatial_coords);
1869
1870 double q = Tools::areaLengthQuality(spatial_coords);
1871 if (!std::isnormal(q))
1872 SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
1873 "Calculated quality of element is not "
1874 "as expected: %f",
1875 q);
1876
1877 if (q < qual_tol && q > 0.)
1878 candidate_el_q_map.insert(std::pair<double, EntityHandle>(q, *nit));
1879 }
1880
1881 double min_q = 1;
1882 CHKERR mField.getInterface<Tools>()->minElQuality<SPACE_DIM>(
1883 all_els, min_q, th_spatial_coords);
1884 MOFEM_LOG("REMESHING", Sev::inform)
1885 << "Old minimum element quality: " << min_q;
1886 // Get the first element using begin()
1887 auto pair = candidate_el_q_map.begin();
1888 MOFEM_LOG("REMESHING", Sev::inform)
1889 << "New minimum element quality: " << pair->first;
1890
1891 for (auto pair = candidate_el_q_map.begin(); pair != candidate_el_q_map.end();
1892 ++pair) {
1893 double quality = pair->first;
1894 Range element;
1895 element.insert(pair->second);
1896 if (!flipped_els.contains(element)) {
1897 // Get edges of element
1898 Range edges;
1899 CHKERR mField.get_moab().get_adjacencies(element, 1, false, edges);
1900
1901 // Get the longest edge
1902 EntityHandle longest_edge;
1903 double longest_edge_length = 0;
1904 std::vector<std::pair<double, EntityHandle>> edge_lengths;
1905 edge_lengths.reserve(edges.size());
1906 for (auto edge : edges) {
1907 edge_lengths.emplace_back(
1908 mField.getInterface<Tools>()->getEdgeLength(edge), edge);
1909 }
1910 if (!edge_lengths.empty()) {
1911 const auto it = std::max_element(
1912 edge_lengths.begin(), edge_lengths.end(),
1913 [](const auto &a, const auto &b) { return a.first < b.first; });
1914 longest_edge_length = it->first;
1915 longest_edge = it->second;
1916 } else {
1917 SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
1918 "Unable to calculate edge lengths to find longest edge.");
1919 }
1920
1921 MOFEM_LOG("REMESHING", Sev::verbose)
1922 << "Edge flip longest edge length: " << longest_edge_length
1923 << " for edge: " << longest_edge;
1924
1925 auto get_skin = [&]() {
1926 Range body_ents;
1927 CHKERR mField.get_moab().get_entities_by_dimension(0, SPACE_DIM,
1928 body_ents);
1929 Skinner skin(&mField.get_moab());
1930 Range skin_ents;
1931 CHKERR skin.find_skin(0, body_ents, false, skin_ents);
1932 return skin_ents;
1933 };
1934
1935 auto filter_true_skin = [&](auto skin) {
1936 Range boundary_ents;
1937 ParallelComm *pcomm =
1938 ParallelComm::get_pcomm(&mField.get_moab(), MYPCOMM_INDEX);
1939 CHKERR pcomm->filter_pstatus(skin, PSTATUS_SHARED | PSTATUS_MULTISHARED,
1940 PSTATUS_NOT, -1, &boundary_ents);
1941 return boundary_ents;
1942 };
1943
1944 Range boundary_ents = get_skin();
1945
1946 MOFEM_LOG("REMESHING", Sev::verbose)
1947 << "Boundary entities: " << boundary_ents;
1948
1949 // Get neighbouring element with the longest edge
1950 Range flip_candidate_els;
1951 CHKERR mField.get_moab().get_adjacencies(&longest_edge, 1, SPACE_DIM,
1952 false, flip_candidate_els);
1953 CHKERR mField.getInterface<BitRefManager>()->filterEntitiesByRefLevel(
1954 virgin_mesh_bit, BitRefLevel().set(), flip_candidate_els);
1955
1956 Range neighbouring_el = subtract(flip_candidate_els, element);
1957 CHKERR mField.getInterface<BitRefManager>()->filterEntitiesByRefLevel(
1958 virgin_mesh_bit, BitRefLevel().set(), neighbouring_el);
1959
1960 if (boundary_ents.contains(Range(longest_edge, longest_edge))) {
1961 continue;
1962 }
1963
1964 if (flipped_els.contains(neighbouring_el))
1965 continue; // Already flipped
1966
1967#ifndef NDEBUG
1968 if (neighbouring_el.size() != 1) {
1969 SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
1970 "Should be 1 neighbouring element to bad element for edge "
1971 "flip. Instead, there are %d",
1972 neighbouring_el.size());
1973 }
1974#endif
1975
1976 MOFEM_LOG("REMESHING", Sev::verbose)
1977 << "flip_candidate_els: " << flip_candidate_els;
1978 MOFEM_LOG("REMESHING", Sev::verbose)
1979 << "Neighbouring element: " << neighbouring_el;
1980
1981 // Check the quality of the neighbouring element
1982 std::vector<EntityHandle> neighbouring_nodes;
1983 CHKERR mField.get_moab().get_connectivity(&neighbouring_el.front(), 1,
1984 neighbouring_nodes, true);
1985
1986 std::vector<EntityHandle> element_nodes;
1987 CHKERR mField.get_moab().get_connectivity(&element.front(), 1,
1988 element_nodes, true);
1989
1990 CHKERR mField.get_moab().tag_get_data(
1991 th_spatial_coords, &neighbouring_nodes.front(), 3, spatial_coords);
1992
1993 double neighbour_qual = Tools::areaLengthQuality(spatial_coords);
1994 if (!std::isnormal(neighbour_qual))
1995 SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
1996 "Calculated quality of neighbouring element is not as "
1997 "expected: %f",
1998 neighbour_qual);
1999
2000 // Get the nodes of flip_candidate_els as well as the nodes of
2001 // longest_edge
2002
2003 MOFEM_LOG("REMESHING", Sev::verbose)
2004 << "Element nodes before swap: "
2005 << get_string_from_vector(element_nodes);
2006 MOFEM_LOG("REMESHING", Sev::verbose)
2007 << "Neighbouring nodes before swap: "
2008 << get_string_from_vector(neighbouring_nodes);
2009
2010 CHKERR save_range(mField.get_moab(), "bad_element.vtk", element);
2011 CHKERR save_range(mField.get_moab(), "bad_element_neighbour.vtk",
2012 neighbouring_el);
2013
2014 // Get new canonical ordering of new nodes and new neighbouring
2015 // nodes
2016 std::vector<EntityHandle> reversed_neighbouring_nodes =
2017 neighbouring_nodes;
2018 std::reverse(reversed_neighbouring_nodes.begin(),
2019 reversed_neighbouring_nodes.end());
2020
2021 int num_matches = 0;
2022 std::vector<bool> mismatch_mask(element_nodes.size());
2023 int loop_counter = 0; // To prevent infinite loop
2024 while (num_matches != 2) {
2025 // Permute first element to the end
2026 std::rotate(reversed_neighbouring_nodes.begin(),
2027 reversed_neighbouring_nodes.begin() + 1,
2028 reversed_neighbouring_nodes.end());
2029 // Create a boolean mask
2030 std::transform(element_nodes.begin(), element_nodes.end(),
2031 reversed_neighbouring_nodes.begin(),
2032 mismatch_mask.begin(), std::equal_to<EntityHandle>());
2033 // Check if common edge is found
2034 num_matches =
2035 std::count(mismatch_mask.begin(), mismatch_mask.end(), true);
2036
2037 ++loop_counter;
2038 if (loop_counter > 3) {
2039 SETERRQ(PETSC_COMM_SELF, MOFEM_STD_EXCEPTION_THROW,
2040 "Not found matching nodes for edge flipping");
2041 }
2042 }
2043
2044 // Get matching nodes
2045 std::vector<EntityHandle> matched_elements(element_nodes.size());
2046 std::transform(element_nodes.begin(), element_nodes.end(),
2047 mismatch_mask.begin(), matched_elements.begin(),
2048 [](EntityHandle el, bool match) {
2049 return match ? el : -1; // Or some other "null" value
2050 });
2051
2052 // Remove zero (or "null") elements
2053 matched_elements.erase(
2054 std::remove(matched_elements.begin(), matched_elements.end(), -1),
2055 matched_elements.end());
2056
2057 // Get mismatching nodes
2058 std::vector<EntityHandle> mismatched_elements(element_nodes.size()),
2059 neighbouring_mismatched_elements(neighbouring_nodes.size());
2060 std::transform(element_nodes.begin(), element_nodes.end(),
2061 mismatch_mask.begin(), mismatched_elements.begin(),
2062 [](EntityHandle el, bool match) {
2063 return match ? -1 : el; // Or some other "null" value
2064 });
2065 std::transform(reversed_neighbouring_nodes.begin(),
2066 reversed_neighbouring_nodes.end(), mismatch_mask.begin(),
2067 neighbouring_mismatched_elements.begin(),
2068 [](EntityHandle el, bool match) {
2069 return match ? -1 : el; // Or some other "null" value
2070 });
2071
2072 // Remove zero (or "null") elements
2073 mismatched_elements.erase(std::remove(mismatched_elements.begin(),
2074 mismatched_elements.end(), -1),
2075 mismatched_elements.end());
2076 neighbouring_mismatched_elements.erase(
2077 std::remove(neighbouring_mismatched_elements.begin(),
2078 neighbouring_mismatched_elements.end(), -1),
2079 neighbouring_mismatched_elements.end());
2080
2081 mismatched_elements.insert(mismatched_elements.end(),
2082 neighbouring_mismatched_elements.begin(),
2083 neighbouring_mismatched_elements.end());
2084
2085 MOFEM_LOG("REMESHING", Sev::verbose)
2086 << "Reversed neighbouring nodes: "
2087 << get_string_from_vector(reversed_neighbouring_nodes);
2088
2089 MOFEM_LOG("REMESHING", Sev::verbose)
2090 << "mismatch mask: " << get_string_from_vector(mismatch_mask);
2091
2092 MOFEM_LOG("REMESHING", Sev::verbose)
2093 << "Old nodes are: " << get_string_from_vector(matched_elements);
2094
2095 MOFEM_LOG("REMESHING", Sev::verbose)
2096 << "New nodes are: " << get_string_from_vector(mismatched_elements);
2097
2098 auto replace_correct_nodes = [](std::vector<EntityHandle> &ABC,
2099 std::vector<EntityHandle> &DBA,
2100 const std::vector<EntityHandle> &AB,
2101 const std::vector<EntityHandle> &CD) {
2103 std::vector<std::vector<EntityHandle>> results;
2104 // Assume AB.size() == 2, CD.size() == 2 for tris
2105 for (int i = 0; i < 2; ++i) { // i: 0 for A, 1 for B
2106 for (int j = 0; j < 2; ++j) { // j: 0 for C, 1 for D
2107 // Only try to replace if CD[j] is not already in ABC
2108 if (std::find(ABC.begin(), ABC.end(), CD[j]) == ABC.end()) {
2109 std::vector<EntityHandle> tmp = ABC;
2110 // Find AB[i] in ABC and replace with CD[j]
2111 auto it = std::find(tmp.begin(), tmp.end(), AB[i]);
2112 if (it != tmp.end()) {
2113 *it = CD[j];
2114 results.push_back(tmp);
2115 }
2116 }
2117 }
2118 }
2119
2120 if (results.size() != 2) {
2121 SETERRQ(PETSC_COMM_SELF, MOFEM_STD_EXCEPTION_THROW,
2122 "Failed to find two valid vertex replacements for edge "
2123 "flip");
2124 }
2125
2126 ABC = results[0];
2127 DBA = results[1];
2128
2130 };
2131
2132 CHKERR replace_correct_nodes(element_nodes, neighbouring_nodes,
2133 matched_elements, mismatched_elements);
2134
2135 MOFEM_LOG("REMESHING", Sev::verbose)
2136 << "Element nodes after swap: "
2137 << get_string_from_vector(element_nodes);
2138 MOFEM_LOG("REMESHING", Sev::verbose)
2139 << "Neighbouring nodes after swap: "
2140 << get_string_from_vector(neighbouring_nodes);
2141
2142 // Calculate the quality of the new elements
2143 CHKERR mField.get_moab().tag_get_data(
2144 th_spatial_coords, &element_nodes.front(), 3, spatial_coords);
2145
2146 double new_qual = Tools::areaLengthQuality(spatial_coords);
2147 if (new_qual < 0.0 || !std::isfinite(new_qual))
2148 SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
2149 "Calculated quality of new element is not as expected: %f",
2150 new_qual);
2151
2152#ifndef NDEBUG
2153 auto check_normal_direction = [&](double qual_val) {
2155 FTensor::Index<'i', 3> i;
2156 auto t_correct_normal = FTensor::Tensor1<double, 3>(0.0, 0.0, 1.0);
2157 auto [new_area, t_new_normal] = Tools::triAreaAndNormal(spatial_coords);
2158 auto t_diff = FTensor::Tensor1<double, 3>();
2159 t_diff(i) = t_new_normal(i) - t_correct_normal(i);
2160 if (qual_val > 1e-6 && t_diff(i) * t_diff(i) > 1e-6) {
2161 SETERRQ(PETSC_COMM_SELF, MOFEM_STD_EXCEPTION_THROW,
2162 "Direction of element to be created is wrong orientation");
2163 }
2165 };
2166
2167 CHKERR check_normal_direction(new_qual);
2168#endif
2169
2170 CHKERR mField.get_moab().tag_get_data(
2171 th_spatial_coords, &neighbouring_nodes.front(), 3, spatial_coords);
2172
2173 double new_neighbour_qual = Tools::areaLengthQuality(spatial_coords);
2174 if (new_neighbour_qual < 0.0 || !std::isfinite(new_neighbour_qual))
2175 SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
2176 "Calculated quality of new neighbouring element is not "
2177 "as expected: %f",
2178 new_neighbour_qual);
2179
2180#ifndef NDEBUG
2181 CHKERR check_normal_direction(new_neighbour_qual);
2182#endif
2183
2184 // If the minimum element quality has improved, do the flip
2185 if (std::min(new_qual, new_neighbour_qual) >
2186 (1. + qual_thresh) * std::min(quality, neighbour_qual)) {
2187 MOFEM_LOG("REMESHING", Sev::inform)
2188 << "Element quality improved from " << quality << " and "
2189 << neighbour_qual << " to " << new_qual << " and "
2190 << new_neighbour_qual << " for elements" << element << " and "
2191 << neighbouring_el;
2192
2193 // then push to creation "pipeline".
2194 flipped_els.merge(flip_candidate_els);
2195 el_q_map.insert(
2196 std::pair<double, EntityHandle>(pair->first, pair->second));
2197 new_connectivity.insert(new_connectivity.end(), element_nodes.begin(),
2198 element_nodes.end());
2199 new_connectivity.insert(new_connectivity.end(),
2200 neighbouring_nodes.begin(),
2201 neighbouring_nodes.end());
2202 }
2203 }
2204 }
2205
2206 if (el_q_map.size() > 0) {
2207 MOFEM_LOG("REMESHING", Sev::verbose) << "Flipped elements: " << flipped_els;
2208 MOFEM_LOG("REMESHING", Sev::verbose)
2209 << "New connectivity: " << get_string_from_vector(new_connectivity);
2210 }
2211
2212 Range edges;
2213 CHKERR mField.getInterface<BitRefManager>()->getEntitiesByDimAndRefLevel(
2214 virgin_mesh_bit, BitRefLevel().set(), SPACE_DIM - 1, edges);
2215 CHKERR mField.get_moab().tag_get_handle(
2216 "SpatialCoord", 3, MB_TYPE_DOUBLE, th_spatial_coords,
2217 MB_TAG_DENSE | MB_TAG_CREAT, def_coord);
2218
2219 Range prev_ref_ents;
2220 CHKERR mField.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
2221 BitRefLevel().set(REFINED_EDGES_BIT), BitRefLevel().set(), MBEDGE,
2222 prev_ref_ents);
2223
2224 for (auto e : edges) {
2225 const EntityHandle *conn;
2226 int num_nodes;
2227 CHKERR mField.get_moab().get_connectivity(e, conn, num_nodes, true);
2228 std::array<double, 6> ref_coords, spatial_coords;
2229 CHKERR mField.get_moab().get_coords(conn, num_nodes, ref_coords.data());
2230 CHKERR mField.get_moab().tag_get_data(th_spatial_coords, conn, num_nodes,
2231 spatial_coords.data());
2232 auto get_length = [](auto &a) {
2234 FTensor::Tensor1<double, 3> p0{a[0], a[1], a[2]};
2235 FTensor::Tensor1<double, 3> p1{a[3], a[4], a[5]};
2236 p1(i) = p1(i) - p0(i);
2237 return p1.l2();
2238 };
2239 auto ref_edge_length = get_length(ref_coords);
2240 auto spatial_edge_length = get_length(spatial_coords);
2241 auto change = spatial_edge_length / ref_edge_length;
2242 if ((change >= 1. + edge_growth_thresh) && (num_refinement_levels > 0) &&
2243 !prev_ref_ents.contains(Range(e, e))) {
2244 do_refine = true;
2245 }
2246 }
2247
2249};
2250//! [Get element quality]
2251
2252//! [Edge flips]
2254 BitRefLevel child_bit) {
2256
2257 moab::Interface &moab = mField.get_moab();
2258
2259 auto make_edge_flip = [&](auto edge, auto adj_faces, Range &new_tris) {
2261
2262 auto get_conn = [&](EntityHandle e, EntityHandle *conn_cpy) {
2264 const EntityHandle *conn;
2265 int num_nodes;
2266 CHKERR moab.get_connectivity(e, conn, num_nodes, true);
2267 std::copy(conn, conn + num_nodes, conn_cpy);
2269 };
2270
2271 auto get_tri_normals = [&](auto &conn) {
2272 std::array<double, 18> coords;
2273 CHKERR moab.get_coords(conn.data(), 6, coords.data());
2274 std::array<FTensor::Tensor1<double, 3>, 2> tri_normals;
2275 for (int t = 0; t != 2; ++t) {
2276 CHKERR Tools::getTriNormal(&coords[9 * t], &tri_normals[t](0));
2277 }
2278 return tri_normals;
2279 };
2280
2281 auto test_flip = [&](auto &&t_normals) {
2282 FTENSOR_INDEX(3, i);
2283 if (t_normals[0](i) * t_normals[1](i) <
2284 std::numeric_limits<float>::epsilon())
2285 return false;
2286 return true;
2287 };
2288
2289 std::array<EntityHandle, 6> adj_conn;
2290 CHKERR get_conn(adj_faces[0], &adj_conn[0]);
2291 CHKERR get_conn(adj_faces[1], &adj_conn[3]);
2292 std::array<EntityHandle, 2> edge_conn;
2293 CHKERR get_conn(edge, edge_conn.data());
2294 std::array<EntityHandle, 2> new_edge_conn;
2295
2296 int j = 1;
2297 for (int i = 0; i != 6; ++i) {
2298 if (adj_conn[i] != edge_conn[0] && adj_conn[i] != edge_conn[1]) {
2299 new_edge_conn[j] = adj_conn[i];
2300 --j;
2301 }
2302 }
2303
2304 auto &new_conn = adj_conn; //< just alias this
2305 for (int t = 0; t != 2; ++t) {
2306 for (int i = 0; i != 3; ++i) {
2307 if (
2308
2309 (adj_conn[3 * t + i % 3] == edge_conn[0] &&
2310 adj_conn[3 * t + (i + 1) % 3] == edge_conn[1])
2311
2312 ||
2313
2314 (adj_conn[3 * t + i % 3] == edge_conn[1] &&
2315 adj_conn[3 * t + (i + 1) % 3] == edge_conn[0])
2316
2317 ) {
2318 new_conn[3 * t + (i + 1) % 3] = new_edge_conn[t];
2319 break;
2320 }
2321 }
2322 }
2323
2324 if (test_flip(get_tri_normals(new_conn))) {
2325 for (int t = 0; t != 2; ++t) {
2326 Range rtri;
2327 CHKERR moab.get_adjacencies(&new_conn[3 * t], SPACE_DIM + 1, SPACE_DIM,
2328 false, rtri);
2329 if (!rtri.size()) {
2330 EntityHandle tri;
2331 CHKERR moab.create_element(MBTRI, &new_conn[3 * t], SPACE_DIM + 1,
2332 tri);
2333 new_tris.insert(tri);
2334 } else {
2335#ifndef NDEBUG
2336 if (rtri.size() != 1) {
2337 MOFEM_LOG("SELF", Sev::error)
2338 << "Multiple tries created during edge flip for edge " << edge
2339 << " adjacent faces " << std::endl
2340 << rtri;
2341 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
2342 "Multiple tries created during edge flip");
2343 }
2344#endif // NDEBUG
2345 new_tris.merge(rtri);
2346 }
2347 }
2348
2349 Range new_edges;
2350 CHKERR moab.get_adjacencies(new_tris, SPACE_DIM - 1, true, new_edges,
2351 moab::Interface::UNION);
2352 } else {
2353
2354 MOFEM_LOG_CHANNEL("SELF");
2355 MOFEM_LOG("SELF", Sev::warning) << "Edge flip rejected for edge " << edge
2356 << " adjacent faces " << adj_faces;
2357 }
2358
2360 };
2361
2362 Range tris;
2363 CHKERR moab.get_entities_by_dimension(0, SPACE_DIM, tris);
2364 CHKERR mField.getInterface<BitRefManager>()->filterEntitiesByRefLevel(
2365 parent_bit, BitRefLevel().set(), tris);
2366 Skinner skin(&moab);
2367 Range skin_edges;
2368 CHKERR skin.find_skin(0, tris, false, skin_edges);
2369
2370 Range edges;
2371 CHKERR moab.get_entities_by_dimension(0, SPACE_DIM - 1, edges);
2372 edges = subtract(edges, skin_edges);
2373 CHKERR mField.getInterface<BitRefManager>()->filterEntitiesByRefLevel(
2374 parent_bit, BitRefLevel().set(), edges);
2375
2376 Range new_tris, flipped_tris, forbidden_tris;
2377 int flip_count = 0;
2378 for (auto edge : edges) {
2379 Range adjacent_tris;
2380 CHKERR moab.get_adjacencies(&edge, 1, SPACE_DIM, true, adjacent_tris);
2381
2382 adjacent_tris = intersect(adjacent_tris, tris);
2383 adjacent_tris = subtract(adjacent_tris, forbidden_tris);
2384 if (adjacent_tris.size() == 2) {
2385
2386#ifndef NDEBUG
2387 int side_number0, sense0, offset0;
2388 CHKERR mField.get_moab().side_number(adjacent_tris[0], edge, side_number0,
2389 sense0, offset0);
2390 int side_number1, sense1, offset1;
2391 CHKERR mField.get_moab().side_number(adjacent_tris[1], edge, side_number1,
2392 sense1, offset1);
2393 if (sense0 * sense1 > 0)
2394 SETERRQ(
2395 PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
2396 "Cannot flip edge with same orientation in both adjacent faces");
2397#endif // NDEBUG
2398
2399 Range new_flipped_tris;
2400 CHKERR make_edge_flip(edge, adjacent_tris, new_flipped_tris);
2401 if (new_flipped_tris.size()) {
2402 flipped_tris.merge(adjacent_tris);
2403 forbidden_tris.merge(adjacent_tris);
2404 new_tris.merge(new_flipped_tris);
2405
2406#ifndef NDEBUG
2407 CHKERR save_range(moab,
2408 "flipped_tris_" + std::to_string(flip_count) + ".vtk",
2409 adjacent_tris);
2411 moab, "new_flipped_tris_" + std::to_string(flip_count) + ".vtk",
2412 new_flipped_tris);
2413
2414#endif // NDEBUG
2415
2416 ++flip_count;
2417 }
2418 }
2419 }
2420
2421 Range all_tris;
2422 CHKERR moab.get_entities_by_dimension(0, SPACE_DIM, all_tris);
2423 Range not_flipped_tris = subtract(all_tris, flipped_tris);
2424
2425 MOFEM_LOG("SELF", Sev::noisy)
2426 << "Flipped " << flip_count << " edges with two adjacent faces.";
2427 CHKERR mField.getInterface<BitRefManager>()->setBitRefLevel(not_flipped_tris,
2428 child_bit);
2429 CHKERR mField.getInterface<BitRefManager>()->setBitRefLevel(new_tris,
2430 child_bit);
2431 CHKERR mField.getInterface<BitRefManager>()->writeBitLevel(
2432 child_bit, BitRefLevel().set(), "edge_flips_before_refinement.vtk", "VTK",
2433 "");
2434
2436}
2437//! [Edge flips]
2438
2439//! [Do Edge Flips]
2441Example::doEdgeFlips(std::multimap<double, EntityHandle> &el_q_map,
2442 Range &flipped_els, Tag &th_spatial_coords,
2443 std::vector<EntityHandle> &new_connectivity) {
2445
2446 ReadUtilIface *read_util;
2447 CHKERR mField.get_moab().query_interface(read_util);
2448
2449 const int num_ele = el_q_map.size() * 2; // each flip creates 2 elements
2450 int num_nod_per_ele;
2451 EntityType ent_type;
2452
2453 if (SPACE_DIM == 2) {
2454 num_nod_per_ele = 3;
2455 ent_type = MBTRI;
2456 } else {
2457 num_nod_per_ele = 4;
2458 ent_type = MBTET;
2459 }
2460
2461 Range new_elements;
2462 auto new_conn = new_connectivity.begin();
2463 for (auto e = 0; e != num_ele; ++e) {
2464 EntityHandle conn[num_nod_per_ele];
2465 for (int n = 0; n < num_nod_per_ele; ++n) {
2466 conn[n] = *new_conn;
2467 ++new_conn;
2468 }
2469 EntityHandle new_ele;
2470 Range adj_ele;
2471 CHKERR mField.get_moab().get_adjacencies(conn, num_nod_per_ele, SPACE_DIM,
2472 false, adj_ele);
2473 if (adj_ele.size()) {
2474 if (adj_ele.size() != 1) {
2475 SETERRQ(PETSC_COMM_SELF, MOFEM_STD_EXCEPTION_THROW,
2476 "Element duplication");
2477 } else {
2478 new_ele = adj_ele.front();
2479 }
2480 } else {
2481 CHKERR mField.get_moab().create_element(ent_type, conn, num_nod_per_ele,
2482 new_ele);
2483 }
2484 new_elements.insert(new_ele);
2485 }
2486
2487 MOFEM_LOG("REMESHING", Sev::verbose)
2488 << "New elements from edge flipping: " << new_elements;
2489
2490 auto reset_flip_bit = [](EntityHandle ent, BitRefLevel &bit) {
2491 bit.set(STORAGE_BIT, true);
2492 bit.set(FLIPPED_BIT, false);
2493 };
2494 CHKERR mField.getInterface<BitRefManager>()->lambdaBitRefLevel(
2495 reset_flip_bit);
2496
2497 auto get_adj = [&](auto ents) {
2498 Range adj;
2499 for (auto d = 0; d != SPACE_DIM; ++d) {
2501 mField.get_moab().get_adjacencies(ents, d, true, adj,
2502 moab::Interface::UNION),
2503 "Getting adjacencies of dimension " + std::to_string(d) + " failed");
2504 }
2505 return adj;
2506 };
2507
2508 Range non_flipped_range;
2509 CHKERR mField.getInterface<BitRefManager>()->getEntitiesByDimAndRefLevel(
2510 virgin_mesh_bit, BitRefLevel().set(), SPACE_DIM, non_flipped_range);
2511
2512 non_flipped_range = subtract(non_flipped_range, flipped_els);
2513 auto flip_bit_ents = new_elements;
2514 flip_bit_ents.merge(non_flipped_range);
2515 auto adj = get_adj(new_elements);
2516 // flip_bit_ents.merge(get_adj(new_elements));
2517
2518 CHKERR mField.getInterface<BitRefManager>()->setBitRefLevel(
2519 flip_bit_ents, flipped_bit, false);
2520
2521 CHKERR mField.getInterface<BitRefManager>()->writeBitLevelByDim(
2522 BitRefLevel().set(FLIPPED_BIT), BitRefLevel().set(), 2,
2523 "new_elements_after_edge_flips.vtk", "VTK", "");
2524
2526};
2527//! [Do Edge Flips]
2528
2529//! [Refine edges]
2530MoFEMErrorCode Example::doEdgeSplits(bool &refined, bool add_ents) {
2532
2533 Tag th_spatial_coords;
2534 double def_coord[3] = {0.0, 0.0, 0.0};
2535
2536 auto refined_mesh = [&](auto level) {
2538 auto bit = BitRefLevel().set(FLIPPED_BIT + level);
2539 Range edges;
2540 CHKERR mField.getInterface<BitRefManager>()->getEntitiesByDimAndRefLevel(
2541 bit, BitRefLevel().set(), SPACE_DIM - 1, edges);
2542 CHKERR mField.get_moab().tag_get_handle(
2543 "SpatialCoord", 3, MB_TYPE_DOUBLE, th_spatial_coords,
2544 MB_TAG_DENSE | MB_TAG_CREAT, def_coord);
2545
2546 Range refine_edges;
2547 if (add_ents)
2548 for (auto e : edges) {
2549 const EntityHandle *conn;
2550 int num_nodes;
2551 CHKERR mField.get_moab().get_connectivity(e, conn, num_nodes, true);
2552 std::array<double, 6> ref_coords, spatial_coords;
2553 CHKERR mField.get_moab().get_coords(conn, num_nodes, ref_coords.data());
2554 CHKERR mField.get_moab().tag_get_data(th_spatial_coords, conn,
2555 num_nodes, spatial_coords.data());
2556 auto get_length = [](auto &a) {
2558 FTensor::Tensor1<double, 3> p0{a[0], a[1], a[2]};
2559 FTensor::Tensor1<double, 3> p1{a[3], a[4], a[5]};
2560 p1(i) = p1(i) - p0(i);
2561 return p1.l2();
2562 };
2563 auto ref_edge_length = get_length(ref_coords);
2564 auto spatial_edge_length = get_length(spatial_coords);
2565 auto change = spatial_edge_length / ref_edge_length;
2566 if (change >= 1. + edge_growth_thresh) {
2567 refine_edges.insert(e);
2568 }
2569 }
2570
2571 if (refine_edges.size())
2572 refined = true;
2573
2574 Range prev_level_ents;
2575 CHKERR mField.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
2576 bit, BitRefLevel().set(), MBEDGE, prev_level_ents);
2577
2578 Range prev_ref_ents;
2579 CHKERR mField.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
2580 BitRefLevel().set(REFINED_EDGES_BIT), BitRefLevel().set(), MBEDGE,
2581 prev_ref_ents);
2582
2583 refine_edges.merge(intersect(prev_ref_ents, prev_level_ents));
2584 CHKERR mField.getInterface<BitRefManager>()->setNthBitRefLevel(
2585 refine_edges, REFINED_EDGES_BIT, true);
2586
2587 auto refine = mField.getInterface<MeshRefinement>();
2588 auto refined_bit = BitRefLevel().set(FIRST_REF_BIT + level);
2589 CHKERR refine->addVerticesInTheMiddleOfEdges(refine_edges, refined_bit);
2590 Range tris_to_refine;
2591 CHKERR mField.getInterface<BitRefManager>()->getEntitiesByDimAndRefLevel(
2592 bit, BitRefLevel().set(), SPACE_DIM, tris_to_refine);
2593 CHKERR refine->refineTris(tris_to_refine, refined_bit, QUIET, false);
2594
2595 auto set_spatial_coords = [&]() {
2597 Range new_vertices;
2598 CHKERR mField.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
2599 refined_bit, refined_bit, MBVERTEX, new_vertices);
2600 auto th_parent_handle =
2601 mField.getInterface<BitRefManager>()->get_th_RefParentHandle();
2602 for (auto v : new_vertices) {
2603 EntityHandle parent;
2604 CHKERR mField.get_moab().tag_get_data(th_parent_handle, &v, 1, &parent);
2605 const EntityHandle *conn;
2606 int num_nodes;
2607 CHKERR mField.get_moab().get_connectivity(parent, conn, num_nodes,
2608 true);
2609 std::array<double, 6> spatial_coords;
2610 CHKERR mField.get_moab().tag_get_data(th_spatial_coords, conn,
2611 num_nodes, spatial_coords.data());
2612 for (auto d = 0; d < 3; ++d) {
2613 spatial_coords[d] += spatial_coords[3 + d];
2614 }
2615 for (auto d = 0; d < 3; ++d) {
2616 spatial_coords[d] /= 2.0;
2617 }
2618 CHKERR mField.get_moab().tag_set_data(th_spatial_coords, &v, 1,
2619 spatial_coords.data());
2620 }
2622 };
2623
2624 CHKERR set_spatial_coords();
2625
2626 CHKERR mField.getInterface<BitRefManager>()->writeBitLevelByDim(
2627 BitRefLevel().set(FIRST_REF_BIT + level), BitRefLevel().set(), 2,
2628 ("A_refined_" + boost::lexical_cast<std::string>(level) + ".vtk")
2629 .c_str(),
2630 "VTK", "");
2631
2633 };
2634
2635 auto reset_ref_bits = [](EntityHandle ent, BitRefLevel &bit) {
2636 bit.set(STORAGE_BIT, true);
2637 for (int l = 0; l < num_refinement_levels; ++l) {
2638 bit.set(FIRST_REF_BIT + l, false);
2639 }
2640 };
2641 CHKERR mField.getInterface<BitRefManager>()->lambdaBitRefLevel(
2642 reset_ref_bits);
2643
2644 for (auto l = 0; l < num_refinement_levels; ++l) {
2645 CHKERR refined_mesh(l);
2646 };
2647
2648 CHKERR mField.getInterface<BitRefManager>()->writeBitLevelByDim(
2650 BitRefLevel().set(), 2, "new_elements_after_edge_splits.vtk", "VTK", "");
2651
2653};
2654//! [Refine edges]
2655
2656//! [Run problem]
2661 if (!restart_flg)
2664 CHKERR thermalBC();
2665 CHKERR OPs();
2666 CHKERR tsSolve();
2668}
2669//! [Run problem]
2670
2671//! [Set up problem]
2675
2676 Range domain_ents;
2677 CHKERR mField.get_moab().get_entities_by_dimension(0, SPACE_DIM, domain_ents,
2678 true);
2679 auto get_ents_by_dim = [&](const auto dim) {
2680 if (dim == SPACE_DIM) {
2681 return domain_ents;
2682 } else {
2683 Range ents;
2684 if (dim == 0)
2685 CHKERR mField.get_moab().get_connectivity(domain_ents, ents, true);
2686 else
2687 CHKERR mField.get_moab().get_entities_by_dimension(0, dim, ents, true);
2688 return ents;
2689 }
2690 };
2691
2692 auto get_base = [&]() {
2693 auto domain_ents = get_ents_by_dim(SPACE_DIM);
2694 if (domain_ents.empty())
2695 CHK_THROW_MESSAGE(MOFEM_NOT_FOUND, "Empty mesh");
2696 const auto type = type_from_handle(domain_ents[0]);
2697 switch (type) {
2698 case MBQUAD:
2699 return DEMKOWICZ_JACOBI_BASE;
2700 case MBHEX:
2701 return DEMKOWICZ_JACOBI_BASE;
2702 case MBTRI:
2704 case MBTET:
2706 default:
2707 CHK_THROW_MESSAGE(MOFEM_NOT_FOUND, "Element type not handled");
2708 }
2709 return NOBASE;
2710 };
2711
2712 const auto base = get_base();
2713 MOFEM_LOG("PLASTICITY", Sev::inform)
2714 << "Base " << ApproximationBaseNames[base];
2715
2716 CHKERR simple->addDomainField("U", H1, base, SPACE_DIM);
2717 CHKERR simple->addDomainField("EP", L2, base, size_symm);
2718 CHKERR simple->addDomainField("TAU", L2, base, 1);
2719 CHKERR simple->addBoundaryField("U", H1, base, SPACE_DIM);
2720
2721 constexpr auto flux_space = (SPACE_DIM == 2) ? HCURL : HDIV;
2722 CHKERR simple->addDomainField("T", L2, base, 1);
2723 CHKERR simple->addDomainField("FLUX", flux_space, DEMKOWICZ_JACOBI_BASE, 1);
2724 CHKERR simple->addBoundaryField("FLUX", flux_space, DEMKOWICZ_JACOBI_BASE, 1);
2725 CHKERR simple->addBoundaryField("TBC", L2, base, 1);
2726
2727 // CHKERR simple->addDataField("GEOMETRY", H1, base, SPACE_DIM);
2728
2729 CHKERR simple->setFieldOrder("U", order);
2730 CHKERR simple->setFieldOrder("EP", ep_order);
2731 CHKERR simple->setFieldOrder("TAU", tau_order);
2732 CHKERR simple->setFieldOrder("FLUX", flux_order);
2733 CHKERR simple->setFieldOrder("T", T_order);
2734 CHKERR simple->setFieldOrder("TBC", T_order);
2735
2736 // CHKERR simple->setFieldOrder("GEOMETRY", geom_order);
2737
2738#ifdef ADD_CONTACT
2739 CHKERR simple->addDomainField("SIGMA", CONTACT_SPACE, DEMKOWICZ_JACOBI_BASE,
2740 SPACE_DIM);
2741 CHKERR simple->addBoundaryField("SIGMA", CONTACT_SPACE, DEMKOWICZ_JACOBI_BASE,
2742 SPACE_DIM);
2743
2744 auto get_skin = [&]() {
2745 Range body_ents;
2746 CHKERR mField.get_moab().get_entities_by_dimension(0, SPACE_DIM, body_ents);
2747 Skinner skin(&mField.get_moab());
2748 Range skin_ents;
2749 CHKERR skin.find_skin(0, body_ents, false, skin_ents);
2750 return skin_ents;
2751 };
2752
2753 auto filter_blocks = [&](auto skin) {
2754 bool is_contact_block = false;
2755 Range contact_range;
2756 for (auto m :
2757 mField.getInterface<MeshsetsManager>()->getCubitMeshsetPtr(std::regex(
2758
2759 (boost::format("%s(.*)") % "CONTACT").str()
2760
2761 ))
2762
2763 ) {
2764 is_contact_block =
2765 true; ///< blocs interation is collective, so that is set irrespective
2766 ///< if there are entities in given rank or not in the block
2767 MOFEM_LOG("CONTACT", Sev::inform)
2768 << "Find contact block set: " << m->getName();
2769 auto meshset = m->getMeshset();
2770 Range contact_meshset_range;
2771 CHKERR mField.get_moab().get_entities_by_dimension(
2772 meshset, SPACE_DIM - 1, contact_meshset_range, true);
2773
2774 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
2775 contact_meshset_range);
2776 contact_range.merge(contact_meshset_range);
2777 }
2778 if (is_contact_block) {
2779 MOFEM_LOG("SYNC", Sev::inform)
2780 << "Nb entities in contact surface: " << contact_range.size();
2782 skin = intersect(skin, contact_range);
2783 }
2784 return skin;
2785 };
2786
2787 auto filter_true_skin = [&](auto skin) {
2788 Range boundary_ents;
2789 ParallelComm *pcomm =
2790 ParallelComm::get_pcomm(&mField.get_moab(), MYPCOMM_INDEX);
2791 CHKERR pcomm->filter_pstatus(skin, PSTATUS_SHARED | PSTATUS_MULTISHARED,
2792 PSTATUS_NOT, -1, &boundary_ents);
2793 return boundary_ents;
2794 };
2795
2796 auto boundary_ents = filter_true_skin(filter_blocks(get_skin()));
2797 CHKERR simple->setFieldOrder("SIGMA", 0);
2798 CHKERR simple->setFieldOrder("SIGMA", order - 1, &boundary_ents);
2799#endif
2800
2802 // Cannot resetup after this block has been defined
2803 // as empty when remeshing
2804 if (qual_tol < std::numeric_limits<double>::epsilon() &&
2806 CHKERR simple->addFieldToEmptyFieldBlocks("U", "TAU");
2807
2808 // auto project_ho_geometry = [&]() {
2809 // Projection10NodeCoordsOnField ent_method(mField, "GEOMETRY");
2810 // return mField.loop_dofs("GEOMETRY", ent_method);
2811 // };
2812 // PetscBool project_geometry = PETSC_TRUE;
2813 // CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-project_geometry",
2814 // &project_geometry, PETSC_NULLPTR);
2815 // if (project_geometry) {
2816 // CHKERR project_ho_geometry();
2817 // }
2818
2820}
2821//! [Set up problem]
2822
2823//! [Create common data]
2826
2827 auto get_command_line_parameters = [&]() {
2829
2830 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-quasi_static",
2831 &is_quasi_static, PETSC_NULLPTR);
2832 MOFEM_LOG("PLASTICITY", Sev::inform)
2833 << "Is quasi static: " << (is_quasi_static ? "true" : "false");
2834
2835 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-ts_dt", &init_dt,
2836 PETSC_NULLPTR);
2837 MOFEM_LOG("THERMOPLASTICITY", Sev::inform) << "Initial dt: " << init_dt;
2838
2839 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-ts_adapt_dt_min", &min_dt,
2840 PETSC_NULLPTR);
2841 MOFEM_LOG("THERMOPLASTICITY", Sev::inform) << "Minimum dt: " << min_dt;
2842
2843 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-min_quality", &qual_tol,
2844 PETSC_NULLPTR);
2845 MOFEM_LOG("REMESHING", Sev::inform)
2846 << "Minumum quality for edge flipping: " << qual_tol;
2847 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "",
2848 "-quality_improvement_threshold", &qual_thresh,
2849 PETSC_NULLPTR);
2850 MOFEM_LOG("REMESHING", Sev::inform)
2851 << "Quality improvement threshold for edge flipping: " << qual_thresh;
2852 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-edge_growth_threshold",
2853 &edge_growth_thresh, PETSC_NULLPTR);
2854 MOFEM_LOG("REMESHING", Sev::inform)
2855 << "Edge growth threshold for edge splitting: " << edge_growth_thresh;
2856 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-num_refinement_levels",
2857 &num_refinement_levels, PETSC_NULLPTR);
2858 MOFEM_LOG("REMESHING", Sev::inform)
2859 << "Number of refinement levels for edge splitting: "
2861
2862 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-scale", &scale,
2863 PETSC_NULLPTR);
2864 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-young_modulus",
2865 &young_modulus, PETSC_NULLPTR);
2866 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-poisson_ratio",
2867 &poisson_ratio, PETSC_NULLPTR);
2868 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-hardening", &H,
2869 PETSC_NULLPTR);
2870 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-hardening_viscous", &visH,
2871 PETSC_NULLPTR);
2872 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-yield_stress", &sigmaY,
2873 PETSC_NULLPTR);
2874 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-cn0", &cn0,
2875 PETSC_NULLPTR);
2876 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-cn1", &cn1,
2877 PETSC_NULLPTR);
2878 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-zeta", &zeta,
2879 PETSC_NULLPTR);
2880 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-Qinf", &Qinf,
2881 PETSC_NULLPTR);
2882 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-b_iso", &b_iso,
2883 PETSC_NULLPTR);
2884 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-C1_k", &C1_k,
2885 PETSC_NULLPTR);
2886 // CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-large_strains",
2887 // &is_large_strains, PETSC_NULLPTR);
2888 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-set_timer", &set_timer,
2889 PETSC_NULLPTR);
2890
2891 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-coeff_expansion",
2892 &default_coeff_expansion, PETSC_NULLPTR);
2893 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-ref_temp",
2894 &default_ref_temp, PETSC_NULLPTR);
2895 CHKERR PetscOptionsGetEList("", "-IC_type", ICTypes, 3,
2896 (PetscInt *)&ic_type, PETSC_NULLPTR);
2897 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-init_temp", &init_temp,
2898 PETSC_NULLPTR);
2899 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-peak_temp", &peak_temp,
2900 PETSC_NULLPTR);
2901 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-width", &width,
2902 PETSC_NULLPTR);
2903
2904 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-capacity",
2905 &default_heat_capacity, PETSC_NULLPTR);
2906 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-conductivity",
2907 &default_heat_conductivity, PETSC_NULLPTR);
2908
2909 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-omega_0", &omega_0,
2910 PETSC_NULLPTR);
2911 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-omega_h", &omega_h,
2912 PETSC_NULLPTR);
2913 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-inelastic_heat_fraction",
2914 &inelastic_heat_fraction, PETSC_NULLPTR);
2915 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-temp_0", &temp_0,
2916 PETSC_NULLPTR);
2917
2918 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-order", &order,
2919 PETSC_NULLPTR);
2920 PetscBool tau_order_is_set; ///< true if tau order is set
2921 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-tau_order", &tau_order,
2922 &tau_order_is_set);
2923 PetscBool ep_order_is_set; ///< true if tau order is set
2924 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-ep_order", &ep_order,
2925 &ep_order_is_set);
2926 PetscBool flux_order_is_set; ///< true if flux order is set
2927 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-flux_order", &flux_order,
2928 &flux_order_is_set);
2929 PetscBool T_order_is_set; ///< true if T order is set
2930 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-T_order", &T_order,
2931 &T_order_is_set);
2932 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-geom_order", &geom_order,
2933 PETSC_NULLPTR);
2934
2935 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-atom_test", &atom_test,
2936 PETSC_NULLPTR);
2937
2938 CHKERR PetscOptionsGetString(PETSC_NULLPTR, "", "-restart", restart_file,
2939 255, &restart_flg);
2940 sscanf(restart_file, "restart_%d.dat", &restart_step);
2941 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-restart_time",
2942 &restart_time, PETSC_NULLPTR);
2943
2944 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-rho", &rho,
2945 PETSC_NULLPTR);
2946 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-alpha_damping",
2947 &alpha_damping, PETSC_NULLPTR);
2948
2949 MOFEM_LOG("PLASTICITY", Sev::inform) << "Young modulus " << young_modulus;
2950 MOFEM_LOG("PLASTICITY", Sev::inform) << "Poisson ratio " << poisson_ratio;
2951 MOFEM_LOG("PLASTICITY", Sev::inform) << "Yield stress " << sigmaY;
2952 MOFEM_LOG("PLASTICITY", Sev::inform) << "Hardening " << H;
2953 MOFEM_LOG("PLASTICITY", Sev::inform) << "Viscous hardening " << visH;
2954 MOFEM_LOG("PLASTICITY", Sev::inform) << "Saturation yield stress " << Qinf;
2955 MOFEM_LOG("PLASTICITY", Sev::inform) << "Saturation exponent " << b_iso;
2956 MOFEM_LOG("PLASTICITY", Sev::inform) << "Kinematic hardening " << C1_k;
2957 MOFEM_LOG("PLASTICITY", Sev::inform) << "cn0 " << cn0;
2958 MOFEM_LOG("PLASTICITY", Sev::inform) << "cn1 " << cn1;
2959 MOFEM_LOG("PLASTICITY", Sev::inform) << "zeta " << zeta;
2960 zeta *= init_dt;
2961 MOFEM_LOG("PLASTICITY", Sev::inform) << "zeta * dt " << zeta;
2962
2963 MOFEM_LOG("THERMAL", Sev::inform)
2964 << "default_ref_temp " << default_ref_temp;
2965 MOFEM_LOG("THERMAL", Sev::inform) << "init_temp " << init_temp;
2966 MOFEM_LOG("THERMAL", Sev::inform) << "peak_temp " << peak_temp;
2967 MOFEM_LOG("THERMAL", Sev::inform) << "width " << width;
2968 MOFEM_LOG("THERMAL", Sev::inform)
2969 << "default_coeff_expansion " << default_coeff_expansion;
2970 MOFEM_LOG("THERMAL", Sev::inform)
2971 << "heat_conductivity " << default_heat_conductivity;
2972 MOFEM_LOG("THERMAL", Sev::inform)
2973 << "heat_capacity " << default_heat_capacity;
2974
2975 MOFEM_LOG("THERMOPLASTICITY", Sev::inform)
2976 << "inelastic_heat_fraction " << inelastic_heat_fraction;
2977 MOFEM_LOG("THERMOPLASTICITY", Sev::inform) << "omega_0 " << omega_0;
2978 MOFEM_LOG("THERMOPLASTICITY", Sev::inform) << "omega_h " << omega_h;
2979
2980 if (tau_order_is_set == PETSC_FALSE)
2981 tau_order = order - 2;
2982 if (ep_order_is_set == PETSC_FALSE)
2983 ep_order = order - 1;
2984
2985 if (flux_order_is_set == PETSC_FALSE)
2986 flux_order = order;
2987 if (T_order_is_set == PETSC_FALSE)
2988 T_order = order - 1;
2989
2990 MOFEM_LOG("PLASTICITY", Sev::inform) << "Approximation order " << order;
2991 MOFEM_LOG("PLASTICITY", Sev::inform)
2992 << "Ep approximation order " << ep_order;
2993 MOFEM_LOG("PLASTICITY", Sev::inform)
2994 << "Tau approximation order " << tau_order;
2995 MOFEM_LOG("THERMAL", Sev::inform)
2996 << "FLUX approximation order " << flux_order;
2997 MOFEM_LOG("THERMAL", Sev::inform) << "T approximation order " << T_order;
2998 // MOFEM_LOG("PLASTICITY", Sev::inform)
2999 // << "Geometry approximation order " << geom_order;
3000
3001 MOFEM_LOG("PLASTICITY", Sev::inform) << "Density " << rho;
3002 MOFEM_LOG("PLASTICITY", Sev::inform) << "alpha_damping " << alpha_damping;
3003
3004 PetscBool is_scale = PETSC_TRUE;
3005 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-is_scale", &is_scale,
3006 PETSC_NULLPTR);
3007 MOFEM_LOG("THERMOPLASTICITY", Sev::inform) << "Scaling used? " << is_scale;
3008
3009 switch (is_scale) {
3010 case PETSC_TRUE:
3011 MOFEM_LOG("THERMOPLASTICITY", Sev::warning)
3012 << "Scaling does not yet work with radiation and convection BCs";
3013 // FIXME: Need to properly sort scaling as well as when using convection
3014 // and radiation BCs
3016 thermal_conductivity_scaling = [&](double thermal_cond, double heat_cap) {
3017 if (heat_cap != 0.0 && thermal_cond != 0.0)
3018 return 1. / (thermal_cond * heat_cap);
3019 else
3020 return 1. / thermal_cond;
3021 };
3022 heat_capacity_scaling = [&](double thermal_cond, double heat_cap) {
3023 if (heat_cap != 0.0)
3024 return 1. / (thermal_cond * heat_cap);
3025 else
3026 return 1.0;
3027 };
3029 [&](double young_modulus, double thermal_cond, double heat_cap) {
3030 if (heat_cap != 0.0)
3031 return young_modulus / (thermal_cond * heat_cap);
3032 else
3033 return young_modulus / thermal_cond;
3034 };
3035 break;
3036 default:
3037 thermal_conductivity_scaling = [&](double thermal_cond, double heat_cap) {
3038 return 1.0;
3039 };
3040 heat_capacity_scaling = [&](double thermal_cond, double heat_cap) {
3041 return 1.0;
3042 };
3044 double thermal_cond,
3045 double heat_cap) { return 1.0; };
3046 break;
3047 }
3048
3049 MOFEM_LOG("PLASTICITY", Sev::inform) << "Scale " << scale;
3050 MOFEM_LOG("THERMAL", Sev::inform)
3051 << "Thermal conductivity scale "
3054 MOFEM_LOG("THERMAL", Sev::inform)
3055 << "Thermal capacity scale "
3058 MOFEM_LOG("THERMOPLASTICITY", Sev::inform)
3059 << "Inelastic heat fraction scale "
3062
3063#ifdef ADD_CONTACT
3064 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-cn_contact",
3065 &ContactOps::cn_contact, PETSC_NULLPTR);
3066 MOFEM_LOG("CONTACT", Sev::inform)
3067 << "cn_contact " << ContactOps::cn_contact;
3068#endif // ADD_CONTACT
3069
3071 };
3072
3073 CHKERR get_command_line_parameters();
3074
3075#ifdef ADD_CONTACT
3076 #ifdef ENABLE_PYTHON_BINDING
3077 sdfPythonPtr = boost::make_shared<ContactOps::SDFPython>();
3078 CHKERR sdfPythonPtr->sdfInit("sdf.py");
3079 ContactOps::sdfPythonWeakPtr = sdfPythonPtr;
3080 #endif
3081#endif // ADD_CONTACT
3082
3084}
3085//! [Create common data]
3086
3087//! [Initial conditions]
3090
3091 auto vol_rule = [](int, int, int ao) { return 2 * ao + geom_order; };
3092
3093 // #ifdef PYTHON_INIT_SURFACE
3094 // auto get_py_surface_init = []() {
3095 // auto py_surf_init = boost::make_shared<SurfacePython>();
3096 // CHKERR py_surf_init->surfaceInit("surface.py");
3097 // surfacePythonWeakPtr = py_surf_init;
3098 // return py_surf_init;
3099 // };
3100 // auto py_surf_init = get_py_surface_init();
3101 // #endif
3102
3103 auto simple = mField.getInterface<Simple>();
3104
3105 // CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(),
3106 // "REMOVE_X",
3107 // "U", 0, 0);
3108 // CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(),
3109 // "REMOVE_Y",
3110 // "U", 1, 1);
3111 // CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(),
3112 // "REMOVE_Z",
3113 // "U", 2, 2);
3114 // CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(),
3115 // "REMOVE_ALL", "U", 0, 3);
3116
3117 // #ifdef ADD_CONTACT
3118 // for (auto b : {"FIX_X", "REMOVE_X"})
3119 // CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), b,
3120 // "SIGMA", 0, 0, false, true);
3121 // for (auto b : {"FIX_Y", "REMOVE_Y"})
3122 // CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), b,
3123 // "SIGMA", 1, 1, false, true);
3124 // for (auto b : {"FIX_Z", "REMOVE_Z"})
3125 // CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), b,
3126 // "SIGMA", 2, 2, false, true);
3127 // for (auto b : {"FIX_ALL", "REMOVE_ALL"})
3128 // CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), b,
3129 // "SIGMA", 0, 3, false, true);
3130 // CHKERR bc_mng->removeBlockDOFsOnEntities(
3131 // simple->getProblemName(), "NO_CONTACT", "SIGMA", 0, 3, false, true);
3132 // #endif
3133
3134 // CHKERR bc_mng->pushMarkDOFsOnEntities<DisplacementCubitBcData>(
3135 // simple->getProblemName(), "U");
3136
3138
3139 auto T_ptr = boost::make_shared<VectorDouble>();
3140
3141 auto post_proc = [&](auto dm) {
3143
3144 auto post_proc_fe = boost::make_shared<PostProcEle>(mField);
3145
3147
3148 post_proc_fe->getOpPtrVector().push_back(
3149 new OpCalculateScalarFieldValues("T", T_ptr));
3150 // post_proc_fe->getOpPtrVector().push_back(
3151 // new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_ptr));
3152 if (atom_test == 8) {
3153
3154 auto TAU_ptr = boost::make_shared<VectorDouble>();
3155 auto EP_ptr = boost::make_shared<MatrixDouble>();
3156
3157 post_proc_fe->getOpPtrVector().push_back(
3158 new OpCalculateScalarFieldValues("TAU", TAU_ptr));
3159 post_proc_fe->getOpPtrVector().push_back(
3161
3162 post_proc_fe->getOpPtrVector().push_back(
3163
3164 new OpPPMap(post_proc_fe->getPostProcMesh(),
3165 post_proc_fe->getMapGaussPts(),
3166
3167 {{"T", T_ptr}, {"TAU", TAU_ptr}},
3168
3169 {},
3170
3171 {},
3172
3173 {{"EP", EP_ptr}}
3174
3175 )
3176
3177 );
3178 } else {
3179 post_proc_fe->getOpPtrVector().push_back(
3180
3181 new OpPPMap(post_proc_fe->getPostProcMesh(),
3182 post_proc_fe->getMapGaussPts(),
3183
3184 {{"T", T_ptr}},
3185
3186 {},
3187
3188 {},
3189
3190 {}
3191
3192 )
3193
3194 );
3195 }
3196
3197 CHKERR DMoFEMLoopFiniteElements(dm, "dFE", post_proc_fe);
3198 CHKERR post_proc_fe->writeFile("out_init.h5m");
3199
3201 };
3202
3203 auto solve_init = [&]() {
3205
3206 auto set_domain_rhs = [&](auto &pip) {
3208
3210
3211 pip.push_back(new OpCalculateScalarFieldValues("T", T_ptr));
3212 pip.push_back(new OpRhsSetInitT<AT, IT>(
3213 "T", nullptr, T_ptr, nullptr, boost::make_shared<double>(init_temp),
3214 boost::make_shared<double>(peak_temp)));
3215
3216 if (atom_test == 8) {
3217 auto TAU_ptr = boost::make_shared<VectorDouble>();
3218 auto EP_ptr = boost::make_shared<MatrixDouble>();
3219
3220 pip.push_back(new OpCalculateScalarFieldValues("TAU", TAU_ptr));
3221 auto min_tau = boost::make_shared<double>(1.0);
3222 auto max_tau = boost::make_shared<double>(2.0);
3223 pip.push_back(new OpRhsSetInitT<AT, IT>("TAU", nullptr, TAU_ptr,
3224 nullptr, min_tau, max_tau));
3225
3227 "EP", EP_ptr));
3228 auto min_EP = boost::make_shared<double>(0.0);
3229 auto max_EP = boost::make_shared<double>(0.01);
3231 "EP", nullptr, EP_ptr, nullptr, min_EP, max_EP));
3232 }
3233
3234 // using B = typename FormsIntegrators<DomainEleOp>::template Assembly<
3235 // AT>::template LinearForm<IT>;
3236 // using OpInternalForceCauchy =
3237 // typename B::template OpGradTimesSymTensor<1, SPACE_DIM, SPACE_DIM>;
3238 // using OpInternalForcePiola =
3239 // typename B::template OpGradTimesTensor<1, SPACE_DIM, SPACE_DIM>;
3240
3241 // using P = PlasticityIntegrators<DomainEleOp>;
3242
3243 // auto [common_plastic_ptr, common_hencky_ptr, common_thermal_ptr,
3244 // common_thermoelastic_ptr, common_thermoplastic_ptr] =
3245 // createCommonThermoPlasticOps<SPACE_DIM, IT, DomainEleOp>(
3246 // mField, "MAT_ELASTIC", "MAT_THERMAL", "MAT_THERMOPLASTIC", pip,
3247 // "U", "EP", "TAU", "T", scale, thermal_conductivity_scale,
3248 // heat_capacity_scale, inelastic_heat_fraction_scale,
3249 // Sev::inform);
3250 // auto m_D_ptr = common_hencky_ptr->matDPtr;
3251
3252 // using B = typename FormsIntegrators<DomainEleOp>::template Assembly<
3253 // AT>::template LinearForm<IT>;
3254 // using H = HenckyOps::HenckyIntegrators<DomainEleOp>;
3255 // auto coeff_expansion_ptr = common_thermal_ptr->getCoeffExpansionPtr();
3256 // auto ref_temp_ptr = common_thermal_ptr->getRefTempPtr();
3257 // pip.push_back(new
3258 // typename H::template
3259 // OpCalculateHenckyThermalStress<SPACE_DIM, IT>(
3260 // "U", T_ptr, common_hencky_ptr,
3261 // coeff_expansion_ptr, ref_temp_ptr));
3262 // pip.push_back(new typename H::template
3263 // OpCalculatePiolaStress<SPACE_DIM, IT>(
3264 // "U", common_hencky_ptr));
3265 // using OpInternalForcePiola =
3266 // typename B::template OpGradTimesTensor<1, SPACE_DIM, SPACE_DIM>;
3267 // pip.push_back(new OpInternalForcePiola(
3268 // "U", common_hencky_ptr->getMatFirstPiolaStress()));
3269
3271 };
3272
3273 auto set_domain_lhs = [&](auto &pip) {
3275
3277
3278 using OpLhsScalarLeastSquaresProj = FormsIntegrators<
3279 DomainEleOp>::Assembly<AT>::BiLinearForm<IT>::OpMass<1, 1>;
3280 pip.push_back(new OpLhsScalarLeastSquaresProj("T", "T"));
3281 if (atom_test == 8) {
3282 pip.push_back(new OpLhsScalarLeastSquaresProj("TAU", "TAU"));
3283 pip.push_back(
3285 "EP", "EP"));
3286 }
3287
3288 // auto [common_plastic_ptr, common_hencky_ptr, common_thermal_ptr,
3289 // common_thermoelastic_ptr, common_thermoplastic_ptr] =
3290 // createCommonThermoPlasticOps<SPACE_DIM, IT, DomainEleOp>(
3291 // mField, "MAT_ELASTIC", "MAT_THERMAL", "MAT_THERMOPLASTIC", pip,
3292 // "U", "EP", "TAU", "T", scale, thermal_conductivity_scale,
3293 // heat_capacity_scale, inelastic_heat_fraction_scale,
3294 // Sev::inform);
3295
3296 // auto m_D_ptr = common_hencky_ptr->matDPtr;
3297
3298 // using B = typename FormsIntegrators<DomainEleOp>::template Assembly<
3299 // AT>::template BiLinearForm<IT>;
3300 // using OpKPiola = typename B::template OpGradTensorGrad<1, SPACE_DIM,
3301 // SPACE_DIM, 1>;
3302
3303 // using H = HenckyIntegrators<DomainEleOp>;
3304 // pip.push_back(new OpCalculateScalarFieldValues("T", T_ptr));
3305 // auto coeff_expansion_ptr = common_thermal_ptr->getCoeffExpansionPtr();
3306 // auto ref_temp_ptr = common_thermal_ptr->getRefTempPtr();
3307 // pip.push_back(new
3308 // typename H::template
3309 // OpCalculateHenckyThermalStress<SPACE_DIM, IT>(
3310 // "U", T_ptr, common_hencky_ptr,
3311 // coeff_expansion_ptr, ref_temp_ptr));
3312 // pip.push_back(new typename H::template
3313 // OpCalculatePiolaStress<SPACE_DIM, IT>(
3314 // "U", common_hencky_ptr));
3315 // pip.push_back(new typename H::template OpHenckyTangent<SPACE_DIM, IT>(
3316 // "U", common_hencky_ptr));
3317 // pip.push_back(new OpKPiola("U", "U",
3318 // common_hencky_ptr->getMatTangent()));
3319 // pip.push_back(new typename HenckyOps::OpCalculateHenckyThermalStressdT<
3320 // SPACE_DIM, IT, AssemblyDomainEleOp>("U", "T",
3321 // common_hencky_ptr,
3322 // coeff_expansion_ptr));
3323
3325 };
3326
3327 auto create_sub_dm = [&](SmartPetscObj<DM> base_dm) {
3328 auto dm_sub = createDM(mField.get_comm(), "DMMOFEM");
3329 CHKERR DMMoFEMCreateSubDM(dm_sub, base_dm, "INIT_DM");
3330 CHKERR DMMoFEMSetSquareProblem(dm_sub, PETSC_TRUE);
3331 CHKERR DMMoFEMAddElement(dm_sub, simple->getDomainFEName());
3332 for (auto f : {"T"}) {
3335 }
3336 if (atom_test == 8) {
3337 for (auto f : {"TAU", "EP"}) {
3340 }
3341 }
3342 CHKERR DMSetUp(dm_sub);
3343 return dm_sub;
3344 };
3345
3346 auto fe_rhs = boost::make_shared<DomainEle>(mField);
3347 auto fe_lhs = boost::make_shared<DomainEle>(mField);
3348 fe_rhs->getRuleHook = vol_rule;
3349 fe_lhs->getRuleHook = vol_rule;
3350 CHKERR set_domain_rhs(fe_rhs->getOpPtrVector());
3351 CHKERR set_domain_lhs(fe_lhs->getOpPtrVector());
3352
3353 auto sub_dm = create_sub_dm(simple->getDM());
3354
3355 auto null_fe = boost::shared_ptr<FEMethod>();
3356 CHKERR DMMoFEMKSPSetComputeOperators(sub_dm, simple->getDomainFEName(),
3357 fe_lhs, null_fe, null_fe);
3358 CHKERR DMMoFEMKSPSetComputeRHS(sub_dm, simple->getDomainFEName(), fe_rhs,
3359 null_fe, null_fe);
3360
3361 auto ksp = MoFEM::createKSP(mField.get_comm());
3362 CHKERR KSPSetDM(ksp, sub_dm);
3363 CHKERR KSPSetFromOptions(ksp);
3364
3365 auto D = createDMVector(sub_dm);
3366
3367 CHKERR KSPSolve(ksp, PETSC_NULLPTR, D);
3368
3369 CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
3370 CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
3371 CHKERR DMoFEMMeshToGlobalVector(sub_dm, D, INSERT_VALUES, SCATTER_REVERSE);
3372
3374 };
3375
3376 CHKERR solve_init();
3377 CHKERR post_proc(simple->getDM());
3378
3379 MOFEM_LOG("THERMAL", Sev::inform) << "Set thermoelastic initial conditions";
3380
3382}
3383//! [Initial conditions]
3384
3385//! [Mechanical boundary conditions]
3388
3389 auto simple = mField.getInterface<Simple>();
3390 auto bc_mng = mField.getInterface<BcManager>();
3391
3392 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "REMOVE_X",
3393 "U", 0, 0, true,
3395 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "REMOVE_Y",
3396 "U", 1, 1, true,
3398 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "REMOVE_Z",
3399 "U", 2, 2, true,
3401 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(),
3402 "REMOVE_ALL", "U", 0, 3, true,
3404
3405#ifdef ADD_CONTACT
3406 for (auto b : {"FIX_X", "REMOVE_X"})
3407 CHKERR bc_mng->removeBlockDOFsOnEntities(
3408 simple->getProblemName(), b, "SIGMA", 0, 0, false, is_distributed_mesh);
3409 for (auto b : {"FIX_Y", "REMOVE_Y"})
3410 CHKERR bc_mng->removeBlockDOFsOnEntities(
3411 simple->getProblemName(), b, "SIGMA", 1, 1, false, is_distributed_mesh);
3412 for (auto b : {"FIX_Z", "REMOVE_Z"})
3413 CHKERR bc_mng->removeBlockDOFsOnEntities(
3414 simple->getProblemName(), b, "SIGMA", 2, 2, false, is_distributed_mesh);
3415 for (auto b : {"FIX_ALL", "REMOVE_ALL"})
3416 CHKERR bc_mng->removeBlockDOFsOnEntities(
3417 simple->getProblemName(), b, "SIGMA", 0, 3, false, is_distributed_mesh);
3418 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(),
3419 "NO_CONTACT", "SIGMA", 0, 3, false,
3421#endif
3422
3423 CHKERR bc_mng->pushMarkDOFsOnEntities<DisplacementCubitBcData>(
3424 simple->getProblemName(), "U");
3425
3426 auto &bc_map = bc_mng->getBcMapByBlockName();
3427 for (auto bc : bc_map)
3428 MOFEM_LOG("PLASTICITY", Sev::verbose) << "Marker " << bc.first;
3429
3431}
3432//! [Mechanical boundary conditions]
3433
3434//! [Thermal boundary conditions]
3437
3438 MOFEM_LOG("SYNC", Sev::noisy) << "bC";
3440
3441 auto simple = mField.getInterface<Simple>();
3442 auto bc_mng = mField.getInterface<BcManager>();
3443
3444 auto get_skin = [&]() {
3445 Range body_ents;
3446 CHKERR mField.get_moab().get_entities_by_dimension(0, SPACE_DIM, body_ents);
3447 Skinner skin(&mField.get_moab());
3448 Range skin_ents;
3449 CHKERR skin.find_skin(0, body_ents, false, skin_ents);
3450 return skin_ents;
3451 };
3452
3453 auto filter_flux_blocks = [&](auto skin, bool temp_bc = false) {
3454 auto remove_cubit_blocks = [&](auto c) {
3456 for (auto m :
3457
3458 mField.getInterface<MeshsetsManager>()->getCubitMeshsetPtr(c)
3459
3460 ) {
3461 Range ents;
3462 CHKERR mField.get_moab().get_entities_by_dimension(
3463 m->getMeshset(), SPACE_DIM - 1, ents, true);
3464 skin = subtract(skin, ents);
3465 }
3467 };
3468
3469 auto remove_named_blocks = [&](auto n) {
3471 for (auto m : mField.getInterface<MeshsetsManager>()->getCubitMeshsetPtr(
3472 std::regex(
3473
3474 (boost::format("%s(.*)") % n).str()
3475
3476 ))
3477
3478 ) {
3479 Range ents;
3480 CHKERR mField.get_moab().get_entities_by_dimension(
3481 m->getMeshset(), SPACE_DIM - 1, ents, true);
3482 skin = subtract(skin, ents);
3483 }
3485 };
3486 if (!temp_bc) {
3487 CHK_THROW_MESSAGE(remove_cubit_blocks(NODESET | TEMPERATURESET),
3488 "remove_cubit_blocks");
3489 CHK_THROW_MESSAGE(remove_named_blocks("TEMPERATURE"),
3490 "remove_named_blocks");
3491 }
3492 CHK_THROW_MESSAGE(remove_cubit_blocks(SIDESET | HEATFLUXSET),
3493 "remove_cubit_blocks");
3494 CHK_THROW_MESSAGE(remove_named_blocks("HEATFLUX"), "remove_named_blocks");
3495 CHK_THROW_MESSAGE(remove_named_blocks("CONVECTION"), "remove_named_blocks");
3496 CHK_THROW_MESSAGE(remove_named_blocks("RADIATION"), "remove_named_blocks");
3497 return skin;
3498 };
3499
3500 auto filter_true_skin = [&](auto skin) {
3501 Range boundary_ents;
3502 ParallelComm *pcomm =
3503 ParallelComm::get_pcomm(&mField.get_moab(), MYPCOMM_INDEX);
3504 CHKERR pcomm->filter_pstatus(skin, PSTATUS_SHARED | PSTATUS_MULTISHARED,
3505 PSTATUS_NOT, -1, &boundary_ents);
3506 return boundary_ents;
3507 };
3508
3509 auto remove_flux_ents = filter_true_skin(filter_flux_blocks(get_skin()));
3510 auto remove_temp_bc_ents =
3511 filter_true_skin(filter_flux_blocks(get_skin(), true));
3512
3513 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
3514 remove_flux_ents);
3515 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
3516 remove_temp_bc_ents);
3517
3518 MOFEM_LOG("SYNC", Sev::noisy) << remove_flux_ents << endl;
3520
3521 MOFEM_LOG("SYNC", Sev::noisy) << remove_temp_bc_ents << endl;
3523
3524#ifndef NDEBUG
3525
3527 mField.get_moab(),
3528 (boost::format("flux_remove_%d.vtk") % mField.get_comm_rank()).str(),
3529 remove_flux_ents);
3530
3531#endif
3532
3533 if (is_distributed_mesh == PETSC_TRUE) {
3534 CHKERR mField.getInterface<ProblemsManager>()->removeDofsOnEntities(
3535 simple->getProblemName(), "FLUX", remove_flux_ents);
3536 CHKERR mField.getInterface<ProblemsManager>()->removeDofsOnEntities(
3537 simple->getProblemName(), "TBC", remove_temp_bc_ents);
3538 } else {
3540 ->removeDofsOnEntitiesNotDistributed(simple->getProblemName(), "FLUX",
3541 remove_flux_ents);
3543 ->removeDofsOnEntitiesNotDistributed(simple->getProblemName(), "TBC",
3544 remove_temp_bc_ents);
3545 }
3546
3547 // auto set_init_temp = [](boost::shared_ptr<FieldEntity> field_entity_ptr) {
3548 // field_entity_ptr->getEntFieldData()[0] = init_temp;
3549 // return 0;
3550 // };
3551 // CHKERR
3552 // mField.getInterface<FieldBlas>()->fieldLambdaOnEntities(set_init_temp,
3553 // "T");
3554
3555 CHKERR bc_mng->pushMarkDOFsOnEntities<HeatFluxCubitBcData>(
3556 simple->getProblemName(), "FLUX", false);
3557
3559}
3560//! [Thermal Boundary conditions]
3561
3562//! [Push operators to pipeline]
3565 auto pip_mng = mField.getInterface<PipelineManager>();
3566 auto simple = mField.getInterface<Simple>();
3567 auto bc_mng = mField.getInterface<BcManager>();
3568
3569 auto boundary_marker =
3570 bc_mng->getMergedBlocksMarker(vector<string>{"HEATFLUX"});
3571
3572 auto integration_rule_bc = [](int, int, int ao) { return 2 * ao; };
3573
3574 auto vol_rule = [](int, int, int ao) { return 2 * ao + geom_order; };
3575
3576 CHKERR pip_mng->setDomainRhsIntegrationRule(vol_rule);
3577 CHKERR pip_mng->setDomainLhsIntegrationRule(vol_rule);
3578
3579 CHKERR pip_mng->setBoundaryLhsIntegrationRule(integration_rule_bc);
3580 CHKERR pip_mng->setBoundaryRhsIntegrationRule(integration_rule_bc);
3581
3582 auto thermal_block_params =
3583 boost::make_shared<ThermoElasticOps::BlockedThermalParameters>();
3584 auto heat_conductivity_ptr = thermal_block_params->getHeatConductivityPtr();
3585 auto heat_capacity_ptr = thermal_block_params->getHeatCapacityPtr();
3586
3587 auto thermoelastic_block_params =
3588 boost::make_shared<ThermoElasticOps::BlockedThermoElasticParameters>();
3589 auto coeff_expansion_ptr = thermoelastic_block_params->getCoeffExpansionPtr();
3590 auto ref_temp_ptr = thermoelastic_block_params->getRefTempPtr();
3591
3592 // Default time scaling of BCs and sources, from command line arguments
3593 auto time_scale =
3594 boost::make_shared<TimeScale>("", false, [](const double) { return 1; });
3595 auto def_time_scale = [time_scale](const double time) {
3596 return (!time_scale->argFileScale) ? time : 1;
3597 };
3598 auto def_file_name = [time_scale](const std::string &&name) {
3599 return (!time_scale->argFileScale) ? name : "";
3600 };
3601
3602 // Files which define scaling for separate variables, if provided
3603 auto time_bodyforce_scaling = boost::make_shared<TimeScale>(
3604 def_file_name("bodyforce_scale.txt"), false, def_time_scale);
3605 auto time_heatsource_scaling = boost::make_shared<TimeScale>(
3606 def_file_name("heatsource_scale.txt"), false, def_time_scale);
3607 auto time_temperature_scaling = boost::make_shared<TimeScale>(
3608 def_file_name("temperature_bc_scale.txt"), false, def_time_scale);
3609 auto time_displacement_scaling = boost::make_shared<TimeScale>(
3610 def_file_name("displacement_bc_scale.txt"), false, def_time_scale);
3611 auto time_flux_scaling = boost::make_shared<TimeScale>(
3612 def_file_name("flux_bc_scale.txt"), false, def_time_scale);
3613 auto time_force_scaling = boost::make_shared<TimeScale>(
3614 def_file_name("force_bc_scale.txt"), false, def_time_scale);
3615
3616 auto add_boundary_ops_lhs = [&](auto &pip) {
3618
3619 pip.push_back(new OpSetBc("FLUX", true, boundary_marker));
3620
3622 pip.push_back(new OpSetHOWeightsOnSubDim<SPACE_DIM>());
3623
3624 // Add Natural BCs to LHS
3626 pip, mField, "U", Sev::inform);
3627
3628#ifdef ADD_CONTACT
3629 CHKERR
3630 ContactOps::opFactoryBoundaryLhs<SPACE_DIM, AT, IT, BoundaryEleOp>(
3631 pip, "SIGMA", "U");
3632 CHKERR
3633 ContactOps::opFactoryBoundaryToDomainLhs<SPACE_DIM, AT, IT, DomainEle>(
3634 mField, pip, simple->getDomainFEName(), "SIGMA", "U", "", vol_rule);
3635#endif // ADD_CONTACT
3636
3637 using T =
3638 NaturalBC<BoundaryEleOp>::template Assembly<PETSC>::BiLinearForm<GAUSS>;
3639 using OpConvectionLhsBC =
3640 T::OpFlux<ThermoElasticOps::ConvectionBcType<BLOCKSET>, 1, 1>;
3641 using OpRadiationLhsBC =
3642 T::OpFlux<ThermoElasticOps::RadiationBcType<BLOCKSET>, 1, 1>;
3643 auto temp_bc_ptr = boost::make_shared<VectorDouble>();
3644 pip.push_back(new OpCalculateScalarFieldValues("TBC", temp_bc_ptr));
3645 T::AddFluxToPipeline<OpConvectionLhsBC>::add(pip, mField, "TBC", "TBC",
3646 "CONVECTION", Sev::verbose);
3647 T::AddFluxToPipeline<OpRadiationLhsBC>::add(
3648 pip, mField, "TBC", "TBC", temp_bc_ptr, "RADIATION", Sev::verbose);
3649
3650 // This is temporary implementation. It be moved to LinearFormsIntegrators,
3651 // however for hybridised case, what is goal of this changes, such function
3652 // is implemented for fluxes in broken space. Thus ultimately this operator
3653 // would be not needed.
3654
3655 struct OpTBCTimesNormalFlux
3657
3659
3660 OpTBCTimesNormalFlux(const std::string row_field_name,
3661 const std::string col_field_name,
3662 boost::shared_ptr<Range> ents_ptr = nullptr)
3663 : OP(row_field_name, col_field_name, OP::OPROWCOL, ents_ptr) {
3664 this->sYmm = false;
3665 this->assembleTranspose = true;
3666 this->onlyTranspose = false;
3667 }
3668
3669 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data,
3670 EntitiesFieldData::EntData &col_data) {
3672
3674
3675 // get integration weights
3676 auto t_w = OP::getFTensor0IntegrationWeight();
3677 // get base function values on rows
3678 auto t_row_base = row_data.getFTensor0N();
3679 // get normal vector
3680 auto t_normal = OP::getFTensor1NormalsAtGaussPts();
3681 // loop over integration points
3682 for (int gg = 0; gg != OP::nbIntegrationPts; gg++) {
3683 // loop over rows base functions
3684 auto a_mat_ptr = &*OP::locMat.data().begin();
3685 int rr = 0;
3686 for (; rr != OP::nbRows; rr++) {
3687 // take into account Jacobian
3688 const double alpha = t_w * t_row_base;
3689 // get column base functions values at gauss point gg
3690 auto t_col_base = col_data.getFTensor1N<3>(gg, 0);
3691 // loop over columns
3692 for (int cc = 0; cc != OP::nbCols; cc++) {
3693 // calculate element of local matrix
3694 // using L2 norm of normal vector for convenient area calculation
3695 // for quads, tris etc.
3696 *a_mat_ptr += alpha * (t_col_base(i) * t_normal(i));
3697 ++t_col_base;
3698 ++a_mat_ptr;
3699 }
3700 ++t_row_base;
3701 }
3702 for (; rr < OP::nbRowBaseFunctions; ++rr)
3703 ++t_row_base;
3704 ++t_normal;
3705 ++t_w; // move to another integration weight
3706 }
3707 EntityType fe_type = OP::getNumeredEntFiniteElementPtr()->getEntType();
3708 if (fe_type == MBTRI) {
3709 OP::locMat /= 2;
3710 }
3712 }
3713 };
3714
3715 pip.push_back(new OpTBCTimesNormalFlux("TBC", "FLUX"));
3716
3718 };
3719
3720 auto add_boundary_ops_rhs = [&](auto &pip) {
3722
3724 pip.push_back(new OpSetHOWeightsOnSubDim<SPACE_DIM>());
3725
3727 pip, mField, "U", {time_scale, time_force_scaling}, "FORCE",
3728 Sev::inform);
3729
3730 // Temperature BC
3731
3732 using OpTemperatureBC =
3735 pip, mField, "FLUX", {time_scale, time_temperature_scaling},
3736 "TEMPERATURE", Sev::inform);
3737
3738 // Note: fluxes for temperature should be aggregated. Here separate is
3739 // NaturalMeshsetType<HEATFLUXSET>, we should add version with BLOCKSET,
3740 // convection, see example tutorials/vec-0/src/NaturalBoundaryBC.hpp.
3741 // and vec-0/elastic.cpp
3742
3743 using OpFluxBC =
3746 pip, mField, "TBC", {time_scale, time_flux_scaling}, "FLUX",
3747 Sev::inform);
3748
3750 using OpConvectionRhsBC =
3751 T::OpFlux<ThermoElasticOps::ConvectionBcType<BLOCKSET>, 1, 1>;
3752 using OpRadiationRhsBC =
3753 T::OpFlux<ThermoElasticOps::RadiationBcType<BLOCKSET>, 1, 1>;
3754 auto temp_bc_ptr = boost::make_shared<VectorDouble>();
3755 pip.push_back(new OpCalculateScalarFieldValues("TBC", temp_bc_ptr));
3756 T::AddFluxToPipeline<OpConvectionRhsBC>::add(
3757 pip, mField, "TBC", temp_bc_ptr, "CONVECTION", Sev::inform);
3758 T::AddFluxToPipeline<OpRadiationRhsBC>::add(pip, mField, "TBC", temp_bc_ptr,
3759 "RADIATION", Sev::inform);
3760
3761 auto mat_flux_ptr = boost::make_shared<MatrixDouble>();
3762 pip.push_back(
3763 new OpCalculateHVecVectorField<3, SPACE_DIM>("FLUX", mat_flux_ptr));
3764
3765 // This is temporary implementation. It be moved to LinearFormsIntegrators,
3766 // however for hybridised case, what is goal of this changes, such function
3767 // is implemented for fluxes in broken space. Thus ultimately this operator
3768 // would be not needed.
3769
3770 struct OpTBCTimesNormalFlux
3772
3774
3775 OpTBCTimesNormalFlux(const std::string field_name,
3776 boost::shared_ptr<MatrixDouble> vec,
3777 boost::shared_ptr<Range> ents_ptr = nullptr)
3778 : OP(field_name, field_name, OP::OPROW, ents_ptr), sourceVec(vec) {}
3779
3780 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data) {
3783 // get integration weights
3784 auto t_w = OP::getFTensor0IntegrationWeight();
3785 // get base function values on rows
3786 auto t_row_base = row_data.getFTensor0N();
3787 // get normal vector
3788 auto t_normal = OP::getFTensor1NormalsAtGaussPts();
3789 // get vector values
3790 auto t_vec = getFTensor1FromMat<SPACE_DIM, 1>(*sourceVec);
3791 // loop over integration points
3792 for (int gg = 0; gg != OP::nbIntegrationPts; gg++) {
3793 // take into account Jacobian
3794 const double alpha = t_w * (t_vec(i) * t_normal(i));
3795 // loop over rows base functions
3796 int rr = 0;
3797 for (; rr != OP::nbRows; ++rr) {
3798 OP::locF[rr] += alpha * t_row_base;
3799 ++t_row_base;
3800 }
3801 for (; rr < OP::nbRowBaseFunctions; ++rr)
3802 ++t_row_base;
3803 ++t_w; // move to another integration weight
3804 ++t_vec;
3805 ++t_normal;
3806 }
3807 EntityType fe_type = OP::getNumeredEntFiniteElementPtr()->getEntType();
3808 if (fe_type == MBTRI) {
3809 OP::locF /= 2;
3810 }
3812 }
3813
3814 protected:
3815 boost::shared_ptr<MatrixDouble> sourceVec;
3816 };
3817 pip.push_back(new OpTBCTimesNormalFlux("TBC", mat_flux_ptr));
3818
3819 struct OpBaseNormalTimesTBC
3821
3823
3824 OpBaseNormalTimesTBC(const std::string field_name,
3825 boost::shared_ptr<VectorDouble> vec,
3826 boost::shared_ptr<Range> ents_ptr = nullptr)
3827 : OP(field_name, field_name, OP::OPROW, ents_ptr), sourceVec(vec) {}
3828
3829 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data) {
3832 // get integration weights
3833 auto t_w = OP::getFTensor0IntegrationWeight();
3834 // get base function values on rows
3835 auto t_row_base = row_data.getFTensor1N<3>();
3836 // get normal vector
3837 auto t_normal = OP::getFTensor1NormalsAtGaussPts();
3838 // get vector values
3839 auto t_vec = getFTensor0FromVec(*sourceVec);
3840 // loop over integration points
3841 for (int gg = 0; gg != OP::nbIntegrationPts; gg++) {
3842 // take into account Jacobian
3843 const double alpha = t_w * t_vec;
3844 // loop over rows base functions
3845 int rr = 0;
3846 for (; rr != OP::nbRows; ++rr) {
3847 OP::locF[rr] += alpha * (t_row_base(i) * t_normal(i));
3848 ++t_row_base;
3849 }
3850 for (; rr < OP::nbRowBaseFunctions; ++rr)
3851 ++t_row_base;
3852 ++t_w; // move to another integration weight
3853 ++t_vec;
3854 ++t_normal;
3855 }
3856 EntityType fe_type = OP::getNumeredEntFiniteElementPtr()->getEntType();
3857 if (fe_type == MBTRI) {
3858 OP::locF /= 2;
3859 }
3861 }
3862
3863 protected:
3864 boost::shared_ptr<VectorDouble> sourceVec;
3865 };
3866
3867 pip.push_back(new OpBaseNormalTimesTBC("FLUX", temp_bc_ptr));
3868
3869#ifdef ADD_CONTACT
3870 CHKERR ContactOps::opFactoryBoundaryRhs<SPACE_DIM, AT, IT, BoundaryEleOp>(
3871 pip, "SIGMA", "U");
3872#endif // ADD_CONTACT
3873
3875 };
3876
3877 auto add_domain_ops_lhs = [&](auto &pip) {
3879
3880 pip.push_back(new OpSetBc("FLUX", true, boundary_marker));
3881
3883 mField, pip, "MAT_THERMAL", thermal_block_params,
3887
3889
3890 if (is_quasi_static == PETSC_FALSE) {
3891
3892 //! [Only used for dynamics]
3895 //! [Only used for dynamics]
3896
3897 auto get_inertia_and_mass_damping = [this](const double, const double,
3898 const double) {
3899 auto *pip = mField.getInterface<PipelineManager>();
3900 auto &fe_domain_lhs = pip->getDomainLhsFE();
3901 return (rho / scale) * fe_domain_lhs->ts_aa +
3902 (alpha_damping / scale) * fe_domain_lhs->ts_a;
3903 };
3904 pip.push_back(new OpMass("U", "U", get_inertia_and_mass_damping));
3905 }
3906
3907 CHKERR opThermoPlasticFactoryDomainLhs<SPACE_DIM, AT, IT, DomainEleOp>(
3908 mField, "MAT_PLASTIC", "MAT_THERMAL", "MAT_THERMOELASTIC",
3909 "MAT_THERMOPLASTIC", pip, "U", "EP", "TAU", "T");
3910
3911 auto hencky_common_data_ptr =
3912 HenckyOps::commonDataFactory<SPACE_DIM, IT, DomainEleOp>(
3913 mField, pip, "U", "MAT_PLASTIC", Sev::inform, scale);
3914 auto mat_D_ptr = hencky_common_data_ptr->matDPtr;
3915 auto mat_grad_ptr = hencky_common_data_ptr->matGradPtr;
3916
3917 pip.push_back(new OpSetBc("FLUX", true, boundary_marker));
3918
3919 auto resistance = [heat_conductivity_ptr](const double, const double,
3920 const double) {
3921 return (1. / (*heat_conductivity_ptr));
3922 };
3923 auto capacity = [heat_capacity_ptr](const double, const double,
3924 const double) {
3925 return -(*heat_capacity_ptr);
3926 };
3927
3928 pip.push_back(new OpHdivHdiv("FLUX", "FLUX", resistance, mat_grad_ptr));
3929 pip.push_back(
3930 new OpHdivT("FLUX", "T", []() constexpr { return -1; }, true));
3931
3932 auto mat_flux_ptr = boost::make_shared<MatrixDouble>();
3933 pip.push_back(
3934 new OpCalculateHVecVectorField<3, SPACE_DIM>("FLUX", mat_flux_ptr));
3935
3936 pip.push_back(
3937 new OpHdivU("FLUX", "U", mat_flux_ptr, resistance, mat_grad_ptr));
3938
3939 auto op_capacity = new OpCapacity("T", "T", capacity);
3940 op_capacity->feScalingFun = [](const FEMethod *fe_ptr) {
3941 return fe_ptr->ts_a;
3942 };
3943 pip.push_back(op_capacity);
3944
3945 pip.push_back(new OpUnSetBc("FLUX"));
3946
3947 auto vec_temp_ptr = boost::make_shared<VectorDouble>();
3948 pip.push_back(new OpCalculateScalarFieldValues("T", vec_temp_ptr));
3950 pip, mField, "T", vec_temp_ptr, "SETTEMP", Sev::verbose);
3951
3952 pip.push_back(new OpUnSetBc("FLUX"));
3953
3955 };
3956
3957 auto add_domain_ops_rhs = [&](auto &pip) {
3959
3960 pip.push_back(new OpSetBc("FLUX", true, boundary_marker));
3961
3963 mField, pip, "MAT_THERMAL", thermal_block_params,
3967
3969
3970 auto hencky_common_data_ptr =
3971 HenckyOps::commonDataFactory<SPACE_DIM, IT, DomainEleOp>(
3972 mField, pip, "U", "MAT_PLASTIC", Sev::inform, scale);
3973 auto mat_D_ptr = hencky_common_data_ptr->matDPtr;
3974 auto mat_grad_ptr = hencky_common_data_ptr->matGradPtr;
3975 auto mat_strain_ptr = boost::make_shared<MatrixDouble>();
3976 auto mat_stress_ptr = boost::make_shared<MatrixDouble>();
3977
3978 auto vec_temp_ptr = boost::make_shared<VectorDouble>();
3979 auto vec_temp_dot_ptr = boost::make_shared<VectorDouble>();
3980 auto mat_flux_ptr = boost::make_shared<MatrixDouble>();
3981 auto vec_temp_div_ptr = boost::make_shared<VectorDouble>();
3982
3983 pip.push_back(new OpCalculateScalarFieldValues("T", vec_temp_ptr));
3984 pip.push_back(new OpCalculateScalarFieldValuesDot("T", vec_temp_dot_ptr));
3986 "FLUX", vec_temp_div_ptr));
3987 pip.push_back(
3988 new OpCalculateHVecVectorField<3, SPACE_DIM>("FLUX", mat_flux_ptr));
3989
3990 auto resistance = [heat_conductivity_ptr](const double, const double,
3991 const double) {
3992 return (1. / (*heat_conductivity_ptr));
3993 };
3994 // negative value is consequence of symmetric system
3995 auto capacity = [heat_capacity_ptr](const double, const double,
3996 const double) {
3997 return -(*heat_capacity_ptr);
3998 };
3999 auto unity = [](const double, const double, const double) constexpr {
4000 return -1.;
4001 };
4002 pip.push_back(
4003 new OpHdivFlux("FLUX", mat_flux_ptr, resistance, mat_grad_ptr));
4004 pip.push_back(new OpHDivTemp("FLUX", vec_temp_ptr, unity));
4005 pip.push_back(new OpBaseDivFlux("T", vec_temp_div_ptr, unity));
4006 pip.push_back(new OpBaseDotT("T", vec_temp_dot_ptr, capacity));
4007
4009 pip, mField, "U",
4010 {boost::make_shared<ScaledTimeScale>("body_force_hist.txt")},
4011 Sev::inform);
4012
4013 // only in case of dynamics
4014 if (is_quasi_static == PETSC_FALSE) {
4015
4016 //! [Only used for dynamics]
4019 //! [Only used for dynamics]
4020
4021 auto mat_acceleration = boost::make_shared<MatrixDouble>();
4023 "U", mat_acceleration));
4024 pip.push_back(
4025 new OpInertiaForce("U", mat_acceleration, [](double, double, double) {
4026 return rho / scale;
4027 }));
4028 if (alpha_damping > 0) {
4029 auto mat_velocity = boost::make_shared<MatrixDouble>();
4030 pip.push_back(
4031 new OpCalculateVectorFieldValuesDot<SPACE_DIM>("U", mat_velocity));
4032 pip.push_back(
4033 new OpInertiaForce("U", mat_velocity, [](double, double, double) {
4034 return alpha_damping / scale;
4035 }));
4036 }
4037 }
4038
4039 CHKERR opThermoPlasticFactoryDomainRhs<SPACE_DIM, AT, IT, DomainEleOp>(
4040 mField, "MAT_PLASTIC", "MAT_THERMAL", "MAT_THERMOELASTIC",
4041 "MAT_THERMOPLASTIC", pip, "U", "EP", "TAU", "T");
4042
4043#ifdef ADD_CONTACT
4044 CHKERR ContactOps::opFactoryDomainRhs<SPACE_DIM, AT, IT, DomainEleOp>(
4045 pip, "SIGMA", "U");
4046#endif // ADD_CONTACT
4047
4048 pip.push_back(new OpUnSetBc("FLUX"));
4049
4051 };
4052
4053 auto create_reaction_pipeline = [&](auto &pip) {
4056 CHKERR PlasticOps::opFactoryDomainReactions<SPACE_DIM, AT, IT, DomainEleOp>(
4057 mField, "MAT_PLASTIC", pip, "U", "EP", "TAU");
4059 };
4060
4061 reactionFe = boost::make_shared<DomainEle>(mField);
4062 reactionFe->getRuleHook = vol_rule;
4063 CHKERR create_reaction_pipeline(reactionFe->getOpPtrVector());
4064 reactionFe->postProcessHook =
4066
4067 // Set BCs by eliminating degrees of freedom
4068 auto get_bc_hook_rhs = [&]() {
4070 mField, pip_mng->getDomainRhsFE(),
4071 {time_scale, time_displacement_scaling});
4072 return hook;
4073 };
4074 auto get_bc_hook_lhs = [&]() {
4076 mField, pip_mng->getDomainLhsFE(),
4077 {time_scale, time_displacement_scaling});
4078 return hook;
4079 };
4080
4081 pip_mng->getDomainRhsFE()->preProcessHook = get_bc_hook_rhs();
4082 pip_mng->getDomainLhsFE()->preProcessHook = get_bc_hook_lhs();
4083
4084 CHKERR add_domain_ops_lhs(pip_mng->getOpDomainLhsPipeline());
4085 CHKERR add_domain_ops_rhs(pip_mng->getOpDomainRhsPipeline());
4086
4087 // Boundary
4088 CHKERR add_boundary_ops_lhs(pip_mng->getOpBoundaryLhsPipeline());
4089 CHKERR add_boundary_ops_rhs(pip_mng->getOpBoundaryRhsPipeline());
4090
4092}
4093//! [Push operators to pipeline]
4094
4095//! [Solve]
4096struct SetUpSchur {
4097
4098 /**
4099 * @brief Create data structure for handling Schur complement
4100 *
4101 * @param m_field
4102 * @param sub_dm Schur complement sub dm
4103 * @param field_split_it IS of Schur block
4104 * @param ao_map AO map from sub dm to main problem
4105 * @return boost::shared_ptr<SetUpSchur>
4106 */
4107 static boost::shared_ptr<SetUpSchur> createSetUpSchur(
4108
4109 MoFEM::Interface &m_field, SmartPetscObj<DM> sub_dm,
4110 SmartPetscObj<IS> field_split_it, SmartPetscObj<AO> ao_map
4111
4112 );
4113 virtual MoFEMErrorCode setUp(TS solver) = 0;
4114
4115protected:
4116 SetUpSchur() = default;
4117};
4118
4119struct MyTsCtx {
4120 boost::shared_ptr<MoFEM::TsCtx> dmts_ctx;
4121 PetscInt snes_iter_counter = 0;
4122};
4123
4124static std::unordered_map<TS, MyTsCtx *> ts_to_ctx;
4125
4126MoFEMErrorCode TSIterationPreStage(TS ts, PetscReal stagetime) {
4128 MyTsCtx *my_ctx = ts_to_ctx[ts];
4129 my_ctx->snes_iter_counter = 0;
4131}
4132
4133// Monitor function
4134MoFEMErrorCode SNESIterationMonitor(SNES snes, PetscInt its, PetscReal norm,
4135 void *ctx) {
4137 MyTsCtx *my_ctx = static_cast<MyTsCtx *>(ctx);
4138 my_ctx->snes_iter_counter++;
4140}
4141
4142PetscErrorCode MyTSResizeSetup(TS ts, PetscInt nstep, PetscReal time, Vec sol,
4143 PetscBool *resize, void *ctx) {
4144 PetscFunctionBegin;
4145 ResizeCtx *rctx = static_cast<ResizeCtx *>(ctx);
4146 *resize = rctx->mesh_changed;
4147 PetscFunctionReturn(0);
4148}
4149
4150PetscErrorCode MyTSResizeTransfer(TS ts, PetscInt nv, Vec ts_vecsin[],
4151 Vec ts_vecsout[], void *ctx) {
4152 PetscFunctionBegin;
4153 ResizeCtx *rctx = static_cast<ResizeCtx *>(ctx);
4154
4155 if (auto ptr = rctx->ptr.lock()) {
4156
4157 MoFEM::Interface &m_field = *(rctx->m_field);
4158
4159 auto bit_mng = m_field.getInterface<BitRefManager>();
4160
4161 auto set_prev_mesh_bit = [](EntityHandle ent, BitRefLevel &bit) {
4162 if (bit[COMPUTATION_BIT]) {
4163 bit.set(COMPUTATION_BIT, false);
4164 bit.set(PREVIOUS_BIT, true);
4165 }
4166 };
4167
4168 CHKERR bit_mng->lambdaBitRefLevel(set_prev_mesh_bit);
4169
4170 std::string improved_reasons = "";
4171
4172 Range edges_to_not_refine;
4173
4174 CHKERR ptr->ExRawPtr->doEdgeFlips(rctx->el_q_map, rctx->flipped_els,
4175 rctx->th_spatial_coords,
4176 rctx->new_connectivity);
4177 if (rctx->el_q_map.size() > 0) {
4178 improved_reasons += ", Edge flipping";
4179 }
4180
4181 bool refined = false;
4182 int step;
4183 CHKERR TSGetStepNumber(ts, &step);
4184 CHKERR ptr->ExRawPtr->doEdgeSplits(refined, (step) ? true : false);
4185 if (refined) {
4186 improved_reasons += ", Edge splitting";
4187 }
4188
4189 // Erase leading ", " from improved_reasons
4190 improved_reasons.erase(0, 2);
4191
4192 if (improved_reasons != "")
4193 MOFEM_LOG("REMESHING", Sev::inform)
4194 << "Improved mesh quality by: " << improved_reasons;
4195
4196#ifndef NDEBUG
4197
4198 // comp_mesh_bit = BitRefLevel().set(COMPUTATION_BIT);
4199 // flipped_bit = BitRefLevel().set(FLIPPED_BIT);
4200 // refined_bit = BitRefLevel().set(FIRST_REF_BIT);
4201 // prev_mesh_bit = BitRefLevel().set(PREVIOUS_BIT);
4202 // virgin_mesh_bit = BitRefLevel().set(VIRGIN_BIT);
4203 // storage_bit = BitRefLevel().set(STORAGE_BIT);
4204
4205 if (m_field.get_comm_rank() == 0) {
4206 CHKERR m_field.getInterface<BitRefManager>()->writeBitLevelByDim(
4207 comp_mesh_bit, BitRefLevel().set(), 2,
4208 "before_mapping_comp_mesh_bit.vtk", "VTK", "");
4209 CHKERR m_field.getInterface<BitRefManager>()->writeBitLevelByDim(
4210 flipped_bit, BitRefLevel().set(), 2, "before_mapping_flipped_bit.vtk",
4211 "VTK", "");
4212 CHKERR m_field.getInterface<BitRefManager>()->writeBitLevelByDim(
4213 refined_bit, BitRefLevel().set(), 2, "before_mapping_refined_bit.vtk",
4214 "VTK", "");
4215 CHKERR m_field.getInterface<BitRefManager>()->writeBitLevelByDim(
4216 prev_mesh_bit, BitRefLevel().set(), 2,
4217 "before_mapping_prev_mesh_bit.vtk", "VTK", "");
4218 CHKERR m_field.getInterface<BitRefManager>()->writeBitLevelByDim(
4219 virgin_mesh_bit, BitRefLevel().set(), 2,
4220 "before_mapping_virgin_mesh_bit.vtk", "VTK", "");
4221 }
4222#endif // NDEBUG
4223
4224 MOFEM_LOG("REMESHING", Sev::verbose) << "number of vectors to map = " << nv;
4225
4226 for (PetscInt i = 0; i < nv; ++i) {
4227 double nrm;
4228 CHKERR VecNorm(ts_vecsin[i], NORM_2, &nrm);
4229 MOFEM_LOG("REMESHING", Sev::warning)
4230 << "Before remeshing: ts_vecsin[" << i << "] norm = " << nrm;
4231 }
4232
4233 auto scatter_mng = m_field.getInterface<VecManager>();
4234 auto simple = m_field.getInterface<Simple>();
4235
4236 // CHKERR m_field.getInterface<BitRefManager>()->writeBitLevel(
4237 // BitRefLevel().set(1), BitRefLevel().set(), "before_resettingup.vtk",
4238 // "VTK", "");
4239
4240 // Rebuilding DM with old and new mesh entities
4241 auto bit = BitRefLevel().set();
4243 {"TAU", "EP", "T"}, {tau_order, ep_order, T_order}, {"U"},
4244 {order}, {"FLUX"}, {flux_order}, bit);
4245
4246 // CHKERR m_field.getInterface<BitRefManager>()->writeBitLevel(
4247 // BitRefLevel().set(1), BitRefLevel().set(), "after_resettingup.vtk",
4248 // "VTK", "");
4249
4250 auto intermediate_dm = createDM(m_field.get_comm(), "DMMOFEM");
4252 intermediate_dm, &m_field, "INTERMEDIATE_DM",
4254 BitRefLevel().set());
4255 CHKERR DMMoFEMSetDestroyProblem(intermediate_dm, PETSC_TRUE);
4256 CHKERR DMSetFromOptions(intermediate_dm);
4257 CHKERR DMMoFEMAddElement(intermediate_dm, simple->getDomainFEName());
4258 CHKERR DMMoFEMSetSquareProblem(intermediate_dm, PETSC_TRUE);
4260 CHKERR DMSetUp(intermediate_dm);
4261
4262 Vec vec_in[nv], vec_out[nv];
4263 for (PetscInt i = 0; i < nv; ++i) {
4264 CHKERR DMCreateGlobalVector(intermediate_dm, &vec_in[i]);
4265 CHKERR VecDuplicate(vec_in[i], &vec_out[i]);
4266 }
4267
4268 VecScatter scatter_to_intermediate;
4269
4270 for (PetscInt i = 0; i < nv; ++i) {
4271 CHKERR scatter_mng->vecScatterCreate(
4272 ts_vecsin[i], simple->getProblemName(), RowColData::ROW, vec_in[i],
4273 "INTERMEDIATE_DM", RowColData::ROW, &scatter_to_intermediate);
4274 CHKERR VecScatterBegin(scatter_to_intermediate, ts_vecsin[i], vec_in[i],
4275 INSERT_VALUES, SCATTER_FORWARD);
4276 CHKERR VecScatterEnd(scatter_to_intermediate, ts_vecsin[i], vec_in[i],
4277 INSERT_VALUES, SCATTER_FORWARD);
4278 }
4279
4280 CHKERR VecScatterDestroy(&scatter_to_intermediate);
4281
4283 intermediate_dm, prev_mesh_bit,
4284 BitRefLevel().set(FLIPPED_BIT + num_refinement_levels), nv, vec_in,
4285 vec_out);
4286
4287 // Build problem on new bit ref level
4288 auto ts_problem_name = simple->getProblemName();
4290 ts_problem_name,
4292 CHKERR m_field.modify_problem_mask_ref_level_set_bit(ts_problem_name,
4293 BitRefLevel().set());
4295 PetscBarrier(nullptr);
4296 CHKERR DMSetUp_MoFEM(simple->getDM());
4297
4298 // Update meshsets for correct BCs
4299 MeshsetsManager *meshsets_manager_ptr;
4300 CHKERR m_field.getInterface(meshsets_manager_ptr);
4301 CHKERR meshsets_manager_ptr->updateAllMeshsetsByEntitiesChildren(
4302 BitRefLevel().set());
4303
4304 CHKERR ptr->ExRawPtr->mechanicalBC();
4305 CHKERR ptr->ExRawPtr->thermalBC();
4306
4307 VecScatter scatter_to_final;
4308
4309 for (PetscInt i = 0; i < nv; ++i) {
4310 CHKERR DMCreateGlobalVector(simple->getDM(), &ts_vecsout[i]);
4311 CHKERR scatter_mng->vecScatterCreate(
4312 ts_vecsout[i], simple->getProblemName(), RowColData::ROW, vec_out[i],
4313 "INTERMEDIATE_DM", RowColData::ROW, &scatter_to_final);
4314 CHKERR VecScatterBegin(scatter_to_final, vec_out[i], ts_vecsout[i],
4315 INSERT_VALUES, SCATTER_REVERSE);
4316 CHKERR VecScatterEnd(scatter_to_final, vec_out[i], ts_vecsout[i],
4317 INSERT_VALUES, SCATTER_REVERSE);
4318 CHKERR VecScatterDestroy(&scatter_to_final);
4319 }
4320
4321 for (PetscInt i = 0; i < nv; ++i) {
4322 CHKERR VecDestroy(&vec_in[i]);
4323 CHKERR VecDestroy(&vec_out[i]);
4324 }
4325
4326 auto set_all_bit = [&](EntityHandle ent, BitRefLevel &bit) {
4327 for (auto l = 0; l <= FLIPPED_BIT + num_refinement_levels; ++l) {
4328 bit.set(STORAGE_BIT, true);
4329 }
4330 if (bit[VIRGIN_BIT]) {
4331 bit.set(VIRGIN_BIT, false);
4332 }
4333 if (bit[FLIPPED_BIT]) {
4334 bit.set(VIRGIN_BIT, true);
4335 }
4336 if (bit[PREVIOUS_BIT]) {
4337 bit.set(PREVIOUS_BIT, false);
4338 }
4340 bit.set(COMPUTATION_BIT, true);
4341 }
4342 };
4343 CHKERR bit_mng->lambdaBitRefLevel(set_all_bit);
4344
4345#ifndef NDEBUG
4346
4347 // comp_mesh_bit = BitRefLevel().set(COMPUTATION_BIT);
4348 // flipped_bit = BitRefLevel().set(FLIPPED_BIT);
4349 // refined_bit = BitRefLevel().set(FIRST_REF_BIT);
4350 // prev_mesh_bit = BitRefLevel().set(PREVIOUS_BIT);
4351 // virgin_mesh_bit = BitRefLevel().set(VIRGIN_BIT);
4352 // storage_bit = BitRefLevel().set(STORAGE_BIT);
4353
4354 if (m_field.get_comm_rank() == 0) {
4355 CHKERR m_field.getInterface<BitRefManager>()->writeBitLevelByDim(
4356 comp_mesh_bit, BitRefLevel().set(), 2,
4357 "after_mapping_comp_mesh_bit.vtk", "VTK", "");
4358 CHKERR m_field.getInterface<BitRefManager>()->writeBitLevelByDim(
4359 flipped_bit, BitRefLevel().set(), 2, "after_mapping_flipped_bit.vtk",
4360 "VTK", "");
4361 CHKERR m_field.getInterface<BitRefManager>()->writeBitLevelByDim(
4362 refined_bit, BitRefLevel().set(), 2, "after_mapping_refined_bit.vtk",
4363 "VTK", "");
4364 CHKERR m_field.getInterface<BitRefManager>()->writeBitLevelByDim(
4365 prev_mesh_bit, BitRefLevel().set(), 2,
4366 "after_mapping_prev_mesh_bit.vtk", "VTK", "");
4367 CHKERR m_field.getInterface<BitRefManager>()->writeBitLevelByDim(
4368 virgin_mesh_bit, BitRefLevel().set(), 2,
4369 "after_mapping_virgin_mesh_bit.vtk", "VTK", "");
4370 }
4371#endif // NDEBUG
4372
4373 CHKERR m_field.modify_problem_ref_level_set_bit(ts_problem_name,
4375 CHKERR m_field.modify_problem_mask_ref_level_set_bit(ts_problem_name,
4376 BitRefLevel().set());
4377
4378 CHKERR TSSetDM(ts, simple->getDM());
4379
4380 auto B = createDMMatrix(simple->getDM());
4381 CHKERR TSSetIJacobian(ts, B, B, nullptr, nullptr);
4382 }
4383
4384 for (PetscInt i = 0; i < nv; ++i) {
4385 double nrm;
4386 CHKERR VecNorm(ts_vecsout[i], NORM_2, &nrm);
4387 MOFEM_LOG("REMESHING", Sev::warning)
4388 << "After remeshing: ts_vecsout[" << i << "] norm = " << nrm;
4389 }
4390
4391 PetscFunctionReturn(0);
4392}
4393
4395
4398
4401 ISManager *is_manager = mField.getInterface<ISManager>();
4402
4403 auto snes_ctx_ptr = getDMSnesCtx(simple->getDM());
4404
4405 auto set_section_monitor = [&](auto solver) {
4407 SNES snes;
4408 CHKERR TSGetSNES(solver, &snes);
4409 CHKERR SNESMonitorSet(snes,
4410 (MoFEMErrorCode (*)(SNES, PetscInt, PetscReal,
4411 void *))MoFEMSNESMonitorFields,
4412 (void *)(snes_ctx_ptr.get()), nullptr);
4414 };
4415
4416 auto create_post_process_elements = [&]() {
4417 auto pp_fe = boost::make_shared<PostProcEle>(mField);
4418
4419 auto push_vol_ops = [this](auto &pip) {
4421
4422 ScalerFunTwoArgs unity_2_args = [&](const double, const double) {
4423 return 1.;
4424 };
4425 ScalerFunThreeArgs unity_3_args = [&](const double, const double,
4426 const double) { return 1.; };
4427
4428 auto [common_plastic_ptr, common_hencky_ptr, common_thermal_ptr,
4429 common_thermoelastic_ptr, common_thermoplastic_ptr] =
4430 createCommonThermoPlasticOps<SPACE_DIM, IT, DomainEleOp>(
4431 mField, "MAT_PLASTIC", "MAT_THERMAL", "MAT_THERMOELASTIC",
4432 "MAT_THERMOPLASTIC", pip, "U", "EP", "TAU", "T", 1., unity_2_args,
4433 unity_2_args, unity_3_args, Sev::inform);
4434
4435 if (common_hencky_ptr) {
4436 if (common_plastic_ptr->mGradPtr != common_hencky_ptr->matGradPtr)
4437 CHK_THROW_MESSAGE(MOFEM_DATA_INCONSISTENCY, "Wrong pointer for grad");
4438 }
4439
4440 return std::make_tuple(common_plastic_ptr, common_hencky_ptr,
4441 common_thermoplastic_ptr);
4442 };
4443
4444 auto push_vol_post_proc_ops = [this](auto &pp_fe, auto &&p) {
4446
4447 auto &pip = pp_fe->getOpPtrVector();
4448
4449 auto [common_plastic_ptr, common_hencky_ptr, common_thermoplastic_ptr] =
4450 p;
4451
4452 auto mat_strain_ptr = boost::make_shared<MatrixDouble>();
4453 auto mat_stress_ptr = boost::make_shared<MatrixDouble>();
4454
4455 auto vec_temp_ptr = boost::make_shared<VectorDouble>();
4456 auto mat_flux_ptr = boost::make_shared<MatrixDouble>();
4457
4458 auto u_ptr = boost::make_shared<MatrixDouble>();
4459 pip.push_back(new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_ptr));
4460
4462
4463 if (is_large_strains) {
4464
4465 pip.push_back(
4466
4467 new OpPPMap(
4468
4469 pp_fe->getPostProcMesh(), pp_fe->getMapGaussPts(),
4470
4471 {{"ISOTROPIC_HARDENING",
4472 common_plastic_ptr->getPlasticIsoHardeningPtr()},
4473 {"PLASTIC_SURFACE",
4474 common_plastic_ptr->getPlasticSurfacePtr()},
4475 {"PLASTIC_MULTIPLIER", common_plastic_ptr->getPlasticTauPtr()},
4476 {"T", common_thermoplastic_ptr->getTempPtr()}},
4477
4478 {{"U", u_ptr},
4479 {"FLUX", common_thermoplastic_ptr->getHeatFluxPtr()}},
4480
4481 {{"GRAD", common_hencky_ptr->matGradPtr},
4482 {"FIRST_PIOLA", common_hencky_ptr->getMatFirstPiolaStress()}},
4483
4484 {{"PLASTIC_STRAIN", common_plastic_ptr->getPlasticStrainPtr()},
4485 {"PLASTIC_FLOW", common_plastic_ptr->getPlasticFlowPtr()},
4486 {"HENCKY_STRAIN", common_hencky_ptr->getMatLogC()},
4487 {"HENCKY_STRESS", common_hencky_ptr->getMatHenckyStress()}}
4488
4489 )
4490
4491 );
4492
4493 } else {
4494
4495 pip.push_back(
4496
4497 new OpPPMap(
4498
4499 pp_fe->getPostProcMesh(), pp_fe->getMapGaussPts(),
4500
4501 {{"PLASTIC_SURFACE",
4502 common_plastic_ptr->getPlasticSurfacePtr()},
4503 {"PLASTIC_MULTIPLIER", common_plastic_ptr->getPlasticTauPtr()},
4504 {"T", common_thermoplastic_ptr->getTempPtr()}},
4505
4506 {{"U", u_ptr},
4507 {"FLUX", common_thermoplastic_ptr->getHeatFluxPtr()}},
4508
4509 {},
4510
4511 {{"STRAIN", common_plastic_ptr->mStrainPtr},
4512 {"STRESS", common_plastic_ptr->mStressPtr},
4513 {"PLASTIC_STRAIN", common_plastic_ptr->getPlasticStrainPtr()},
4514 {"PLASTIC_FLOW", common_plastic_ptr->getPlasticFlowPtr()}}
4515
4516 )
4517
4518 );
4519 }
4520
4522 };
4523
4524 // Defaults to outputting volume for 2D and skin for 3D
4525 PetscBool post_proc_vol = PETSC_FALSE;
4526 PetscBool post_proc_skin = PETSC_TRUE;
4527 switch (SPACE_DIM) {
4528 case 2:
4529 post_proc_vol = PETSC_TRUE;
4530 post_proc_skin = PETSC_FALSE;
4531 break;
4532 case 3:
4533 post_proc_vol = PETSC_FALSE;
4534 post_proc_skin = PETSC_TRUE;
4535 break;
4536 default:
4537 CHK_THROW_MESSAGE(MOFEM_NOT_FOUND, "SPACE_DIM neither 2 nor 3");
4538 break;
4539 }
4540 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-post_proc_vol",
4541 &post_proc_vol, PETSC_NULLPTR);
4542 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-post_proc_skin",
4543 &post_proc_skin, PETSC_NULLPTR);
4544
4545 auto vol_post_proc = [this, push_vol_post_proc_ops, push_vol_ops,
4546 &post_proc_vol]() {
4547 if (post_proc_vol == PETSC_FALSE)
4548 return boost::shared_ptr<PostProcEle>();
4549 auto pp_fe = boost::make_shared<PostProcEle>(mField);
4551 push_vol_post_proc_ops(pp_fe, push_vol_ops(pp_fe->getOpPtrVector())),
4552 "push_vol_post_proc_ops");
4553 return pp_fe;
4554 };
4555
4556 auto skin_post_proc = [this, push_vol_post_proc_ops, push_vol_ops,
4557 &post_proc_skin]() {
4558 if (post_proc_skin == PETSC_FALSE)
4559 return boost::shared_ptr<SkinPostProcEle>();
4560
4561 auto simple = mField.getInterface<Simple>();
4562 auto pp_fe = boost::make_shared<SkinPostProcEle>(mField);
4563 auto op_side = new OpLoopSide<SideEle>(mField, simple->getDomainFEName(),
4564 SPACE_DIM, Sev::verbose);
4565 pp_fe->getOpPtrVector().push_back(op_side);
4566 CHK_MOAB_THROW(push_vol_post_proc_ops(
4567 pp_fe, push_vol_ops(op_side->getOpPtrVector())),
4568 "push_vol_post_proc_ops");
4569 return pp_fe;
4570 };
4571
4572 return std::make_pair(vol_post_proc(), skin_post_proc());
4573 };
4574
4575 auto scatter_create = [&](auto D, auto coeff) {
4577 CHKERR is_manager->isCreateProblemFieldAndRank(simple->getProblemName(),
4578 ROW, "U", coeff, coeff, is);
4579 int loc_size;
4580 CHKERR ISGetLocalSize(is, &loc_size);
4581 Vec v;
4582 CHKERR VecCreateMPI(mField.get_comm(), loc_size, PETSC_DETERMINE, &v);
4583 VecScatter scatter;
4584 CHKERR VecScatterCreate(D, is, v, PETSC_NULLPTR, &scatter);
4585 return std::make_tuple(SmartPetscObj<Vec>(v),
4586 SmartPetscObj<VecScatter>(scatter));
4587 };
4588
4589 boost::shared_ptr<SetPtsData> field_eval_data;
4590 boost::shared_ptr<MatrixDouble> u_field_ptr;
4591
4592 std::array<double, 3> field_eval_coords = {0., 0., 0.};
4593 int coords_dim = 3;
4594 CHKERR PetscOptionsGetRealArray(NULL, NULL, "-field_eval_coords",
4595 field_eval_coords.data(), &coords_dim,
4596 &do_eval_field);
4597
4598 boost::shared_ptr<std::map<std::string, boost::shared_ptr<VectorDouble>>>
4599 scalar_field_ptrs = boost::make_shared<
4600 std::map<std::string, boost::shared_ptr<VectorDouble>>>();
4601 boost::shared_ptr<std::map<std::string, boost::shared_ptr<MatrixDouble>>>
4602 vector_field_ptrs = boost::make_shared<
4603 std::map<std::string, boost::shared_ptr<MatrixDouble>>>();
4604 boost::shared_ptr<std::map<std::string, boost::shared_ptr<MatrixDouble>>>
4605 sym_tensor_field_ptrs = boost::make_shared<
4606 std::map<std::string, boost::shared_ptr<MatrixDouble>>>();
4607 boost::shared_ptr<std::map<std::string, boost::shared_ptr<MatrixDouble>>>
4608 tensor_field_ptrs = boost::make_shared<
4609 std::map<std::string, boost::shared_ptr<MatrixDouble>>>();
4610
4611 auto test_monitor_ptr = boost::make_shared<FEMethod>();
4612
4613 if (do_eval_field && atom_test == 0) {
4614 field_eval_data =
4615 mField.getInterface<FieldEvaluatorInterface>()->getData<DomainEle>();
4616 CHKERR mField.getInterface<FieldEvaluatorInterface>()->buildTree<SPACE_DIM>(
4617 field_eval_data, simple->getDomainFEName());
4618
4619 field_eval_data->setEvalPoints(field_eval_coords.data(), 1);
4620 auto no_rule = [](int, int, int) { return -1; };
4621 auto field_eval_fe_ptr = field_eval_data->feMethodPtr.lock();
4622 field_eval_fe_ptr->getRuleHook = no_rule;
4623
4625 field_eval_fe_ptr->getOpPtrVector(), {H1, HDIV});
4626
4627 ScalerFunTwoArgs unity_2_args = [&](const double, const double) {
4628 return 1.;
4629 };
4630 ScalerFunThreeArgs unity_3_args = [&](const double, const double,
4631 const double) { return 1.; };
4632
4633 auto [common_plastic_ptr, common_hencky_ptr, common_thermal_ptr,
4634 common_thermoelastic_ptr, common_thermoplastic_ptr] =
4635 createCommonThermoPlasticOps<SPACE_DIM, IT, DomainEleOp>(
4636 mField, "MAT_PLASTIC", "MAT_THERMAL", "MAT_THERMOELASTIC",
4637 "MAT_THERMOPLASTIC", field_eval_fe_ptr->getOpPtrVector(), "U", "EP",
4638 "TAU", "T", 1., unity_2_args, unity_2_args, unity_3_args,
4639 Sev::inform);
4640
4641 auto u_field_ptr = boost::make_shared<MatrixDouble>();
4642 field_eval_fe_ptr->getOpPtrVector().push_back(
4643 new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_field_ptr));
4644 auto T_field_ptr = boost::make_shared<VectorDouble>();
4645 field_eval_fe_ptr->getOpPtrVector().push_back(
4646 new OpCalculateScalarFieldValues("T", T_field_ptr));
4647 auto FLUX_field_ptr = boost::make_shared<MatrixDouble>();
4648 field_eval_fe_ptr->getOpPtrVector().push_back(
4649 new OpCalculateHVecVectorField<3, SPACE_DIM>("FLUX", FLUX_field_ptr));
4650
4651 if ((common_plastic_ptr) && (common_hencky_ptr) && (scalar_field_ptrs)) {
4652 if (is_large_strains) {
4653 scalar_field_ptrs->insert(std::make_pair("TEMPERATURE", T_field_ptr));
4654 scalar_field_ptrs->insert(std::make_pair(
4655 "PLASTIC_SURFACE", common_plastic_ptr->getPlasticSurfacePtr()));
4656 scalar_field_ptrs->insert(std::make_pair(
4657 "PLASTIC_MULTIPLIER", common_plastic_ptr->getPlasticTauPtr()));
4658 vector_field_ptrs->insert(std::make_pair("U", u_field_ptr));
4659 vector_field_ptrs->insert(std::make_pair("FLUX", FLUX_field_ptr));
4660 sym_tensor_field_ptrs->insert(std::make_pair(
4661 "PLASTIC_STRAIN", common_plastic_ptr->getPlasticStrainPtr()));
4662 sym_tensor_field_ptrs->insert(std::make_pair(
4663 "PLASTIC_FLOW", common_plastic_ptr->getPlasticFlowPtr()));
4664 sym_tensor_field_ptrs->insert(std::make_pair(
4665 "HENCKY_STRESS", common_hencky_ptr->getMatHenckyStress()));
4666 sym_tensor_field_ptrs->insert(
4667 std::make_pair("HENCKY_STRAIN", common_hencky_ptr->getMatLogC()));
4668 tensor_field_ptrs->insert(
4669 std::make_pair("GRAD", common_hencky_ptr->matGradPtr));
4670 tensor_field_ptrs->insert(std::make_pair(
4671 "FIRST_PIOLA", common_hencky_ptr->getMatFirstPiolaStress()));
4672 } else {
4673 scalar_field_ptrs->insert(std::make_pair("TEMPERATURE", T_field_ptr));
4674 scalar_field_ptrs->insert(std::make_pair(
4675 "PLASTIC_SURFACE", common_plastic_ptr->getPlasticSurfacePtr()));
4676 scalar_field_ptrs->insert(std::make_pair(
4677 "PLASTIC_MULTIPLIER", common_plastic_ptr->getPlasticTauPtr()));
4678 vector_field_ptrs->insert(std::make_pair("U", u_field_ptr));
4679 vector_field_ptrs->insert(std::make_pair("FLUX", FLUX_field_ptr));
4680 sym_tensor_field_ptrs->insert(
4681 std::make_pair("STRAIN", common_plastic_ptr->mStrainPtr));
4682 sym_tensor_field_ptrs->insert(
4683 std::make_pair("STRESS", common_plastic_ptr->mStressPtr));
4684 sym_tensor_field_ptrs->insert(std::make_pair(
4685 "PLASTIC_STRAIN", common_plastic_ptr->getPlasticStrainPtr()));
4686 sym_tensor_field_ptrs->insert(std::make_pair(
4687 "PLASTIC_FLOW", common_plastic_ptr->getPlasticFlowPtr()));
4688 }
4689 }
4690 } else if (atom_test > 0) {
4691 field_eval_data =
4692 mField.getInterface<FieldEvaluatorInterface>()->getData<DomainEle>();
4693
4694 CHKERR mField.getInterface<FieldEvaluatorInterface>()->buildTree<SPACE_DIM>(
4695 field_eval_data, simple->getDomainFEName());
4696
4697 field_eval_data->setEvalPoints(field_eval_coords.data(), 1);
4698 auto no_rule = [](int, int, int) { return -1; };
4699
4700 auto field_eval_fe_ptr = field_eval_data->feMethodPtr.lock();
4701 field_eval_fe_ptr->getRuleHook = no_rule;
4702
4704 field_eval_fe_ptr->getOpPtrVector(), {H1, HDIV});
4705
4706 ScalerFunTwoArgs unity_2_args = [&](const double, const double) {
4707 return 1.;
4708 };
4709 ScalerFunThreeArgs unity_3_args = [&](const double, const double,
4710 const double) { return 1.; };
4711
4712 auto [common_plastic_ptr, common_hencky_ptr, common_thermal_ptr,
4713 common_thermoelastic_ptr, common_thermoplastic_ptr] =
4714 createCommonThermoPlasticOps<SPACE_DIM, IT, DomainEleOp>(
4715 mField, "MAT_PLASTIC", "MAT_THERMAL", "MAT_THERMOELASTIC",
4716 "MAT_THERMOPLASTIC", field_eval_fe_ptr->getOpPtrVector(), "U", "EP",
4717 "TAU", "T", 1, unity_2_args, unity_2_args, unity_3_args,
4718 Sev::inform);
4719
4720 auto dispGradPtr = common_hencky_ptr->matGradPtr;
4721 auto mat_stress_ptr = boost::make_shared<MatrixDouble>();
4722
4723 auto coeff_expansion_ptr = common_thermoelastic_ptr->getCoeffExpansionPtr();
4724 auto ref_temp_ptr = common_thermoelastic_ptr->getRefTempPtr();
4725
4726 field_eval_fe_ptr->getOpPtrVector().push_back(
4727 new OpCalculateScalarFieldValues("T", tempFieldPtr));
4728 field_eval_fe_ptr->getOpPtrVector().push_back(
4729 new OpCalculateHVecVectorField<3, SPACE_DIM>("FLUX", fluxFieldPtr));
4730 field_eval_fe_ptr->getOpPtrVector().push_back(
4731 new OpCalculateVectorFieldValues<SPACE_DIM>("U", dispFieldPtr));
4732 field_eval_fe_ptr->getOpPtrVector().push_back(
4734 dispGradPtr));
4735 plasticMultiplierFieldPtr = common_plastic_ptr->getPlasticTauPtr();
4736 plasticStrainFieldPtr = common_plastic_ptr->getPlasticStrainPtr();
4737
4739
4740 field_eval_fe_ptr->getOpPtrVector().push_back(
4741 new typename H::template OpCalculateHenckyThermoPlasticStress<SPACE_DIM,
4742 IT, 0>(
4743 "U", tempFieldPtr, common_hencky_ptr, coeff_expansion_ptr,
4744 ref_temp_ptr));
4745 if (!IS_LARGE_STRAINS) {
4746 field_eval_fe_ptr->getOpPtrVector().push_back(
4748 common_hencky_ptr->getMatFirstPiolaStress(), stressFieldPtr));
4749 field_eval_fe_ptr->getOpPtrVector().push_back(
4750 new OpSymmetrizeTensor<SPACE_DIM>(dispGradPtr, strainFieldPtr));
4751 } else {
4752 field_eval_fe_ptr->getOpPtrVector().push_back(
4753 new typename H::template OpCalculateLogC<SPACE_DIM, IT>(
4754 "U", common_hencky_ptr));
4755 stressFieldPtr = common_hencky_ptr->getMatFirstPiolaStress();
4756 strainFieldPtr = common_hencky_ptr->getMatLogC();
4757 };
4758 }
4759
4760 auto set_time_monitor = [&](auto dm, auto solver) {
4762 if (atom_test == 0) {
4763 boost::shared_ptr<Monitor<SPACE_DIM>> monitor_ptr(new Monitor<SPACE_DIM>(
4764 dm, create_post_process_elements(), reactionFe, uXScatter, uYScatter,
4765 uZScatter, field_eval_coords, field_eval_data, scalar_field_ptrs,
4766 vector_field_ptrs, sym_tensor_field_ptrs, tensor_field_ptrs));
4767 boost::shared_ptr<ForcesAndSourcesCore> null;
4768 CHKERR DMMoFEMTSSetMonitor(dm, solver, simple->getDomainFEName(),
4769 monitor_ptr, null, null);
4770 } else {
4771
4772 test_monitor_ptr->preProcessHook = [&]() {
4774
4775 CHKERR mField.getInterface<FieldEvaluatorInterface>()
4776 ->evalFEAtThePoint<SPACE_DIM>(
4777 field_eval_coords.data(), 1e-12, simple->getProblemName(),
4778 simple->getDomainFEName(), field_eval_data,
4779 mField.get_comm_rank(), mField.get_comm_rank(), nullptr,
4780 MF_EXIST, QUIET);
4781
4782 auto eval_num_vec = createVectorMPI(mField.get_comm(), PETSC_DECIDE, 1);
4783 CHKERR VecZeroEntries(eval_num_vec);
4784 if (tempFieldPtr->size()) {
4785 CHKERR VecSetValue(eval_num_vec, 0, 1, ADD_VALUES);
4786 }
4787 CHKERR VecAssemblyBegin(eval_num_vec);
4788 CHKERR VecAssemblyEnd(eval_num_vec);
4789
4790 double eval_num;
4791 CHKERR VecSum(eval_num_vec, &eval_num);
4792 if (!(int)eval_num) {
4793 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
4794 "atom test %d failed: did not find elements to evaluate "
4795 "the field, check the coordinates",
4796 atom_test);
4797 }
4798
4799 if (tempFieldPtr->size()) {
4800 auto t_temp = getFTensor0FromVec(*tempFieldPtr);
4801 MOFEM_LOG("THERMOPLASTICITY", Sev::inform)
4802 << "Eval point T magnitude: " << t_temp;
4803 if (atom_test && fabs(test_monitor_ptr->ts_t - 10) < 1e-12) {
4804 if (atom_test <= 3 && fabs(t_temp - 554.48) > 1e-2) {
4805 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
4806 "atom test %d failed: wrong temperature value",
4807 atom_test);
4808 }
4809 if (atom_test == 4 && fabs(t_temp - 250) > 1e-2) {
4810 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
4811 "atom test %d failed: wrong temperature value",
4812 atom_test);
4813 }
4814 if (atom_test == 5 && fabs(t_temp - 1) > 1e-2) {
4815 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
4816 "atom test %d failed: wrong temperature value",
4817 atom_test);
4818 }
4819 }
4820 if (atom_test == 8 && fabs(t_temp - 0.5) > 1e-12) {
4821 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
4822 "atom test %d failed: wrong temperature value", atom_test);
4823 }
4824 }
4825 if (fluxFieldPtr->size1()) {
4827 auto t_flux = getFTensor1FromMat<SPACE_DIM>(*fluxFieldPtr);
4828 auto flux_mag = sqrt(t_flux(i) * t_flux(i));
4829 MOFEM_LOG("THERMOPLASTICITY", Sev::inform)
4830 << "Eval point FLUX magnitude: " << flux_mag;
4831 if (atom_test && fabs(test_monitor_ptr->ts_t - 10) < 1e-12) {
4832 if (atom_test <= 3 && fabs(flux_mag - 27008.0) > 2e1) {
4833 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
4834 "atom test %d failed: wrong flux value", atom_test);
4835 }
4836 if (atom_test == 4 && fabs(flux_mag - 150e3) > 1e-1) {
4837 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
4838 "atom test %d failed: wrong flux value", atom_test);
4839 }
4840 if (atom_test == 5 && fabs(flux_mag) > 1e-6) {
4841 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
4842 "atom test %d failed: wrong flux value", atom_test);
4843 }
4844 }
4845 }
4846 if (dispFieldPtr->size1()) {
4848 auto t_disp = getFTensor1FromMat<SPACE_DIM>(*dispFieldPtr);
4849 auto disp_mag = sqrt(t_disp(i) * t_disp(i));
4850 MOFEM_LOG("THERMOPLASTICITY", Sev::inform)
4851 << "Eval point U magnitude: " << disp_mag;
4852 if (atom_test && fabs(test_monitor_ptr->ts_t - 10) < 1e-12) {
4853 if (atom_test == 1 && fabs(disp_mag - 0.00345) > 1e-5) {
4854 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
4855 "atom test %d failed: wrong displacement value",
4856 atom_test);
4857 }
4858 if ((atom_test == 2 || atom_test == 3) &&
4859 fabs(disp_mag - 0.00265) > 1e-5) {
4860 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
4861 "atom test %d failed: wrong displacement value",
4862 atom_test);
4863 }
4864 if ((atom_test == 5) &&
4865 fabs(t_disp(0) - (std::sqrt(std::exp(0.2)) - 1)) > 1e-5 &&
4866 fabs(t_disp(1) - (std::sqrt(std::exp(0.2)) - 1)) > 1e-5) {
4867 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
4868 "atom test %d failed: wrong displacement value",
4869 atom_test);
4870 }
4871 }
4872 }
4873 if (strainFieldPtr->size1()) {
4875 auto t_strain =
4876 getFTensor2SymmetricFromMat<SPACE_DIM>(*strainFieldPtr);
4877 auto t_strain_trace = t_strain(i, i);
4878 if (atom_test && fabs(test_monitor_ptr->ts_t - 10) < 1e-12) {
4879 if (atom_test == 1 && fabs(t_strain_trace - 0.00679) > 1e-5) {
4880 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
4881 "atom test %d failed: wrong strain value", atom_test);
4882 }
4883 if ((atom_test == 2 || atom_test == 3) &&
4884 fabs(t_strain_trace - 0.00522) > 1e-5) {
4885 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
4886 "atom test %d failed: wrong strain value", atom_test);
4887 }
4888 if ((atom_test == 5) && fabs(t_strain_trace - 0.2) > 1e-5) {
4889 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
4890 "atom test %d failed: wrong strain value", atom_test);
4891 }
4892 }
4893 }
4894 if (stressFieldPtr->size1()) {
4895 double von_mises_stress;
4896 auto getVonMisesStress = [&](auto t_stress) {
4898 von_mises_stress = std::sqrt(
4899 0.5 *
4900 ((t_stress(0, 0) - t_stress(1, 1)) *
4901 (t_stress(0, 0) - t_stress(1, 1)) +
4902 (SPACE_DIM == 3 ? (t_stress(1, 1) - t_stress(2, 2)) *
4903 (t_stress(1, 1) - t_stress(2, 2))
4904 : 0) +
4905 (SPACE_DIM == 3 ? (t_stress(2, 2) - t_stress(0, 0)) *
4906 (t_stress(2, 2) - t_stress(0, 0))
4907 : 0) +
4908 6 * (t_stress(0, 1) * t_stress(0, 1) +
4909 (SPACE_DIM == 3 ? t_stress(1, 2) * t_stress(1, 2) : 0) +
4910 (SPACE_DIM == 3 ? t_stress(2, 0) * t_stress(2, 0) : 0))));
4912 };
4913 if (!IS_LARGE_STRAINS) {
4914 auto t_stress =
4915 getFTensor2SymmetricFromMat<SPACE_DIM>(*stressFieldPtr);
4916 CHKERR getVonMisesStress(t_stress);
4917 } else {
4918 auto t_stress =
4919 getFTensor2FromMat<SPACE_DIM, SPACE_DIM>(*stressFieldPtr);
4920 CHKERR getVonMisesStress(t_stress);
4921 }
4922 MOFEM_LOG("THERMOPLASTICITY", Sev::inform)
4923 << "Eval point von Mises Stress: " << von_mises_stress;
4924 if (atom_test && fabs(test_monitor_ptr->ts_t - 10) < 1e-12) {
4925 if (atom_test == 1 && fabs(von_mises_stress - 523.0) > 5e-1) {
4926 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
4927 "atom test %d failed: wrong von Mises stress value",
4928 atom_test);
4929 }
4930 if (atom_test == 2 && fabs(von_mises_stress - 16.3) > 5e-2) {
4931 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
4932 "atom test %d failed: wrong von Mises stress value",
4933 atom_test);
4934 }
4935 if (atom_test == 3 && fabs(von_mises_stress - 14.9) > 5e-2) {
4936 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
4937 "atom test %d failed: wrong von Mises stress value",
4938 atom_test);
4939 }
4940 if (atom_test == 5 && fabs(von_mises_stress) > 5e-2) {
4941 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
4942 "atom test %d failed: wrong von Mises stress value",
4943 atom_test);
4944 }
4945 }
4946 }
4947 if (plasticMultiplierFieldPtr->size()) {
4948 auto t_plastic_multiplier =
4949 getFTensor0FromVec(*plasticMultiplierFieldPtr);
4950 MOFEM_LOG("THERMOPLASTICITY", Sev::inform)
4951 << "Eval point TAU magnitude: " << t_plastic_multiplier;
4952 if (atom_test == 8 && fabs(t_plastic_multiplier - 1.5) > 1e-12) {
4953 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
4954 "atom test %d failed: wrong plastic multiplier value",
4955 atom_test);
4956 }
4957 }
4958 if (plasticStrainFieldPtr->size1()) {
4961 auto t_plastic_strain =
4962 getFTensor2SymmetricFromMat<SPACE_DIM>(*plasticStrainFieldPtr);
4963 MOFEM_LOG("THERMOPLASTICITY", Sev::inform)
4964 << "Eval point EP(0,0) = " << t_plastic_strain(0, 0)
4965 << ", EP(0,1) = " << t_plastic_strain(0, 1)
4966 << ", EP(1,1) = " << t_plastic_strain(1, 1);
4967 if (atom_test == 8) {
4968 if (fabs(t_plastic_strain(0, 0) - 0.005) > 1e-12) {
4969 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
4970 "atom test %d failed: wrong EP(0,0) value", atom_test);
4971 }
4972 if (fabs(t_plastic_strain(0, 1) - 0.025) > 1e-12) {
4973 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
4974 "atom test %d failed: wrong EP(0,1) value", atom_test);
4975 }
4976 if (fabs(t_plastic_strain(1, 1) - 0.015) > 1e-12) {
4977 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
4978 "atom test %d failed: wrong EP(1,1) value", atom_test);
4979 }
4980 }
4981 }
4982
4983 MOFEM_LOG_SYNCHRONISE(mField.get_comm());
4985 };
4986 auto null = boost::shared_ptr<FEMethod>();
4987 CHKERR DMMoFEMTSSetMonitor(dm, solver, simple->getDomainFEName(), null,
4988 test_monitor_ptr, null);
4989 };
4990
4992 };
4993
4994 auto set_schur_pc = [&](auto solver,
4995 boost::shared_ptr<SetUpSchur> &schur_ptr) {
4997
4998 auto name_prb = simple->getProblemName();
4999
5000 // create sub dm for Schur complement
5001 auto create_schur_dm = [&](SmartPetscObj<DM> base_dm,
5002 SmartPetscObj<DM> &dm_sub) {
5004 dm_sub = createDM(mField.get_comm(), "DMMOFEM");
5005 CHKERR DMMoFEMCreateSubDM(dm_sub, base_dm, "SCHUR");
5006 CHKERR DMMoFEMSetSquareProblem(dm_sub, PETSC_TRUE);
5007 CHKERR DMMoFEMAddElement(dm_sub, simple->getDomainFEName());
5008 CHKERR DMMoFEMAddElement(dm_sub, simple->getBoundaryFEName());
5009 for (auto f : {"U", "FLUX"}) {
5012 }
5013 CHKERR DMSetUp(dm_sub);
5014
5016 };
5017
5018 auto create_block_dm = [&](SmartPetscObj<DM> base_dm,
5019 SmartPetscObj<DM> &dm_sub) {
5021 dm_sub = createDM(mField.get_comm(), "DMMOFEM");
5022 CHKERR DMMoFEMCreateSubDM(dm_sub, base_dm, "BLOCK");
5023 CHKERR DMMoFEMSetSquareProblem(dm_sub, PETSC_TRUE);
5024 CHKERR DMMoFEMAddElement(dm_sub, simple->getDomainFEName());
5025 CHKERR DMMoFEMAddElement(dm_sub, simple->getBoundaryFEName());
5026#ifdef ADD_CONTACT
5027 for (auto f : {"SIGMA", "EP", "TAU", "T"}) {
5030 }
5031#else
5032 for (auto f : {"EP", "TAU", "T"}) {
5035 }
5036#endif
5037 CHKERR DMSetUp(dm_sub);
5039 };
5040
5041 // Create nested (sub BC) Schur DM
5042 if constexpr (AT == AssemblyType::BLOCK_SCHUR) {
5043
5044 SmartPetscObj<DM> dm_schur;
5045 CHKERR create_schur_dm(simple->getDM(), dm_schur);
5046 SmartPetscObj<DM> dm_block;
5047 CHKERR create_block_dm(simple->getDM(), dm_block);
5048
5049#ifdef ADD_CONTACT
5050
5051 auto get_nested_mat_data = [&](auto schur_dm, auto block_dm) {
5052 auto block_mat_data = createBlockMatStructure(
5053 simple->getDM(),
5054
5055 {
5056
5057 {simple->getDomainFEName(),
5058
5059 {{"U", "U"},
5060 {"SIGMA", "SIGMA"},
5061 {"U", "SIGMA"},
5062 {"SIGMA", "U"},
5063 {"EP", "EP"},
5064 {"TAU", "TAU"},
5065 {"U", "EP"},
5066 {"EP", "U"},
5067 {"EP", "TAU"},
5068 {"TAU", "EP"},
5069 {"TAU", "U"},
5070 {"T", "T"},
5071 {"U", "T"},
5072 {"T", "U"},
5073 {"EP", "T"},
5074 {"T", "EP"},
5075 {"TAU", "T"},
5076 {"T", "TAU"}
5077
5078 }},
5079
5080 {simple->getBoundaryFEName(),
5081
5082 {{"SIGMA", "SIGMA"}, {"U", "SIGMA"}, {"SIGMA", "U"}
5083
5084 }}
5085
5086 }
5087
5088 );
5089
5091
5092 {dm_schur, dm_block}, block_mat_data,
5093
5094 {"SIGMA", "EP", "TAU", "T"}, {nullptr, nullptr, nullptr, nullptr},
5095 true
5096
5097 );
5098 };
5099
5100#else
5101
5102 auto get_nested_mat_data = [&](auto schur_dm, auto block_dm) {
5103 auto block_mat_data =
5105
5106 {{simple->getDomainFEName(),
5107
5108 {{"U", "U"},
5109 {"EP", "EP"},
5110 {"TAU", "TAU"},
5111 {"U", "EP"},
5112 {"EP", "U"},
5113 {"EP", "TAU"},
5114 {"TAU", "U"},
5115 {"TAU", "EP"},
5116 {"T", "T"},
5117 {"T", "U"},
5118 {"T", "FLUX"},
5119 {"T", "EP"},
5120 {"FLUX", "T"},
5121 {"FLUX", "U"},
5122 {"U", "T"},
5123 {"EP", "T"},
5124 {"TAU", "T"}
5125
5126 }}}
5127
5128 );
5129
5131
5132 {dm_schur, dm_block}, block_mat_data,
5133
5134 {"EP", "TAU", "T"}, {nullptr, nullptr, nullptr}, false
5135
5136 );
5137 };
5138
5139#endif
5140
5141 auto nested_mat_data = get_nested_mat_data(dm_schur, dm_block);
5142 CHKERR DMMoFEMSetNestSchurData(simple->getDM(), nested_mat_data);
5143
5144 auto block_is = getDMSubData(dm_block)->getSmartRowIs();
5145 auto ao_schur = getDMSubData(dm_schur)->getSmartRowMap();
5146
5147 // Indices has to be map fro very to level, while assembling Schur
5148 // complement.
5149 schur_ptr =
5150 SetUpSchur::createSetUpSchur(mField, dm_schur, block_is, ao_schur);
5151 CHKERR schur_ptr->setUp(solver);
5152 }
5153
5155 };
5156
5157 auto dm = simple->getDM();
5158 auto D = createDMVector(dm);
5159 auto DD = vectorDuplicate(D);
5160 uXScatter = scatter_create(D, 0);
5161 uYScatter = scatter_create(D, 1);
5162 if constexpr (SPACE_DIM == 3)
5163 uZScatter = scatter_create(D, 2);
5164
5165 auto create_solver = [pip_mng]() {
5166 if (is_quasi_static == PETSC_TRUE)
5167 return pip_mng->createTSIM();
5168 else
5169 return pip_mng->createTSIM2();
5170 };
5171
5172 SmartPetscObj<Vec> solution_vector;
5173 CHKERR DMCreateGlobalVector_MoFEM(dm, solution_vector);
5174
5175 if (restart_flg) {
5176 PetscViewer viewer;
5177 CHKERR PetscViewerBinaryOpen(PETSC_COMM_WORLD, restart_file, FILE_MODE_READ,
5178 &viewer);
5179 CHKERR VecLoad(solution_vector, viewer);
5180 CHKERR PetscViewerDestroy(&viewer);
5181 CHKERR DMoFEMMeshToLocalVector(dm, solution_vector, INSERT_VALUES,
5182 SCATTER_REVERSE);
5183 }
5184
5185 auto solver = create_solver();
5186
5187 auto active_pre_lhs = []() {
5189 std::fill(PlasticOps::CommonData::activityData.begin(),
5192 };
5193
5194 auto active_post_lhs = [&]() {
5196 auto get_iter = [&]() {
5197 SNES snes;
5198 CHK_THROW_MESSAGE(TSGetSNES(solver, &snes), "Can not get SNES");
5199 int iter;
5200 CHK_THROW_MESSAGE(SNESGetIterationNumber(snes, &iter),
5201 "Can not get iter");
5202 return iter;
5203 };
5204
5205 auto iter = get_iter();
5206 if (iter >= 0) {
5207
5208 std::array<int, 5> activity_data;
5209 std::fill(activity_data.begin(), activity_data.end(), 0);
5210 MPI_Allreduce(PlasticOps::CommonData::activityData.data(),
5211 activity_data.data(), activity_data.size(), MPI_INT,
5212 MPI_SUM, mField.get_comm());
5213
5214 int &active_points = activity_data[0];
5215 int &avtive_full_elems = activity_data[1];
5216 int &avtive_elems = activity_data[2];
5217 int &nb_points = activity_data[3];
5218 int &nb_elements = activity_data[4];
5219
5220 if (nb_points) {
5221
5222 double proc_nb_points =
5223 100 * static_cast<double>(active_points) / nb_points;
5224 double proc_nb_active =
5225 100 * static_cast<double>(avtive_elems) / nb_elements;
5226 double proc_nb_full_active = 100;
5227 if (avtive_elems)
5228 proc_nb_full_active =
5229 100 * static_cast<double>(avtive_full_elems) / avtive_elems;
5230
5231 MOFEM_LOG_C("PLASTICITY", Sev::inform,
5232 "Iter %d nb pts %d nb active pts %d (%3.3f\%) nb active "
5233 "elements %d "
5234 "(%3.3f\%) nb full active elems %d (%3.3f\%)",
5235 iter, nb_points, active_points, proc_nb_points,
5236 avtive_elems, proc_nb_active, avtive_full_elems,
5237 proc_nb_full_active, iter);
5238 }
5239 }
5240
5242 };
5243
5244 auto add_active_dofs_elem = [&](auto dm) {
5246 auto fe_pre_proc = boost::make_shared<FEMethod>();
5247 fe_pre_proc->preProcessHook = active_pre_lhs;
5248 auto fe_post_proc = boost::make_shared<FEMethod>();
5249 fe_post_proc->postProcessHook = active_post_lhs;
5250 auto ts_ctx_ptr = getDMTsCtx(dm);
5251 ts_ctx_ptr->getPreProcessIJacobian().push_front(fe_pre_proc);
5252 ts_ctx_ptr->getPostProcessIJacobian().push_back(fe_post_proc);
5254 };
5255
5256 auto set_essential_bc = [&](auto dm, auto solver) {
5258 // This is low level pushing finite elements (pipelines) to solver
5259
5260 auto pre_proc_ptr = boost::make_shared<FEMethod>();
5261 auto post_proc_rhs_ptr = boost::make_shared<FEMethod>();
5262 auto post_proc_lhs_ptr = boost::make_shared<FEMethod>();
5263
5264 // Add boundary condition scaling
5265 auto disp_time_scale = boost::make_shared<TimeScale>();
5266
5267 auto get_bc_hook_rhs = [this, pre_proc_ptr, disp_time_scale]() {
5268 EssentialPreProc<DisplacementCubitBcData> hook(mField, pre_proc_ptr,
5269 {disp_time_scale}, false);
5270 return hook;
5271 };
5272 pre_proc_ptr->preProcessHook = get_bc_hook_rhs();
5273
5274 auto get_post_proc_hook_rhs = [this, post_proc_rhs_ptr]() {
5277 mField, post_proc_rhs_ptr, nullptr, Sev::verbose)();
5279 mField, post_proc_rhs_ptr, 1.)();
5281 };
5282 auto get_post_proc_hook_lhs = [this, post_proc_lhs_ptr]() {
5284 mField, post_proc_lhs_ptr, 1.);
5285 };
5286 post_proc_rhs_ptr->postProcessHook = get_post_proc_hook_rhs;
5287
5288 auto ts_ctx_ptr = getDMTsCtx(dm);
5289 ts_ctx_ptr->getPreProcessIFunction().push_front(pre_proc_ptr);
5290 ts_ctx_ptr->getPreProcessIJacobian().push_front(pre_proc_ptr);
5291 ts_ctx_ptr->getPostProcessIFunction().push_back(post_proc_rhs_ptr);
5292 post_proc_lhs_ptr->postProcessHook = get_post_proc_hook_lhs();
5293 ts_ctx_ptr->getPostProcessIJacobian().push_back(post_proc_lhs_ptr);
5294
5296 };
5297
5298 CHKERR DMoFEMMeshToLocalVector(dm, D, INSERT_VALUES, SCATTER_FORWARD);
5299
5300 if (is_quasi_static == PETSC_TRUE) {
5301 CHKERR TSSetSolution(solver, D);
5302 } else {
5303 CHKERR TS2SetSolution(solver, D, DD);
5304 }
5305
5306 auto set_up_adapt = [&](auto solver) {
5308 CHKERR TSAdaptRegister(TSADAPTMOFEM, TSAdaptCreateMoFEM);
5309 TSAdapt adapt;
5310 CHKERR TSGetAdapt(solver, &adapt);
5312 };
5313
5314 CHKERR set_section_monitor(solver);
5315 CHKERR set_time_monitor(dm, solver);
5316 CHKERR set_up_adapt(solver);
5317 CHKERR TSSetFromOptions(solver);
5318
5319 thermoplastic_raw_ptr = this;
5320
5321 CHKERR TSSetTime(solver, restart_time);
5322 CHKERR TSSetStepNumber(solver, restart_step);
5323
5324 CHKERR add_active_dofs_elem(dm);
5325 boost::shared_ptr<SetUpSchur> schur_ptr;
5326 CHKERR set_schur_pc(solver, schur_ptr);
5327 CHKERR set_essential_bc(dm, solver);
5328
5329 auto my_ctx = boost::make_shared<MyTsCtx>();
5330
5331 ts_to_ctx[solver] = my_ctx.get();
5332
5333 SNES snes;
5334 CHKERR TSGetSNES(solver, &snes);
5335
5336 CHKERR SNESMonitorSet(snes, SNESIterationMonitor, my_ctx.get(), NULL);
5337
5338 CHKERR TSSetPreStage(solver, TSIterationPreStage);
5339
5340 auto my_rhs = [](TS ts, PetscReal t, Vec u, Vec u_t, Vec F, void *ctx) {
5341 MyTsCtx *my_ts_ctx = static_cast<MyTsCtx *>(ctx);
5342 auto ts_ctx = my_ts_ctx->dmts_ctx;
5343 auto &m_field = ts_ctx->mField;
5344 auto simple = m_field.getInterface<Simple>();
5345
5346 // Get the iteration number of the snes solver
5347 SNES snes;
5348 CHK_THROW_MESSAGE(TSGetSNES(ts, &snes), "Cannot get SNES");
5349
5350 double time_increment;
5351 CHK_THROW_MESSAGE(TSGetTimeStep(ts, &time_increment), "Cannot get iter");
5352 if (time_increment < min_dt) {
5353 SETERRQ(PETSC_COMM_SELF, MOFEM_STD_EXCEPTION_THROW,
5354 "Minimum time increment exceeded");
5355 }
5356
5357 if (my_ts_ctx->snes_iter_counter == 0) {
5358 int error = system("rm ./out_snes_residual_iter_*.h5m > /dev/null 2>&1");
5359 }
5360
5361 // Get the time step
5362 double ts_dt;
5363 CHK_THROW_MESSAGE(TSGetTimeStep(ts, &ts_dt),
5364 "Cannot get timestep from TS object");
5365
5366 if (ts_dt < min_dt) {
5367 SETERRQ(PETSC_COMM_SELF, MOFEM_STD_EXCEPTION_THROW,
5368 "Minimum timestep exceeded");
5369 }
5370
5371 // Post process the residuals
5372 auto post_proc = [&](auto dm, auto f_res, auto sol, auto sol_dot,
5373 auto out_name) {
5375
5376 auto smart_f_res = SmartPetscObj<Vec>(f_res, true);
5377 auto smart_sol = SmartPetscObj<Vec>(sol, true);
5378 auto smart_sol_dot = SmartPetscObj<Vec>(sol_dot, true);
5379
5380 auto post_proc_fe =
5381 boost::make_shared<PostProcBrokenMeshInMoab<DomainEle>>(
5382 ts_ctx->mField);
5383 auto &pip = post_proc_fe->getOpPtrVector();
5385
5387
5388 // pointers for residuals
5389 auto disp_res_mat = boost::make_shared<MatrixDouble>();
5390 auto tau_res_vec = boost::make_shared<VectorDouble>();
5391 auto plastic_strain_res_mat = boost::make_shared<MatrixDouble>();
5392 auto flux_res_mat = boost::make_shared<MatrixDouble>();
5393 auto temp_res_vec = boost::make_shared<VectorDouble>();
5394
5396 "U", disp_res_mat, smart_f_res));
5397 pip.push_back(
5398 new OpCalculateScalarFieldValues("TAU", tau_res_vec, smart_f_res));
5400 "EP", plastic_strain_res_mat, smart_f_res));
5401 // pip.push_back(
5402 // new OpCalculateHVecVectorField<3, SPACE_DIM>("FLUX", flux_res_mat,
5403 // smart_f_res));
5404 pip.push_back(
5405 new OpCalculateScalarFieldValues("T", temp_res_vec, smart_f_res));
5406
5407 // pointers for fields
5408 auto disp_mat = boost::make_shared<MatrixDouble>();
5409 auto tau_vec = boost::make_shared<VectorDouble>();
5410 auto plastic_strain_mat = boost::make_shared<MatrixDouble>();
5411 auto flux_mat = boost::make_shared<MatrixDouble>();
5412 auto temp_vec = boost::make_shared<VectorDouble>();
5413
5414 pip.push_back(new OpCalculateVectorFieldValues<SPACE_DIM>("U", disp_mat));
5415 pip.push_back(new OpCalculateScalarFieldValues("TAU", tau_vec));
5417 "EP", plastic_strain_mat));
5418 // pip.push_back(
5419 // new OpCalculateVectorFieldValues<SPACE_DIM>("FLUX", flux_mat,
5420 // smart_sol));
5421 pip.push_back(new OpCalculateScalarFieldValues("T", temp_vec));
5422
5423 // pointers for rates of fields
5424 auto disp_dot_mat = boost::make_shared<MatrixDouble>();
5425 auto tau_dot_vec = boost::make_shared<VectorDouble>();
5426 auto plastic_strain_dot_mat = boost::make_shared<MatrixDouble>();
5427 auto flux_dot_mat = boost::make_shared<MatrixDouble>();
5428 auto temp_dot_vec = boost::make_shared<VectorDouble>();
5429
5431 "U", disp_dot_mat, smart_sol_dot));
5432 pip.push_back(
5433 new OpCalculateScalarFieldValues("TAU", tau_dot_vec, smart_sol_dot));
5435 "EP", plastic_strain_dot_mat, smart_sol_dot));
5436 // pip.push_back(
5437 // new OpCalculateHVecVectorField<3, SPACE_DIM>("FLUX", flux_dot_mat,
5438 // smart_sol_dot));
5439 pip.push_back(
5440 new OpCalculateScalarFieldValues("T", temp_dot_vec, smart_sol_dot));
5441
5442 constexpr auto size_symm = (SPACE_DIM * (SPACE_DIM + 1)) / 2;
5443 auto make_d_mat = [&]() {
5444 return boost::make_shared<MatrixDouble>(size_symm * size_symm, 1);
5445 };
5446
5447 auto push_vol_ops = [&](auto &pip) {
5448 ScalerFunTwoArgs unity_2_args = [&](const double, const double) {
5449 return 1.;
5450 };
5451 ScalerFunThreeArgs unity_3_args = [&](const double, const double,
5452 const double) { return 1.; };
5453
5454 auto [common_plastic_ptr, common_hencky_ptr, common_thermal_ptr,
5455 common_thermoelastic_ptr, common_thermoplastic_ptr] =
5458 m_field, "MAT_PLASTIC", "MAT_THERMAL", "MAT_THERMOELASTIC",
5459 "MAT_THERMOPLASTIC", pip, "U", "EP", "TAU", "T", 1.,
5460 unity_2_args, unity_2_args, unity_3_args, Sev::inform);
5461
5462 if (common_hencky_ptr) {
5463 if (common_plastic_ptr->mGradPtr != common_hencky_ptr->matGradPtr)
5465 "Wrong pointer for grad");
5466 }
5467
5468 return std::make_tuple(common_plastic_ptr, common_hencky_ptr,
5469 common_thermoplastic_ptr);
5470 };
5471
5472 auto push_vol_post_proc_ops = [&](auto &pp_fe, auto &&p) {
5474
5475 auto &pip = pp_fe->getOpPtrVector();
5476
5477 auto [common_plastic_ptr, common_hencky_ptr, common_thermoplastic_ptr] =
5478 p;
5479
5480 auto mat_strain_ptr = boost::make_shared<MatrixDouble>();
5481 auto mat_stress_ptr = boost::make_shared<MatrixDouble>();
5482
5483 auto vec_temp_ptr = boost::make_shared<VectorDouble>();
5484 auto mat_flux_ptr = boost::make_shared<MatrixDouble>();
5485
5486 auto u_ptr = boost::make_shared<MatrixDouble>();
5487 pip.push_back(new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_ptr));
5488
5490
5491 if (is_large_strains) {
5492
5493 pip.push_back(
5494
5495 new OpPPMap(
5496
5497 pp_fe->getPostProcMesh(), pp_fe->getMapGaussPts(),
5498
5499 {{"RESIDUAL_TAU", tau_res_vec},
5500 {"RESIDUAL_T", temp_res_vec},
5501 {"TAU", tau_vec},
5502 {"T", temp_vec},
5503 {"RATE_TAU", tau_dot_vec},
5504 {"RATE_T", temp_dot_vec},
5505 {"ISOTROPIC_HARDENING",
5506 common_plastic_ptr->getPlasticIsoHardeningPtr()},
5507 {"PLASTIC_SURFACE",
5508 common_plastic_ptr->getPlasticSurfacePtr()},
5509 {"PLASTIC_MULTIPLIER",
5510 common_plastic_ptr->getPlasticTauPtr()},
5511 {"YIELD_FUNCTION",
5512 common_plastic_ptr->getPlasticSurfacePtr()},
5513 {"T", common_thermoplastic_ptr->getTempPtr()}},
5514
5515 {{"RESIDUAL_U", disp_res_mat},
5516 {"RATE_U", disp_dot_mat},
5517 {"U", u_ptr},
5518 {"FLUX", common_thermoplastic_ptr->getHeatFluxPtr()}},
5519
5520 {{"GRAD", common_hencky_ptr->matGradPtr},
5521 {"FIRST_PIOLA",
5522 common_hencky_ptr->getMatFirstPiolaStress()}},
5523
5524 {{"RESIDUAL_EP", plastic_strain_res_mat},
5525 {"RATE_EP", plastic_strain_dot_mat},
5526 {"PLASTIC_STRAIN",
5527 common_plastic_ptr->getPlasticStrainPtr()},
5528 {"PLASTIC_FLOW", common_plastic_ptr->getPlasticFlowPtr()},
5529 {"HENCKY_STRAIN", common_hencky_ptr->getMatLogC()},
5530 {"HENCKY_STRESS", common_hencky_ptr->getMatHenckyStress()}}
5531
5532 )
5533
5534 );
5535
5536 } else {
5537
5538 pip.push_back(
5539
5540 new OpPPMap(
5541
5542 pp_fe->getPostProcMesh(), pp_fe->getMapGaussPts(),
5543
5544 {{"RESIDUAL_TAU", tau_res_vec},
5545 {"RESIDUAL_T", temp_res_vec},
5546 {"TAU", tau_vec},
5547 {"T", temp_vec},
5548 {"RATE_TAU", tau_dot_vec},
5549 {"RATE_T", temp_dot_vec},
5550 {"ISOTROPIC_HARDENING",
5551 common_plastic_ptr->getPlasticIsoHardeningPtr()},
5552 {"PLASTIC_SURFACE",
5553 common_plastic_ptr->getPlasticSurfacePtr()},
5554 {"PLASTIC_MULTIPLIER",
5555 common_plastic_ptr->getPlasticTauPtr()},
5556 {"YIELD_FUNCTION",
5557 common_plastic_ptr->getPlasticSurfacePtr()},
5558 {"T", common_thermoplastic_ptr->getTempPtr()}},
5559
5560 {{"RESIDUAL_U", disp_res_mat},
5561 // {"RESIDUAL_FLUX", flux_res_mat},
5562 {"U", disp_mat},
5563 // {"FLUX", flux_mat},
5564 {"RATE_U", disp_dot_mat},
5565 {"U", u_ptr},
5566 {"FLUX", common_thermoplastic_ptr->getHeatFluxPtr()}},
5567
5568 {},
5569
5570 {{"RESIDUAL_PLASTIC_STRAIN", plastic_strain_res_mat},
5571 {"PLASTIC_STRAIN", plastic_strain_mat},
5572 {"RATE_PLASTIC_STRAIN", plastic_strain_dot_mat},
5573 {"STRAIN", common_plastic_ptr->mStrainPtr},
5574 {"STRESS", common_plastic_ptr->mStressPtr},
5575 {"PLASTIC_STRAIN",
5576 common_plastic_ptr->getPlasticStrainPtr()},
5577 {"PLASTIC_FLOW", common_plastic_ptr->getPlasticFlowPtr()}}
5578
5579 )
5580
5581 );
5582 }
5583
5585 };
5586
5587 CHK_MOAB_THROW(push_vol_post_proc_ops(post_proc_fe, push_vol_ops(pip)),
5588 "push_vol_post_proc_ops");
5589
5590 CHKERR DMoFEMLoopFiniteElements(dm, simple->getDomainFEName(),
5591 post_proc_fe);
5592
5593 post_proc_fe->writeFile(out_name);
5595 };
5596
5597 // Output the RHS
5598
5599 auto set_RHS = TsSetIFunction(ts, t, u, u_t, F, ts_ctx.get());
5600 CHKERR post_proc(simple->getDM(),
5601 //
5602 F, u, u_t,
5603 //
5604 "out_snes_residual_iter_" +
5605 std::to_string(my_ts_ctx->snes_iter_counter) + ".h5m");
5606 return set_RHS;
5607 };
5608
5609 PetscBool is_output_residual_fields = PETSC_FALSE;
5610 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-output_residual_fields",
5611 &is_output_residual_fields, PETSC_NULLPTR);
5612
5613 if (is_output_residual_fields == PETSC_TRUE) {
5614 my_ctx->dmts_ctx = getDMTsCtx(simple->getDM());
5615 // auto ts_ctx_ptr = getDMTsCtx(simple->getDM());
5616 CHKERR TSSetIFunction(solver, PETSC_NULLPTR, my_rhs, my_ctx.get());
5617 }
5618
5619 CHKERR TSSetDM(solver, dm);
5620
5621 auto ts_pre_post_proc = boost::make_shared<TSPrePostProc>();
5622 tsPrePostProc = ts_pre_post_proc;
5623
5624 if (auto ptr = tsPrePostProc.lock()) {
5625 ptr->ExRawPtr = this;
5626 std::multimap<double, EntityHandle> no_el_q_map;
5627 Range no_flipped_els;
5628 std::vector<EntityHandle> no_new_connectivity;
5629 Tag no_th_spatial_coords;
5630
5631 ResizeCtx *ctx = new ResizeCtx{
5632 &mField, PETSC_FALSE, no_el_q_map,
5633 no_flipped_els, no_new_connectivity, no_th_spatial_coords};
5634 PetscBool rollback =
5635 PETSC_TRUE; // choose true if you want to restart current step
5636 CHKERR TSSetResize(solver, rollback, MyTSResizeSetup, MyTSResizeTransfer,
5637 ctx);
5638 CHKERR TSSetApplicationContext(solver, (void *)ctx);
5639 // ptr->globSol = createDMVector(dm);
5640 // CHKERR DMoFEMMeshToLocalVector(dm, ptr->globSol, INSERT_VALUES,
5641 // SCATTER_FORWARD);
5642 // CHKERR VecAssemblyBegin(ptr->globSol);
5643 // CHKERR VecAssemblyEnd(ptr->globSol);
5644 MOFEM_LOG_CHANNEL("TIMER");
5645 MOFEM_LOG_TAG("TIMER", "timer");
5646 if (set_timer)
5647 BOOST_LOG_SCOPED_THREAD_ATTR("Timeline", attrs::timer());
5648 MOFEM_LOG("TIMER", Sev::verbose) << "TSSetUp";
5649 CHKERR ptr->tsSetUp(solver);
5650 CHKERR TSSetUp(solver);
5651 MOFEM_LOG("TIMER", Sev::verbose) << "TSSetUp <= done";
5652 MOFEM_LOG("TIMER", Sev::verbose) << "TSSolve";
5653 CHKERR TSSolve(solver, PETSC_NULLPTR);
5654 MOFEM_LOG("TIMER", Sev::verbose) << "TSSolve <= done";
5655 }
5656
5658}
5659//! [Solve]
5660
5661static char help[] = "...\n\n";
5662
5663int main(int argc, char *argv[]) {
5664
5665#ifdef ADD_CONTACT
5666 #ifdef ENABLE_PYTHON_BINDING
5667 Py_Initialize();
5668 np::initialize();
5669 #endif
5670#endif // ADD_CONTACT
5671
5672 // Initialisation of MoFEM/PETSc and MOAB data structures
5673 const char param_file[] = "param_file.petsc";
5674 MoFEM::Core::Initialize(&argc, &argv, param_file, help);
5675
5676 // Add logging channel for example
5677 auto core_log = logging::core::get();
5678 core_log->add_sink(
5680 core_log->add_sink(
5682 core_log->add_sink(
5683 LogManager::createSink(LogManager::getStrmWorld(), "THERMOPLASTICITY"));
5684 core_log->add_sink(
5686 core_log->add_sink(
5688 LogManager::setLog("PLASTICITY");
5689 LogManager::setLog("THERMAL");
5690 LogManager::setLog("THERMOPLASTICITY");
5691 LogManager::setLog("REMESHING");
5692 MOFEM_LOG_TAG("PLASTICITY", "Plasticity");
5693 MOFEM_LOG_TAG("THERMAL", "Thermal");
5694 MOFEM_LOG_TAG("THERMOPLASTICITY", "Thermoplasticity");
5695 MOFEM_LOG_TAG("REMESHING", "Remeshing");
5696
5697#ifdef ADD_CONTACT
5698 core_log->add_sink(
5700 LogManager::setLog("CONTACT");
5701 MOFEM_LOG_TAG("CONTACT", "Contact");
5702#endif // ADD_CONTACT
5703
5704 try {
5705
5706 //! [Register MoFEM discrete manager in PETSc]
5707 DMType dm_name = "DMMOFEM";
5708 CHKERR DMRegister_MoFEM(dm_name);
5709 //! [Register MoFEM discrete manager in PETSc
5710
5711 //! [Create MoAB]
5712 moab::Core mb_instance; ///< mesh database
5713 moab::Interface &moab = mb_instance; ///< mesh database interface
5714 //! [Create MoAB]
5715
5716 //! [Create MoFEM]
5717 MoFEM::Core core(moab); ///< finite element database
5718 MoFEM::Interface &m_field = core; ///< finite element database interface
5719 //! [Create MoFEM]
5720
5721 //! [Load mesh]
5722 Simple *simple = m_field.getInterface<Simple>();
5724
5725 simple->getBitRefLevel() = comp_mesh_bit;
5726 simple->getBitRefLevelMask() = BitRefLevel().set();
5727
5728 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-is_distributed_mesh",
5729 &is_distributed_mesh, PETSC_NULLPTR);
5730 if (is_distributed_mesh == PETSC_TRUE) {
5731 CHKERR simple->loadFile();
5732 } else {
5733 char meshFileName[255];
5734 CHKERR PetscOptionsGetString(PETSC_NULLPTR, PETSC_NULLPTR, "-file_name",
5735 meshFileName, 255, PETSC_NULLPTR);
5736 CHKERR simple->loadFile("", meshFileName);
5737 }
5738
5739 Range ents;
5740 CHKERR m_field.get_moab().get_entities_by_dimension(0, SPACE_DIM, ents,
5741 true);
5742 CHKERR m_field.getInterface<BitRefManager>()->setBitRefLevel(
5744 false);
5745 //! [Load mesh]
5746
5747 //! [Example]
5748 Example ex(m_field);
5749 CHKERR ex.runProblem();
5750 //! [Example]
5751 }
5753
5755
5756#ifdef ADD_CONTACT
5757 #ifdef ENABLE_PYTHON_BINDING
5758 if (Py_FinalizeEx() < 0) {
5759 exit(120);
5760 }
5761 #endif
5762#endif // ADD_CONTACT
5763
5764 return 0;
5765}
5766
5767struct SetUpSchurImpl : public SetUpSchur {
5768
5770 SmartPetscObj<IS> field_split_is, SmartPetscObj<AO> ao_up)
5771 : SetUpSchur(), mField(m_field), subDM(sub_dm),
5772 fieldSplitIS(field_split_is), aoSchur(ao_up) {
5773 if (S) {
5775 "Is expected that schur matrix is not "
5776 "allocated. This is "
5777 "possible only is PC is set up twice");
5778 }
5779 }
5780 virtual ~SetUpSchurImpl() { S.reset(); }
5781
5785
5786private:
5788
5789 MoFEM::Interface &mField;
5790 SmartPetscObj<DM> subDM; ///< field split sub dm
5791 SmartPetscObj<IS> fieldSplitIS; ///< IS for split Schur block
5792 SmartPetscObj<AO> aoSchur; ///> main DM to subDM
5793};
5794
5797 auto simple = mField.getInterface<Simple>();
5798 auto pip_mng = mField.getInterface<PipelineManager>();
5799
5800 SNES snes;
5801 CHKERR TSGetSNES(solver, &snes);
5802 KSP ksp;
5803 CHKERR SNESGetKSP(snes, &ksp);
5804 CHKERR KSPSetFromOptions(ksp);
5805
5806 PC pc;
5807 CHKERR KSPGetPC(ksp, &pc);
5808 PetscBool is_pcfs = PETSC_FALSE;
5809 PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &is_pcfs);
5810 if (is_pcfs) {
5811 if (S) {
5813 "Is expected that schur matrix is not "
5814 "allocated. This is "
5815 "possible only is PC is set up twice");
5816 }
5817
5819 CHKERR MatSetBlockSize(S, SPACE_DIM);
5820
5821 // Set DM to use shell block matrix
5822 DM solver_dm;
5823 CHKERR TSGetDM(solver, &solver_dm);
5824 CHKERR DMSetMatType(solver_dm, MATSHELL);
5825
5826 auto ts_ctx_ptr = getDMTsCtx(solver_dm);
5827 auto A = createDMBlockMat(simple->getDM());
5828 auto P = createDMNestSchurMat(simple->getDM());
5829
5830 if (is_quasi_static == PETSC_TRUE) {
5831 auto swap_assemble = [](TS ts, PetscReal t, Vec u, Vec u_t, PetscReal a,
5832 Mat A, Mat B, void *ctx) {
5833 return TsSetIJacobian(ts, t, u, u_t, a, B, A, ctx);
5834 };
5835 CHKERR TSSetIJacobian(solver, A, P, swap_assemble, ts_ctx_ptr.get());
5836 } else {
5837 auto swap_assemble = [](TS ts, PetscReal t, Vec u, Vec u_t, Vec utt,
5838 PetscReal a, PetscReal aa, Mat A, Mat B,
5839 void *ctx) {
5840 return TsSetI2Jacobian(ts, t, u, u_t, utt, a, aa, B, A, ctx);
5841 };
5842 CHKERR TSSetI2Jacobian(solver, A, P, swap_assemble, ts_ctx_ptr.get());
5843 }
5844 CHKERR KSPSetOperators(ksp, A, P);
5845
5846 auto set_ops = [&]() {
5848 auto pip_mng = mField.getInterface<PipelineManager>();
5849
5850#ifndef ADD_CONTACT
5851 // Boundary
5852 pip_mng->getOpBoundaryLhsPipeline().push_front(
5854 pip_mng->getOpBoundaryLhsPipeline().push_back(createOpSchurAssembleEnd(
5855
5856 {"EP", "TAU", "T"}, {nullptr, nullptr, nullptr}, aoSchur, S, false,
5857 false
5858
5859 ));
5860 // Domain
5861 pip_mng->getOpDomainLhsPipeline().push_front(
5863 pip_mng->getOpDomainLhsPipeline().push_back(createOpSchurAssembleEnd(
5864
5865 {"EP", "TAU", "T"}, {nullptr, nullptr, nullptr}, aoSchur, S, false,
5866 false
5867
5868 ));
5869#else
5870
5871 double eps_stab = 1e-4;
5872 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-eps_stab", &eps_stab,
5873 PETSC_NULLPTR);
5874
5877 using OpMassStab = B::OpMass<3, SPACE_DIM * SPACE_DIM>;
5878
5879 // Boundary
5880 pip_mng->getOpBoundaryLhsPipeline().push_front(
5882 pip_mng->getOpBoundaryLhsPipeline().push_back(
5883 new OpMassStab("SIGMA", "SIGMA", [eps_stab](double, double, double) {
5884 return eps_stab;
5885 }));
5886 pip_mng->getOpBoundaryLhsPipeline().push_back(createOpSchurAssembleEnd(
5887
5888 {"SIGMA", "EP", "TAU", "T"}, {nullptr, nullptr, nullptr, nullptr},
5889 aoSchur, S, false, false
5890
5891 ));
5892 // Domain
5893 pip_mng->getOpDomainLhsPipeline().push_front(
5895 pip_mng->getOpDomainLhsPipeline().push_back(createOpSchurAssembleEnd(
5896
5897 {"SIGMA", "EP", "TAU", "T"}, {nullptr, nullptr, nullptr, nullptr},
5898 aoSchur, S, false, false
5899
5900 ));
5901#endif // ADD_CONTACT
5903 };
5904
5905 auto set_assemble_elems = [&]() {
5907 auto schur_asmb_pre_proc = boost::make_shared<FEMethod>();
5908 schur_asmb_pre_proc->preProcessHook = [this]() {
5910 CHKERR MatZeroEntries(S);
5911 MOFEM_LOG("TIMER", Sev::verbose) << "Lhs Assemble Begin";
5913 };
5914 auto schur_asmb_post_proc = boost::make_shared<FEMethod>();
5915
5916 schur_asmb_post_proc->postProcessHook = [this, schur_asmb_post_proc]() {
5918 MOFEM_LOG("TIMER", Sev::verbose) << "Lhs Assemble End";
5919
5920 // Apply essential constrains to Schur complement
5921 CHKERR MatAssemblyBegin(S, MAT_FINAL_ASSEMBLY);
5922 CHKERR MatAssemblyEnd(S, MAT_FINAL_ASSEMBLY);
5924 mField, schur_asmb_post_proc, 1, S, aoSchur)();
5925
5927 };
5928 auto ts_ctx_ptr = getDMTsCtx(simple->getDM());
5929 ts_ctx_ptr->getPreProcessIJacobian().push_front(schur_asmb_pre_proc);
5930 ts_ctx_ptr->getPostProcessIJacobian().push_front(schur_asmb_post_proc);
5932 };
5933
5934 auto set_pc = [&]() {
5936 CHKERR PCFieldSplitSetIS(pc, NULL, fieldSplitIS);
5937 CHKERR PCFieldSplitSetSchurPre(pc, PC_FIELDSPLIT_SCHUR_PRE_USER, S);
5939 };
5940
5941 auto set_diagonal_pc = [&]() {
5943 KSP *subksp;
5944 CHKERR PCFieldSplitSchurGetSubKSP(pc, PETSC_NULLPTR, &subksp);
5945 auto get_pc = [](auto ksp) {
5946 PC pc_raw;
5947 CHKERR KSPGetPC(ksp, &pc_raw);
5948 return SmartPetscObj<PC>(pc_raw,
5949 true); // bump reference
5950 };
5951 CHKERR setSchurA00MatSolvePC(get_pc(subksp[0]));
5952 CHKERR PetscFree(subksp);
5954 };
5955
5956 CHKERR set_ops();
5957 CHKERR set_pc();
5958 CHKERR set_assemble_elems();
5959
5960 CHKERR TSSetUp(solver);
5961 CHKERR KSPSetUp(ksp);
5962 CHKERR set_diagonal_pc();
5963
5964 } else {
5965 pip_mng->getOpBoundaryLhsPipeline().push_front(
5967 pip_mng->getOpBoundaryLhsPipeline().push_back(
5968 createOpSchurAssembleEnd({}, {}));
5969 pip_mng->getOpDomainLhsPipeline().push_front(createOpSchurAssembleBegin());
5970 pip_mng->getOpDomainLhsPipeline().push_back(
5971 createOpSchurAssembleEnd({}, {}));
5972 }
5973
5974 // fieldSplitIS.reset();
5975 // aoSchur.reset();
5977}
5978
5979boost::shared_ptr<SetUpSchur>
5981 SmartPetscObj<DM> sub_dm, SmartPetscObj<IS> is_sub,
5982 SmartPetscObj<AO> ao_up) {
5983 return boost::shared_ptr<SetUpSchur>(
5984 new SetUpSchurImpl(m_field, sub_dm, is_sub, ao_up));
5985}
static auto filter_true_skin(MoFEM::Interface &m_field, Range &&skin)
static auto get_skin(MoFEM::Interface &m_field, Range body_ents)
#define MOFEM_LOG_SEVERITY_SYNC(comm, severity)
Synchronise "SYNC" on curtain severity level.
#define MOFEM_LOG_SYNCHRONISE(comm)
Synchronise "SYNC" channel.
#define MOFEM_LOG_C(channel, severity, format,...)
#define MOFEM_TAG_AND_LOG(channel, severity, tag)
Tag and log in channel.
#define FTENSOR_INDEX(DIM, I)
#define TSADAPTMOFEM
Definition TsCtx.hpp:10
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.
@ QUIET
@ VERBOSE
@ ROW
#define CATCH_ERRORS
Catch errors.
@ MF_EXIST
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base .
Definition definitions.h:60
@ NOBASE
Definition definitions.h:59
@ DEMKOWICZ_JACOBI_BASE
Definition definitions.h:66
#define BITREFLEVEL_SIZE
max number of refinements
#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.
@ TEMPERATURESET
@ HEATFLUXSET
@ NODESET
@ SIDESET
@ MOFEM_NOT_FOUND
Definition definitions.h:33
@ MOFEM_STD_EXCEPTION_THROW
Definition definitions.h:39
@ 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
Order displacement.
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::LinearForm< GAUSS >::OpBaseTimesVector< 1, SPACE_DIM, 1 > OpInertiaForce
PetscErrorCode ShapeMBTRI(double *N, const double *X, const double *Y, const int G_DIM)
calculate shape functions on triangle
Definition fem_tools.c:182
@ F
constexpr auto t_kd
PetscErrorCode DMMoFEMSetIsPartitioned(DM dm, PetscBool is_partitioned)
Definition DMMoFEM.cpp:1113
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 DMMoFEMSNESSetFunction(DM dm, const char fe_name[], MoFEM::FEMethod *method, MoFEM::BasicMethod *pre_only, MoFEM::BasicMethod *post_only)
set SNES residual evaluation function
Definition DMMoFEM.cpp:708
PetscErrorCode DMMoFEMSetSquareProblem(DM dm, PetscBool square_problem)
set squared problem
Definition DMMoFEM.cpp:450
PetscErrorCode DMMoFEMCreateMoFEM(DM dm, MoFEM::Interface *m_field_ptr, const char problem_name[], const MoFEM::BitRefLevel bit_level, const MoFEM::BitRefLevel bit_mask=MoFEM::BitRefLevel().set())
Must be called by user to set MoFEM data structures.
Definition DMMoFEM.cpp:114
PetscErrorCode DMoFEMMeshToLocalVector(DM dm, Vec l, InsertMode mode, ScatterMode scatter_mode)
set local (or ghosted) vector values on mesh for partition only
Definition DMMoFEM.cpp:514
PetscErrorCode DMMoFEMAddSubFieldRow(DM dm, const char field_name[])
Definition DMMoFEM.cpp:238
PetscErrorCode DMMoFEMSNESSetJacobian(DM dm, const char fe_name[], MoFEM::FEMethod *method, MoFEM::BasicMethod *pre_only, MoFEM::BasicMethod *post_only)
set SNES Jacobian evaluation function
Definition DMMoFEM.cpp:749
PetscErrorCode DMRegister_MoFEM(const char sname[])
Register MoFEM problem.
Definition DMMoFEM.cpp:43
PetscErrorCode DMMoFEMKSPSetComputeRHS(DM dm, const char fe_name[], MoFEM::FEMethod *method, MoFEM::BasicMethod *pre_only, MoFEM::BasicMethod *post_only)
set KSP right hand side evaluation function
Definition DMMoFEM.cpp:627
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)
Get smart vector from DM.
Definition DMMoFEM.hpp:1234
PetscErrorCode DMMoFEMAddSubFieldCol(DM dm, const char field_name[])
Definition DMMoFEM.cpp:280
auto createDMMatrix(DM dm)
Get smart matrix from DM.
Definition DMMoFEM.hpp:1191
PetscErrorCode DMCreateGlobalVector_MoFEM(DM dm, Vec *g)
DMShellSetCreateGlobalVector.
Definition DMMoFEM.cpp:1157
PetscErrorCode DMoFEMMeshToGlobalVector(DM dm, Vec g, InsertMode mode, ScatterMode scatter_mode)
set ghosted vector values on all existing mesh entities
Definition DMMoFEM.cpp:525
PetscErrorCode DMMoFEMKSPSetComputeOperators(DM dm, const char fe_name[], MoFEM::FEMethod *method, MoFEM::BasicMethod *pre_only, MoFEM::BasicMethod *post_only)
Set KSP operators and push mofem finite element methods.
Definition DMMoFEM.cpp:668
PetscErrorCode DMSetUp_MoFEM(DM dm)
Definition DMMoFEM.cpp:1297
PetscErrorCode DMoFEMLoopFiniteElementsUpAndLowRank(DM dm, const char fe_name[], MoFEM::FEMethod *method, int low_rank, int up_rank, CacheTupleWeakPtr cache_ptr=CacheTupleSharedPtr())
Executes FEMethod for finite elements in DM.
Definition DMMoFEM.cpp:557
MoFEMErrorCode lambdaBitRefLevel(boost::function< void(EntityHandle ent, BitRefLevel &bit)> fun) const
Process bit ref level by lambda function.
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.
SeverityLevel
Severity levels.
#define MOFEM_LOG_TAG(channel, tag)
Tag channel.
#define MOFEM_LOG_CHANNEL(channel)
Set and reset channel.
MoFEMErrorCode getCubitMeshsetPtr(const int ms_id, const CubitBCType cubit_bc_type, const CubitMeshSets **cubit_meshset_ptr) const
get cubit meshset
virtual MoFEMErrorCode modify_problem_mask_ref_level_set_bit(const std::string &name_problem, const BitRefLevel &bit)=0
set dof mask ref level for problem
virtual MoFEMErrorCode modify_problem_ref_level_set_bit(const std::string &name_problem, const BitRefLevel &bit)=0
set ref level for problem
MoFEMErrorCode pushMarkDOFsOnEntities(const std::string problem_name, const std::string block_name, const std::string field_name, int lo, int hi, bool get_low_dim_ents=true)
Mark DOFs on block entities for boundary conditions.
auto bit
set bit
FTensor::Index< 'i', SPACE_DIM > i
const double c
speed of light (cm/ns)
double D
const double v
phase velocity of light in medium (cm/ns)
const double n
refractive index of diffusive medium
MoFEM::TsCtx * ts_ctx
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
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
std::bitset< BITREFLEVEL_SIZE > BitRefLevel
Bit structure attached to each entity identifying to what mesh entity is attached.
Definition Types.hpp:40
implementation of Data Operators for Forces and Sources
Definition Common.hpp:10
auto type_from_handle(const EntityHandle h)
get type from entity handle
auto createKSP(MPI_Comm comm)
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:1276
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:2585
auto createSNES(MPI_Comm comm)
PetscErrorCode DMMoFEMSetDestroyProblem(DM dm, PetscBool destroy_problem)
Definition DMMoFEM.cpp:434
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:596
MoFEMErrorCode setSchurA00MatSolvePC(SmartPetscObj< PC > pc)
Set PC for A00 block.
Definition Schur.cpp:2627
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)
PetscErrorCode TsSetIFunction(TS ts, PetscReal t, Vec u, Vec u_t, Vec F, void *ctx)
Set IFunction for TS solver.
Definition TsCtx.cpp:56
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 createVectorMPI(MPI_Comm comm, PetscInt n, PetscInt N)
Create MPI Vector.
auto getDMSubData(DM dm)
Get sub problem data structure.
Definition DMMoFEM.hpp:1292
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:2343
static auto getFTensor0FromVec(ublas::vector< T, A > &data)
Get tensor rank 0 (scalar) form data vector.
OpCalculateScalarFieldValuesFromPetscVecImpl< PetscData::CTX_SET_X_T > OpCalculateScalarFieldValuesDot
PetscErrorCode PetscOptionsGetEList(PetscOptions *, const char pre[], const char name[], const char *const *list, PetscInt next, PetscInt *value, PetscBool *set)
PetscErrorCode PetscOptionsGetString(PetscOptions *, const char pre[], const char name[], char str[], size_t size, PetscBool *set)
auto get_temp_meshset_ptr(moab::Interface &moab)
Create smart pointer to temporary meshset.
MoFEMErrorCode DMMoFEMSetNestSchurData(DM dm, boost::shared_ptr< NestSchurData >)
Definition DMMoFEM.cpp:1554
auto getDMSnesCtx(DM dm)
Get SNES context data structure used by DM.
Definition DMMoFEM.hpp:1262
auto createDMNestSchurMat(DM dm)
Definition DMMoFEM.hpp:1218
auto createDM(MPI_Comm comm, const std::string dm_type_name)
Creates smart DM object.
PetscErrorCode TSAdaptCreateMoFEM(TSAdapt adapt)
Craete MOFEM adapt.
Definition TsCtx.cpp:829
OpSchurAssembleBase * createOpSchurAssembleBegin()
Definition Schur.cpp:2580
auto createDMBlockMat(DM dm)
Definition DMMoFEM.hpp:1211
boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > Pip
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::BiLinearForm< GAUSS >::OpMixDivTimesScalar< SPACE_DIM > OpHdivT
Integrate Lhs div of base of flux times base of temperature (FLUX x T) and transpose of it,...
OpHdivHdivImpl< SPACE_DIM, IS_LARGE_STRAINS > OpHdivHdiv
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::BiLinearForm< GAUSS >::OpMass< 1, 1 > OpCapacity
Integrate Lhs base of temperature times (heat capacity) times base of temperature (T x T)
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::LinearForm< GAUSS >::OpBaseTimesScalar< 1 > OpBaseDotT
Integrate Rhs base of temperature time heat capacity times heat rate (T)
OpBaseDotT OpBaseDivFlux
Integrate Rhs base of temperature times divergence of flux (T)
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::LinearForm< GAUSS >::OpMixDivTimesU< 3, 1, SPACE_DIM > OpHDivTemp
Integrate Rhs div flux base times temperature (T)
OpCalculateQdotQLhs_dU< SPACE_DIM, GAUSS, AssemblyDomainEleOp, IS_LARGE_STRAINS > OpHdivU
Integrate Lhs of flux term coupled to displacement field.
OpHdivFluxImpl< SPACE_DIM, IS_LARGE_STRAINS > OpHdivFlux
MoFEMErrorCode addMatThermalBlockOps(MoFEM::Interface &m_field, boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > &pipeline, std::string block_name, boost::shared_ptr< BlockedThermalParameters > blockedParamsPtr, double default_heat_conductivity, double default_heat_capacity, double default_thermal_conductivity_scale, double default_thermal_capacity_scale, Sev sev, ScalerFunTwoArgs thermal_conductivity_scaling_func, ScalerFunTwoArgs heat_capacity_scaling_func)
MoFEMErrorCode addMatThermoElasticBlockOps(MoFEM::Interface &m_field, boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > &pipeline, std::string block_name, boost::shared_ptr< BlockedThermoElasticParameters > blockedParamsPtr, double default_coeff_expansion, double default_ref_temp, Sev sev)
MoFEMErrorCode addMatThermoPlasticBlockOps(MoFEM::Interface &m_field, boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > &pipeline, std::string thermoplastic_block_name, boost::shared_ptr< ThermoPlasticBlockedParameters > blockedParamsPtr, boost::shared_ptr< ThermoElasticOps::BlockedThermalParameters > &blockedThermalParamsPtr, Sev sev, ScalerFunThreeArgs inelastic_heat_fraction_scaling)
int r
Definition sdf.py:8
FormsIntegrators< DomainEleOp >::Assembly< A >::LinearForm< I >::OpGradTimesTensor< 1, FIELD_DIM, SPACE_DIM > OpGradTimesTensor
constexpr IntegrationType I
constexpr AssemblyType A
[Define dimension]
OpPostProcMapInMoab< SPACE_DIM, SPACE_DIM > OpPPMap
constexpr double t
plate stiffness
Definition plate.cpp:58
constexpr auto field_name
#define QUAD_2D_TABLE_SIZE
Definition quad.h:174
#define QUAD_3D_TABLE_SIZE
Definition quad.h:186
static QUAD *const QUAD_2D_TABLE[]
Definition quad.h:175
OpBaseImpl< PETSC, EdgeEleOp > OpBase
Definition radiation.cpp:29
constexpr double heat_conductivity
Definition radiation.cpp:36
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::LinearForm< GAUSS >::OpGradTimesTensor< 1, SPACE_DIM, SPACE_DIM > OpInternalForcePiola
Definition seepage.cpp:65
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::BiLinearForm< GAUSS >::OpGradTensorGrad< 1, SPACE_DIM, SPACE_DIM, 1 > OpKPiola
[Only used for dynamics]
Definition seepage.cpp:63
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::BiLinearForm< GAUSS >::OpMass< 1, SPACE_DIM > OpMass
[Only used with Hooke equation (linear material model)]
Definition seepage.cpp:56
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::LinearForm< GAUSS >::OpGradTimesSymTensor< 1, SPACE_DIM, SPACE_DIM > OpInternalForceCauchy
Definition seepage.cpp:51
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::BiLinearForm< GAUSS >::OpGradSymTensorGrad< 1, SPACE_DIM, SPACE_DIM, 0 > OpKCauchy
[Only used with Hooke equation (linear material model)]
Definition seepage.cpp:49
FTensor::Index< 'm', 3 > m
void temp(int x, int y=10)
Definition simple.cpp:4
Rhs for testing EP mapping with initial conditions.
PipelineManager::ElementsAndOpsByDim< 2 >::DomainEleOnRange DomainEleOnRange
PipelineManager::ElementsAndOpsByDim< 2 >::FaceSideEle SideEle
Definition plastic.cpp:29
PipelineManager::ElementsAndOpsByDim< 3 >::FaceSideEle SideEle
Definition plastic.cpp:36
PipelineManager::ElementsAndOpsByDim< 3 >::DomainEleOnRange DomainEleOnRange
double getScale(const double time)
Get scaling at given time.
[Example]
Definition plastic.cpp:216
MoFEMErrorCode thermalBC()
[Mechanical boundary conditions]
boost::shared_ptr< VectorDouble > tempFieldPtr
MoFEMErrorCode opThermoPlasticFactoryDomainLhs(MoFEM::Interface &m_field, std::string block_name, std::string thermal_block_name, std::string thermoelastic_block_name, std::string thermoplastic_block_name, Pip &pip, std::string u, std::string ep, std::string tau, std::string temperature)
boost::shared_ptr< DomainEle > reactionFe
Definition plastic.cpp:235
MoFEMErrorCode edgeFlips(BitRefLevel parent_bit, BitRefLevel child_bit)
boost::shared_ptr< MatrixDouble > strainFieldPtr
MoFEMErrorCode doEdgeSplits(bool &refine, bool add_ents)
[Do Edge Flips]
boost::shared_ptr< MatrixDouble > dispGradPtr
MoFEMErrorCode tsSolve()
FieldApproximationBase base
Choice of finite element basis functions
Definition plot_base.cpp:68
std::tuple< SmartPetscObj< Vec >, SmartPetscObj< VecScatter > > uYScatter
Definition plastic.cpp:238
MoFEMErrorCode mechanicalBC()
[Initial conditions]
MoFEMErrorCode createCommonData()
friend struct TSPrePostProc
MoFEMErrorCode getElementQuality(std::multimap< double, EntityHandle > &el_q_map, Range &flipped_els, std::vector< EntityHandle > &new_connectivity, bool &do_refine, Tag &th_spatial_coords)
[Get element quality]
boost::shared_ptr< VectorDouble > plasticMultiplierFieldPtr
Example(MoFEM::Interface &m_field)
MoFEMErrorCode OPs()
MoFEMErrorCode runProblem()
boost::shared_ptr< MatrixDouble > stressFieldPtr
MoFEM::Interface & mField
Reference to MoFEM interface.
Definition plastic.cpp:226
std::tuple< SmartPetscObj< Vec >, SmartPetscObj< VecScatter > > uZScatter
Definition plastic.cpp:239
boost::shared_ptr< MatrixDouble > fluxFieldPtr
MoFEMErrorCode setupProblem()
boost::shared_ptr< MatrixDouble > dispFieldPtr
boost::shared_ptr< MatrixDouble > plasticStrainFieldPtr
MoFEMErrorCode opThermoPlasticFactoryDomainRhs(MoFEM::Interface &m_field, std::string block_name, std::string thermal_block_name, std::string thermoelastic_block_name, std::string thermoplastic_block_name, Pip &pip, std::string u, std::string ep, std::string tau, std::string temperature)
std::tuple< SmartPetscObj< Vec >, SmartPetscObj< VecScatter > > uXScatter
Definition plastic.cpp:237
MoFEMErrorCode doEdgeFlips(std::multimap< double, EntityHandle > &el_q_map, Range &flipped_els, Tag &th_spatial_coords, std::vector< EntityHandle > &new_connectivity)
[Edge flips]
MoFEMErrorCode initialConditions()
[Create common data]
auto createCommonThermoPlasticOps(MoFEM::Interface &m_field, std::string plastic_block_name, std::string thermal_block_name, std::string thermoelastic_block_name, std::string thermoplastic_block_name, boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > &pip, std::string u, std::string ep, std::string tau, std::string temperature, double scale, ScalerFunTwoArgs thermal_conductivity_scaling, ScalerFunTwoArgs heat_capacity_scaling, ScalerFunThreeArgs inelastic_heat_fraction_scaling, Sev sev, bool with_rates=true)
Add operators pushing bases from local to physical configuration.
Boundary condition manager for finite element problem setup.
Managing BitRefLevels.
Managing BitRefLevels.
virtual int get_comm_size() const =0
virtual moab::Interface & get_moab()=0
virtual MPI_Comm & get_comm() const =0
virtual int get_comm_rank() const =0
Core (interface) class.
Definition Core.hpp:82
static MoFEMErrorCode Initialize(int *argc, char ***args, const char file[], const char help[])
Initializes the MoFEM database PETSc, MOAB and MPI.
Definition Core.cpp:72
static MoFEMErrorCode Finalize()
Checks for options to be called at the conclusion of the program.
Definition Core.cpp:118
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)
FTensor::Tensor0< FTensor::PackPtr< double *, 1 > > getFTensor0N(const FieldApproximationBase base)
Get base function as Tensor0.
FTensor::Tensor1< FTensor::PackPtr< double *, Tensor_Dim >, Tensor_Dim > getFTensor1N(FieldApproximationBase base)
Get base functions for Hdiv/Hcurl spaces.
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
Structure for user loop methods on finite elements.
Basic algebra on fields.
Definition FieldBlas.hpp:21
Field evaluator interface.
SetIntegrationPtsMethodData SetPtsData
structure to get information from mofem into EntitiesFieldData
Definition of the heat flux bc data structure.
Definition BCData.hpp:423
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.
Mesh refinement interface.
MoFEMErrorCode addVerticesInTheMiddleOfEdges(const EntityHandle meshset, const BitRefLevel &bit, const bool recursive=false, int verb=QUIET, EntityHandle start_v=0)
make vertices in the middle of edges in meshset and add them to refinement levels defined by bit
Interface for managing meshsets containing materials and boundary conditions.
MoFEMErrorCode updateAllMeshsetsByEntitiesChildren(const BitRefLevel &bit)
Update all blocksets, sidesets and node sets.
Assembly methods.
Definition Natural.hpp:65
Natural boundary conditions.
Definition Natural.hpp:57
Get vector field for H-div approximation.
Calculate divergence of vector field.
Get field gradients at integration pts for scalar field rank 0, i.e. vector field.
Specialization for double precision scalar field values calculation.
Calculate symmetric tensor field rates ant integratio pts.
Calculate symmetric tensor field values at integration pts.
Get field gradients at integration pts for scalar field rank 0, i.e. vector field.
Approximate field values for given petsc vector.
Specialization for double precision vector field values calculation.
Enforce essential constrains on lhs.
Definition Essential.hpp:81
Enforce essential constrains on rhs.
Definition Essential.hpp:65
Element used to execute operators on side of the element.
Post post-proc data at points from hash maps.
Set indices on entities on finite element.
Operator for symmetrizing tensor fields.
Unset indices on entities on finite element.
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
Problem manager is used to build and partition problems.
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.
Auxiliary tools.
Definition Tools.hpp:19
static constexpr std::array< double, 6 > diffShapeFunMBTRI
Definition Tools.hpp:104
static MoFEMErrorCode getTriNormal(const double *coords, double *normal, double *d_normal=nullptr)
Get the Tri Normal objectGet triangle normal.
Definition Tools.cpp:353
static double getEdgeLength(const double *edge_coords)
Get edge length.
Definition Tools.cpp:418
MoFEM::Interface & mField
Definition TsCtx.hpp:19
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.
Vector manager is used to create vectors \mofem_vectors.
boost::shared_ptr< MoFEM::TsCtx > dmts_ctx
PetscInt snes_iter_counter
[Target temperature]
static std::array< int, 5 > activityData
int npoints
Definition quad.h:29
boost::weak_ptr< TSPrePostProc > ptr
MoFEM::Interface * m_field
std::vector< EntityHandle > new_connectivity
std::multimap< double, EntityHandle > el_q_map
PetscBool mesh_changed
MoFEMErrorCode operator()(ForcesAndSourcesCore *fe_raw_ptr, int order_row, int order_col, int order_data)
static std::map< long int, MatrixDouble > mapRefCoords
SmartPetscObj< DM > subDM
field split sub dm
Definition plastic.cpp:1680
SmartPetscObj< Mat > S
SmartPetscObj< AO > aoSchur
Definition plastic.cpp:1682
MoFEMErrorCode setUp(TS solver)
SmartPetscObj< IS > fieldSplitIS
IS for split Schur block.
Definition plastic.cpp:1681
SetUpSchurImpl(MoFEM::Interface &m_field, SmartPetscObj< DM > sub_dm, SmartPetscObj< IS > field_split_is, SmartPetscObj< AO > ao_up)
MoFEMErrorCode setUp(SmartPetscObj< KSP >)
virtual ~SetUpSchurImpl()
MoFEMErrorCode postProc()
MoFEMErrorCode preProc()
MoFEM::Interface & mField
[Push operators to pipeline]
SetUpSchur()=default
static boost::shared_ptr< SetUpSchur > createSetUpSchur(MoFEM::Interface &m_field, SmartPetscObj< DM > sub_dm, SmartPetscObj< IS > field_split_it, SmartPetscObj< AO > ao_map)
Create data structure for handling Schur complement.
static boost::shared_ptr< SetUpSchur > createSetUpSchur(MoFEM::Interface &m_field)
virtual MoFEMErrorCode setUp(TS solver)=0
MoFEMErrorCode mapFields(SmartPetscObj< DM > &intermediateDM, BitRefLevel parentBit, BitRefLevel childBit, PetscInt numVecs=1, Vec vecsToMapFrom[]=PETSC_NULLPTR, Vec vecsToMapTo[]=PETSC_NULLPTR)
MoFEMErrorCode reSetUp(std::vector< std::string > L2Fields, std::vector< int > L2Oders, std::vector< std::string > H1Fields, std::vector< int > H1Orders, std::vector< std::string > HdivFields, std::vector< int > HdivOrders, BitRefLevel bIt)
Set of functions called by PETSc solver used to refine and update mesh.
virtual ~TSPrePostProc()=default
static MoFEMErrorCode tsPreProc(TS ts)
Pre process time step.
static MoFEMErrorCode tsPostProc(TS ts)
Post process time step.
TSPrePostProc()=default
static MoFEMErrorCode tsPostProc(TS ts)
Post process time step.
static MoFEMErrorCode tsPreStage(TS ts)
static MoFEMErrorCode tsPreProc(TS ts)
Pre process time step.
MoFEMErrorCode tsSetUp(TS ts)
Used to setup TS solver.
constexpr AssemblyType AT
constexpr IntegrationType IT
double iso_hardening_dtemp(double tau, double H, double omega_0, double Qinf, double omega_h, double b_iso, double sigmaY, double temp_0, double temp)
double young_modulus
Young modulus.
@ IC_UNIFORM
@ IC_LINEAR
@ IC_GAUSSIAN
double default_heat_capacity_scale
auto save_range
constexpr AssemblyType AT
double exp_D
static boost::weak_ptr< TSPrePostProc > tsPrePostProc
double C1_k
Kinematic hardening.
int post_processing_counter
double peak_temp
double exp_softening(double temp_hat)
PetscBool order_face
double Qinf
Saturation yield stress.
char restart_file[255]
BitRefLevel flipped_bit
constexpr IntegrationType IT
static char help[]
[Solve]
ThermoPlasticityBits
@ FLIPPED_BIT
@ FIRST_REF_BIT
@ REFINED_EDGES_BIT
@ STORAGE_BIT
@ PREVIOUS_BIT
@ VIRGIN_BIT
@ COMPUTATION_BIT
auto init_T
Initialisation function for temperature field.
double default_thermal_conductivity_scale
BitRefLevel storage_bit
ScalerFunTwoArgs heat_capacity_scaling
double dH_thermal_dtemp(double H, double omega_h)
constexpr bool IS_LARGE_STRAINS
double rho
ScalerFunThreeArgs inelastic_heat_fraction_scaling
int atom_test
PetscBool is_distributed_mesh
#define EXECUTABLE_DIMENSION
PetscBool do_eval_field
Evaluate field.
PetscBool is_quasi_static
double dy_0_thermal_dtemp(double sigmaY, double omega_0)
boost::function< double(const double, const double, const double)> ScalerFunThreeArgs
double alpha_damping
constexpr int SPACE_DIM
ICType ic_type
double visH
Viscous hardening.
double poisson_ratio
Poisson ratio.
boost::function< double(const double, const double)> ScalerFunTwoArgs
double iso_hardening(double tau, double H, double omega_0, double Qinf, double omega_h, double b_iso, double sigmaY, double temp_0, double temp)
double init_dt
Example * thermoplastic_raw_ptr
PetscErrorCode MyTSResizeSetup(TS ts, PetscInt nstep, PetscReal time, Vec sol, PetscBool *resize, void *ctx)
BitRefLevel virgin_mesh_bit
int restart_step
double qual_tol
static std::unordered_map< TS, ResizeCtx * > ts_to_rctx
double default_ref_temp
PetscErrorCode MyTSResizeTransfer(TS, PetscInt, Vec[], Vec[], void *)
double qual_thresh
PetscBool order_edge
double Qinf_thermal(double Qinf, double omega_h, double temp_0, double temp)
BitRefLevel comp_mesh_bit
auto kinematic_hardening(FTensor::Tensor2_symmetric< T, DIM > &t_plastic_strain, double C1_k)
double default_heat_capacity
PetscBool set_timer
Set timer.
const char *const ICTypes[]
double temp_hat(double temp)
const bool is_large_strains
double edge_growth_thresh
PetscBool order_volume
double scale
constexpr auto size_symm
auto postProcessHere(MoFEM::Interface &m_field, SmartPetscObj< DM > &dm, std::string output_name, int &counter= *(new int(0)))
PetscBool restart_flg
int flux_order
Order of tau field.
MoFEMErrorCode TSIterationPreStage(TS ts, PetscReal stagetime)
double zeta
regularisation parameter
int T_order
Order of ep field.
ElementsAndOps< SPACE_DIM >::DomainEleOnRange DomainEleOnRange
BitRefLevel prev_mesh_bit
double y_0_thermal(double sigmaY, double omega_0, double temp_0, double temp)
double init_temp
double H
Hardening.
double width
Width of Gaussian distribution.
auto linear_distribution
double default_coeff_expansion
int tau_order
Order of tau field.
double iso_hardening_dtau(double tau, double H, double omega_0, double Qinf, double omega_h, double b_iso, double sigmaY, double temp_0, double temp)
auto uniform_distribution
auto get_string_from_vector
auto printOnAllCores(MoFEM::Interface &m_field, const std::string &out_put_string, const auto &out_put_quantity)
MoFEMErrorCode SNESIterationMonitor(SNES snes, PetscInt its, PetscReal norm, void *ctx)
double omega_0
flow stress softening
double iso_hardening_exp(double tau, double b_iso)
auto postProcessPETScHere(MoFEM::Interface &m_field, SmartPetscObj< DM > &dm, Vec sol, std::string output_name)
double H_thermal(double H, double omega_h, double temp_0, double temp)
double restart_time
double cn0
int order
Order displacement.
double b_iso
Saturation exponent.
auto Gaussian_distribution
BitRefLevel refined_bit
int geom_order
Order if fixed.
double sigmaY
Yield stress.
ScalerFunTwoArgs thermal_conductivity_scaling
double default_heat_conductivity
auto kinematic_hardening_dplastic_strain(double C1_k)
double inelastic_heat_fraction
fraction of plastic dissipation converted to heat
double min_dt
int num_refinement_levels
double temp_0
reference temperature for thermal softening
static std::unordered_map< TS, MyTsCtx * > ts_to_ctx
int ep_order
Order of ep field.
double dQinf_thermal_dtemp(double Qinf, double omega_h)
double exp_C
double cn1
constexpr FieldSpace CONTACT_SPACE
double omega_h
hardening softening
double young_modulus
Young modulus.
Definition plastic.cpp:125
double C1_k
Kinematic hardening.
Definition plastic.cpp:133
double Qinf
Saturation yield stress.
Definition plastic.cpp:131
double rho
Definition plastic.cpp:144
ElementsAndOps< SPACE_DIM >::SideEle SideEle
Definition plastic.cpp:61
int atom_test
Atom test.
Definition plastic.cpp:121
PetscBool is_quasi_static
[Operators used for contact]
Definition plastic.cpp:143
double alpha_damping
Definition plastic.cpp:145
double visH
Viscous hardening.
Definition plastic.cpp:129
double poisson_ratio
Poisson ratio.
Definition plastic.cpp:126
PetscBool set_timer
Set timer.
Definition plastic.cpp:118
double scale
Definition plastic.cpp:123
constexpr auto size_symm
Definition plastic.cpp:42
double zeta
Viscous hardening.
Definition plastic.cpp:130
double H
Hardening.
Definition plastic.cpp:128
int tau_order
Order of tau files.
Definition plastic.cpp:139
double cn0
Definition plastic.cpp:135
double b_iso
Saturation exponent.
Definition plastic.cpp:132
PetscBool is_large_strains
Large strains.
Definition plastic.cpp:117
int geom_order
Order if fixed.
Definition plastic.cpp:141
double sigmaY
Yield stress.
Definition plastic.cpp:127
int ep_order
Order of ep files.
Definition plastic.cpp:140
double cn1
Definition plastic.cpp:136
constexpr FieldSpace CONTACT_SPACE
[Specialisation for assembly]
Definition plastic.cpp:52
#define SCHUR_ASSEMBLE
Definition contact.cpp:18
#define FINITE_DEFORMATION_FLAG
auto save_range
constexpr bool IS_LARGE_STRAINS
double default_ref_temp
double default_heat_capacity
double default_coeff_expansion
double default_heat_conductivity
constexpr int SPACE_DIM
[Define dimension]
Definition elastic.cpp:19
constexpr AssemblyType A
[Define dimension]
Definition elastic.cpp:22
constexpr int SPACE_DIM