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