v0.15.0
Loading...
Searching...
No Matches
EshelbianPlasticity.cpp
Go to the documentation of this file.
1/**
2 * \file EshelbianPlasticity.cpp
3 * \example mofem/users_modules/eshelbian_plasticity/src/impl/EshelbianPlasticity.cpp
4 *
5 * \brief Eshelbian plasticity implementation
6 *
7 * \copyright 2024. Various authors, some of them anonymous contributors under
8 * MiT core contributors license agreement.
9 */
10
11#define SINGULARITY
12#include <MoFEM.hpp>
13using namespace MoFEM;
14
16
18#include <boost/math/constants/constants.hpp>
19
20#include <cholesky.hpp>
21#ifdef ENABLE_PYTHON_BINDING
22 #include <boost/python.hpp>
23 #include <boost/python/def.hpp>
24 #include <boost/python/numpy.hpp>
25namespace bp = boost::python;
26namespace np = boost::python::numpy;
27
28 #pragma message "With ENABLE_PYTHON_BINDING"
29
30#else
31
32 #pragma message "Without ENABLE_PYTHON_BINDING"
33
34#endif
35
36#include <EshelbianAux.hpp>
37#include <EshelbianContact.hpp>
38
39extern "C" {
40#include <phg-quadrule/quad.h>
41}
42
43#include <queue>
44
45namespace EshelbianPlasticity {
54
55} // namespace EshelbianPlasticity
56
57static auto send_type(MoFEM::Interface &m_field, Range r,
58 const EntityType type) {
59 ParallelComm *pcomm =
60 ParallelComm::get_pcomm(&m_field.get_moab(), MYPCOMM_INDEX);
61
62 auto dim = CN::Dimension(type);
63
64 std::vector<int> sendcounts(pcomm->size());
65 std::vector<int> displs(pcomm->size());
66 std::vector<int> sendbuf(r.size());
67 if (pcomm->rank() == 0) {
68 for (auto p = 1; p != pcomm->size(); p++) {
69 auto part_ents = m_field.getInterface<CommInterface>()
70 ->getPartEntities(m_field.get_moab(), p)
71 .subset_by_dimension(SPACE_DIM);
72 Range faces;
73 CHKERR m_field.get_moab().get_adjacencies(part_ents, dim, true, faces,
74 moab::Interface::UNION);
75 faces = intersect(faces, r);
76 sendcounts[p] = faces.size();
77 displs[p] = sendbuf.size();
78 for (auto f : faces) {
79 auto id = id_from_handle(f);
80 sendbuf.push_back(id);
81 }
82 }
83 }
84
85 int recv_data;
86 MPI_Scatter(sendcounts.data(), 1, MPI_INT, &recv_data, 1, MPI_INT, 0,
87 pcomm->comm());
88 std::vector<int> recvbuf(recv_data);
89 MPI_Scatterv(sendbuf.data(), sendcounts.data(), displs.data(), MPI_INT,
90 recvbuf.data(), recv_data, MPI_INT, 0, pcomm->comm());
91
92 if (pcomm->rank() > 0) {
93 Range r;
94 for (auto &f : recvbuf) {
95 r.insert(ent_form_type_and_id(type, f));
96 }
97 return r;
98 }
99
100 return r;
101}
102
104 const std::string block_name, int dim) {
105 Range r;
106
107 auto mesh_mng = m_field.getInterface<MeshsetsManager>();
108 auto bcs = mesh_mng->getCubitMeshsetPtr(
109
110 std::regex((boost::format("%s(.*)") % block_name).str())
111
112 );
113
114 for (auto bc : bcs) {
115 Range faces;
116 CHK_MOAB_THROW(bc->getMeshsetIdEntitiesByDimension(m_field.get_moab(), dim,
117 faces, true),
118 "get meshset ents");
119 r.merge(faces);
120 }
121
122 return r;
123};
124
126 const std::string block_name, int dim) {
127 std::map<std::string, Range> r;
128
129 auto mesh_mng = m_field.getInterface<MeshsetsManager>();
130 auto bcs = mesh_mng->getCubitMeshsetPtr(
131
132 std::regex((boost::format("%s(.*)") % block_name).str())
133
134 );
135
136 for (auto bc : bcs) {
137 Range faces;
138 CHK_MOAB_THROW(bc->getMeshsetIdEntitiesByDimension(m_field.get_moab(), dim,
139 faces, true),
140 "get meshset ents");
141 r[bc->getName()] = faces;
142 }
143
144 return r;
145}
146
147static auto get_block_meshset(MoFEM::Interface &m_field, const int ms_id,
148 const unsigned int cubit_bc_type) {
149 auto mesh_mng = m_field.getInterface<MeshsetsManager>();
150 EntityHandle meshset;
151 CHKERR mesh_mng->getMeshset(ms_id, cubit_bc_type, meshset);
152 return meshset;
153};
154
155static auto save_range(moab::Interface &moab, const std::string name,
156 const Range r, std::vector<Tag> tags = {}) {
158 auto out_meshset = get_temp_meshset_ptr(moab);
159 CHKERR moab.add_entities(*out_meshset, r);
160 if (r.size()) {
161 CHKERR moab.write_file(name.c_str(), "VTK", "", out_meshset->get_ptr(), 1,
162 tags.data(), tags.size());
163 } else {
164 MOFEM_LOG("SELF", Sev::warning) << "Empty range for " << name;
165 }
167};
168
169static auto filter_true_skin(MoFEM::Interface &m_field, Range &&skin) {
170 Range boundary_ents;
171 ParallelComm *pcomm =
172 ParallelComm::get_pcomm(&m_field.get_moab(), MYPCOMM_INDEX);
173 CHK_MOAB_THROW(pcomm->filter_pstatus(skin,
174 PSTATUS_SHARED | PSTATUS_MULTISHARED,
175 PSTATUS_NOT, -1, &boundary_ents),
176 "filter_pstatus");
177 return boundary_ents;
178};
179
180static auto filter_owners(MoFEM::Interface &m_field, Range skin) {
181 Range owner_ents;
182 ParallelComm *pcomm =
183 ParallelComm::get_pcomm(&m_field.get_moab(), MYPCOMM_INDEX);
184 CHK_MOAB_THROW(pcomm->filter_pstatus(skin, PSTATUS_NOT_OWNED, PSTATUS_NOT, -1,
185 &owner_ents),
186 "filter_pstatus");
187 return owner_ents;
188};
189
190static auto get_skin(MoFEM::Interface &m_field, Range body_ents) {
191 Skinner skin(&m_field.get_moab());
192 Range skin_ents;
193 CHK_MOAB_THROW(skin.find_skin(0, body_ents, false, skin_ents), "find_skin");
194 return skin_ents;
195};
196
198 Range crack_faces) {
199 ParallelComm *pcomm =
200 ParallelComm::get_pcomm(&m_field.get_moab(), MYPCOMM_INDEX);
201 auto &moab = m_field.get_moab();
202 Range crack_skin_without_bdy;
203 if (pcomm->rank() == 0) {
204 Range crack_edges;
205 CHKERR moab.get_adjacencies(crack_faces, 1, true, crack_edges,
206 moab::Interface::UNION);
207 auto crack_skin = get_skin(m_field, crack_faces);
208 Range body_ents;
210 m_field.get_moab().get_entities_by_dimension(0, SPACE_DIM, body_ents),
211 "get_entities_by_dimension");
212 auto body_skin = get_skin(m_field, body_ents);
213 Range body_skin_edges;
214 CHK_MOAB_THROW(moab.get_adjacencies(body_skin, 1, true, body_skin_edges,
215 moab::Interface::UNION),
216 "get_adjacencies");
217 crack_skin_without_bdy = subtract(crack_skin, body_skin_edges);
218 auto front_edges_map = get_range_from_block_map(m_field, "FRONT", 1);
219 for (auto &m : front_edges_map) {
220 auto add_front = subtract(m.second, crack_edges);
221 auto i = intersect(m.second, crack_edges);
222 if (i.empty()) {
223 crack_skin_without_bdy.merge(add_front);
224 } else {
225 auto i_skin = get_skin(m_field, i);
226 Range adj_i_skin;
227 CHKERR moab.get_adjacencies(i_skin, 1, true, adj_i_skin,
228 moab::Interface::UNION);
229 adj_i_skin = subtract(intersect(adj_i_skin, m.second), crack_edges);
230 crack_skin_without_bdy.merge(adj_i_skin);
231 }
232 }
233 }
234 return send_type(m_field, crack_skin_without_bdy, MBEDGE);
235}
236
238 Range crack_faces) {
239
240 ParallelComm *pcomm =
241 ParallelComm::get_pcomm(&m_field.get_moab(), MYPCOMM_INDEX);
242
243 MOFEM_LOG("EP", Sev::noisy) << "get_two_sides_of_crack_surface";
244
245 if (!pcomm->rank()) {
246
247 auto impl = [&](auto &saids) {
249
250 auto &moab = m_field.get_moab();
251
252 auto get_adj = [&](auto e, auto dim) {
253 Range adj;
254 CHK_MOAB_THROW(m_field.get_moab().get_adjacencies(
255 e, dim, true, adj, moab::Interface::UNION),
256 "get adj");
257 return adj;
258 };
259
260 auto get_conn = [&](auto e) {
261 Range conn;
262 CHK_MOAB_THROW(m_field.get_moab().get_connectivity(e, conn, true),
263 "get connectivity");
264 return conn;
265 };
266
267 constexpr bool debug = false;
268 Range body_ents;
269 CHKERR m_field.get_moab().get_entities_by_dimension(0, SPACE_DIM,
270 body_ents);
271 auto body_skin = get_skin(m_field, body_ents);
272 auto body_skin_edges = get_adj(body_skin, 1);
273
274 auto crack_skin =
275 subtract(get_skin(m_field, crack_faces), body_skin_edges);
276 auto crack_skin_conn = get_conn(crack_skin);
277 auto crack_skin_conn_edges = get_adj(crack_skin_conn, 1);
278 auto crack_edges = get_adj(crack_faces, 1);
279 crack_edges = subtract(crack_edges, crack_skin);
280 auto all_tets = get_adj(crack_edges, 3);
281 crack_edges = subtract(crack_edges, crack_skin_conn_edges);
282 auto crack_conn = get_conn(crack_edges);
283 all_tets.merge(get_adj(crack_conn, 3));
284
285 if (debug) {
286 CHKERR save_range(m_field.get_moab(), "crack_faces.vtk", crack_faces);
287 CHKERR save_range(m_field.get_moab(), "all_crack_tets.vtk", all_tets);
288 CHKERR save_range(m_field.get_moab(), "crack_edges_all.vtk",
289 crack_edges);
290 }
291
292 if (crack_faces.size()) {
293 auto grow = [&](auto r) {
294 auto crack_faces_conn = get_conn(crack_faces);
295 Range v;
296 auto size_r = 0;
297 while (size_r != r.size() && r.size() > 0) {
298 size_r = r.size();
299 CHKERR moab.get_connectivity(r, v, true);
300 v = subtract(v, crack_faces_conn);
301 if (v.size()) {
302 CHKERR moab.get_adjacencies(v, SPACE_DIM, true, r,
303 moab::Interface::UNION);
304 r = intersect(r, all_tets);
305 }
306 if (r.empty()) {
307 break;
308 }
309 }
310 return r;
311 };
312
313 Range all_tets_ord = all_tets;
314 while (all_tets.size()) {
315 Range faces = get_adj(unite(saids.first, saids.second), 2);
316 faces = subtract(crack_faces, faces);
317 if (faces.size()) {
318 Range tets;
319 auto fit = faces.begin();
320 for (; fit != faces.end(); ++fit) {
321 tets = intersect(get_adj(Range(*fit, *fit), 3), all_tets);
322 if (tets.size() == 2) {
323 break;
324 }
325 }
326 if (tets.empty()) {
327 break;
328 } else {
329 saids.first.insert(tets[0]);
330 saids.first = grow(saids.first);
331 all_tets = subtract(all_tets, saids.first);
332 if (tets.size() == 2) {
333 saids.second.insert(tets[1]);
334 saids.second = grow(saids.second);
335 all_tets = subtract(all_tets, saids.second);
336 }
337 }
338 } else {
339 break;
340 }
341 }
342
343 saids.first = subtract(all_tets_ord, saids.second);
344 saids.second = subtract(all_tets_ord, saids.first);
345 }
346
348 };
349
350 std::pair<Range, Range> saids;
351 if (crack_faces.size())
352 CHK_THROW_MESSAGE(impl(saids), "get crack both sides");
353 return saids;
354 }
355
356 MOFEM_LOG("EP", Sev::noisy) << "get_two_sides_of_crack_surface <- done";
357
358 return std::pair<Range, Range>();
359}
360
361namespace EshelbianPlasticity {
362
364
365 SetIntegrationAtFrontVolume(boost::shared_ptr<Range> front_nodes,
366 boost::shared_ptr<Range> front_edges)
367 : frontNodes(front_nodes), frontEdges(front_edges){};
368
370 int order_col, int order_data) {
372
373 constexpr bool debug = false;
374
375 constexpr int numNodes = 4;
376 constexpr int numEdges = 6;
377 constexpr int refinementLevels = 6;
378
379 auto &m_field = fe_raw_ptr->mField;
380 auto fe_ptr = static_cast<Fe *>(fe_raw_ptr);
381 auto fe_handle = fe_ptr->getFEEntityHandle();
382
383 auto set_base_quadrature = [&]() {
385 int rule = 2 * order_data + 1;
386 if (rule < QUAD_3D_TABLE_SIZE) {
387 if (QUAD_3D_TABLE[rule]->dim != 3) {
388 SETERRQ(m_field.get_comm(), MOFEM_DATA_INCONSISTENCY,
389 "wrong dimension");
390 }
391 if (QUAD_3D_TABLE[rule]->order < rule) {
392 SETERRQ(m_field.get_comm(), MOFEM_DATA_INCONSISTENCY,
393 "wrong order %d != %d", QUAD_3D_TABLE[rule]->order, rule);
394 }
395 const size_t nb_gauss_pts = QUAD_3D_TABLE[rule]->npoints;
396 auto &gauss_pts = fe_ptr->gaussPts;
397 gauss_pts.resize(4, nb_gauss_pts, false);
398 cblas_dcopy(nb_gauss_pts, &QUAD_3D_TABLE[rule]->points[1], 4,
399 &gauss_pts(0, 0), 1);
400 cblas_dcopy(nb_gauss_pts, &QUAD_3D_TABLE[rule]->points[2], 4,
401 &gauss_pts(1, 0), 1);
402 cblas_dcopy(nb_gauss_pts, &QUAD_3D_TABLE[rule]->points[3], 4,
403 &gauss_pts(2, 0), 1);
404 cblas_dcopy(nb_gauss_pts, QUAD_3D_TABLE[rule]->weights, 1,
405 &gauss_pts(3, 0), 1);
406 auto &data = fe_ptr->dataOnElement[H1];
407 data->dataOnEntities[MBVERTEX][0].getN(NOBASE).resize(nb_gauss_pts, 4,
408 false);
409 double *shape_ptr =
410 &*data->dataOnEntities[MBVERTEX][0].getN(NOBASE).data().begin();
411 cblas_dcopy(4 * nb_gauss_pts, QUAD_3D_TABLE[rule]->points, 1, shape_ptr,
412 1);
413 } else {
414 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
415 "rule > quadrature order %d < %d", rule, QUAD_3D_TABLE_SIZE);
416 }
418 };
419
420 CHKERR set_base_quadrature();
421
423
424 auto get_singular_nodes = [&]() {
425 int num_nodes;
426 const EntityHandle *conn;
427 CHKERR m_field.get_moab().get_connectivity(fe_handle, conn, num_nodes,
428 true);
429 std::bitset<numNodes> singular_nodes;
430 for (auto nn = 0; nn != numNodes; ++nn) {
431 if (frontNodes->find(conn[nn]) != frontNodes->end()) {
432 singular_nodes.set(nn);
433 } else {
434 singular_nodes.reset(nn);
435 }
436 }
437 return singular_nodes;
438 };
439
440 auto get_singular_edges = [&]() {
441 std::bitset<numEdges> singular_edges;
442 for (int ee = 0; ee != numEdges; ee++) {
443 EntityHandle edge;
444 CHKERR m_field.get_moab().side_element(fe_handle, 1, ee, edge);
445 if (frontEdges->find(edge) != frontEdges->end()) {
446 singular_edges.set(ee);
447 } else {
448 singular_edges.reset(ee);
449 }
450 }
451 return singular_edges;
452 };
453
454 auto set_gauss_pts = [&](auto &ref_gauss_pts) {
456 fe_ptr->gaussPts.swap(ref_gauss_pts);
457 const size_t nb_gauss_pts = fe_ptr->gaussPts.size2();
458 auto &data = fe_ptr->dataOnElement[H1];
459 data->dataOnEntities[MBVERTEX][0].getN(NOBASE).resize(nb_gauss_pts, 4);
460 double *shape_ptr =
461 &*data->dataOnEntities[MBVERTEX][0].getN(NOBASE).data().begin();
462 CHKERR ShapeMBTET(shape_ptr, &fe_ptr->gaussPts(0, 0),
463 &fe_ptr->gaussPts(1, 0), &fe_ptr->gaussPts(2, 0),
464 nb_gauss_pts);
466 };
467
468 auto singular_nodes = get_singular_nodes();
469 if (singular_nodes.count()) {
470 auto it_map_ref_coords = mapRefCoords.find(singular_nodes.to_ulong());
471 if (it_map_ref_coords != mapRefCoords.end()) {
472 CHKERR set_gauss_pts(it_map_ref_coords->second);
474 } else {
475
476 auto refine_quadrature = [&]() {
478
479 const int max_level = refinementLevels;
480 EntityHandle tet;
481
482 moab::Core moab_ref;
483 double base_coords[] = {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1};
484 EntityHandle nodes[4];
485 for (int nn = 0; nn != 4; nn++)
486 CHKERR moab_ref.create_vertex(&base_coords[3 * nn], nodes[nn]);
487 CHKERR moab_ref.create_element(MBTET, nodes, 4, tet);
488 MoFEM::CoreTmp<-1> mofem_ref_core(moab_ref, PETSC_COMM_SELF, -2);
489 MoFEM::Interface &m_field_ref = mofem_ref_core;
490 {
491 Range tets(tet, tet);
492 Range edges;
493 CHKERR m_field_ref.get_moab().get_adjacencies(
494 tets, 1, true, edges, moab::Interface::UNION);
495 CHKERR m_field_ref.getInterface<BitRefManager>()->setBitRefLevel(
496 tets, BitRefLevel().set(0), false, VERBOSE);
497 }
498
499 Range nodes_at_front;
500 for (int nn = 0; nn != numNodes; nn++) {
501 if (singular_nodes[nn]) {
502 EntityHandle ent;
503 CHKERR moab_ref.side_element(tet, 0, nn, ent);
504 nodes_at_front.insert(ent);
505 }
506 }
507
508 auto singular_edges = get_singular_edges();
509
510 EntityHandle meshset;
511 CHKERR moab_ref.create_meshset(MESHSET_SET, meshset);
512 for (int ee = 0; ee != numEdges; ee++) {
513 if (singular_edges[ee]) {
514 EntityHandle ent;
515 CHKERR moab_ref.side_element(tet, 1, ee, ent);
516 CHKERR moab_ref.add_entities(meshset, &ent, 1);
517 }
518 }
519
520 // refine mesh
521 auto *m_ref = m_field_ref.getInterface<MeshRefinement>();
522 for (int ll = 0; ll != max_level; ll++) {
523 Range edges;
524 CHKERR m_field_ref.getInterface<BitRefManager>()
525 ->getEntitiesByTypeAndRefLevel(BitRefLevel().set(ll),
526 BitRefLevel().set(), MBEDGE,
527 edges);
528 Range ref_edges;
529 CHKERR moab_ref.get_adjacencies(
530 nodes_at_front, 1, true, ref_edges, moab::Interface::UNION);
531 ref_edges = intersect(ref_edges, edges);
532 Range ents;
533 CHKERR moab_ref.get_entities_by_type(meshset, MBEDGE, ents, true);
534 ref_edges = intersect(ref_edges, ents);
535 Range tets;
536 CHKERR m_field_ref.getInterface<BitRefManager>()
537 ->getEntitiesByTypeAndRefLevel(
538 BitRefLevel().set(ll), BitRefLevel().set(), MBTET, tets);
539 CHKERR m_ref->addVerticesInTheMiddleOfEdges(
540 ref_edges, BitRefLevel().set(ll + 1));
541 CHKERR m_ref->refineTets(tets, BitRefLevel().set(ll + 1));
542 CHKERR m_field_ref.getInterface<BitRefManager>()
543 ->updateMeshsetByEntitiesChildren(meshset,
544 BitRefLevel().set(ll + 1),
545 meshset, MBEDGE, true);
546 }
547
548 // get ref coords
549 Range tets;
550 CHKERR m_field_ref.getInterface<BitRefManager>()
551 ->getEntitiesByTypeAndRefLevel(BitRefLevel().set(max_level),
552 BitRefLevel().set(), MBTET,
553 tets);
554
555 if (debug) {
556 CHKERR save_range(moab_ref, "ref_tets.vtk", tets);
557 }
558
559 MatrixDouble ref_coords(tets.size(), 12, false);
560 int tt = 0;
561 for (Range::iterator tit = tets.begin(); tit != tets.end();
562 tit++, tt++) {
563 int num_nodes;
564 const EntityHandle *conn;
565 CHKERR moab_ref.get_connectivity(*tit, conn, num_nodes, false);
566 CHKERR moab_ref.get_coords(conn, num_nodes, &ref_coords(tt, 0));
567 }
568
569 auto &data = fe_ptr->dataOnElement[H1];
570 const size_t nb_gauss_pts = fe_ptr->gaussPts.size2();
571 MatrixDouble ref_gauss_pts(4, nb_gauss_pts * ref_coords.size1());
572 MatrixDouble &shape_n =
573 data->dataOnEntities[MBVERTEX][0].getN(NOBASE);
574 int gg = 0;
575 for (size_t tt = 0; tt != ref_coords.size1(); tt++) {
576 double *tet_coords = &ref_coords(tt, 0);
577 double det = Tools::tetVolume(tet_coords);
578 det *= 6;
579 for (size_t ggg = 0; ggg != nb_gauss_pts; ++ggg, ++gg) {
580 for (int dd = 0; dd != 3; dd++) {
581 ref_gauss_pts(dd, gg) =
582 shape_n(ggg, 0) * tet_coords[3 * 0 + dd] +
583 shape_n(ggg, 1) * tet_coords[3 * 1 + dd] +
584 shape_n(ggg, 2) * tet_coords[3 * 2 + dd] +
585 shape_n(ggg, 3) * tet_coords[3 * 3 + dd];
586 }
587 ref_gauss_pts(3, gg) = fe_ptr->gaussPts(3, ggg) * det;
588 }
589 }
590
591 mapRefCoords[singular_nodes.to_ulong()].swap(ref_gauss_pts);
592 CHKERR set_gauss_pts(mapRefCoords[singular_nodes.to_ulong()]);
593
595 };
596
597 CHKERR refine_quadrature();
598 }
599 }
600 }
601
603 }
604
605private:
606 struct Fe : public ForcesAndSourcesCore {
607 using ForcesAndSourcesCore::dataOnElement;
608
609 private:
610 using ForcesAndSourcesCore::ForcesAndSourcesCore;
611 };
612
613 boost::shared_ptr<Range> frontNodes;
614 boost::shared_ptr<Range> frontEdges;
615
616 static inline std::map<long int, MatrixDouble> mapRefCoords;
617};
618
620
621 using FunRule = boost::function<int(int)>;
622 FunRule funRule = [](int p) { return 2 * (p + 1); };
623
624 SetIntegrationAtFrontFace(boost::shared_ptr<Range> front_nodes,
625 boost::shared_ptr<Range> front_edges)
626 : frontNodes(front_nodes), frontEdges(front_edges){};
627
628 SetIntegrationAtFrontFace(boost::shared_ptr<Range> front_nodes,
629 boost::shared_ptr<Range> front_edges,
630 FunRule fun_rule)
631 : frontNodes(front_nodes), frontEdges(front_edges), funRule(fun_rule){};
632
634 int order_col, int order_data) {
636
637 constexpr bool debug = false;
638
639 constexpr int numNodes = 3;
640 constexpr int numEdges = 3;
641 constexpr int refinementLevels = 6;
642
643 auto &m_field = fe_raw_ptr->mField;
644 auto fe_ptr = static_cast<Fe *>(fe_raw_ptr);
645 auto fe_handle = fe_ptr->getFEEntityHandle();
646
647 auto set_base_quadrature = [&]() {
649 int rule = funRule(order_data);
650 if (rule < QUAD_2D_TABLE_SIZE) {
651 if (QUAD_2D_TABLE[rule]->dim != 2) {
652 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "wrong dimension");
653 }
654 if (QUAD_2D_TABLE[rule]->order < rule) {
655 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
656 "wrong order %d != %d", QUAD_2D_TABLE[rule]->order, rule);
657 }
658 const size_t nb_gauss_pts = QUAD_2D_TABLE[rule]->npoints;
659 fe_ptr->gaussPts.resize(3, nb_gauss_pts, false);
660 cblas_dcopy(nb_gauss_pts, &QUAD_2D_TABLE[rule]->points[1], 3,
661 &fe_ptr->gaussPts(0, 0), 1);
662 cblas_dcopy(nb_gauss_pts, &QUAD_2D_TABLE[rule]->points[2], 3,
663 &fe_ptr->gaussPts(1, 0), 1);
664 cblas_dcopy(nb_gauss_pts, QUAD_2D_TABLE[rule]->weights, 1,
665 &fe_ptr->gaussPts(2, 0), 1);
666 auto &data = fe_ptr->dataOnElement[H1];
667 data->dataOnEntities[MBVERTEX][0].getN(NOBASE).resize(nb_gauss_pts, 3,
668 false);
669 double *shape_ptr =
670 &*data->dataOnEntities[MBVERTEX][0].getN(NOBASE).data().begin();
671 cblas_dcopy(3 * nb_gauss_pts, QUAD_2D_TABLE[rule]->points, 1, shape_ptr,
672 1);
673 data->dataOnEntities[MBVERTEX][0].getDiffN(NOBASE).resize(3, 2, false);
674 std::copy(
676 data->dataOnEntities[MBVERTEX][0].getDiffN(NOBASE).data().begin());
677
678 } else {
679 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
680 "rule > quadrature order %d < %d", rule, QUAD_3D_TABLE_SIZE);
681 }
683 };
684
685 CHKERR set_base_quadrature();
686
688
689 auto get_singular_nodes = [&]() {
690 int num_nodes;
691 const EntityHandle *conn;
692 CHKERR m_field.get_moab().get_connectivity(fe_handle, conn, num_nodes,
693 true);
694 std::bitset<numNodes> singular_nodes;
695 for (auto nn = 0; nn != numNodes; ++nn) {
696 if (frontNodes->find(conn[nn]) != frontNodes->end()) {
697 singular_nodes.set(nn);
698 } else {
699 singular_nodes.reset(nn);
700 }
701 }
702 return singular_nodes;
703 };
704
705 auto get_singular_edges = [&]() {
706 std::bitset<numEdges> singular_edges;
707 for (int ee = 0; ee != numEdges; ee++) {
708 EntityHandle edge;
709 CHKERR m_field.get_moab().side_element(fe_handle, 1, ee, edge);
710 if (frontEdges->find(edge) != frontEdges->end()) {
711 singular_edges.set(ee);
712 } else {
713 singular_edges.reset(ee);
714 }
715 }
716 return singular_edges;
717 };
718
719 auto set_gauss_pts = [&](auto &ref_gauss_pts) {
721 fe_ptr->gaussPts.swap(ref_gauss_pts);
722 const size_t nb_gauss_pts = fe_ptr->gaussPts.size2();
723 auto &data = fe_ptr->dataOnElement[H1];
724 data->dataOnEntities[MBVERTEX][0].getN(NOBASE).resize(nb_gauss_pts, 4);
725 double *shape_ptr =
726 &*data->dataOnEntities[MBVERTEX][0].getN(NOBASE).data().begin();
727 CHKERR ShapeMBTRI(shape_ptr, &fe_ptr->gaussPts(0, 0),
728 &fe_ptr->gaussPts(1, 0), nb_gauss_pts);
730 };
731
732 auto singular_nodes = get_singular_nodes();
733 if (singular_nodes.count()) {
734 auto it_map_ref_coords = mapRefCoords.find(singular_nodes.to_ulong());
735 if (it_map_ref_coords != mapRefCoords.end()) {
736 CHKERR set_gauss_pts(it_map_ref_coords->second);
738 } else {
739
740 auto refine_quadrature = [&]() {
742
743 const int max_level = refinementLevels;
744
745 moab::Core moab_ref;
746 double base_coords[] = {0, 0, 0, 1, 0, 0, 0, 1, 0};
747 EntityHandle nodes[numNodes];
748 for (int nn = 0; nn != numNodes; nn++)
749 CHKERR moab_ref.create_vertex(&base_coords[3 * nn], nodes[nn]);
750 EntityHandle tri;
751 CHKERR moab_ref.create_element(MBTRI, nodes, numNodes, tri);
752 MoFEM::CoreTmp<-1> mofem_ref_core(moab_ref, PETSC_COMM_SELF, -2);
753 MoFEM::Interface &m_field_ref = mofem_ref_core;
754 {
755 Range tris(tri, tri);
756 Range edges;
757 CHKERR m_field_ref.get_moab().get_adjacencies(
758 tris, 1, true, edges, moab::Interface::UNION);
759 CHKERR m_field_ref.getInterface<BitRefManager>()->setBitRefLevel(
760 tris, BitRefLevel().set(0), false, VERBOSE);
761 }
762
763 Range nodes_at_front;
764 for (int nn = 0; nn != numNodes; nn++) {
765 if (singular_nodes[nn]) {
766 EntityHandle ent;
767 CHKERR moab_ref.side_element(tri, 0, nn, ent);
768 nodes_at_front.insert(ent);
769 }
770 }
771
772 auto singular_edges = get_singular_edges();
773
774 EntityHandle meshset;
775 CHKERR moab_ref.create_meshset(MESHSET_SET, meshset);
776 for (int ee = 0; ee != numEdges; ee++) {
777 if (singular_edges[ee]) {
778 EntityHandle ent;
779 CHKERR moab_ref.side_element(tri, 1, ee, ent);
780 CHKERR moab_ref.add_entities(meshset, &ent, 1);
781 }
782 }
783
784 // refine mesh
785 auto *m_ref = m_field_ref.getInterface<MeshRefinement>();
786 for (int ll = 0; ll != max_level; ll++) {
787 Range edges;
788 CHKERR m_field_ref.getInterface<BitRefManager>()
789 ->getEntitiesByTypeAndRefLevel(BitRefLevel().set(ll),
790 BitRefLevel().set(), MBEDGE,
791 edges);
792 Range ref_edges;
793 CHKERR moab_ref.get_adjacencies(
794 nodes_at_front, 1, true, ref_edges, moab::Interface::UNION);
795 ref_edges = intersect(ref_edges, edges);
796 Range ents;
797 CHKERR moab_ref.get_entities_by_type(meshset, MBEDGE, ents, true);
798 ref_edges = intersect(ref_edges, ents);
799 Range tris;
800 CHKERR m_field_ref.getInterface<BitRefManager>()
801 ->getEntitiesByTypeAndRefLevel(
802 BitRefLevel().set(ll), BitRefLevel().set(), MBTRI, tris);
803 CHKERR m_ref->addVerticesInTheMiddleOfEdges(
804 ref_edges, BitRefLevel().set(ll + 1));
805 CHKERR m_ref->refineTris(tris, BitRefLevel().set(ll + 1));
806 CHKERR m_field_ref.getInterface<BitRefManager>()
807 ->updateMeshsetByEntitiesChildren(meshset,
808 BitRefLevel().set(ll + 1),
809 meshset, MBEDGE, true);
810 }
811
812 // get ref coords
813 Range tris;
814 CHKERR m_field_ref.getInterface<BitRefManager>()
815 ->getEntitiesByTypeAndRefLevel(BitRefLevel().set(max_level),
816 BitRefLevel().set(), MBTRI,
817 tris);
818
819 if (debug) {
820 CHKERR save_range(moab_ref, "ref_tris.vtk", tris);
821 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "debug");
822 }
823
824 MatrixDouble ref_coords(tris.size(), 9, false);
825 int tt = 0;
826 for (Range::iterator tit = tris.begin(); tit != tris.end();
827 tit++, tt++) {
828 int num_nodes;
829 const EntityHandle *conn;
830 CHKERR moab_ref.get_connectivity(*tit, conn, num_nodes, false);
831 CHKERR moab_ref.get_coords(conn, num_nodes, &ref_coords(tt, 0));
832 }
833
834 auto &data = fe_ptr->dataOnElement[H1];
835 const size_t nb_gauss_pts = fe_ptr->gaussPts.size2();
836 MatrixDouble ref_gauss_pts(3, nb_gauss_pts * ref_coords.size1());
837 MatrixDouble &shape_n =
838 data->dataOnEntities[MBVERTEX][0].getN(NOBASE);
839 int gg = 0;
840 for (size_t tt = 0; tt != ref_coords.size1(); tt++) {
841 double *tri_coords = &ref_coords(tt, 0);
843 CHKERR Tools::getTriNormal(tri_coords, &t_normal(0));
844 auto det = t_normal.l2();
845 for (size_t ggg = 0; ggg != nb_gauss_pts; ++ggg, ++gg) {
846 for (int dd = 0; dd != 2; dd++) {
847 ref_gauss_pts(dd, gg) =
848 shape_n(ggg, 0) * tri_coords[3 * 0 + dd] +
849 shape_n(ggg, 1) * tri_coords[3 * 1 + dd] +
850 shape_n(ggg, 2) * tri_coords[3 * 2 + dd];
851 }
852 ref_gauss_pts(2, gg) = fe_ptr->gaussPts(2, ggg) * det;
853 }
854 }
855
856 mapRefCoords[singular_nodes.to_ulong()].swap(ref_gauss_pts);
857 CHKERR set_gauss_pts(mapRefCoords[singular_nodes.to_ulong()]);
858
860 };
861
862 CHKERR refine_quadrature();
863 }
864 }
865 }
866
868 }
869
870private:
871 struct Fe : public ForcesAndSourcesCore {
872 using ForcesAndSourcesCore::dataOnElement;
873
874 private:
875 using ForcesAndSourcesCore::ForcesAndSourcesCore;
876 };
877
878 boost::shared_ptr<Range> frontNodes;
879 boost::shared_ptr<Range> frontEdges;
880
881 static inline std::map<long int, MatrixDouble> mapRefCoords;
882};
883
884double EshelbianCore::exponentBase = exp(1);
885boost::function<double(const double)> EshelbianCore::f = EshelbianCore::f_log_e;
886boost::function<double(const double)> EshelbianCore::d_f =
888boost::function<double(const double)> EshelbianCore::dd_f =
890boost::function<double(const double)> EshelbianCore::inv_f =
892boost::function<double(const double)> EshelbianCore::inv_d_f =
894boost::function<double(const double)> EshelbianCore::inv_dd_f =
896
898EshelbianCore::query_interface(boost::typeindex::type_index type_index,
899 UnknownInterface **iface) const {
900 *iface = const_cast<EshelbianCore *>(this);
901 return 0;
902}
903
904MoFEMErrorCode OpJacobian::doWork(int side, EntityType type, EntData &data) {
906
907 if (evalRhs)
908 CHKERR evaluateRhs(data);
909
910 if (evalLhs)
911 CHKERR evaluateLhs(data);
912
914}
915
917 CHK_THROW_MESSAGE(getOptions(), "getOptions failed");
918}
919
921
924 const char *list_rots[] = {"small", "moderate", "large", "no_h1"};
925 const char *list_symm[] = {"symm", "not_symm"};
926 const char *list_release[] = {"griffith_force", "griffith_skeleton"};
927 const char *list_stretches[] = {"linear", "log", "log_quadratic"};
928 PetscInt choice_rot = EshelbianCore::rotSelector;
929 PetscInt choice_grad = EshelbianCore::gradApproximator;
930 PetscInt choice_symm = EshelbianCore::symmetrySelector;
931 PetscInt choice_release = EshelbianCore::energyReleaseSelector;
932 PetscInt choice_stretch = StretchSelector::LOG;
933 char analytical_expr_file_name[255] = "analytical_expr.py";
934
935 PetscOptionsBegin(PETSC_COMM_WORLD, "", "Eshelbian plasticity",
936 "none");
937 CHKERR PetscOptionsInt("-space_order", "approximation oder for space", "",
938 spaceOrder, &spaceOrder, PETSC_NULLPTR);
939 CHKERR PetscOptionsInt("-space_h1_order", "approximation oder for space", "",
940 spaceH1Order, &spaceH1Order, PETSC_NULLPTR);
941 CHKERR PetscOptionsInt("-material_order", "approximation oder for material",
942 "", materialOrder, &materialOrder, PETSC_NULLPTR);
943 CHKERR PetscOptionsScalar("-viscosity_alpha_u", "viscosity", "", alphaU,
944 &alphaU, PETSC_NULLPTR);
945 CHKERR PetscOptionsScalar("-viscosity_alpha_w", "viscosity", "", alphaW,
946 &alphaW, PETSC_NULLPTR);
947 CHKERR PetscOptionsScalar("-viscosity_alpha_omega", "rot viscosity", "",
948 alphaOmega, &alphaOmega, PETSC_NULLPTR);
949 CHKERR PetscOptionsScalar("-density_alpha_rho", "density", "", alphaRho,
950 &alphaRho, PETSC_NULLPTR);
951 CHKERR PetscOptionsEList("-rotations", "rotations", "", list_rots,
952 LARGE_ROT + 1, list_rots[choice_rot], &choice_rot,
953 PETSC_NULLPTR);
954 CHKERR PetscOptionsEList("-grad", "gradient of defamation approximate", "",
955 list_rots, NO_H1_CONFIGURATION + 1,
956 list_rots[choice_grad], &choice_grad, PETSC_NULLPTR);
957 CHKERR PetscOptionsEList("-symm", "symmetric variant", "", list_symm, 2,
958 list_symm[choice_symm], &choice_symm, PETSC_NULLPTR);
959
960 CHKERR PetscOptionsScalar("-exponent_base", "exponent_base", "", exponentBase,
961 &EshelbianCore::exponentBase, PETSC_NULLPTR);
962 CHKERR PetscOptionsEList("-stretches", "stretches", "", list_stretches,
963 StretchSelector::STRETCH_SELECTOR_LAST,
964 list_stretches[choice_stretch], &choice_stretch,
965 PETSC_NULLPTR);
966
967 CHKERR PetscOptionsBool("-no_stretch", "do not solve for stretch", "",
968 noStretch, &noStretch, PETSC_NULLPTR);
969 CHKERR PetscOptionsBool("-set_singularity", "set singularity", "",
970 setSingularity, &setSingularity, PETSC_NULLPTR);
971 CHKERR PetscOptionsBool("-l2_user_base_scale", "streach scale", "",
972 l2UserBaseScale, &l2UserBaseScale, PETSC_NULLPTR);
973
974 // dynamic relaxation
975 CHKERR PetscOptionsBool("-dynamic_relaxation", "dynamic time relaxation", "",
976 dynamicRelaxation, &dynamicRelaxation, PETSC_NULLPTR);
977
978 // contact parameters
979 CHKERR PetscOptionsInt("-contact_max_post_proc_ref_level", "refinement level",
981 PETSC_NULLPTR);
982
983 // cracking parameters
984 CHKERR PetscOptionsBool("-cracking_on", "cracking ON", "", crackingOn,
985 &crackingOn, PETSC_NULLPTR);
986 CHKERR PetscOptionsScalar("-cracking_start_time", "cracking start time", "",
987 crackingStartTime, &crackingStartTime, PETSC_NULLPTR);
988 CHKERR PetscOptionsScalar("-griffith_energy", "Griffith energy", "",
989 griffithEnergy, &griffithEnergy, PETSC_NULLPTR);
990 CHKERR PetscOptionsEList("-energy_release_variant", "energy release variant",
991 "", list_release, 2, list_release[choice_release],
992 &choice_release, PETSC_NULLPTR);
993 CHKERR PetscOptionsInt("-nb_J_integral_levels", "Number of J integarl levels",
995 PETSC_NULLPTR); // backward compatibility
996 CHKERR PetscOptionsInt(
997 "-nb_J_integral_contours", "Number of J integral contours", "",
999
1000 // internal stress
1001 char tag_name[255] = "";
1002 CHKERR PetscOptionsString("-internal_stress_tag_name",
1003 "internal stress tag name", "", "", tag_name, 255,
1004 PETSC_NULLPTR);
1005 internalStressTagName = string(tag_name);
1006 CHKERR PetscOptionsInt(
1007 "-internal_stress_interp_order", "internal stress interpolation order",
1009 CHKERR PetscOptionsBool("-internal_stress_voigt", "Voigt index notation", "",
1011 PETSC_NULLPTR);
1012
1013 CHKERR PetscOptionsGetString(PETSC_NULLPTR, PETSC_NULLPTR, "-analytical_expr_file",
1014 analytical_expr_file_name, 255, PETSC_NULLPTR);
1015
1016 PetscOptionsEnd();
1017
1019 SETERRQ(PETSC_COMM_WORLD, MOFEM_NOT_IMPLEMENTED,
1020 "Unsupported internal stress interpolation order %d",
1022 }
1023
1024 if (setSingularity) {
1025 l2UserBaseScale = PETSC_TRUE;
1026 }
1027
1028 EshelbianCore::rotSelector = static_cast<RotSelector>(choice_rot);
1029 EshelbianCore::gradApproximator = static_cast<RotSelector>(choice_grad);
1030 EshelbianCore::stretchSelector = static_cast<StretchSelector>(choice_stretch);
1031 EshelbianCore::symmetrySelector = static_cast<SymmetrySelector>(choice_symm);
1033 static_cast<EnergyReleaseSelector>(choice_release);
1034
1036 case StretchSelector::LINEAR:
1043 break;
1044 case StretchSelector::LOG:
1045 if (std::fabs(EshelbianCore::exponentBase - exp(1)) >
1046 std::numeric_limits<float>::epsilon()) {
1053 } else {
1060 }
1061 break;
1062 case StretchSelector::LOG_QUADRATIC:
1066 EshelbianCore::inv_f = [](const double x) {
1068 "No logarithmic quadratic stretch for this case");
1069 return 0;
1070 };
1073 break; // no stretch, do not use stretch functions
1074 default:
1075 SETERRQ(mField.get_comm(), MOFEM_DATA_INCONSISTENCY, "Unknown stretch");
1076 break;
1077 };
1078
1079 MOFEM_LOG("EP", Sev::inform) << "spaceOrder: -space_order " << spaceOrder;
1080 MOFEM_LOG("EP", Sev::inform)
1081 << "spaceH1Order: -space_h1_order " << spaceH1Order;
1082 MOFEM_LOG("EP", Sev::inform)
1083 << "materialOrder: -material_order " << materialOrder;
1084 MOFEM_LOG("EP", Sev::inform) << "alphaU: -viscosity_alpha_u " << alphaU;
1085 MOFEM_LOG("EP", Sev::inform) << "alphaW: -viscosity_alpha_w " << alphaW;
1086 MOFEM_LOG("EP", Sev::inform)
1087 << "alphaOmega: -viscosity_alpha_omega " << alphaOmega;
1088 MOFEM_LOG("EP", Sev::inform) << "alphaRho: -density_alpha_rho " << alphaRho;
1089 MOFEM_LOG("EP", Sev::inform)
1090 << "Rotations: -rotations " << list_rots[EshelbianCore::rotSelector];
1091 MOFEM_LOG("EP", Sev::inform) << "Gradient of deformation "
1092 << list_rots[EshelbianCore::gradApproximator];
1093 MOFEM_LOG("EP", Sev::inform)
1094 << "Symmetry: -symm " << list_symm[EshelbianCore::symmetrySelector];
1095 if (exponentBase != exp(1))
1096 MOFEM_LOG("EP", Sev::inform)
1097 << "Base exponent: -exponent_base " << EshelbianCore::exponentBase;
1098 else
1099 MOFEM_LOG("EP", Sev::inform) << "Base exponent e";
1100 MOFEM_LOG("EP", Sev::inform)
1101 << "Stretch: -stretches " << list_stretches[choice_stretch];
1102 MOFEM_LOG("EP", Sev::inform) << "No stretch: -no_stretch " << (noStretch)
1103 ? "yes"
1104 : "no";
1105
1106 MOFEM_LOG("EP", Sev::inform)
1107 << "Dynamic relaxation: -dynamic_relaxation " << (dynamicRelaxation)
1108 ? "yes"
1109 : "no";
1110 MOFEM_LOG("EP", Sev::inform)
1111 << "Singularity: -set_singularity " << (setSingularity)
1112 ? "yes"
1113 : "no";
1114 MOFEM_LOG("EP", Sev::inform)
1115 << "L2 user base scale: -l2_user_base_scale " << (l2UserBaseScale)
1116 ? "yes"
1117 : "no";
1118
1119 MOFEM_LOG("EP", Sev::inform) << "Cracking on: -cracking_on " << (crackingOn)
1120 ? "yes"
1121 : "no";
1122 MOFEM_LOG("EP", Sev::inform)
1123 << "Cracking start time: -cracking_start_time " << crackingStartTime;
1124 MOFEM_LOG("EP", Sev::inform)
1125 << "Griffith energy: -griffith_energy " << griffithEnergy;
1126 MOFEM_LOG("EP", Sev::inform)
1127 << "Energy release variant: -energy_release_variant "
1128 << list_release[EshelbianCore::energyReleaseSelector];
1129 MOFEM_LOG("EP", Sev::inform)
1130 << "Number of J integral contours: -nb_J_integral_contours "
1132
1133#ifdef ENABLE_PYTHON_BINDING
1134 auto file_exists = [](std::string myfile) {
1135 std::ifstream file(myfile.c_str());
1136 if (file) {
1137 return true;
1138 }
1139 return false;
1140 };
1141
1142 if (file_exists(analytical_expr_file_name)) {
1143 MOFEM_LOG("EP", Sev::inform) << analytical_expr_file_name << " file found";
1144
1145 AnalyticalExprPythonPtr = boost::make_shared<AnalyticalExprPython>();
1146 CHKERR AnalyticalExprPythonPtr->analyticalExprInit(
1147 analytical_expr_file_name);
1148 AnalyticalExprPythonWeakPtr = AnalyticalExprPythonPtr;
1149 } else {
1150 MOFEM_LOG("EP", Sev::warning)
1151 << analytical_expr_file_name << " file NOT found";
1152 }
1153#endif
1154
1155 if (spaceH1Order == -1)
1157
1159}
1160
1163
1164 auto get_tets = [&]() {
1165 Range tets;
1166 CHKERR mField.get_moab().get_entities_by_type(meshset, MBTET, tets);
1167 return tets;
1168 };
1169
1170 auto get_tets_skin = [&]() {
1171 Range tets_skin_part;
1172 Skinner skin(&mField.get_moab());
1173 CHKERR skin.find_skin(0, get_tets(), false, tets_skin_part);
1174 ParallelComm *pcomm =
1175 ParallelComm::get_pcomm(&mField.get_moab(), MYPCOMM_INDEX);
1176 Range tets_skin;
1177 CHKERR pcomm->filter_pstatus(tets_skin_part,
1178 PSTATUS_SHARED | PSTATUS_MULTISHARED,
1179 PSTATUS_NOT, -1, &tets_skin);
1180 return tets_skin;
1181 };
1182
1183 auto subtract_boundary_conditions = [&](auto &&tets_skin) {
1184 // That mean, that hybrid field on all faces on which traction is applied,
1185 // on other faces, or enforcing displacements as
1186 // natural boundary condition.
1188 for (auto &v : *bcSpatialTractionVecPtr) {
1189 tets_skin = subtract(tets_skin, v.faces);
1190 }
1192 for (auto &v : *bcSpatialAnalyticalTractionVecPtr) {
1193 tets_skin = subtract(tets_skin, v.faces);
1194 }
1195
1197 for (auto &v : *bcSpatialPressureVecPtr) {
1198 tets_skin = subtract(tets_skin, v.faces);
1199 }
1200
1201 return tets_skin;
1202 };
1203
1204 auto add_blockset = [&](auto block_name, auto &&tets_skin) {
1205 auto crack_faces =
1206 get_range_from_block(mField, "block_name", SPACE_DIM - 1);
1207 tets_skin.merge(crack_faces);
1208 return tets_skin;
1209 };
1210
1211 auto subtract_blockset = [&](auto block_name, auto &&tets_skin) {
1212 auto contact_range =
1213 get_range_from_block(mField, block_name, SPACE_DIM - 1);
1214 tets_skin = subtract(tets_skin, contact_range);
1215 return tets_skin;
1216 };
1217
1218 auto get_stress_trace_faces = [&](auto &&tets_skin) {
1219 Range faces;
1220 CHKERR mField.get_moab().get_adjacencies(get_tets(), SPACE_DIM - 1, true,
1221 faces, moab::Interface::UNION);
1222 Range trace_faces = subtract(faces, tets_skin);
1223 return trace_faces;
1224 };
1225
1226 auto tets = get_tets();
1227
1228 // remove also contact faces, i.e. that is also kind of hybrid field but
1229 // named but used to enforce contact conditions
1230 auto trace_faces = get_stress_trace_faces(
1231
1232 subtract_blockset("CONTACT",
1233 subtract_boundary_conditions(get_tets_skin()))
1234
1235 );
1236
1237 contactFaces = boost::make_shared<Range>(intersect(
1238 trace_faces, get_range_from_block(mField, "CONTACT", SPACE_DIM - 1)));
1240 boost::make_shared<Range>(subtract(trace_faces, *contactFaces));
1241 // materialSkeletonFaces =
1242 // boost::make_shared<Range>(get_stress_trace_faces(Range()));
1243
1244#ifndef NDEBUG
1245 if (contactFaces->size())
1247 "contact_faces_" +
1248 std::to_string(mField.get_comm_rank()) + ".vtk",
1249 *contactFaces);
1250 if (skeletonFaces->size())
1252 "skeleton_faces_" +
1253 std::to_string(mField.get_comm_rank()) + ".vtk",
1254 *skeletonFaces);
1255 // if (skeletonFaces->size())
1256 // CHKERR save_range(mField.get_moab(), "material_skeleton_faces.vtk",
1257 // *materialSkeletonFaces);
1258#endif
1259
1260 auto add_broken_hdiv_field = [this, meshset](const std::string field_name,
1261 const int order) {
1263
1265
1266 auto get_side_map_hdiv = [&]() {
1267 return std::vector<
1268
1269 std::pair<EntityType,
1271
1272 >>{
1273
1274 {MBTET,
1275 [&](BaseFunction::DofsSideMap &dofs_side_map) -> MoFEMErrorCode {
1276 return TetPolynomialBase::setDofsSideMap(HDIV, DISCONTINUOUS, base,
1277 dofs_side_map);
1278 }}
1279
1280 };
1281 };
1282
1284 get_side_map_hdiv(), MB_TAG_DENSE, MF_ZERO);
1286 CHKERR mField.set_field_order(meshset, MBTET, field_name, order);
1288 };
1289
1290 auto add_l2_field = [this, meshset](const std::string field_name,
1291 const int order, const int dim) {
1294 MB_TAG_DENSE, MF_ZERO);
1296 CHKERR mField.set_field_order(meshset, MBTET, field_name, order);
1298 };
1299
1300 auto add_h1_field = [this, meshset](const std::string field_name,
1301 const int order, const int dim) {
1304 MB_TAG_DENSE, MF_ZERO);
1306 CHKERR mField.set_field_order(meshset, MBVERTEX, field_name, 1);
1307 CHKERR mField.set_field_order(meshset, MBEDGE, field_name, order);
1308 CHKERR mField.set_field_order(meshset, MBTRI, field_name, order);
1309 CHKERR mField.set_field_order(meshset, MBTET, field_name, order);
1311 };
1312
1313 auto add_l2_field_by_range = [this](const std::string field_name,
1314 const int order, const int dim,
1315 const int field_dim, Range &&r) {
1318 MB_TAG_DENSE, MF_ZERO);
1319 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(r);
1323 };
1324
1325 auto add_bubble_field = [this, meshset](const std::string field_name,
1326 const int order, const int dim) {
1328 CHKERR mField.add_field(field_name, HDIV, USER_BASE, dim, MB_TAG_DENSE,
1329 MF_ZERO);
1330 // Modify field
1331 auto field_ptr = mField.get_field_structure(field_name);
1332 auto field_order_table =
1333 const_cast<Field *>(field_ptr)->getFieldOrderTable();
1334 auto get_cgg_bubble_order_zero = [](int p) { return 0; };
1335 auto get_cgg_bubble_order_tet = [](int p) {
1336 return NBVOLUMETET_CCG_BUBBLE(p);
1337 };
1338 field_order_table[MBVERTEX] = get_cgg_bubble_order_zero;
1339 field_order_table[MBEDGE] = get_cgg_bubble_order_zero;
1340 field_order_table[MBTRI] = get_cgg_bubble_order_zero;
1341 field_order_table[MBTET] = get_cgg_bubble_order_tet;
1343 CHKERR mField.set_field_order(meshset, MBTRI, field_name, order);
1344 CHKERR mField.set_field_order(meshset, MBTET, field_name, order);
1346 };
1347
1348 auto add_user_l2_field = [this, meshset](const std::string field_name,
1349 const int order, const int dim) {
1351 CHKERR mField.add_field(field_name, L2, USER_BASE, dim, MB_TAG_DENSE,
1352 MF_ZERO);
1353 // Modify field
1354 auto field_ptr = mField.get_field_structure(field_name);
1355 auto field_order_table =
1356 const_cast<Field *>(field_ptr)->getFieldOrderTable();
1357 auto zero_dofs = [](int p) { return 0; };
1358 auto dof_l2_tet = [](int p) { return NBVOLUMETET_L2(p); };
1359 field_order_table[MBVERTEX] = zero_dofs;
1360 field_order_table[MBEDGE] = zero_dofs;
1361 field_order_table[MBTRI] = zero_dofs;
1362 field_order_table[MBTET] = dof_l2_tet;
1364 CHKERR mField.set_field_order(meshset, MBTET, field_name, order);
1366 };
1367
1368 // spatial fields
1369 CHKERR add_broken_hdiv_field(piolaStress, spaceOrder);
1370 CHKERR add_bubble_field(bubbleField, spaceOrder, 1);
1371 CHKERR add_l2_field(spatialL2Disp, spaceOrder - 1, 3);
1372 CHKERR add_user_l2_field(rotAxis, spaceOrder - 1, 3);
1373 CHKERR add_user_l2_field(stretchTensor, noStretch ? -1 : spaceOrder, 6);
1374
1375 if (!skeletonFaces)
1376 SETERRQ(mField.get_comm(), MOFEM_DATA_INCONSISTENCY, "No skeleton faces");
1377 if (!contactFaces)
1378 SETERRQ(mField.get_comm(), MOFEM_DATA_INCONSISTENCY, "No contact faces");
1379
1380 auto get_hybridised_disp = [&]() {
1381 auto faces = *skeletonFaces;
1382 auto skin = subtract_boundary_conditions(get_tets_skin());
1383 for (auto &bc : *bcSpatialNormalDisplacementVecPtr) {
1384 faces.merge(intersect(bc.faces, skin));
1385 }
1386 return faces;
1387 };
1388
1389 CHKERR add_l2_field_by_range(hybridSpatialDisp, spaceOrder - 1, 2, 3,
1390 get_hybridised_disp());
1391 CHKERR add_l2_field_by_range(contactDisp, spaceOrder - 1, 2, 3,
1393
1394 // spatial displacement
1395 CHKERR add_h1_field(spatialH1Disp, spaceH1Order, 3);
1396 // material positions
1397 CHKERR add_h1_field(materialH1Positions, 2, 3);
1398
1399 // Eshelby stress
1400 // CHKERR add_broken_hdiv_field(eshelbyStress, spaceOrder);
1401 // CHKERR add_l2_field(materialL2Disp, spaceOrder - 1, 3);
1402 // CHKERR add_l2_field_by_range(hybridMaterialDisp, spaceOrder - 1, 2, 3,
1403 // Range(*materialSkeletonFaces));
1404
1406
1408}
1409
1412
1413 Range meshset_ents;
1414 CHKERR mField.get_moab().get_entities_by_handle(meshset, meshset_ents);
1415
1416 auto project_ho_geometry = [&](auto field) {
1418 return mField.loop_dofs(field, ent_method);
1419 };
1420 CHKERR project_ho_geometry(materialH1Positions);
1421
1422 auto get_adj_front_edges = [&](auto &front_edges) {
1423 Range front_crack_nodes;
1424 Range crack_front_edges_with_both_nodes_not_at_front;
1425
1426 if (mField.get_comm_rank() == 0) {
1427 auto &moab = mField.get_moab();
1429 moab.get_connectivity(front_edges, front_crack_nodes, true),
1430 "get_connectivity failed");
1431 Range crack_front_edges;
1432 CHK_MOAB_THROW(moab.get_adjacencies(front_crack_nodes, SPACE_DIM - 2,
1433 false, crack_front_edges,
1434 moab::Interface::UNION),
1435 "get_adjacencies failed");
1436 Range crack_front_edges_nodes;
1437 CHK_MOAB_THROW(moab.get_connectivity(crack_front_edges,
1438 crack_front_edges_nodes, true),
1439 "get_connectivity failed");
1440 // those nodes are hannging nodes
1441 crack_front_edges_nodes =
1442 subtract(crack_front_edges_nodes, front_crack_nodes);
1443 Range crack_front_edges_with_both_nodes_not_at_front;
1445 moab.get_adjacencies(crack_front_edges_nodes, 1, false,
1446 crack_front_edges_with_both_nodes_not_at_front,
1447 moab::Interface::UNION),
1448 "get_adjacencies failed");
1449 // those edges are have one node not at the crack front
1450 crack_front_edges_with_both_nodes_not_at_front =
1451 intersect(crack_front_edges,
1452 crack_front_edges_with_both_nodes_not_at_front);
1453 }
1454
1455 front_crack_nodes = send_type(mField, front_crack_nodes, MBVERTEX);
1456 crack_front_edges_with_both_nodes_not_at_front = send_type(
1457 mField, crack_front_edges_with_both_nodes_not_at_front, MBEDGE);
1458
1459 return std::make_pair(boost::make_shared<Range>(front_crack_nodes),
1460 boost::make_shared<Range>(
1461 crack_front_edges_with_both_nodes_not_at_front));
1462 };
1463
1464 crackFaces = boost::make_shared<Range>(
1465 get_range_from_block(mField, "CRACK", SPACE_DIM - 1));
1466 frontEdges =
1467 boost::make_shared<Range>(get_crack_front_edges(mField, *crackFaces));
1468 auto [front_vertices, front_adj_edges] = get_adj_front_edges(*frontEdges);
1469 frontVertices = front_vertices;
1470 frontAdjEdges = front_adj_edges;
1471
1472 MOFEM_LOG("EP", Sev::inform)
1473 << "Number of crack faces: " << crackFaces->size();
1474 MOFEM_LOG("EP", Sev::inform)
1475 << "Number of front edges: " << frontEdges->size();
1476 MOFEM_LOG("EP", Sev::inform)
1477 << "Number of front vertices: " << frontVertices->size();
1478 MOFEM_LOG("EP", Sev::inform)
1479 << "Number of front adjacent edges: " << frontAdjEdges->size();
1480
1481#ifndef NDEBUG
1482 if (crackingOn) {
1483 auto rank = mField.get_comm_rank();
1484 // CHKERR save_range(mField.get_moab(),
1485 // (boost::format("meshset_ents_%d.vtk") % rank).str(),
1486 // meshset_ents);
1488 (boost::format("crack_faces_%d.vtk") % rank).str(),
1489 *crackFaces);
1491 (boost::format("front_edges_%d.vtk") % rank).str(),
1492 *frontEdges);
1493 // CHKERR save_range(mField.get_moab(),
1494 // (boost::format("front_vertices_%d.vtk") % rank).str(),
1495 // *frontVertices);
1496 // CHKERR save_range(mField.get_moab(),
1497 // (boost::format("front_adj_edges_%d.vtk") % rank).str(),
1498 // *frontAdjEdges);
1499 }
1500#endif // NDEBUG
1501
1502 auto set_singular_dofs = [&](auto &front_adj_edges, auto &front_vertices) {
1504 auto &moab = mField.get_moab();
1505
1506 double eps = 1;
1507 double beta = 0;
1508 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "-singularity_eps", &beta,
1509 PETSC_NULLPTR);
1510 MOFEM_LOG("EP", Sev::inform) << "Singularity eps " << beta;
1511 eps -= beta;
1512
1513 auto field_blas = mField.getInterface<FieldBlas>();
1514 auto lambda =
1515 [&](boost::shared_ptr<FieldEntity> field_entity_ptr) -> MoFEMErrorCode {
1517 FTENSOR_INDEX(3, i);
1518 FTENSOR_INDEX(3, j);
1519
1520 auto nb_dofs = field_entity_ptr->getEntFieldData().size();
1521 if (nb_dofs == 0) {
1523 }
1524
1525#ifndef NDEBUG
1526 if (field_entity_ptr->getNbOfCoeffs() != 3)
1528 "Expected 3 coefficients per edge");
1529 if (nb_dofs % 3 != 0)
1531 "Expected multiple of 3 coefficients per edge");
1532#endif // NDEBUG
1533
1534 auto get_conn = [&]() {
1535 int num_nodes;
1536 const EntityHandle *conn;
1537 CHKERR moab.get_connectivity(field_entity_ptr->getEnt(), conn,
1538 num_nodes, false);
1539 return std::make_pair(conn, num_nodes);
1540 };
1541
1542 auto get_dir = [&](auto &&conn_p) {
1543 auto [conn, num_nodes] = conn_p;
1544 double coords[6];
1545 CHKERR moab.get_coords(conn, num_nodes, coords);
1546 FTensor::Tensor1<double, 3> t_edge_dir{coords[3] - coords[0],
1547 coords[4] - coords[1],
1548 coords[5] - coords[2]};
1549 return t_edge_dir;
1550 };
1551
1552 auto get_singularity_dof = [&](auto &&conn_p, auto &&t_edge_dir) {
1553 auto [conn, num_nodes] = conn_p;
1554 FTensor::Tensor1<double, 3> t_singularity_dof{0., 0., 0.};
1555 if (front_vertices.find(conn[0]) != front_vertices.end()) {
1556 t_singularity_dof(i) = t_edge_dir(i) * (-eps);
1557 } else if (front_vertices.find(conn[1]) != front_vertices.end()) {
1558 t_singularity_dof(i) = t_edge_dir(i) * eps;
1559 }
1560 return t_singularity_dof;
1561 };
1562
1563 auto t_singularity_dof =
1564 get_singularity_dof(get_conn(), get_dir(get_conn()));
1565
1566 auto field_data = field_entity_ptr->getEntFieldData();
1568 &field_data[0], &field_data[1], &field_data[2]};
1569
1570 t_dof(i) = t_singularity_dof(i);
1571 ++t_dof;
1572 for (auto n = 1; n < field_data.size() / 3; ++n) {
1573 t_dof(i) = 0;
1574 ++t_dof;
1575 }
1576
1578 };
1579
1580 CHKERR field_blas->fieldLambdaOnEntities(lambda, materialH1Positions,
1581 &front_adj_edges);
1582
1584 };
1585
1586 if (setSingularity)
1587 CHKERR set_singular_dofs(*frontAdjEdges, *frontVertices);
1588
1590}
1591
1595
1596 // set finite element fields
1597 auto add_field_to_fe = [this](const std::string fe,
1598 const std::string field_name) {
1604 };
1605
1610
1611 CHKERR add_field_to_fe(elementVolumeName, piolaStress);
1612 CHKERR add_field_to_fe(elementVolumeName, bubbleField);
1613 if (!noStretch)
1614 CHKERR add_field_to_fe(elementVolumeName, stretchTensor);
1615 CHKERR add_field_to_fe(elementVolumeName, rotAxis);
1616 CHKERR add_field_to_fe(elementVolumeName, spatialL2Disp);
1617 CHKERR add_field_to_fe(elementVolumeName, spatialH1Disp);
1618 CHKERR add_field_to_fe(elementVolumeName, contactDisp);
1621
1622 // build finite elements data structures
1624 }
1625
1626 // if (!mField.check_finite_element(materialVolumeElement)) {
1627
1628 // Range front_edges = get_range_from_block(mField, "FRONT", SPACE_DIM - 2);
1629
1630 // Range front_elements;
1631 // for (auto l = 0; l != frontLayers; ++l) {
1632 // Range front_elements_layer;
1633 // CHKERR mField.get_moab().get_adjacencies(front_edges, SPACE_DIM, true,
1634 // front_elements_layer,
1635 // moab::Interface::UNION);
1636 // front_elements.merge(front_elements_layer);
1637 // front_edges.clear();
1638 // CHKERR mField.get_moab().get_adjacencies(front_elements_layer,
1639 // SPACE_DIM - 2, true,
1640 // front_edges,
1641 // moab::Interface::UNION);
1642 // }
1643
1644 // CHKERR mField.add_finite_element(materialVolumeElement, MF_ZERO);
1645 // CHKERR mField.add_ents_to_finite_element_by_type(front_elements, MBTET,
1646 // materialVolumeElement);
1647 // // CHKERR add_field_to_fe(materialVolumeElement, eshelbyStress);
1648 // // CHKERR add_field_to_fe(materialVolumeElement, materialL2Disp);
1649 // CHKERR mField.build_finite_elements(materialVolumeElement);
1650 // }
1651
1653}
1654
1658
1659 Range meshset_ents;
1660 CHKERR mField.get_moab().get_entities_by_handle(meshset, meshset_ents);
1661
1662 auto set_fe_adjacency = [&](auto fe_name) {
1665 boost::make_shared<ParentFiniteElementAdjacencyFunctionSkeleton<2>>(
1668 fe_name, MBTRI, *parentAdjSkeletonFunctionDim2);
1670 };
1671
1672 // set finite element fields
1673 auto add_field_to_fe = [this](const std::string fe,
1674 const std::string field_name) {
1681 };
1682
1684
1685 Range natural_bc_elements;
1686 if (bcSpatialDispVecPtr) {
1687 for (auto &v : *bcSpatialDispVecPtr) {
1688 natural_bc_elements.merge(v.faces);
1689 }
1690 }
1692 for (auto &v : *bcSpatialRotationVecPtr) {
1693 natural_bc_elements.merge(v.faces);
1694 }
1695 }
1697 for (auto &v : *bcSpatialNormalDisplacementVecPtr) {
1698 natural_bc_elements.merge(v.faces);
1699 }
1700 }
1703 natural_bc_elements.merge(v.faces);
1704 }
1705 }
1707 for (auto &v : *bcSpatialTractionVecPtr) {
1708 natural_bc_elements.merge(v.faces);
1709 }
1710 }
1712 for (auto &v : *bcSpatialAnalyticalTractionVecPtr) {
1713 natural_bc_elements.merge(v.faces);
1714 }
1715 }
1717 for (auto &v : *bcSpatialPressureVecPtr) {
1718 natural_bc_elements.merge(v.faces);
1719 }
1720 }
1721 natural_bc_elements = intersect(natural_bc_elements, meshset_ents);
1722
1724 CHKERR mField.add_ents_to_finite_element_by_type(natural_bc_elements, MBTRI,
1726 CHKERR add_field_to_fe(naturalBcElement, piolaStress);
1727 CHKERR add_field_to_fe(naturalBcElement, hybridSpatialDisp);
1728 CHKERR set_fe_adjacency(naturalBcElement);
1730 }
1731
1732 auto get_skin = [&](auto &body_ents) {
1733 Skinner skin(&mField.get_moab());
1734 Range skin_ents;
1735 CHKERR skin.find_skin(0, body_ents, false, skin_ents);
1736 return skin_ents;
1737 };
1738
1739 auto filter_true_skin = [&](auto &&skin) {
1740 Range boundary_ents;
1741 ParallelComm *pcomm =
1742 ParallelComm::get_pcomm(&mField.get_moab(), MYPCOMM_INDEX);
1743 CHKERR pcomm->filter_pstatus(skin, PSTATUS_SHARED | PSTATUS_MULTISHARED,
1744 PSTATUS_NOT, -1, &boundary_ents);
1745 return boundary_ents;
1746 };
1747
1749
1750 Range body_ents;
1751 CHKERR mField.get_moab().get_entities_by_dimension(meshset, SPACE_DIM,
1752 body_ents);
1753 auto skin = filter_true_skin(get_skin(body_ents));
1754
1762 contactDisp);
1765 // CHKERR add_field_to_fe(skinElement, hybridSpatialDisp);
1766 // CHKERR add_field_to_fe(skinElement, hybridMaterialDisp);
1767
1769 }
1770
1772 if (contactFaces) {
1773 MOFEM_LOG("EP", Sev::inform)
1774 << "Contact elements " << contactFaces->size();
1778 CHKERR add_field_to_fe(contactElement, piolaStress);
1779 CHKERR add_field_to_fe(contactElement, hybridSpatialDisp);
1780 CHKERR add_field_to_fe(contactElement, contactDisp);
1781 CHKERR add_field_to_fe(contactElement, spatialH1Disp);
1782 CHKERR set_fe_adjacency(contactElement);
1784 }
1785 }
1786
1788 if (!skeletonFaces)
1789 SETERRQ(mField.get_comm(), MOFEM_DATA_INCONSISTENCY, "No skeleton faces");
1790 MOFEM_LOG("EP", Sev::inform)
1791 << "Skeleton elements " << skeletonFaces->size();
1795 CHKERR add_field_to_fe(skeletonElement, piolaStress);
1796 CHKERR add_field_to_fe(skeletonElement, hybridSpatialDisp);
1797 CHKERR add_field_to_fe(skeletonElement, contactDisp);
1798 CHKERR add_field_to_fe(skeletonElement, spatialH1Disp);
1799 CHKERR set_fe_adjacency(skeletonElement);
1801 }
1802
1803 // if (!mField.check_finite_element(materialSkeletonElement)) {
1804
1805 // Range front_edges = get_range_from_block(mField, "FRONT", SPACE_DIM -
1806 // 2);
1807
1808 // Range front_elements;
1809 // for (auto l = 0; l != frontLayers; ++l) {
1810 // Range front_elements_layer;
1811 // CHKERR mField.get_moab().get_adjacencies(front_edges, SPACE_DIM,
1812 // true,
1813 // front_elements_layer,
1814 // moab::Interface::UNION);
1815 // front_elements.merge(front_elements_layer);
1816 // front_edges.clear();
1817 // CHKERR mField.get_moab().get_adjacencies(front_elements_layer,
1818 // SPACE_DIM - 2, true,
1819 // front_edges,
1820 // moab::Interface::UNION);
1821 // }
1822 // Range body_ents;
1823 // CHKERR mField.get_moab().get_entities_by_dimension(0, SPACE_DIM,
1824 // body_ents); Range front_elements_faces; CHKERR
1825 // mField.get_moab().get_adjacencies(front_elements, SPACE_DIM - 1,
1826 // true, front_elements_faces,
1827 // moab::Interface::UNION);
1828 // auto body_skin = filter_true_skin(get_skin(body_ents));
1829 // auto front_elements_skin = filter_true_skin(get_skin(front_elements));
1830 // Range material_skeleton_faces =
1831 // subtract(front_elements_faces, front_elements_skin);
1832 // material_skeleton_faces.merge(intersect(front_elements_skin,
1833 // body_skin));
1834
1835 // #ifndef NDEBUG
1836 // CHKERR save_range(mField.get_moab(), "front_elements.vtk",
1837 // front_elements); CHKERR save_range(mField.get_moab(),
1838 // "front_elements_skin.vtk",
1839 // front_elements_skin);
1840 // CHKERR save_range(mField.get_moab(), "material_skeleton_faces.vtk",
1841 // material_skeleton_faces);
1842 // #endif
1843
1844 // CHKERR mField.add_finite_element(materialSkeletonElement, MF_ZERO);
1845 // CHKERR mField.add_ents_to_finite_element_by_type(
1846 // material_skeleton_faces, MBTRI, materialSkeletonElement);
1847 // // CHKERR add_field_to_fe(materialSkeletonElement, eshelbyStress);
1848 // // CHKERR add_field_to_fe(materialSkeletonElement, hybridMaterialDisp);
1849 // CHKERR set_fe_adjacency(materialSkeletonElement);
1850 // CHKERR mField.build_finite_elements(materialSkeletonElement);
1851 // }
1852
1854}
1855
1857 const EntityHandle meshset) {
1859
1860 // find adjacencies between finite elements and dofs
1862
1863 // Create coupled problem
1864 dM = createDM(mField.get_comm(), "DMMOFEM");
1865 CHKERR DMMoFEMCreateMoFEM(dM, &mField, "ESHELBY_PLASTICITY", bit,
1866 BitRefLevel().set());
1867 CHKERR DMMoFEMSetDestroyProblem(dM, PETSC_TRUE);
1868 CHKERR DMMoFEMSetIsPartitioned(dM, PETSC_TRUE);
1874
1875 mField.getInterface<ProblemsManager>()->buildProblemFromFields = PETSC_TRUE;
1876 CHKERR DMSetUp(dM);
1877 mField.getInterface<ProblemsManager>()->buildProblemFromFields = PETSC_FALSE;
1878
1879 auto remove_dofs_on_broken_skin = [&](const std::string prb_name) {
1881 for (int d : {0, 1, 2}) {
1882 std::vector<boost::weak_ptr<NumeredDofEntity>> dofs_to_remove;
1884 ->getSideDofsOnBrokenSpaceEntities(
1885 dofs_to_remove, prb_name, ROW, piolaStress,
1887 // remove piola dofs, i.e. traction free boundary
1888 CHKERR mField.getInterface<ProblemsManager>()->removeDofs(prb_name, ROW,
1889 dofs_to_remove);
1890 CHKERR mField.getInterface<ProblemsManager>()->removeDofs(prb_name, COL,
1891 dofs_to_remove);
1892 }
1894 };
1895 CHKERR remove_dofs_on_broken_skin("ESHELBY_PLASTICITY");
1896
1897 // Create elastic sub-problem
1898 dmElastic = createDM(mField.get_comm(), "DMMOFEM");
1899 CHKERR DMMoFEMCreateSubDM(dmElastic, dM, "ELASTIC_PROBLEM");
1905 if (!noStretch) {
1907 }
1917 CHKERR DMSetUp(dmElastic);
1918
1919 // dmMaterial = createDM(mField.get_comm(), "DMMOFEM");
1920 // CHKERR DMMoFEMCreateSubDM(dmMaterial, dM, "MATERIAL_PROBLEM");
1921 // CHKERR DMMoFEMSetDestroyProblem(dmMaterial, PETSC_TRUE);
1922 // CHKERR DMMoFEMAddSubFieldRow(dmMaterial, eshelbyStress);
1923 // CHKERR DMMoFEMAddSubFieldRow(dmMaterial, materialL2Disp);
1924 // CHKERR DMMoFEMAddElement(dmMaterh elementVolumeName);
1925 // CHKERR DMMoFEMAddElement(dmMaterial, naturalBcElement);
1926 // CHKERR DMMoFEMAddElement(dmMaterial, skinElement);
1927 // CHKERR DMMoFEMSetSquareProblem(dmMaterial, PETSC_TRUE);
1928 // CHKERR DMMoFEMSetIsPartitioned(dmMaterial, PETSC_TRUE);
1929 // CHKERR DMSetUp(dmMaterial);
1930
1931 auto set_zero_block = [&]() {
1933 if (!noStretch) {
1934 CHKERR mField.getInterface<ProblemsManager>()->addFieldToEmptyFieldBlocks(
1935 "ELASTIC_PROBLEM", spatialL2Disp, stretchTensor);
1936 CHKERR mField.getInterface<ProblemsManager>()->addFieldToEmptyFieldBlocks(
1937 "ELASTIC_PROBLEM", stretchTensor, spatialL2Disp);
1938 }
1939 CHKERR mField.getInterface<ProblemsManager>()->addFieldToEmptyFieldBlocks(
1940 "ELASTIC_PROBLEM", spatialL2Disp, rotAxis);
1941 CHKERR mField.getInterface<ProblemsManager>()->addFieldToEmptyFieldBlocks(
1942 "ELASTIC_PROBLEM", rotAxis, spatialL2Disp);
1943 CHKERR mField.getInterface<ProblemsManager>()->addFieldToEmptyFieldBlocks(
1944 "ELASTIC_PROBLEM", spatialL2Disp, bubbleField);
1945 CHKERR mField.getInterface<ProblemsManager>()->addFieldToEmptyFieldBlocks(
1946 "ELASTIC_PROBLEM", bubbleField, spatialL2Disp);
1947 if (!noStretch) {
1948 CHKERR mField.getInterface<ProblemsManager>()->addFieldToEmptyFieldBlocks(
1949 "ELASTIC_PROBLEM", bubbleField, bubbleField);
1950 CHKERR
1951 mField.getInterface<ProblemsManager>()->addFieldToEmptyFieldBlocks(
1952 "ELASTIC_PROBLEM", piolaStress, piolaStress);
1953 CHKERR mField.getInterface<ProblemsManager>()->addFieldToEmptyFieldBlocks(
1954 "ELASTIC_PROBLEM", bubbleField, piolaStress);
1955 CHKERR mField.getInterface<ProblemsManager>()->addFieldToEmptyFieldBlocks(
1956 "ELASTIC_PROBLEM", piolaStress, bubbleField);
1957 }
1958
1961 };
1962
1963 auto set_section = [&]() {
1965 PetscSection section;
1966 CHKERR mField.getInterface<ISManager>()->sectionCreate("ELASTIC_PROBLEM",
1967 &section);
1968 CHKERR DMSetSection(dmElastic, section);
1969 CHKERR DMSetGlobalSection(dmElastic, section);
1970 CHKERR PetscSectionDestroy(&section);
1972 };
1973
1974 CHKERR set_zero_block();
1975 CHKERR set_section();
1976
1977 dmPrjSpatial = createDM(mField.get_comm(), "DMMOFEM");
1978 CHKERR DMMoFEMCreateSubDM(dmPrjSpatial, dM, "PROJECT_SPATIAL");
1984 CHKERR DMSetUp(dmPrjSpatial);
1985
1986 // CHKERR mField.getInterface<BcManager>()
1987 // ->pushMarkDOFsOnEntities<DisplacementCubitBcData>(
1988 // "PROJECT_SPATIAL", spatialH1Disp, true, false);
1989
1991}
1992
1993BcDisp::BcDisp(std::string name, std::vector<double> attr, Range faces)
1994 : blockName(name), faces(faces) {
1995 vals.resize(3, false);
1996 flags.resize(3, false);
1997 for (int ii = 0; ii != 3; ++ii) {
1998 vals[ii] = attr[ii];
1999 flags[ii] = static_cast<int>(attr[ii + 3]);
2000 }
2001
2002 MOFEM_LOG("EP", Sev::inform) << "Add BCDisp " << name;
2003 MOFEM_LOG("EP", Sev::inform)
2004 << "Add BCDisp vals " << vals[0] << " " << vals[1] << " " << vals[2];
2005 MOFEM_LOG("EP", Sev::inform)
2006 << "Add BCDisp flags " << flags[0] << " " << flags[1] << " " << flags[2];
2007 MOFEM_LOG("EP", Sev::inform) << "Add BCDisp nb. of faces " << faces.size();
2008}
2009
2010BcRot::BcRot(std::string name, std::vector<double> attr, Range faces)
2011 : blockName(name), faces(faces) {
2012 vals.resize(attr.size(), false);
2013 for (int ii = 0; ii != attr.size(); ++ii) {
2014 vals[ii] = attr[ii];
2015 }
2016 theta = attr[3];
2017}
2018
2019TractionBc::TractionBc(std::string name, std::vector<double> attr, Range faces)
2020 : blockName(name), faces(faces) {
2021 vals.resize(3, false);
2022 flags.resize(3, false);
2023 for (int ii = 0; ii != 3; ++ii) {
2024 vals[ii] = attr[ii];
2025 flags[ii] = static_cast<int>(attr[ii + 3]);
2026 }
2027
2028 MOFEM_LOG("EP", Sev::inform) << "Add BCForce " << name;
2029 MOFEM_LOG("EP", Sev::inform)
2030 << "Add BCForce vals " << vals[0] << " " << vals[1] << " " << vals[2];
2031 MOFEM_LOG("EP", Sev::inform)
2032 << "Add BCForce flags " << flags[0] << " " << flags[1] << " " << flags[2];
2033 MOFEM_LOG("EP", Sev::inform) << "Add BCForce nb. of faces " << faces.size();
2034}
2035
2037 std::vector<double> attr,
2038 Range faces)
2039 : blockName(name), faces(faces) {
2040
2041 blockName = name;
2042 if (attr.size() < 1) {
2044 "Wrong size of normal displacement BC");
2045 }
2046
2047 val = attr[0];
2048
2049 MOFEM_LOG("EP", Sev::inform) << "Add NormalDisplacementBc " << name;
2050 MOFEM_LOG("EP", Sev::inform) << "Add NormalDisplacementBc val " << val;
2051 MOFEM_LOG("EP", Sev::inform)
2052 << "Add NormalDisplacementBc nb. of faces " << faces.size();
2053}
2054
2055PressureBc::PressureBc(std::string name, std::vector<double> attr, Range faces)
2056 : blockName(name), faces(faces) {
2057
2058 blockName = name;
2059 if (attr.size() < 1) {
2061 "Wrong size of normal displacement BC");
2062 }
2063
2064 val = attr[0];
2065
2066 MOFEM_LOG("EP", Sev::inform) << "Add PressureBc " << name;
2067 MOFEM_LOG("EP", Sev::inform) << "Add PressureBc val " << val;
2068 MOFEM_LOG("EP", Sev::inform)
2069 << "Add PressureBc nb. of faces " << faces.size();
2070}
2071
2072
2073ExternalStrain::ExternalStrain(std::string name, std::vector<double> attr,
2074 Range ents)
2075 : blockName(name), ents(ents) {
2076
2077 blockName = name;
2078 if (attr.size() < 2) {
2080 "Wrong size of external strain attribute");
2081 }
2082
2083 val = attr[0];
2084 bulkModulusK = attr[1];
2085
2086 MOFEM_LOG("EP", Sev::inform) << "Add ExternalStrain " << name;
2087 MOFEM_LOG("EP", Sev::inform) << "Add ExternalStrain val " << val;
2088 MOFEM_LOG("EP", Sev::inform) << "Add ExternalStrain bulk modulus K "
2089 << bulkModulusK;
2090 MOFEM_LOG("EP", Sev::inform)
2091 << "Add ExternalStrain nb. of tets " << ents.size();
2092
2093
2094}
2095
2097 std::vector<double> attr,
2098 Range faces)
2099 : blockName(name), faces(faces) {
2100
2101 blockName = name;
2102 if (attr.size() < 3) {
2104 "Wrong size of analytical displacement BC");
2105 }
2106
2107 flags.resize(3, false);
2108 for (int ii = 0; ii != 3; ++ii) {
2109 flags[ii] = attr[ii];
2110 }
2111
2112 MOFEM_LOG("EP", Sev::inform) << "Add AnalyticalDisplacementBc " << name;
2113 MOFEM_LOG("EP", Sev::inform)
2114 << "Add AnalyticalDisplacementBc flags " << flags[0] << " " << flags[1]
2115 << " " << flags[2];
2116 MOFEM_LOG("EP", Sev::inform)
2117 << "Add AnalyticalDisplacementBc nb. of faces " << faces.size();
2118}
2119
2121 std::vector<double> attr,
2122 Range faces)
2123 : blockName(name), faces(faces) {
2124
2125 blockName = name;
2126 if (attr.size() < 3) {
2128 "Wrong size of analytical traction BC");
2129 }
2130
2131 flags.resize(3, false);
2132 for (int ii = 0; ii != 3; ++ii) {
2133 flags[ii] = attr[ii];
2134 }
2135
2136 MOFEM_LOG("EP", Sev::inform) << "Add AnalyticalTractionBc " << name;
2137 MOFEM_LOG("EP", Sev::inform)
2138 << "Add AnalyticalTractionBc flags " << flags[0] << " " << flags[1]
2139 << " " << flags[2];
2140 MOFEM_LOG("EP", Sev::inform)
2141 << "Add AnalyticalTractionBc nb. of faces " << faces.size();
2142}
2143
2144
2147 boost::shared_ptr<TractionFreeBc> &bc_ptr,
2148 const std::string contact_set_name) {
2150
2151 // get skin from all tets
2152 Range tets;
2153 CHKERR mField.get_moab().get_entities_by_type(meshset, MBTET, tets);
2154 Range tets_skin_part;
2155 Skinner skin(&mField.get_moab());
2156 CHKERR skin.find_skin(0, tets, false, tets_skin_part);
2157 ParallelComm *pcomm =
2158 ParallelComm::get_pcomm(&mField.get_moab(), MYPCOMM_INDEX);
2159 Range tets_skin;
2160 CHKERR pcomm->filter_pstatus(tets_skin_part,
2161 PSTATUS_SHARED | PSTATUS_MULTISHARED,
2162 PSTATUS_NOT, -1, &tets_skin);
2163
2164 bc_ptr->resize(3);
2165 for (int dd = 0; dd != 3; ++dd)
2166 (*bc_ptr)[dd] = tets_skin;
2167
2168 // Do not remove dofs on which traction is applied
2169 if (bcSpatialDispVecPtr)
2170 for (auto &v : *bcSpatialDispVecPtr) {
2171 if (v.flags[0])
2172 (*bc_ptr)[0] = subtract((*bc_ptr)[0], v.faces);
2173 if (v.flags[1])
2174 (*bc_ptr)[1] = subtract((*bc_ptr)[1], v.faces);
2175 if (v.flags[2])
2176 (*bc_ptr)[2] = subtract((*bc_ptr)[2], v.faces);
2177 }
2178
2179 // Do not remove dofs on which rotation is applied
2180 if (bcSpatialRotationVecPtr)
2181 for (auto &v : *bcSpatialRotationVecPtr) {
2182 (*bc_ptr)[0] = subtract((*bc_ptr)[0], v.faces);
2183 (*bc_ptr)[1] = subtract((*bc_ptr)[1], v.faces);
2184 (*bc_ptr)[2] = subtract((*bc_ptr)[2], v.faces);
2185 }
2186
2187 if (bcSpatialNormalDisplacementVecPtr)
2188 for (auto &v : *bcSpatialNormalDisplacementVecPtr) {
2189 (*bc_ptr)[0] = subtract((*bc_ptr)[0], v.faces);
2190 (*bc_ptr)[1] = subtract((*bc_ptr)[1], v.faces);
2191 (*bc_ptr)[2] = subtract((*bc_ptr)[2], v.faces);
2192 }
2193
2194 if (bcSpatialAnalyticalDisplacementVecPtr)
2195 for (auto &v : *bcSpatialAnalyticalDisplacementVecPtr) {
2196 if (v.flags[0])
2197 (*bc_ptr)[0] = subtract((*bc_ptr)[0], v.faces);
2198 if (v.flags[1])
2199 (*bc_ptr)[1] = subtract((*bc_ptr)[1], v.faces);
2200 if (v.flags[2])
2201 (*bc_ptr)[2] = subtract((*bc_ptr)[2], v.faces);
2202 }
2203
2204 if (bcSpatialTractionVecPtr)
2205 for (auto &v : *bcSpatialTractionVecPtr) {
2206 (*bc_ptr)[0] = subtract((*bc_ptr)[0], v.faces);
2207 (*bc_ptr)[1] = subtract((*bc_ptr)[1], v.faces);
2208 (*bc_ptr)[2] = subtract((*bc_ptr)[2], v.faces);
2209 }
2210
2211 if (bcSpatialAnalyticalTractionVecPtr)
2212 for (auto &v : *bcSpatialAnalyticalTractionVecPtr) {
2213 (*bc_ptr)[0] = subtract((*bc_ptr)[0], v.faces);
2214 (*bc_ptr)[1] = subtract((*bc_ptr)[1], v.faces);
2215 (*bc_ptr)[2] = subtract((*bc_ptr)[2], v.faces);
2216 }
2217
2218 if (bcSpatialPressureVecPtr)
2219 for (auto &v : *bcSpatialPressureVecPtr) {
2220 (*bc_ptr)[0] = subtract((*bc_ptr)[0], v.faces);
2221 (*bc_ptr)[1] = subtract((*bc_ptr)[1], v.faces);
2222 (*bc_ptr)[2] = subtract((*bc_ptr)[2], v.faces);
2223 }
2224
2225 // remove contact
2226 for (auto m : mField.getInterface<MeshsetsManager>()->getCubitMeshsetPtr(
2227 std::regex((boost::format("%s(.*)") % contact_set_name).str()))) {
2228 Range faces;
2229 CHKERR m->getMeshsetIdEntitiesByDimension(mField.get_moab(), 2, faces,
2230 true);
2231 (*bc_ptr)[0] = subtract((*bc_ptr)[0], faces);
2232 (*bc_ptr)[1] = subtract((*bc_ptr)[1], faces);
2233 (*bc_ptr)[2] = subtract((*bc_ptr)[2], faces);
2234 }
2235
2237}
2238
2239/**
2240 * @brief Set integration rule on element
2241 * \param order on row
2242 * \param order on column
2243 * \param order on data
2244 *
2245 * Use maximal oder on data in order to determine integration rule
2246 *
2247 */
2248struct VolRule {
2249 int operator()(int p_row, int p_col, int p_data) const {
2250 return 2 * p_data + 1;
2251 }
2252};
2253
2254struct FaceRule {
2255 int operator()(int p_row, int p_col, int p_data) const {
2256 return 2 * (p_data + 1);
2257 }
2258};
2259
2260
2261
2263 const int tag, const bool do_rhs, const bool do_lhs, const bool calc_rates,
2264 SmartPetscObj<Vec> var_vec,
2265 boost::shared_ptr<VolumeElementForcesAndSourcesCore> fe) {
2267
2268 auto bubble_cache =
2269 boost::make_shared<CGGUserPolynomialBase::CachePhi>(0, 0, MatrixDouble());
2270 fe->getUserPolynomialBase() =
2271 boost::make_shared<CGGUserPolynomialBase>(bubble_cache);
2272 EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
2273 fe->getOpPtrVector(), {HDIV, H1, L2}, materialH1Positions, frontAdjEdges);
2274
2275 // set integration rule
2276 fe->getRuleHook = [](int, int, int) { return -1; };
2277 fe->setRuleHook = SetIntegrationAtFrontVolume(frontVertices, frontAdjEdges);
2278 // fe->getRuleHook = VolRule();
2279
2280 if (!dataAtPts) {
2281 dataAtPts =
2282 boost::shared_ptr<DataAtIntegrationPts>(new DataAtIntegrationPts());
2283 dataAtPts->physicsPtr = physicalEquations;
2284 }
2285
2286 // calculate fields values
2287 fe->getOpPtrVector().push_back(new OpCalculateHVecTensorField<3, 3>(
2288 piolaStress, dataAtPts->getApproxPAtPts()));
2289 fe->getOpPtrVector().push_back(new OpCalculateHTensorTensorField<3, 3>(
2290 bubbleField, dataAtPts->getApproxPAtPts(), MBMAXTYPE));
2291 fe->getOpPtrVector().push_back(new OpCalculateHVecTensorDivergence<3, 3>(
2292 piolaStress, dataAtPts->getDivPAtPts()));
2293
2294 if (noStretch) {
2295 fe->getOpPtrVector().push_back(
2296 physicalEquations->returnOpCalculateStretchFromStress(
2297 dataAtPts, physicalEquations));
2298 } else {
2299 fe->getOpPtrVector().push_back(
2301 stretchTensor, dataAtPts->getLogStretchTensorAtPts(), MBTET));
2302 }
2303
2304 fe->getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
2305 rotAxis, dataAtPts->getRotAxisAtPts(), MBTET));
2306 fe->getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
2307 rotAxis, dataAtPts->getRotAxis0AtPts(), solTSStep, MBTET));
2308 fe->getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
2309 spatialL2Disp, dataAtPts->getSmallWL2AtPts(), MBTET));
2310
2311 // H1 displacements
2312 fe->getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
2313 spatialH1Disp, dataAtPts->getSmallWH1AtPts()));
2314 fe->getOpPtrVector().push_back(new OpCalculateVectorFieldGradient<3, 3>(
2315 spatialH1Disp, dataAtPts->getSmallWGradH1AtPts()));
2316
2317 // velocities
2318 if (calc_rates) {
2319 fe->getOpPtrVector().push_back(new OpCalculateVectorFieldValuesDot<3>(
2320 spatialL2Disp, dataAtPts->getSmallWL2DotAtPts(), MBTET));
2321 if (noStretch) {
2322 } else {
2323 fe->getOpPtrVector().push_back(
2325 stretchTensor, dataAtPts->getLogStretchDotTensorAtPts(), MBTET));
2326 fe->getOpPtrVector().push_back(
2328 stretchTensor, dataAtPts->getGradLogStretchDotTensorAtPts(),
2329 MBTET));
2330 }
2331 fe->getOpPtrVector().push_back(new OpCalculateVectorFieldValuesDot<3>(
2332 rotAxis, dataAtPts->getRotAxisDotAtPts(), MBTET));
2333 fe->getOpPtrVector().push_back(new OpCalculateVectorFieldGradientDot<3, 3>(
2334 rotAxis, dataAtPts->getRotAxisGradDotAtPts(), MBTET));
2335
2336 // acceleration
2337 if (std::abs(alphaRho) > std::numeric_limits<double>::epsilon()) {
2338 fe->getOpPtrVector().push_back(new OpCalculateVectorFieldValuesDotDot<3>(
2339 spatialL2Disp, dataAtPts->getSmallWL2DotDotAtPts(), MBTET));
2340 }
2341 }
2342
2343 // variations
2344 if (var_vec.use_count()) {
2345 fe->getOpPtrVector().push_back(new OpCalculateHVecTensorField<3, 3>(
2346 piolaStress, dataAtPts->getVarPiolaPts(), boost::make_shared<double>(1),
2347 var_vec));
2348 fe->getOpPtrVector().push_back(new OpCalculateHTensorTensorField<3, 3>(
2349 bubbleField, dataAtPts->getVarPiolaPts(), boost::make_shared<double>(1),
2350 var_vec, MBMAXTYPE));
2351 fe->getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
2352 rotAxis, dataAtPts->getVarRotAxisPts(), var_vec, MBTET));
2353 fe->getOpPtrVector().push_back(new OpCalculateHVecTensorDivergence<3, 3>(
2354 piolaStress, dataAtPts->getDivVarPiolaPts(), var_vec));
2355 fe->getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
2356 spatialL2Disp, dataAtPts->getVarWL2Pts(), var_vec, MBTET));
2357
2358 if (noStretch) {
2359 fe->getOpPtrVector().push_back(
2360 physicalEquations->returnOpCalculateVarStretchFromStress(
2361 dataAtPts, physicalEquations));
2362 } else {
2363 fe->getOpPtrVector().push_back(
2365 stretchTensor, dataAtPts->getVarLogStreachPts(), var_vec, MBTET));
2366 }
2367 }
2368
2369 // calculate other derived quantities
2370 fe->getOpPtrVector().push_back(new OpCalculateRotationAndSpatialGradient(
2371 dataAtPts, ((do_rhs || do_lhs) && calc_rates) ? alphaOmega : 0.));
2372
2373 // evaluate integration points
2374 if (noStretch) {
2375 } else {
2376 fe->getOpPtrVector().push_back(physicalEquations->returnOpJacobian(
2377 tag, do_rhs, do_lhs, dataAtPts, physicalEquations));
2378 }
2379
2381}
2382
2384 const int tag, const bool add_elastic, const bool add_material,
2385 boost::shared_ptr<VolumeElementForcesAndSourcesCore> &fe_rhs,
2386 boost::shared_ptr<VolumeElementForcesAndSourcesCore> &fe_lhs) {
2388
2389 /** Contact requires that body is marked */
2390 auto get_body_range = [this](auto name, int dim) {
2391 std::map<int, Range> map;
2392
2393 for (auto m_ptr :
2394 mField.getInterface<MeshsetsManager>()->getCubitMeshsetPtr(std::regex(
2395
2396 (boost::format("%s(.*)") % name).str()
2397
2398 ))
2399
2400 ) {
2401 Range ents;
2402 CHK_MOAB_THROW(m_ptr->getMeshsetIdEntitiesByDimension(mField.get_moab(),
2403 dim, ents, true),
2404 "by dim");
2405 map[m_ptr->getMeshsetId()] = ents;
2406 }
2407
2408 return map;
2409 };
2410
2411 auto rule_contact = [](int, int, int o) { return -1; };
2412 auto refine = Tools::refineTriangle(contactRefinementLevels);
2413
2414 auto set_rule_contact = [refine](
2415
2416 ForcesAndSourcesCore *fe_raw_ptr, int order_row,
2417 int order_col, int order_data
2418
2419 ) {
2421 auto rule = 2 * order_data;
2422 fe_raw_ptr->gaussPts = Tools::refineTriangleIntegrationPts(rule, refine);
2424 };
2425
2426 // Right hand side
2427 fe_rhs = boost::make_shared<VolumeElementForcesAndSourcesCore>(mField);
2428 CHKERR setBaseVolumeElementOps(tag, true, false, true, SmartPetscObj<Vec>(),
2429 fe_rhs);
2430
2431 // elastic
2432 if (add_elastic) {
2433
2434 fe_rhs->getOpPtrVector().push_back(
2435 new OpSpatialEquilibrium(spatialL2Disp, dataAtPts, alphaW, alphaRho));
2436 fe_rhs->getOpPtrVector().push_back(
2437 new OpSpatialRotation(rotAxis, dataAtPts, alphaOmega));
2438 if (noStretch) {
2439 // do nothing - no stretch approximation
2440 } else {
2441 if (!internalStressTagName.empty()) {
2442 switch (internalStressInterpOrder) {
2443 case 0:
2444 fe_rhs->getOpPtrVector().push_back(
2445 new OpGetInternalStress<0>(dataAtPts, internalStressTagName));
2446 break;
2447 case 1:
2448 fe_rhs->getOpPtrVector().push_back(
2449 new OpGetInternalStress<1>(dataAtPts, internalStressTagName));
2450 break;
2451 default:
2452 SETERRQ(PETSC_COMM_WORLD, MOFEM_NOT_IMPLEMENTED,
2453 "Unsupported internal stress interpolation order %d",
2454 internalStressInterpOrder);
2455 }
2456 if (internalStressVoigt) {
2457 fe_rhs->getOpPtrVector().push_back(
2458 new OpSpatialPhysicalInternalStress<true>(stretchTensor,
2459 dataAtPts));
2460 } else {
2461 fe_rhs->getOpPtrVector().push_back(
2463 dataAtPts));
2464 }
2465 }
2466 if (auto op = physicalEquations->returnOpSpatialPhysicalExternalStrain(
2467 stretchTensor, dataAtPts, externalStrainVecPtr, timeScaleMap)) {
2468 fe_rhs->getOpPtrVector().push_back(op);
2469 } else if (externalStrainVecPtr && !externalStrainVecPtr->empty()) {
2470 SETERRQ(PETSC_COMM_WORLD, MOFEM_NOT_IMPLEMENTED,
2471 "OpSpatialPhysicalExternalStrain not implemented for this "
2472 "material");
2473 }
2474
2475 fe_rhs->getOpPtrVector().push_back(
2476 physicalEquations->returnOpSpatialPhysical(stretchTensor, dataAtPts,
2477 alphaU));
2478 }
2479 fe_rhs->getOpPtrVector().push_back(
2480 new OpSpatialConsistencyP(piolaStress, dataAtPts));
2481 fe_rhs->getOpPtrVector().push_back(
2482 new OpSpatialConsistencyBubble(bubbleField, dataAtPts));
2483 fe_rhs->getOpPtrVector().push_back(
2484 new OpSpatialConsistencyDivTerm(piolaStress, dataAtPts));
2485
2486 auto set_hybridisation = [&](auto &pip) {
2488
2489 using BoundaryEle =
2491 using EleOnSide =
2493 using SideEleOp = EleOnSide::UserDataOperator;
2494 using BdyEleOp = BoundaryEle::UserDataOperator;
2495
2496 // First: Iterate over skeleton FEs adjacent to Domain FEs
2497 // Note: BoundaryEle, i.e. uses skeleton interation rule
2498 auto op_loop_skeleton_side = new OpLoopSide<BoundaryEle>(
2499 mField, skeletonElement, SPACE_DIM - 1, Sev::noisy);
2500 // op_loop_skeleton_side->getSideFEPtr()->getRuleHook = FaceRule();
2501 op_loop_skeleton_side->getSideFEPtr()->getRuleHook = [](int, int, int) {
2502 return -1;
2503 };
2504 op_loop_skeleton_side->getSideFEPtr()->setRuleHook =
2505 SetIntegrationAtFrontFace(frontVertices, frontAdjEdges);
2506
2507 CHKERR EshelbianPlasticity::
2508 AddHOOps<SPACE_DIM - 1, SPACE_DIM, SPACE_DIM>::add(
2509 op_loop_skeleton_side->getOpPtrVector(), {L2},
2510 materialH1Positions, frontAdjEdges);
2511
2512 // Second: Iterate over domain FEs adjacent to skelton, particularly one
2513 // domain element.
2514 auto broken_data_ptr =
2515 boost::make_shared<std::vector<BrokenBaseSideData>>();
2516 // Note: EleOnSide, i.e. uses on domain projected skeleton rule
2517 auto op_loop_domain_side = new OpBrokenLoopSide<EleOnSide>(
2518 mField, elementVolumeName, SPACE_DIM, Sev::noisy);
2519 op_loop_domain_side->getSideFEPtr()->getUserPolynomialBase() =
2520 boost::make_shared<CGGUserPolynomialBase>();
2521 CHKERR
2522 EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
2523 op_loop_domain_side->getOpPtrVector(), {HDIV, H1, L2},
2524 materialH1Positions, frontAdjEdges);
2525 op_loop_domain_side->getOpPtrVector().push_back(
2526 new OpGetBrokenBaseSideData<SideEleOp>(piolaStress, broken_data_ptr));
2527 auto flux_mat_ptr = boost::make_shared<MatrixDouble>();
2528 op_loop_domain_side->getOpPtrVector().push_back(
2530 flux_mat_ptr));
2531 op_loop_domain_side->getOpPtrVector().push_back(
2532 new OpSetFlux<SideEleOp>(broken_data_ptr, flux_mat_ptr));
2533
2534 // Assemble on skeleton
2535 op_loop_skeleton_side->getOpPtrVector().push_back(op_loop_domain_side);
2537 GAUSS>::OpBrokenSpaceConstrainDHybrid<SPACE_DIM>;
2539 GAUSS>::OpBrokenSpaceConstrainDFlux<SPACE_DIM>;
2540 op_loop_skeleton_side->getOpPtrVector().push_back(new OpC_dHybrid(
2541 hybridSpatialDisp, broken_data_ptr, boost::make_shared<double>(1.0)));
2542 auto hybrid_ptr = boost::make_shared<MatrixDouble>();
2543 op_loop_skeleton_side->getOpPtrVector().push_back(
2544 new OpCalculateVectorFieldValues<SPACE_DIM>(hybridSpatialDisp,
2545 hybrid_ptr));
2546 op_loop_skeleton_side->getOpPtrVector().push_back(new OpC_dBroken(
2547 broken_data_ptr, hybrid_ptr, boost::make_shared<double>(1.0)));
2548
2549 // Add skeleton to domain pipeline
2550 pip.push_back(op_loop_skeleton_side);
2551
2553 };
2554
2555 auto set_contact = [&](auto &pip) {
2557
2558 using BoundaryEle =
2560 using EleOnSide =
2562 using SideEleOp = EleOnSide::UserDataOperator;
2563 using BdyEleOp = BoundaryEle::UserDataOperator;
2564
2565 // First: Iterate over skeleton FEs adjacent to Domain FEs
2566 // Note: BoundaryEle, i.e. uses skeleton interation rule
2567 auto op_loop_skeleton_side = new OpLoopSide<BoundaryEle>(
2568 mField, contactElement, SPACE_DIM - 1, Sev::noisy);
2569
2570 op_loop_skeleton_side->getSideFEPtr()->getRuleHook = rule_contact;
2571 op_loop_skeleton_side->getSideFEPtr()->setRuleHook = set_rule_contact;
2572 CHKERR EshelbianPlasticity::
2573 AddHOOps<SPACE_DIM - 1, SPACE_DIM, SPACE_DIM>::add(
2574 op_loop_skeleton_side->getOpPtrVector(), {L2},
2575 materialH1Positions, frontAdjEdges);
2576
2577 // Second: Iterate over domain FEs adjacent to skelton, particularly
2578 // one domain element.
2579 auto broken_data_ptr =
2580 boost::make_shared<std::vector<BrokenBaseSideData>>();
2581
2582 // Data storing contact fields
2583 auto contact_common_data_ptr =
2584 boost::make_shared<ContactOps::CommonData>();
2585
2586 auto add_ops_domain_side = [&](auto &pip) {
2588 // Note: EleOnSide, i.e. uses on domain projected skeleton rule
2589 auto op_loop_domain_side = new OpBrokenLoopSide<EleOnSide>(
2590 mField, elementVolumeName, SPACE_DIM, Sev::noisy);
2591 op_loop_domain_side->getSideFEPtr()->getUserPolynomialBase() =
2592 boost::make_shared<CGGUserPolynomialBase>();
2593 CHKERR
2594 EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
2595 op_loop_domain_side->getOpPtrVector(), {HDIV, H1, L2},
2596 materialH1Positions, frontAdjEdges);
2597 op_loop_domain_side->getOpPtrVector().push_back(
2598 new OpGetBrokenBaseSideData<SideEleOp>(piolaStress,
2599 broken_data_ptr));
2600 op_loop_domain_side->getOpPtrVector().push_back(
2602 piolaStress, contact_common_data_ptr->contactTractionPtr()));
2603 pip.push_back(op_loop_domain_side);
2605 };
2606
2607 auto add_ops_contact_rhs = [&](auto &pip) {
2609 // get body id and SDF range
2610 auto contact_sfd_map_range_ptr =
2611 boost::make_shared<std::map<int, Range>>(
2612 get_body_range("CONTACT_SDF", SPACE_DIM - 1));
2613
2614 pip.push_back(new OpCalculateVectorFieldValues<3>(
2615 contactDisp, contact_common_data_ptr->contactDispPtr()));
2616 auto u_h1_ptr = boost::make_shared<MatrixDouble>();
2617 pip.push_back(
2618 new OpCalculateVectorFieldValues<3>(spatialH1Disp, u_h1_ptr));
2619 pip.push_back(new OpTreeSearch(
2620 contactTreeRhs, contact_common_data_ptr, u_h1_ptr,
2621 get_range_from_block(mField, "CONTACT", SPACE_DIM - 1), nullptr,
2622 nullptr));
2624 contactDisp, contact_common_data_ptr, contactTreeRhs,
2625 contact_sfd_map_range_ptr));
2626 pip.push_back(
2628 broken_data_ptr, contact_common_data_ptr, contactTreeRhs));
2629
2631 };
2632
2633 // push ops to face/side pipeline
2634 CHKERR add_ops_domain_side(op_loop_skeleton_side->getOpPtrVector());
2635 CHKERR add_ops_contact_rhs(op_loop_skeleton_side->getOpPtrVector());
2636
2637 // Add skeleton to domain pipeline
2638 pip.push_back(op_loop_skeleton_side);
2639
2641 };
2642
2643 CHKERR set_hybridisation(fe_rhs->getOpPtrVector());
2644 CHKERR set_contact(fe_rhs->getOpPtrVector());
2645
2646 // Body forces
2647 using BodyNaturalBC =
2649 Assembly<PETSC>::LinearForm<GAUSS>;
2650 using OpBodyForce =
2651 BodyNaturalBC::OpFlux<NaturalMeshsetType<BLOCKSET>, 1, 3>;
2652
2653 auto body_time_scale =
2654 boost::make_shared<DynamicRelaxationTimeScale>("body_force.txt");
2655 CHKERR BodyNaturalBC::AddFluxToPipeline<OpBodyForce>::add(
2656 fe_rhs->getOpPtrVector(), mField, spatialL2Disp, {body_time_scale},
2657 "BODY_FORCE", Sev::inform);
2658 }
2659
2660 // Left hand side
2661 fe_lhs = boost::make_shared<VolumeElementForcesAndSourcesCore>(mField);
2662 CHKERR setBaseVolumeElementOps(tag, true, true, true, SmartPetscObj<Vec>(),
2663 fe_lhs);
2664
2665 // elastic
2666 if (add_elastic) {
2667
2668 if (noStretch) {
2669 fe_lhs->getOpPtrVector().push_back(
2670 new OpSpatialConsistency_dP_dP(piolaStress, piolaStress, dataAtPts));
2671 fe_lhs->getOpPtrVector().push_back(new OpSpatialConsistency_dBubble_dP(
2672 bubbleField, piolaStress, dataAtPts));
2673 fe_lhs->getOpPtrVector().push_back(
2674 new OpSpatialConsistency_dBubble_dBubble(bubbleField, bubbleField,
2675 dataAtPts));
2676 } else {
2677 fe_lhs->getOpPtrVector().push_back(
2678 physicalEquations->returnOpSpatialPhysical_du_du(
2679 stretchTensor, stretchTensor, dataAtPts, alphaU));
2680 fe_lhs->getOpPtrVector().push_back(new OpSpatialPhysical_du_dP(
2681 stretchTensor, piolaStress, dataAtPts, true));
2682 fe_lhs->getOpPtrVector().push_back(new OpSpatialPhysical_du_dBubble(
2683 stretchTensor, bubbleField, dataAtPts, true));
2684 fe_lhs->getOpPtrVector().push_back(new OpSpatialPhysical_du_domega(
2685 stretchTensor, rotAxis, dataAtPts,
2686 symmetrySelector == SYMMETRIC ? true : false));
2687 }
2688
2689 fe_lhs->getOpPtrVector().push_back(new OpSpatialEquilibrium_dw_dP(
2690 spatialL2Disp, piolaStress, dataAtPts, true));
2691 fe_lhs->getOpPtrVector().push_back(new OpSpatialEquilibrium_dw_dw(
2692 spatialL2Disp, spatialL2Disp, dataAtPts, alphaW, alphaRho));
2693
2694 fe_lhs->getOpPtrVector().push_back(new OpSpatialConsistency_dP_domega(
2695 piolaStress, rotAxis, dataAtPts,
2696 symmetrySelector == SYMMETRIC ? true : false));
2697 fe_lhs->getOpPtrVector().push_back(new OpSpatialConsistency_dBubble_domega(
2698 bubbleField, rotAxis, dataAtPts,
2699 symmetrySelector == SYMMETRIC ? true : false));
2700
2701 if (symmetrySelector > SYMMETRIC) {
2702 if (!noStretch) {
2703 fe_lhs->getOpPtrVector().push_back(new OpSpatialRotation_domega_du(
2704 rotAxis, stretchTensor, dataAtPts, false));
2705 }
2706 fe_lhs->getOpPtrVector().push_back(new OpSpatialRotation_domega_dP(
2707 rotAxis, piolaStress, dataAtPts, false));
2708 fe_lhs->getOpPtrVector().push_back(new OpSpatialRotation_domega_dBubble(
2709 rotAxis, bubbleField, dataAtPts, false));
2710 }
2711 fe_lhs->getOpPtrVector().push_back(new OpSpatialRotation_domega_domega(
2712 rotAxis, rotAxis, dataAtPts, alphaOmega));
2713
2714 auto set_hybridisation = [&](auto &pip) {
2716
2717 using BoundaryEle =
2719 using EleOnSide =
2721 using SideEleOp = EleOnSide::UserDataOperator;
2722 using BdyEleOp = BoundaryEle::UserDataOperator;
2723
2724 // First: Iterate over skeleton FEs adjacent to Domain FEs
2725 // Note: BoundaryEle, i.e. uses skeleton interation rule
2726 auto op_loop_skeleton_side = new OpLoopSide<BoundaryEle>(
2727 mField, skeletonElement, SPACE_DIM - 1, Sev::noisy);
2728 // op_loop_skeleton_side->getSideFEPtr()->getRuleHook = FaceRule();
2729 op_loop_skeleton_side->getSideFEPtr()->getRuleHook = [](int, int, int) {
2730 return -1;
2731 };
2732 op_loop_skeleton_side->getSideFEPtr()->setRuleHook =
2733 SetIntegrationAtFrontFace(frontVertices, frontAdjEdges);
2734 CHKERR EshelbianPlasticity::
2735 AddHOOps<SPACE_DIM - 1, SPACE_DIM, SPACE_DIM>::add(
2736 op_loop_skeleton_side->getOpPtrVector(), {L2},
2737 materialH1Positions, frontAdjEdges);
2738
2739 // Second: Iterate over domain FEs adjacent to skelton, particularly one
2740 // domain element.
2741 auto broken_data_ptr =
2742 boost::make_shared<std::vector<BrokenBaseSideData>>();
2743 // Note: EleOnSide, i.e. uses on domain projected skeleton rule
2744 auto op_loop_domain_side = new OpBrokenLoopSide<EleOnSide>(
2745 mField, elementVolumeName, SPACE_DIM, Sev::noisy);
2746 op_loop_domain_side->getSideFEPtr()->getUserPolynomialBase() =
2747 boost::make_shared<CGGUserPolynomialBase>();
2748 CHKERR
2749 EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
2750 op_loop_domain_side->getOpPtrVector(), {HDIV, H1, L2},
2751 materialH1Positions, frontAdjEdges);
2752 op_loop_domain_side->getOpPtrVector().push_back(
2753 new OpGetBrokenBaseSideData<SideEleOp>(piolaStress, broken_data_ptr));
2754
2755 op_loop_skeleton_side->getOpPtrVector().push_back(op_loop_domain_side);
2757 GAUSS>::OpBrokenSpaceConstrain<SPACE_DIM>;
2758 op_loop_skeleton_side->getOpPtrVector().push_back(
2759 new OpC(hybridSpatialDisp, broken_data_ptr,
2760 boost::make_shared<double>(1.0), true, false));
2761
2762 pip.push_back(op_loop_skeleton_side);
2763
2765 };
2766
2767 auto set_contact = [&](auto &pip) {
2769
2770 using BoundaryEle =
2772 using EleOnSide =
2774 using SideEleOp = EleOnSide::UserDataOperator;
2775 using BdyEleOp = BoundaryEle::UserDataOperator;
2776
2777 // First: Iterate over skeleton FEs adjacent to Domain FEs
2778 // Note: BoundaryEle, i.e. uses skeleton interation rule
2779 auto op_loop_skeleton_side = new OpLoopSide<BoundaryEle>(
2780 mField, contactElement, SPACE_DIM - 1, Sev::noisy);
2781
2782 op_loop_skeleton_side->getSideFEPtr()->getRuleHook = rule_contact;
2783 op_loop_skeleton_side->getSideFEPtr()->setRuleHook = set_rule_contact;
2784 CHKERR EshelbianPlasticity::
2785 AddHOOps<SPACE_DIM - 1, SPACE_DIM, SPACE_DIM>::add(
2786 op_loop_skeleton_side->getOpPtrVector(), {L2},
2787 materialH1Positions, frontAdjEdges);
2788
2789 // Second: Iterate over domain FEs adjacent to skelton, particularly
2790 // one domain element.
2791 auto broken_data_ptr =
2792 boost::make_shared<std::vector<BrokenBaseSideData>>();
2793
2794 // Data storing contact fields
2795 auto contact_common_data_ptr =
2796 boost::make_shared<ContactOps::CommonData>();
2797
2798 auto add_ops_domain_side = [&](auto &pip) {
2800 // Note: EleOnSide, i.e. uses on domain projected skeleton rule
2801 auto op_loop_domain_side = new OpBrokenLoopSide<EleOnSide>(
2802 mField, elementVolumeName, SPACE_DIM, Sev::noisy);
2803 op_loop_domain_side->getSideFEPtr()->getUserPolynomialBase() =
2804 boost::make_shared<CGGUserPolynomialBase>();
2805 CHKERR
2806 EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
2807 op_loop_domain_side->getOpPtrVector(), {HDIV, H1, L2},
2808 materialH1Positions, frontAdjEdges);
2809 op_loop_domain_side->getOpPtrVector().push_back(
2810 new OpGetBrokenBaseSideData<SideEleOp>(piolaStress,
2811 broken_data_ptr));
2812 op_loop_domain_side->getOpPtrVector().push_back(
2814 piolaStress, contact_common_data_ptr->contactTractionPtr()));
2815 pip.push_back(op_loop_domain_side);
2817 };
2818
2819 auto add_ops_contact_lhs = [&](auto &pip) {
2821 pip.push_back(new OpCalculateVectorFieldValues<3>(
2822 contactDisp, contact_common_data_ptr->contactDispPtr()));
2823 auto u_h1_ptr = boost::make_shared<MatrixDouble>();
2824 pip.push_back(
2825 new OpCalculateVectorFieldValues<3>(spatialH1Disp, u_h1_ptr));
2826 pip.push_back(new OpTreeSearch(
2827 contactTreeRhs, contact_common_data_ptr, u_h1_ptr,
2828 get_range_from_block(mField, "CONTACT", SPACE_DIM - 1), nullptr,
2829 nullptr));
2830
2831 // get body id and SDF range
2832 auto contact_sfd_map_range_ptr =
2833 boost::make_shared<std::map<int, Range>>(
2834 get_body_range("CONTACT_SDF", SPACE_DIM - 1));
2835
2837 contactDisp, contactDisp, contact_common_data_ptr, contactTreeRhs,
2838 contact_sfd_map_range_ptr));
2839 pip.push_back(
2841 contactDisp, broken_data_ptr, contact_common_data_ptr,
2842 contactTreeRhs, contact_sfd_map_range_ptr));
2843 pip.push_back(
2845 broken_data_ptr, contactDisp, contact_common_data_ptr,
2846 contactTreeRhs));
2847
2849 };
2850
2851 // push ops to face/side pipeline
2852 CHKERR add_ops_domain_side(op_loop_skeleton_side->getOpPtrVector());
2853 CHKERR add_ops_contact_lhs(op_loop_skeleton_side->getOpPtrVector());
2854
2855 // Add skeleton to domain pipeline
2856 pip.push_back(op_loop_skeleton_side);
2857
2859 };
2860
2861 CHKERR set_hybridisation(fe_lhs->getOpPtrVector());
2862 CHKERR set_contact(fe_lhs->getOpPtrVector());
2863 }
2864
2865 if (add_material) {
2866 }
2867
2869}
2870
2872 const bool add_elastic, const bool add_material,
2873 boost::shared_ptr<FaceElementForcesAndSourcesCore> &fe_rhs,
2874 boost::shared_ptr<FaceElementForcesAndSourcesCore> &fe_lhs) {
2876
2877 fe_rhs = boost::make_shared<FaceElementForcesAndSourcesCore>(mField);
2878 fe_lhs = boost::make_shared<FaceElementForcesAndSourcesCore>(mField);
2879
2880 // set integration rule
2881 // fe_rhs->getRuleHook = [](int, int, int p) { return 2 * (p + 1); };
2882 // fe_lhs->getRuleHook = [](int, int, int p) { return 2 * (p + 1); };
2883 fe_rhs->getRuleHook = [](int, int, int) { return -1; };
2884 fe_lhs->getRuleHook = [](int, int, int) { return -1; };
2885 fe_rhs->setRuleHook = SetIntegrationAtFrontFace(frontVertices, frontAdjEdges);
2886 fe_lhs->setRuleHook = SetIntegrationAtFrontFace(frontVertices, frontAdjEdges);
2887
2888 CHKERR
2889 EshelbianPlasticity::AddHOOps<SPACE_DIM - 1, SPACE_DIM, SPACE_DIM>::add(
2890 fe_rhs->getOpPtrVector(), {L2}, materialH1Positions, frontAdjEdges);
2891 CHKERR
2892 EshelbianPlasticity::AddHOOps<SPACE_DIM - 1, SPACE_DIM, SPACE_DIM>::add(
2893 fe_lhs->getOpPtrVector(), {L2}, materialH1Positions, frontAdjEdges);
2894
2895 if (add_elastic) {
2896
2897 auto get_broken_op_side = [this](auto &pip) {
2898 using EleOnSide =
2900 using SideEleOp = EleOnSide::UserDataOperator;
2901 // Iterate over domain FEs adjacent to boundary.
2902 auto broken_data_ptr =
2903 boost::make_shared<std::vector<BrokenBaseSideData>>();
2904 // Note: EleOnSide, i.e. uses on domain projected skeleton rule
2905 auto op_loop_domain_side = new OpLoopSide<EleOnSide>(
2906 mField, elementVolumeName, SPACE_DIM, Sev::noisy);
2907 op_loop_domain_side->getSideFEPtr()->getUserPolynomialBase() =
2908 boost::make_shared<CGGUserPolynomialBase>();
2909 CHKERR
2910 EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
2911 op_loop_domain_side->getOpPtrVector(), {HDIV, H1, L2},
2912 materialH1Positions, frontAdjEdges);
2913 op_loop_domain_side->getOpPtrVector().push_back(
2914 new OpGetBrokenBaseSideData<SideEleOp>(piolaStress, broken_data_ptr));
2915 boost::shared_ptr<double> piola_scale_ptr(new double);
2916 op_loop_domain_side->getOpPtrVector().push_back(
2917 physicalEquations->returnOpSetScale(piola_scale_ptr,
2918 physicalEquations));
2919
2920 auto piola_stress_mat_ptr = boost::make_shared<MatrixDouble>();
2921 op_loop_domain_side->getOpPtrVector().push_back(
2922 new OpCalculateHVecTensorField<3, 3>(piolaStress,
2923 piola_stress_mat_ptr));
2924 pip.push_back(op_loop_domain_side);
2925 return std::make_tuple(broken_data_ptr, piola_scale_ptr,
2926 piola_stress_mat_ptr);
2927 };
2928
2929 auto set_rhs = [&]() {
2931
2932 auto [broken_data_ptr, piola_scale_ptr, piola_stress_mat_ptr] =
2933 get_broken_op_side(fe_rhs->getOpPtrVector());
2934
2935 fe_rhs->getOpPtrVector().push_back(
2936 new OpDispBc(broken_data_ptr, bcSpatialDispVecPtr, timeScaleMap));
2937 fe_rhs->getOpPtrVector().push_back(new OpAnalyticalDispBc(
2938 broken_data_ptr, bcSpatialAnalyticalDisplacementVecPtr,
2939 timeScaleMap));
2940 fe_rhs->getOpPtrVector().push_back(new OpRotationBc(
2941 broken_data_ptr, bcSpatialRotationVecPtr, timeScaleMap));
2942
2943 fe_rhs->getOpPtrVector().push_back(
2944 new OpBrokenTractionBc(hybridSpatialDisp, bcSpatialTractionVecPtr,
2945 piola_scale_ptr, timeScaleMap));
2946 auto hybrid_grad_ptr = boost::make_shared<MatrixDouble>();
2947 // if you push gradient of L2 base to physical element, it will not work.
2948 fe_rhs->getOpPtrVector().push_back(
2950 hybridSpatialDisp, hybrid_grad_ptr));
2951 fe_rhs->getOpPtrVector().push_back(new OpBrokenPressureBc(
2952 hybridSpatialDisp, bcSpatialPressureVecPtr, piola_scale_ptr,
2953 hybrid_grad_ptr, timeScaleMap));
2954 fe_rhs->getOpPtrVector().push_back(new OpBrokenAnalyticalTractionBc(
2955 hybridSpatialDisp, bcSpatialAnalyticalTractionVecPtr, piola_scale_ptr,
2956 timeScaleMap));
2957
2958 auto hybrid_ptr = boost::make_shared<MatrixDouble>();
2959 fe_rhs->getOpPtrVector().push_back(
2960 new OpCalculateVectorFieldValues<SPACE_DIM>(hybridSpatialDisp,
2961 hybrid_ptr));
2962 fe_rhs->getOpPtrVector().push_back(new OpNormalDispRhsBc(
2963 hybridSpatialDisp, hybrid_ptr, piola_stress_mat_ptr,
2964 bcSpatialNormalDisplacementVecPtr, timeScaleMap));
2965
2966 auto get_normal_disp_bc_faces = [&]() {
2967 auto faces =
2968 get_range_from_block(mField, "NORMAL_DISPLACEMENT", SPACE_DIM - 1);
2969 return boost::make_shared<Range>(faces);
2970 };
2971
2972 using BoundaryEle =
2974 using BdyEleOp = BoundaryEle::UserDataOperator;
2976 GAUSS>::OpBrokenSpaceConstrainDFlux<SPACE_DIM>;
2977 fe_rhs->getOpPtrVector().push_back(new OpC_dBroken(
2978 broken_data_ptr, hybrid_ptr, boost::make_shared<double>(1.0),
2979 get_normal_disp_bc_faces()));
2980
2982 };
2983
2984 auto set_lhs = [&]() {
2986
2987 auto [broken_data_ptr, piola_scale_ptr, piola_stress_mat_ptr] =
2988 get_broken_op_side(fe_lhs->getOpPtrVector());
2989
2990 fe_lhs->getOpPtrVector().push_back(new OpNormalDispLhsBc_dU(
2991 hybridSpatialDisp, bcSpatialNormalDisplacementVecPtr, timeScaleMap));
2992 fe_lhs->getOpPtrVector().push_back(new OpNormalDispLhsBc_dP(
2993 hybridSpatialDisp, broken_data_ptr, bcSpatialNormalDisplacementVecPtr,
2994 timeScaleMap));
2995
2996 auto hybrid_grad_ptr = boost::make_shared<MatrixDouble>();
2997 // if you push gradient of L2 base to physical element, it will not work.
2998 fe_rhs->getOpPtrVector().push_back(
3000 hybridSpatialDisp, hybrid_grad_ptr));
3001 fe_lhs->getOpPtrVector().push_back(new OpBrokenPressureBcLhs_dU(
3002 hybridSpatialDisp, bcSpatialPressureVecPtr, hybrid_grad_ptr,
3003 timeScaleMap));
3004
3005 auto get_normal_disp_bc_faces = [&]() {
3006 auto faces =
3007 get_range_from_block(mField, "NORMAL_DISPLACEMENT", SPACE_DIM - 1);
3008 return boost::make_shared<Range>(faces);
3009 };
3010
3011 using BoundaryEle =
3013 using BdyEleOp = BoundaryEle::UserDataOperator;
3015 GAUSS>::OpBrokenSpaceConstrain<SPACE_DIM>;
3016 fe_lhs->getOpPtrVector().push_back(new OpC(
3017 hybridSpatialDisp, broken_data_ptr, boost::make_shared<double>(1.0),
3018 true, true, get_normal_disp_bc_faces()));
3019
3021 };
3022
3023 CHKERR set_rhs();
3024 CHKERR set_lhs();
3025 }
3026
3028}
3029
3031
3032 boost::shared_ptr<ContactTree> &fe_contact_tree
3033
3034) {
3036
3037 /** Contact requires that body is marked */
3038 auto get_body_range = [this](auto name, int dim, auto sev) {
3039 std::map<int, Range> map;
3040
3041 for (auto m_ptr :
3042 mField.getInterface<MeshsetsManager>()->getCubitMeshsetPtr(std::regex(
3043
3044 (boost::format("%s(.*)") % name).str()
3045
3046 ))
3047
3048 ) {
3049 Range ents;
3050 CHK_MOAB_THROW(m_ptr->getMeshsetIdEntitiesByDimension(mField.get_moab(),
3051 dim, ents, true),
3052 "by dim");
3053 map[m_ptr->getMeshsetId()] = ents;
3054 MOFEM_LOG("EPSYNC", sev) << "Meshset: " << m_ptr->getMeshsetId() << " "
3055 << ents.size() << " entities";
3056 }
3057
3058 MOFEM_LOG_SEVERITY_SYNC(mField.get_comm(), sev);
3059 return map;
3060 };
3061
3062 auto get_map_skin = [this](auto &&map) {
3063 ParallelComm *pcomm =
3064 ParallelComm::get_pcomm(&mField.get_moab(), MYPCOMM_INDEX);
3065
3066 Skinner skin(&mField.get_moab());
3067 for (auto &m : map) {
3068 Range skin_faces;
3069 CHKERR skin.find_skin(0, m.second, false, skin_faces);
3070 CHK_MOAB_THROW(pcomm->filter_pstatus(skin_faces,
3071 PSTATUS_SHARED | PSTATUS_MULTISHARED,
3072 PSTATUS_NOT, -1, nullptr),
3073 "filter");
3074 m.second.swap(skin_faces);
3075 }
3076 return map;
3077 };
3078
3079 /* The above code is written in C++ and it appears to be defining and using
3080 various operations on boundary elements and side elements. */
3082 using BoundaryEleOp = BoundaryEle::UserDataOperator;
3083
3084 auto contact_common_data_ptr = boost::make_shared<ContactOps::CommonData>();
3085
3086 auto calcs_side_traction = [&](auto &pip) {
3088 using EleOnSide =
3090 using SideEleOp = EleOnSide::UserDataOperator;
3091 auto op_loop_domain_side = new OpLoopSide<EleOnSide>(
3092 mField, elementVolumeName, SPACE_DIM, Sev::noisy);
3093 op_loop_domain_side->getSideFEPtr()->getUserPolynomialBase() =
3094 boost::make_shared<CGGUserPolynomialBase>();
3095 EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
3096 op_loop_domain_side->getOpPtrVector(), {HDIV, H1, L2},
3097 materialH1Positions, frontAdjEdges);
3098 op_loop_domain_side->getOpPtrVector().push_back(
3100 piolaStress, contact_common_data_ptr->contactTractionPtr(),
3101 boost::make_shared<double>(1.0)));
3102 pip.push_back(op_loop_domain_side);
3104 };
3105
3106 auto add_contact_three = [&]() {
3108 auto tree_moab_ptr = boost::make_shared<moab::Core>();
3109 fe_contact_tree = boost::make_shared<ContactTree>(
3110 mField, tree_moab_ptr, spaceOrder,
3111 get_body_range("CONTACT", SPACE_DIM - 1, Sev::inform));
3112 fe_contact_tree->getOpPtrVector().push_back(
3114 contactDisp, contact_common_data_ptr->contactDispPtr()));
3115 CHKERR calcs_side_traction(fe_contact_tree->getOpPtrVector());
3116 auto u_h1_ptr = boost::make_shared<MatrixDouble>();
3117 fe_contact_tree->getOpPtrVector().push_back(
3118 new OpCalculateVectorFieldValues<3>(spatialH1Disp, u_h1_ptr));
3119 fe_contact_tree->getOpPtrVector().push_back(
3120 new OpMoveNode(fe_contact_tree, contact_common_data_ptr, u_h1_ptr));
3122 };
3123
3124 CHKERR add_contact_three();
3125
3127}
3128
3131
3132 // Add contact operators. Note that only for rhs. THe lhs is assembled with
3133 // volume element, to enable schur complement evaluation.
3134 CHKERR setContactElementRhsOps(contactTreeRhs);
3135
3136 CHKERR setVolumeElementOps(tag, true, false, elasticFeRhs, elasticFeLhs);
3137 CHKERR setFaceElementOps(true, false, elasticBcRhs, elasticBcLhs);
3138
3139 auto adj_cache =
3140 boost::make_shared<ForcesAndSourcesCore::UserDataOperator::AdjCache>();
3141
3142 auto get_op_contact_bc = [&]() {
3144 auto op_loop_side = new OpLoopSide<SideEle>(
3145 mField, contactElement, SPACE_DIM - 1, Sev::noisy, adj_cache);
3146 return op_loop_side;
3147 };
3148
3150}
3151
3154 boost::shared_ptr<FEMethod> null;
3155
3156 if (std::abs(alphaRho) > std::numeric_limits<double>::epsilon()) {
3157
3158 CHKERR DMMoFEMTSSetI2Function(dm, elementVolumeName, elasticFeRhs, null,
3159 null);
3160 CHKERR DMMoFEMTSSetI2Function(dm, naturalBcElement, elasticBcRhs, null,
3161 null);
3162 CHKERR DMMoFEMTSSetI2Jacobian(dm, elementVolumeName, elasticFeLhs, null,
3163 null);
3164 CHKERR DMMoFEMTSSetI2Jacobian(dm, naturalBcElement, elasticBcLhs, null,
3165 null);
3166
3167 } else {
3168 CHKERR DMMoFEMTSSetIFunction(dm, elementVolumeName, elasticFeRhs, null,
3169 null);
3170 CHKERR DMMoFEMTSSetIFunction(dm, naturalBcElement, elasticBcRhs, null,
3171 null);
3172 CHKERR DMMoFEMTSSetIJacobian(dm, elementVolumeName, elasticFeLhs, null,
3173 null);
3174 CHKERR DMMoFEMTSSetIJacobian(dm, naturalBcElement, elasticBcLhs, null,
3175 null);
3176 }
3177
3179}
3180
3182#include "impl/SetUpSchurImpl.cpp"
3185
3187
3188 inline static auto setup(EshelbianCore *ep_ptr, TS ts, Vec x,
3189 bool set_ts_monitor) {
3190
3191#ifdef ENABLE_PYTHON_BINDING
3192 auto setup_sdf = [&]() {
3193 boost::shared_ptr<ContactOps::SDFPython> sdf_python_ptr;
3194
3195 auto file_exists = [](std::string myfile) {
3196 std::ifstream file(myfile.c_str());
3197 if (file) {
3198 return true;
3199 }
3200 return false;
3201 };
3202
3203 char sdf_file_name[255] = "sdf.py";
3204 CHKERR PetscOptionsGetString(PETSC_NULLPTR, PETSC_NULLPTR, "-sdf_file",
3205 sdf_file_name, 255, PETSC_NULLPTR);
3206
3207 if (file_exists(sdf_file_name)) {
3208 MOFEM_LOG("EP", Sev::inform) << sdf_file_name << " file found";
3209 sdf_python_ptr = boost::make_shared<ContactOps::SDFPython>();
3210 CHKERR sdf_python_ptr->sdfInit(sdf_file_name);
3211 ContactOps::sdfPythonWeakPtr = sdf_python_ptr;
3212 MOFEM_LOG("EP", Sev::inform) << "SdfPython initialized";
3213 } else {
3214 MOFEM_LOG("EP", Sev::warning) << sdf_file_name << " file NOT found";
3215 }
3216 return sdf_python_ptr;
3217 };
3218 auto sdf_python_ptr = setup_sdf();
3219#endif
3220
3221 auto setup_ts_monitor = [&]() {
3222 boost::shared_ptr<TsCtx> ts_ctx;
3224 if (set_ts_monitor) {
3225 CHKERR TSMonitorSet(ts, TsMonitorSet, ts_ctx.get(), PETSC_NULLPTR);
3226 auto monitor_ptr = boost::make_shared<EshelbianMonitor>(*ep_ptr);
3227 ts_ctx->getLoopsMonitor().push_back(
3228 TsCtx::PairNameFEMethodPtr(ep_ptr->elementVolumeName, monitor_ptr));
3229 }
3230 MOFEM_LOG("EP", Sev::inform) << "TS monitor setup";
3231 return std::make_tuple(ts_ctx);
3232 };
3233
3234 auto setup_snes_monitor = [&]() {
3236 SNES snes;
3237 CHKERR TSGetSNES(ts, &snes);
3238 auto snes_ctx = getDMSnesCtx(ep_ptr->dmElastic);
3239 CHKERR SNESMonitorSet(snes,
3240 (MoFEMErrorCode (*)(SNES, PetscInt, PetscReal,
3241 void *))MoFEMSNESMonitorEnergy,
3242 (void *)(snes_ctx.get()), PETSC_NULLPTR);
3243 MOFEM_LOG("EP", Sev::inform) << "SNES monitor setup";
3245 };
3246
3247 auto setup_snes_conergence_test = [&]() {
3249
3250 auto snes_convergence_test = [](SNES snes, PetscInt it, PetscReal xnorm,
3251 PetscReal snorm, PetscReal fnorm,
3252 SNESConvergedReason *reason, void *cctx) {
3254 // EshelbianCore *ep_ptr = (EshelbianCore *)cctx;
3255 CHKERR SNESConvergedDefault(snes, it, xnorm, snorm, fnorm, reason,
3256 PETSC_NULLPTR);
3257
3258 Vec x_update, r;
3259 CHKERR SNESGetSolutionUpdate(snes, &x_update);
3260 CHKERR SNESGetFunction(snes, &r, PETSC_NULLPTR, PETSC_NULLPTR);
3261
3262 // *reason = SNES_CONVERGED_ITERATING;
3263 // if (!it) {
3264 // /* set parameter for default relative tolerance convergence test */
3265 // snes->ttol = fnorm * snes->rtol;
3266 // snes->rnorm0 = fnorm;
3267 // }
3268 // if (PetscIsInfOrNanReal(fnorm)) {
3269 // MOFEM_LOG("EP", Sev::error)
3270 // << "SNES convergence test: function norm is NaN";
3271 // *reason = SNES_DIVERGED_FNORM_NAN;
3272 // } else if (fnorm < snes->abstol && (it || !snes->forceiteration)) {
3273 // MOFEM_LOG("EP", Sev::inform)
3274 // << "SNES convergence test: Converged due to function norm "
3275 // << std::setw(14) << std::setprecision(12) << std::scientific
3276 // << fnorm << " < " << std::setw(14) << std::setprecision(12)
3277 // << std::scientific << snes->abstol;
3278
3279 // PetscCall(PetscInfo(
3280 // snes, "Converged due to function norm %14.12e < %14.12e\n",
3281 // (double)fnorm, (double)snes->abstol));
3282 // *reason = SNES_CONVERGED_FNORM_ABS;
3283 // } else if (snes->nfuncs >= snes->max_funcs && snes->max_funcs >= 0) {
3284 // PetscCall(PetscInfo(
3285 // snes,
3286 // "Exceeded maximum number of function evaluations: %" PetscInt_FMT
3287 // " > %" PetscInt_FMT "\n",
3288 // snes->nfuncs, snes->max_funcs));
3289 // *reason = SNES_DIVERGED_FUNCTION_COUNT;
3290 // }
3291
3292 // if (it && !*reason) {
3293 // if (fnorm <= snes->ttol) {
3294 // PetscCall(PetscInfo(snes,
3295 // "Converged due to function norm %14.12e < "
3296 // "%14.12e (relative tolerance)\n",
3297 // (double)fnorm, (double)snes->ttol));
3298 // *reason = SNES_CONVERGED_FNORM_RELATIVE;
3299 // } else if (snorm < snes->stol * xnorm) {
3300 // PetscCall(PetscInfo(snes,
3301 // "Converged due to small update length: %14.12e "
3302 // "< %14.12e * %14.12e\n",
3303 // (double)snorm, (double)snes->stol,
3304 // (double)xnorm));
3305 // *reason = SNES_CONVERGED_SNORM_RELATIVE;
3306 // } else if (snes->divtol != PETSC_UNLIMITED &&
3307 // (fnorm > snes->divtol * snes->rnorm0)) {
3308 // PetscCall(PetscInfo(snes,
3309 // "Diverged due to increase in function norm: "
3310 // "%14.12e > %14.12e * %14.12e\n",
3311 // (double)fnorm, (double)snes->divtol,
3312 // (double)snes->rnorm0));
3313 // *reason = SNES_DIVERGED_DTOL;
3314 // }
3315 // }
3316
3318 };
3319
3320 // SNES snes;
3321 // CHKERR TSGetSNES(ts, &snes);
3322 // CHKERR SNESSetConvergenceTest(snes, snes_convergence_test, ep_ptr,
3323 // PETSC_NULLPTR);
3324 // MOFEM_LOG("EP", Sev::inform) << "SNES convergence test setup";
3326 };
3327
3328 auto setup_section = [&]() {
3329 PetscSection section_raw;
3330 CHKERR DMGetSection(ep_ptr->dmElastic, &section_raw);
3331 int num_fields;
3332 CHKERR PetscSectionGetNumFields(section_raw, &num_fields);
3333 for (int ff = 0; ff != num_fields; ff++) {
3334 const char *field_name;
3335 CHKERR PetscSectionGetFieldName(section_raw, ff, &field_name);
3336 MOFEM_LOG_C("EP", Sev::inform, "Field %d name %s", ff, field_name);
3337 }
3338 return section_raw;
3339 };
3340
3341 auto set_vector_on_mesh = [&]() {
3343 CHKERR DMoFEMMeshToLocalVector(ep_ptr->dmElastic, x, INSERT_VALUES,
3344 SCATTER_FORWARD);
3345 CHKERR VecGhostUpdateBegin(x, INSERT_VALUES, SCATTER_FORWARD);
3346 CHKERR VecGhostUpdateEnd(x, INSERT_VALUES, SCATTER_FORWARD);
3347 MOFEM_LOG("EP", Sev::inform) << "Vector set on mesh";
3349 };
3350
3351 auto setup_schur_block_solver = [&]() {
3352 MOFEM_LOG("EP", Sev::inform) << "Setting up Schur block solver";
3353 CHKERR TSAppendOptionsPrefix(ts, "elastic_");
3354 CHKERR TSSetFromOptions(ts);
3355 CHKERR TSSetDM(ts, ep_ptr->dmElastic);
3356 // Adding field split solver
3357 boost::shared_ptr<EshelbianCore::SetUpSchur> schur_ptr;
3358 if constexpr (A == AssemblyType::BLOCK_MAT) {
3359 schur_ptr =
3361 CHK_THROW_MESSAGE(schur_ptr->setUp(ts), "setup schur");
3362 }
3363 MOFEM_LOG("EP", Sev::inform) << "Setting up Schur block solver done";
3364 return schur_ptr;
3365 };
3366
3367 // Warning: sequence of construction is not guaranteed for tuple. You have
3368 // to enforce order by proper packaging.
3369
3370#ifdef ENABLE_PYTHON_BINDING
3371 return std::make_tuple(setup_sdf(), setup_ts_monitor(),
3372 setup_snes_monitor(), setup_snes_conergence_test(),
3373 setup_section(), set_vector_on_mesh(),
3374 setup_schur_block_solver());
3375#else
3376 return std::make_tuple(setup_ts_monitor(), setup_snes_monitor(),
3377 setup_snes_conergence_test(), setup_section(),
3378 set_vector_on_mesh(), setup_schur_block_solver());
3379#endif
3380 }
3381};
3382
3385
3386 PetscBool debug_model = PETSC_FALSE;
3387 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-debug_model", &debug_model,
3388 PETSC_NULLPTR);
3389
3390 if (debug_model == PETSC_TRUE) {
3391 auto ts_ctx_ptr = getDMTsCtx(dmElastic);
3392 auto post_proc = [&](TS ts, PetscReal t, Vec u, Vec u_t, Vec u_tt, Vec F,
3393 void *ctx) {
3395
3396 SNES snes;
3397 CHKERR TSGetSNES(ts, &snes);
3398 int it;
3399 CHKERR SNESGetIterationNumber(snes, &it);
3400 std::string file_name = "snes_iteration_" + std::to_string(it) + ".h5m";
3401 CHKERR postProcessResults(1, file_name, F, u_t);
3402 std::string file_skel_name =
3403 "snes_iteration_skel_" + std::to_string(it) + ".h5m";
3404
3405 auto get_material_force_tag = [&]() {
3406 auto &moab = mField.get_moab();
3407 Tag tag;
3408 CHK_MOAB_THROW(moab.tag_get_handle("MaterialForce", tag),
3409 "can't get tag");
3410 return tag;
3411 };
3412
3413 CHKERR calculateFaceMaterialForce(1, ts);
3414 CHKERR postProcessSkeletonResults(1, file_skel_name, F,
3415 {get_material_force_tag()});
3416
3418 };
3419 ts_ctx_ptr->tsDebugHook = post_proc;
3420 }
3421
3422 auto storage = solve_elastic_setup::setup(this, ts, x, true);
3423
3424 if (std::abs(alphaRho) > std::numeric_limits<double>::epsilon()) {
3425 Vec xx;
3426 CHKERR VecDuplicate(x, &xx);
3427 CHKERR VecZeroEntries(xx);
3428 CHKERR TS2SetSolution(ts, x, xx);
3429 CHKERR VecDestroy(&xx);
3430 } else {
3431 CHKERR TSSetSolution(ts, x);
3432 }
3433
3434 TetPolynomialBase::switchCacheBaseOn<HDIV>(
3435 {elasticFeLhs.get(), elasticFeRhs.get()});
3436 CHKERR TSSetUp(ts);
3437 CHKERR TSSetPreStep(ts, TSElasticPostStep::preStepFun);
3438 CHKERR TSSetPostStep(ts, TSElasticPostStep::postStepFun);
3440 CHKERR TSSolve(ts, PETSC_NULLPTR);
3442 TetPolynomialBase::switchCacheBaseOff<HDIV>(
3443 {elasticFeLhs.get(), elasticFeRhs.get()});
3444
3445 SNES snes;
3446 CHKERR TSGetSNES(ts, &snes);
3447 int lin_solver_iterations;
3448 CHKERR SNESGetLinearSolveIterations(snes, &lin_solver_iterations);
3449 MOFEM_LOG("EP", Sev::inform)
3450 << "Number of linear solver iterations " << lin_solver_iterations;
3451
3452 PetscBool test_cook_flg = PETSC_FALSE;
3453 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-test_cook", &test_cook_flg,
3454 PETSC_NULLPTR);
3455 if (test_cook_flg) {
3456 constexpr int expected_lin_solver_iterations = 11;
3457 if (lin_solver_iterations > expected_lin_solver_iterations)
3458 SETERRQ(
3459 PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
3460 "Expected number of iterations is different than expected %d > %d",
3461 lin_solver_iterations, expected_lin_solver_iterations);
3462 }
3463
3464 PetscBool test_sslv116_flag = PETSC_FALSE;
3465 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-test_sslv116",
3466 &test_sslv116_flag, PETSC_NULLPTR);
3467
3468 if (test_sslv116_flag) {
3469 double max_val = 0.0;
3470 double min_val = 0.0;
3471 auto field_min_max = [&](boost::shared_ptr<FieldEntity> ent_ptr) {
3473 auto ent_type = ent_ptr->getEntType();
3474 if (ent_type == MBVERTEX) {
3475 max_val = std::max(ent_ptr->getEntFieldData()[SPACE_DIM - 1], max_val);
3476 min_val = std::min(ent_ptr->getEntFieldData()[SPACE_DIM - 1], min_val);
3477 }
3479 };
3480 CHKERR mField.getInterface<FieldBlas>()->fieldLambdaOnEntities(
3481 field_min_max, spatialH1Disp);
3482
3483 double global_max_val = 0.0;
3484 double global_min_val = 0.0;
3485 MPI_Allreduce(&max_val, &global_max_val, 1, MPI_DOUBLE, MPI_MAX,
3486 mField.get_comm());
3487 MPI_Allreduce(&min_val, &global_min_val, 1, MPI_DOUBLE, MPI_MIN,
3488 mField.get_comm());
3489 MOFEM_LOG("EP", Sev::inform)
3490 << "Max " << spatialH1Disp << " value: " << global_max_val;
3491 MOFEM_LOG("EP", Sev::inform)
3492 << "Min " << spatialH1Disp << " value: " << global_min_val;
3493
3494 double ref_max_val = 0.00767;
3495 double ref_min_val = -0.00329;
3496 if (std::abs(global_max_val - ref_max_val) > 1e-5) {
3497 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
3498 "Incorrect max value of the displacement field: %f != %f",
3499 global_max_val, ref_max_val);
3500 }
3501 if (std::abs(global_min_val - ref_min_val) > 4e-5) {
3502 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
3503 "Incorrect min value of the displacement field: %f != %f",
3504 global_min_val, ref_min_val);
3505 }
3506 }
3507
3508 CHKERR gettingNorms();
3509
3511}
3512
3514 int start_step,
3515 double start_time) {
3517
3518 auto storage = solve_elastic_setup::setup(this, ts, x, false);
3519
3520 double final_time = 1;
3521 double delta_time = 0.1;
3522 int max_it = 10;
3523 PetscBool ts_h1_update = PETSC_FALSE;
3524
3525 PetscOptionsBegin(PETSC_COMM_WORLD, "", "Dynamic Relaxation Options",
3526 "none");
3527
3528 CHKERR PetscOptionsScalar("-dynamic_final_time",
3529 "dynamic relaxation final time", "", final_time,
3530 &final_time, PETSC_NULLPTR);
3531 CHKERR PetscOptionsScalar("-dynamic_delta_time",
3532 "dynamic relaxation final time", "", delta_time,
3533 &delta_time, PETSC_NULLPTR);
3534 CHKERR PetscOptionsInt("-dynamic_max_it", "dynamic relaxation iterations", "",
3535 max_it, &max_it, PETSC_NULLPTR);
3536 CHKERR PetscOptionsBool("-dynamic_h1_update", "update each ts step", "",
3537 ts_h1_update, &ts_h1_update, PETSC_NULLPTR);
3538
3539 PetscOptionsEnd();
3540
3541 auto setup_ts_monitor = [&]() {
3542 auto monitor_ptr = boost::make_shared<EshelbianMonitor>(*this);
3543 return monitor_ptr;
3544 };
3545 auto monitor_ptr = setup_ts_monitor();
3546
3547 TetPolynomialBase::switchCacheBaseOn<HDIV>(
3548 {elasticFeLhs.get(), elasticFeRhs.get()});
3549 CHKERR TSSetUp(ts);
3551
3552 double ts_delta_time;
3553 CHKERR TSGetTimeStep(ts, &ts_delta_time);
3554
3555 if (ts_h1_update) {
3556 CHKERR TSSetPreStep(ts, TSElasticPostStep::preStepFun);
3557 CHKERR TSSetPostStep(ts, TSElasticPostStep::postStepFun);
3558 }
3559
3562
3563 dynamicTime = start_time;
3564 dynamicStep = start_step;
3565 monitor_ptr->ts_u = PETSC_NULLPTR;
3566 monitor_ptr->ts_t = dynamicTime;
3567 monitor_ptr->ts_step = dynamicStep;
3568 CHKERR DMoFEMLoopFiniteElements(dmElastic, elementVolumeName, monitor_ptr);
3569 MOFEM_LOG("EP", Sev::inform) << "IT " << dynamicStep << " Time "
3570 << dynamicTime << " delta time " << delta_time;
3571 dynamicTime += delta_time;
3572 ++dynamicStep;
3573
3574 for (; dynamicTime < final_time; dynamicTime += delta_time) {
3575 MOFEM_LOG("EP", Sev::inform) << "IT " << dynamicStep << " Time "
3576 << dynamicTime << " delta time " << delta_time;
3577
3578 CHKERR TSSetStepNumber(ts, 0);
3579 CHKERR TSSetTime(ts, 0);
3580 CHKERR TSSetTimeStep(ts, ts_delta_time);
3581 if (!ts_h1_update) {
3583 }
3584 CHKERR TSSolve(ts, PETSC_NULLPTR);
3585 if (!ts_h1_update) {
3587 }
3588
3589 monitor_ptr->ts_u = PETSC_NULLPTR;
3590 monitor_ptr->ts_t = dynamicTime;
3591 monitor_ptr->ts_step = dynamicStep;
3592 CHKERR DMoFEMLoopFiniteElements(dmElastic, elementVolumeName, monitor_ptr);
3593
3594 ++dynamicStep;
3595 if (dynamicStep > max_it)
3596 break;
3597 }
3598
3600 TetPolynomialBase::switchCacheBaseOff<HDIV>(
3601 {elasticFeLhs.get(), elasticFeRhs.get()});
3602
3604}
3605
3608
3609 auto set_block = [&](auto name, int dim) {
3610 std::map<int, Range> map;
3611 auto set_tag_impl = [&](auto name) {
3613 auto mesh_mng = mField.getInterface<MeshsetsManager>();
3614 auto bcs = mesh_mng->getCubitMeshsetPtr(
3615
3616 std::regex((boost::format("%s(.*)") % name).str())
3617
3618 );
3619 for (auto bc : bcs) {
3620 Range r;
3621 CHKERR bc->getMeshsetIdEntitiesByDimension(mField.get_moab(), dim, r,
3622 true);
3623 map[bc->getMeshsetId()] = r;
3624 }
3626 };
3627
3628 CHKERR set_tag_impl(name);
3629
3630 return std::make_pair(name, map);
3631 };
3632
3633 auto set_skin = [&](auto &&map) {
3634 for (auto &m : map.second) {
3635 auto s = filter_true_skin(mField, get_skin(mField, m.second));
3636 m.second.swap(s);
3637 }
3638 return map;
3639 };
3640
3641 auto set_tag = [&](auto &&map) {
3642 Tag th;
3643 auto name = map.first;
3644 int def_val[] = {-1};
3646 mField.get_moab().tag_get_handle(name, 1, MB_TYPE_INTEGER, th,
3647 MB_TAG_SPARSE | MB_TAG_CREAT, def_val),
3648 "create tag");
3649 for (auto &m : map.second) {
3650 int id = m.first;
3651 CHK_MOAB_THROW(mField.get_moab().tag_clear_data(th, m.second, &id),
3652 "clear tag");
3653 }
3654 return th;
3655 };
3656
3657 listTagsToTransfer.push_back(set_tag(set_skin(set_block("BODY", 3))));
3658 listTagsToTransfer.push_back(set_tag(set_skin(set_block("MAT_ELASTIC", 3))));
3659 listTagsToTransfer.push_back(
3660 set_tag(set_skin(set_block("MAT_NEOHOOKEAN", 3))));
3661 listTagsToTransfer.push_back(set_tag(set_block("CONTACT", 2)));
3662
3664}
3665
3667EshelbianCore::postProcessResults(const int tag, const std::string file,
3668 Vec f_residual, Vec var_vector,
3669 std::vector<Tag> tags_to_transfer) {
3671
3672 // mark crack surface
3673 if (crackingOn) {
3674 Tag th;
3675 rval = mField.get_moab().tag_get_handle("CRACK", th);
3676 if (rval == MB_SUCCESS) {
3677 CHKERR mField.get_moab().tag_delete(th);
3678 }
3679 int def_val[] = {0};
3680 CHKERR mField.get_moab().tag_get_handle(
3681 "CRACK", 1, MB_TYPE_INTEGER, th, MB_TAG_SPARSE | MB_TAG_CREAT, def_val);
3682 int mark[] = {1};
3683 CHKERR mField.get_moab().tag_clear_data(th, *crackFaces, mark);
3684 tags_to_transfer.push_back(th);
3685
3686 auto get_tag = [&](auto name, auto dim) {
3687 auto &mob = mField.get_moab();
3688 Tag tag;
3689 double def_val[] = {0., 0., 0.};
3690 CHK_MOAB_THROW(mob.tag_get_handle(name, dim, MB_TYPE_DOUBLE, tag,
3691 MB_TAG_CREAT | MB_TAG_SPARSE, def_val),
3692 "create tag");
3693 return tag;
3694 };
3695
3696 tags_to_transfer.push_back(get_tag("MaterialForce", 3));
3697 // tags_to_transfer.push_back(get_tag("GriffithForce", 1));
3698 }
3699
3700 // add tags to transfer
3701 for (auto t : listTagsToTransfer) {
3702 tags_to_transfer.push_back(t);
3703 }
3704
3705 if (!dataAtPts) {
3706 dataAtPts =
3707 boost::shared_ptr<DataAtIntegrationPts>(new DataAtIntegrationPts());
3708 }
3709
3710 struct exclude_sdf {
3711 exclude_sdf(Range &&r) : map(r) {}
3712 bool operator()(FEMethod *fe_method_ptr) {
3713 auto ent = fe_method_ptr->getFEEntityHandle();
3714 if (map.find(ent) != map.end()) {
3715 return false;
3716 }
3717 return true;
3718 }
3719
3720 private:
3721 Range map;
3722 };
3723
3724 contactTreeRhs->exeTestHook =
3725 exclude_sdf(get_range_from_block(mField, "CONTACT_SDF", SPACE_DIM - 1));
3726
3727 CHKERR DMoFEMLoopFiniteElements(dM, contactElement, contactTreeRhs);
3728
3729 auto get_post_proc = [&](auto &post_proc_mesh, auto sense) {
3731 auto post_proc_ptr =
3732 boost::make_shared<PostProcBrokenMeshInMoabBaseCont<FaceEle>>(
3733 mField, post_proc_mesh);
3734 EshelbianPlasticity::AddHOOps<SPACE_DIM - 1, SPACE_DIM, SPACE_DIM>::add(
3735 post_proc_ptr->getOpPtrVector(), {L2}, materialH1Positions,
3736 frontAdjEdges);
3737
3738 auto domain_ops = [&](auto &fe, int sense) {
3740 fe.getUserPolynomialBase() =
3741 boost::shared_ptr<BaseFunction>(new CGGUserPolynomialBase());
3742 EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
3743 fe.getOpPtrVector(), {HDIV, H1, L2}, materialH1Positions,
3744 frontAdjEdges);
3745 auto piola_scale_ptr = boost::make_shared<double>(1.0);
3746 fe.getOpPtrVector().push_back(physicalEquations->returnOpSetScale(
3747 piola_scale_ptr, physicalEquations));
3748 fe.getOpPtrVector().push_back(new OpCalculateHVecTensorField<3, 3>(
3749 piolaStress, dataAtPts->getApproxPAtPts(), piola_scale_ptr));
3750 fe.getOpPtrVector().push_back(new OpCalculateHTensorTensorField<3, 3>(
3751 bubbleField, dataAtPts->getApproxPAtPts(), piola_scale_ptr,
3752 SmartPetscObj<Vec>(), MBMAXTYPE));
3753 if (noStretch) {
3754 fe.getOpPtrVector().push_back(
3755 physicalEquations->returnOpCalculateStretchFromStress(
3756 dataAtPts, physicalEquations));
3757 } else {
3758 fe.getOpPtrVector().push_back(
3760 stretchTensor, dataAtPts->getLogStretchTensorAtPts(), MBTET));
3761 }
3762 if (var_vector) {
3763 auto vec = SmartPetscObj<Vec>(var_vector, true);
3764 fe.getOpPtrVector().push_back(new OpCalculateHVecTensorField<3, 3>(
3765 piolaStress, dataAtPts->getVarPiolaPts(),
3766 boost::make_shared<double>(1), vec));
3767 fe.getOpPtrVector().push_back(new OpCalculateHTensorTensorField<3, 3>(
3768 bubbleField, dataAtPts->getVarPiolaPts(),
3769 boost::make_shared<double>(1), vec, MBMAXTYPE));
3770 fe.getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
3771 rotAxis, dataAtPts->getVarRotAxisPts(), vec, MBTET));
3772 if (noStretch) {
3773 fe.getOpPtrVector().push_back(
3774 physicalEquations->returnOpCalculateVarStretchFromStress(
3775 dataAtPts, physicalEquations));
3776 } else {
3777 fe.getOpPtrVector().push_back(
3779 stretchTensor, dataAtPts->getVarLogStreachPts(), vec, MBTET));
3780 }
3781 }
3782
3783 fe.getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
3784 rotAxis, dataAtPts->getRotAxisAtPts(), MBTET));
3785 fe.getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
3786 rotAxis, dataAtPts->getRotAxis0AtPts(), solTSStep, MBTET));
3787
3788 fe.getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
3789 spatialL2Disp, dataAtPts->getSmallWL2AtPts(), MBTET));
3790 fe.getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
3791 spatialH1Disp, dataAtPts->getSmallWH1AtPts()));
3792 fe.getOpPtrVector().push_back(new OpCalculateVectorFieldGradient<3, 3>(
3793 spatialH1Disp, dataAtPts->getSmallWGradH1AtPts()));
3794 // evaluate derived quantities
3795 fe.getOpPtrVector().push_back(
3797
3798 // evaluate integration points
3799 fe.getOpPtrVector().push_back(physicalEquations->returnOpJacobian(
3800 tag, true, false, dataAtPts, physicalEquations));
3801 if (auto op =
3802 physicalEquations->returnOpCalculateEnergy(dataAtPts, nullptr)) {
3803 fe.getOpPtrVector().push_back(op);
3804 fe.getOpPtrVector().push_back(new OpCalculateEshelbyStress(dataAtPts));
3805 }
3806
3807 // // post-proc
3811
3812 struct OpSidePPMap : public OpPPMap {
3813 OpSidePPMap(moab::Interface &post_proc_mesh,
3814 std::vector<EntityHandle> &map_gauss_pts,
3815 DataMapVec data_map_scalar, DataMapMat data_map_vec,
3816 DataMapMat data_map_mat, DataMapMat data_symm_map_mat,
3817 int sense)
3818 : OpPPMap(post_proc_mesh, map_gauss_pts, data_map_scalar,
3819 data_map_vec, data_map_mat, data_symm_map_mat),
3820 tagSense(sense) {}
3821
3822 MoFEMErrorCode doWork(int side, EntityType type,
3825
3826 if (tagSense != OpPPMap::getSkeletonSense())
3828
3829 CHKERR OpPPMap::doWork(side, type, data);
3831 }
3832
3833 private:
3834 int tagSense;
3835 };
3836
3837 OpPPMap::DataMapMat vec_fields;
3838 vec_fields["SpatialDisplacementL2"] = dataAtPts->getSmallWL2AtPts();
3839 vec_fields["SpatialDisplacementH1"] = dataAtPts->getSmallWH1AtPts();
3840 vec_fields["Omega"] = dataAtPts->getRotAxisAtPts();
3841 vec_fields["ContactDisplacement"] = dataAtPts->getContactL2AtPts();
3842 vec_fields["AngularMomentum"] = dataAtPts->getLeviKirchhoffAtPts();
3843 vec_fields["X"] = dataAtPts->getLargeXH1AtPts();
3844 if (!noStretch) {
3845 vec_fields["EiegnLogStreach"] = dataAtPts->getEigenValsAtPts();
3846 }
3847 if (var_vector) {
3848 auto vec = SmartPetscObj<Vec>(var_vector, true);
3849 vec_fields["VarOmega"] = dataAtPts->getVarRotAxisPts();
3850 vec_fields["VarSpatialDisplacementL2"] =
3851 boost::make_shared<MatrixDouble>();
3852 fe.getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
3853 spatialL2Disp, vec_fields["VarSpatialDisplacementL2"], vec, MBTET));
3854 }
3855 if (f_residual) {
3856 auto vec = SmartPetscObj<Vec>(f_residual, true);
3857 vec_fields["ResSpatialDisplacementL2"] =
3858 boost::make_shared<MatrixDouble>();
3859 fe.getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
3860 spatialL2Disp, vec_fields["ResSpatialDisplacementL2"], vec, MBTET));
3861 vec_fields["ResOmega"] = boost::make_shared<MatrixDouble>();
3862 fe.getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
3863 rotAxis, vec_fields["ResOmega"], vec, MBTET));
3864 }
3865
3866 OpPPMap::DataMapMat mat_fields;
3867 mat_fields["PiolaStress"] = dataAtPts->getApproxPAtPts();
3868 if (var_vector) {
3869 mat_fields["VarPiolaStress"] = dataAtPts->getVarPiolaPts();
3870 }
3871 if (f_residual) {
3872 auto vec = SmartPetscObj<Vec>(f_residual, true);
3873 mat_fields["ResPiolaStress"] = boost::make_shared<MatrixDouble>();
3874 fe.getOpPtrVector().push_back(new OpCalculateHVecTensorField<3, 3>(
3875 piolaStress, mat_fields["ResPiolaStress"],
3876 boost::make_shared<double>(1), vec));
3877 fe.getOpPtrVector().push_back(new OpCalculateHTensorTensorField<3, 3>(
3878 bubbleField, mat_fields["ResPiolaStress"],
3879 boost::make_shared<double>(1), vec, MBMAXTYPE));
3880 }
3881 if (!internalStressTagName.empty()) {
3882 mat_fields[internalStressTagName] = dataAtPts->getInternalStressAtPts();
3883 switch (internalStressInterpOrder) {
3884 case 0:
3885 fe.getOpPtrVector().push_back(
3886 new OpGetInternalStress<0>(dataAtPts, internalStressTagName));
3887 break;
3888 case 1:
3889 fe.getOpPtrVector().push_back(
3890 new OpGetInternalStress<1>(dataAtPts, internalStressTagName));
3891 break;
3892 default:
3893 SETERRQ(PETSC_COMM_WORLD, MOFEM_NOT_IMPLEMENTED,
3894 "Unsupported internal stress interpolation order %d",
3895 internalStressInterpOrder);
3896 }
3897 }
3898
3899 OpPPMap::DataMapMat mat_fields_symm;
3900 mat_fields_symm["LogSpatialStretch"] =
3901 dataAtPts->getLogStretchTensorAtPts();
3902 mat_fields_symm["SpatialStretch"] = dataAtPts->getStretchTensorAtPts();
3903 if (var_vector) {
3904 mat_fields_symm["VarLogSpatialStretch"] =
3905 dataAtPts->getVarLogStreachPts();
3906 }
3907 if (f_residual) {
3908 auto vec = SmartPetscObj<Vec>(f_residual, true);
3909 if (!noStretch) {
3910 mat_fields_symm["ResLogSpatialStretch"] =
3911 boost::make_shared<MatrixDouble>();
3912 fe.getOpPtrVector().push_back(
3914 stretchTensor, mat_fields_symm["ResLogSpatialStretch"], vec,
3915 MBTET));
3916 }
3917 }
3918
3919 fe.getOpPtrVector().push_back(
3920
3921 new OpSidePPMap(
3922
3923 post_proc_ptr->getPostProcMesh(), post_proc_ptr->getMapGaussPts(),
3924
3925 {},
3926
3927 vec_fields,
3928
3929 mat_fields,
3930
3931 mat_fields_symm,
3932
3933 sense
3934
3935 )
3936
3937 );
3938
3939 fe.getOpPtrVector().push_back(new OpPostProcDataStructure(
3940 post_proc_ptr->getPostProcMesh(), post_proc_ptr->getMapGaussPts(),
3941 dataAtPts, sense));
3942
3944 };
3945
3946 post_proc_ptr->getOpPtrVector().push_back(
3947 new OpCalculateVectorFieldValues<3>(contactDisp,
3948 dataAtPts->getContactL2AtPts()));
3949
3950 auto X_h1_ptr = boost::make_shared<MatrixDouble>();
3951 // H1 material positions
3952 post_proc_ptr->getOpPtrVector().push_back(
3953 new OpCalculateVectorFieldValues<3>(materialH1Positions,
3954 dataAtPts->getLargeXH1AtPts()));
3955
3956 // domain
3958 mField, elementVolumeName, SPACE_DIM);
3959 domain_ops(*(op_loop_side->getSideFEPtr()), sense);
3960 post_proc_ptr->getOpPtrVector().push_back(op_loop_side);
3961
3962 return post_proc_ptr;
3963 };
3964
3965 // contact
3966 auto calcs_side_traction_and_displacements = [&](auto &post_proc_ptr,
3967 auto &pip) {
3969 auto contact_common_data_ptr = boost::make_shared<ContactOps::CommonData>();
3970 // evaluate traction
3971 using EleOnSide =
3973 using SideEleOp = EleOnSide::UserDataOperator;
3974 auto op_loop_domain_side = new OpLoopSide<EleOnSide>(
3975 mField, elementVolumeName, SPACE_DIM, Sev::noisy);
3976 op_loop_domain_side->getSideFEPtr()->getUserPolynomialBase() =
3977 boost::shared_ptr<BaseFunction>(new CGGUserPolynomialBase());
3978 EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
3979 op_loop_domain_side->getOpPtrVector(), {HDIV, H1, L2},
3980 materialH1Positions, frontAdjEdges);
3981 op_loop_domain_side->getOpPtrVector().push_back(
3983 piolaStress, contact_common_data_ptr->contactTractionPtr(),
3984 boost::make_shared<double>(1.0)));
3985 pip.push_back(op_loop_domain_side);
3986 // evaluate contact displacement and contact conditions
3987 auto u_h1_ptr = boost::make_shared<MatrixDouble>();
3988 pip.push_back(new OpCalculateVectorFieldValues<3>(spatialH1Disp, u_h1_ptr));
3990 contactDisp, contact_common_data_ptr->contactDispPtr()));
3991 pip.push_back(new OpTreeSearch(
3992 contactTreeRhs, contact_common_data_ptr, u_h1_ptr,
3993 get_range_from_block(mField, "CONTACT", SPACE_DIM - 1),
3994 &post_proc_ptr->getPostProcMesh(), &post_proc_ptr->getMapGaussPts()));
3995
3996 if (f_residual) {
3997
3998 using BoundaryEle =
4000 auto op_this = new OpLoopThis<BoundaryEle>(mField, contactElement);
4001 pip.push_back(op_this);
4002 auto contact_residual = boost::make_shared<MatrixDouble>();
4003 op_this->getOpPtrVector().push_back(
4005 contactDisp, contact_residual,
4006 SmartPetscObj<Vec>(f_residual, true)));
4008 op_this->getOpPtrVector().push_back(
4009
4010 new OpPPMap(
4011
4012 post_proc_ptr->getPostProcMesh(), post_proc_ptr->getMapGaussPts(),
4013
4014 {},
4015
4016 {{"res_contact", contact_residual}},
4017
4018 {},
4019
4020 {}
4021
4022 )
4023
4024 );
4025 }
4026
4028 };
4029
4030 auto post_proc_mesh = boost::make_shared<moab::Core>();
4031 auto post_proc_ptr = get_post_proc(post_proc_mesh, 1);
4032 auto post_proc_negative_sense_ptr = get_post_proc(post_proc_mesh, -1);
4033 CHKERR calcs_side_traction_and_displacements(post_proc_ptr,
4034 post_proc_ptr->getOpPtrVector());
4035
4036 auto own_tets =
4037 CommInterface::getPartEntities(mField.get_moab(), mField.get_comm_rank())
4038 .subset_by_dimension(SPACE_DIM);
4039 Range own_faces;
4040 CHKERR mField.get_moab().get_adjacencies(own_tets, SPACE_DIM - 1, true,
4041 own_faces, moab::Interface::UNION);
4042
4043 auto get_post_negative = [&](auto &&ents) {
4044 auto crack_faces_pos = ents;
4045 auto crack_faces_neg = crack_faces_pos;
4046 auto skin = get_skin(mField, own_tets);
4047 auto crack_on_proc_skin = intersect(crack_faces_pos, skin);
4048 for (auto f : crack_on_proc_skin) {
4049 Range tet;
4050 CHKERR mField.get_moab().get_adjacencies(&f, 1, SPACE_DIM, false, tet);
4051 tet = intersect(tet, own_tets);
4052 int side_number, sense, offset;
4053 CHKERR mField.get_moab().side_number(tet[0], f, side_number, sense,
4054 offset);
4055 if (sense == 1) {
4056 crack_faces_neg.erase(f);
4057 } else {
4058 crack_faces_pos.erase(f);
4059 }
4060 }
4061 return std::make_pair(crack_faces_pos, crack_faces_neg);
4062 };
4063
4064 auto get_crack_faces = [&](auto crack_faces) {
4065 auto get_adj = [&](auto e, auto dim) {
4066 Range adj;
4067 CHKERR mField.get_moab().get_adjacencies(e, dim, true, adj,
4068 moab::Interface::UNION);
4069 return adj;
4070 };
4071 auto tets = get_adj(crack_faces, 3);
4072 auto faces = subtract(get_adj(tets, 2), crack_faces);
4073 tets = subtract(tets, get_adj(faces, 3));
4074 return subtract(crack_faces, get_adj(tets, 2));
4075 };
4076
4077 auto [crack_faces_pos, crack_faces_neg] =
4078 get_post_negative(intersect(own_faces, get_crack_faces(*crackFaces)));
4079
4080 auto only_crack_faces = [&](FEMethod *fe_method_ptr) {
4081 auto ent = fe_method_ptr->getFEEntityHandle();
4082 if (crack_faces_pos.find(ent) == crack_faces_pos.end()) {
4083 return false;
4084 }
4085 return true;
4086 };
4087
4088 auto only_negative_crack_faces = [&](FEMethod *fe_method_ptr) {
4089 auto ent = fe_method_ptr->getFEEntityHandle();
4090 if (crack_faces_neg.find(ent) == crack_faces_neg.end()) {
4091 return false;
4092 }
4093 return true;
4094 };
4095
4096 auto get_adj_front = [&]() {
4097 auto skeleton_faces = *skeletonFaces;
4098 Range adj_front;
4099 CHKERR mField.get_moab().get_adjacencies(*frontEdges, 2, true, adj_front,
4100 moab::Interface::UNION);
4101
4102 adj_front = intersect(adj_front, skeleton_faces);
4103 adj_front = subtract(adj_front, *crackFaces);
4104 adj_front = intersect(own_faces, adj_front);
4105 return adj_front;
4106 };
4107
4108 post_proc_ptr->setTagsToTransfer(tags_to_transfer);
4109 post_proc_negative_sense_ptr->setTagsToTransfer(tags_to_transfer);
4110
4111 auto post_proc_begin =
4112 PostProcBrokenMeshInMoabBaseBegin(mField, post_proc_mesh);
4113 CHKERR DMoFEMPreProcessFiniteElements(dM, post_proc_begin.getFEMethod());
4114 CHKERR DMoFEMLoopFiniteElements(dM, skinElement, post_proc_ptr);
4115 post_proc_ptr->exeTestHook = only_crack_faces;
4116 post_proc_negative_sense_ptr->exeTestHook = only_negative_crack_faces;
4118 dM, skeletonElement, post_proc_ptr, 0, mField.get_comm_size());
4119 CHKERR DMoFEMLoopFiniteElementsUpAndLowRank(dM, skeletonElement,
4120 post_proc_negative_sense_ptr, 0,
4121 mField.get_comm_size());
4122
4123 constexpr bool debug = false;
4124 if (debug) {
4125
4126 auto [adj_front_pos, adj_front_neg] =
4127 get_post_negative(filter_owners(mField, get_adj_front()));
4128
4129 auto only_front_faces_pos = [adj_front_pos](FEMethod *fe_method_ptr) {
4130 auto ent = fe_method_ptr->getFEEntityHandle();
4131 if (adj_front_pos.find(ent) == adj_front_pos.end()) {
4132 return false;
4133 }
4134 return true;
4135 };
4136
4137 auto only_front_faces_neg = [adj_front_neg](FEMethod *fe_method_ptr) {
4138 auto ent = fe_method_ptr->getFEEntityHandle();
4139 if (adj_front_neg.find(ent) == adj_front_neg.end()) {
4140 return false;
4141 }
4142 return true;
4143 };
4144
4145 post_proc_ptr->exeTestHook = only_front_faces_pos;
4147 dM, skeletonElement, post_proc_ptr, 0, mField.get_comm_size());
4148 post_proc_negative_sense_ptr->exeTestHook = only_front_faces_neg;
4149 CHKERR DMoFEMLoopFiniteElementsUpAndLowRank(dM, skeletonElement,
4150 post_proc_negative_sense_ptr, 0,
4151 mField.get_comm_size());
4152 }
4153 auto post_proc_end = PostProcBrokenMeshInMoabBaseEnd(mField, post_proc_mesh);
4154 CHKERR DMoFEMPostProcessFiniteElements(dM, post_proc_end.getFEMethod());
4155
4156 CHKERR post_proc_end.writeFile(file.c_str());
4158}
4159
4161EshelbianCore::postProcessSkeletonResults(const int tag, const std::string file,
4162 Vec f_residual,
4163 std::vector<Tag> tags_to_transfer) {
4165
4167
4168 auto post_proc_mesh = boost::make_shared<moab::Core>();
4169 auto post_proc_ptr =
4170 boost::make_shared<PostProcBrokenMeshInMoabBaseCont<FaceEle>>(
4171 mField, post_proc_mesh);
4172 EshelbianPlasticity::AddHOOps<SPACE_DIM - 1, SPACE_DIM - 1, SPACE_DIM>::add(
4173 post_proc_ptr->getOpPtrVector(), {L2}, materialH1Positions,
4175
4176 auto hybrid_disp = boost::make_shared<MatrixDouble>();
4177 post_proc_ptr->getOpPtrVector().push_back(
4179 post_proc_ptr->getOpPtrVector().push_back(
4181 hybridSpatialDisp, dataAtPts->getGradHybridDispAtPts()));
4182
4183 auto op_loop_domain_side =
4185 mField, elementVolumeName, SPACE_DIM, Sev::noisy);
4186 post_proc_ptr->getOpPtrVector().push_back(op_loop_domain_side);
4187
4188 // evaluated in side domain, that is op_loop_domain_side
4189 op_loop_domain_side->getSideFEPtr()->getUserPolynomialBase() =
4190 boost::make_shared<CGGUserPolynomialBase>();
4191 EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
4192 op_loop_domain_side->getOpPtrVector(), {HDIV, H1, L2},
4194 op_loop_domain_side->getOpPtrVector().push_back(
4196 piolaStress, dataAtPts->getApproxPAtPts()));
4197 op_loop_domain_side->getOpPtrVector().push_back(
4199 bubbleField, dataAtPts->getApproxPAtPts(), MBMAXTYPE));
4200 op_loop_domain_side->getOpPtrVector().push_back(
4202 rotAxis, dataAtPts->getRotAxisAtPts(), MBTET));
4203 if (noStretch) {
4204 op_loop_domain_side->getOpPtrVector().push_back(
4205 physicalEquations->returnOpCalculateStretchFromStress(
4207 } else {
4208 op_loop_domain_side->getOpPtrVector().push_back(
4210 stretchTensor, dataAtPts->getLogStretchTensorAtPts(), MBTET));
4211 }
4212
4214
4215 OpPPMap::DataMapMat vec_fields;
4216 vec_fields["HybridDisplacement"] = hybrid_disp;
4217 vec_fields["Omega"] = dataAtPts->getRotAxisAtPts();
4218 OpPPMap::DataMapMat mat_fields;
4219 mat_fields["PiolaStress"] = dataAtPts->getApproxPAtPts();
4220 mat_fields["HybridDisplacementGradient"] =
4221 dataAtPts->getGradHybridDispAtPts();
4222 OpPPMap::DataMapMat mat_fields_symm;
4223 mat_fields_symm["LogSpatialStretch"] = dataAtPts->getLogStretchTensorAtPts();
4224
4225 post_proc_ptr->getOpPtrVector().push_back(
4226
4227 new OpPPMap(
4228
4229 post_proc_ptr->getPostProcMesh(), post_proc_ptr->getMapGaussPts(),
4230
4231 {},
4232
4233 vec_fields,
4234
4235 mat_fields,
4236
4237 mat_fields_symm
4238
4239 )
4240
4241 );
4242
4243 if (f_residual) {
4244 auto hybrid_res = boost::make_shared<MatrixDouble>();
4245 post_proc_ptr->getOpPtrVector().push_back(
4247 hybridSpatialDisp, hybrid_res,
4248 SmartPetscObj<Vec>(f_residual, true)));
4250 post_proc_ptr->getOpPtrVector().push_back(
4251
4252 new OpPPMap(
4253
4254 post_proc_ptr->getPostProcMesh(), post_proc_ptr->getMapGaussPts(),
4255
4256 {},
4257
4258 {{"res_hybrid", hybrid_res}},
4259
4260 {},
4261
4262 {}
4263
4264 )
4265
4266 );
4267 }
4268
4269 post_proc_ptr->setTagsToTransfer(tags_to_transfer);
4270
4271 auto post_proc_begin =
4272 PostProcBrokenMeshInMoabBaseBegin(mField, post_proc_mesh);
4273 CHKERR DMoFEMPreProcessFiniteElements(dM, post_proc_begin.getFEMethod());
4274 CHKERR DMoFEMLoopFiniteElements(dM, skeletonElement, post_proc_ptr);
4275 auto post_proc_end = PostProcBrokenMeshInMoabBaseEnd(mField, post_proc_mesh);
4276 CHKERR DMoFEMPostProcessFiniteElements(dM, post_proc_end.getFEMethod());
4277
4278 CHKERR post_proc_end.writeFile(file.c_str());
4279
4281}
4282
4285
4286 constexpr bool debug = false;
4287
4288 auto get_tags_vec = [&](std::vector<std::pair<std::string, int>> names) {
4289 std::vector<Tag> tags;
4290 tags.reserve(names.size());
4291 auto create_and_clean = [&]() {
4293 for (auto n : names) {
4294 tags.push_back(Tag());
4295 auto &tag = tags.back();
4296 auto &moab = mField.get_moab();
4297 auto rval = moab.tag_get_handle(n.first.c_str(), tag);
4298 if (rval == MB_SUCCESS) {
4299 moab.tag_delete(tag);
4300 }
4301 double def_val[] = {0., 0., 0.};
4302 CHKERR moab.tag_get_handle(n.first.c_str(), n.second, MB_TYPE_DOUBLE,
4303 tag, MB_TAG_CREAT | MB_TAG_SPARSE, def_val);
4304 }
4306 };
4307 CHK_THROW_MESSAGE(create_and_clean(), "create_and_clean");
4308 return tags;
4309 };
4310
4311 enum ExhangeTags { MATERIALFORCE, AREAGROWTH, GRIFFITHFORCE, FACEPRESSURE };
4312
4313 auto tags = get_tags_vec({{"MaterialForce", 3},
4314 {"AreaGrowth", 3},
4315 {"GriffithForce", 1},
4316 {"FacePressure", 1}});
4317
4318 auto calculate_material_forces = [&]() {
4320
4321 /**
4322 * @brief Create element to integration faces energies
4323 */
4324 auto get_face_material_force_fe = [&]() {
4326 auto fe_ptr = boost::make_shared<FaceEle>(mField);
4327 fe_ptr->getRuleHook = [](int, int, int) { return -1; };
4328 fe_ptr->setRuleHook =
4329 SetIntegrationAtFrontFace(frontVertices, frontAdjEdges);
4330
4331 // hybrid disp, evalated on face first
4332 EshelbianPlasticity::AddHOOps<2, 2, 3>::add(
4333 fe_ptr->getOpPtrVector(), {L2}, materialH1Positions, frontAdjEdges);
4334 fe_ptr->getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
4335 hybridSpatialDisp, dataAtPts->getHybridDispAtPts()));
4336 fe_ptr->getOpPtrVector().push_back(
4338 hybridSpatialDisp, dataAtPts->getGradHybridDispAtPts()));
4339 auto op_loop_domain_side =
4341 mField, elementVolumeName, SPACE_DIM, Sev::noisy);
4342 fe_ptr->getOpPtrVector().push_back(op_loop_domain_side);
4343 fe_ptr->getOpPtrVector().push_back(new OpFaceMaterialForce(dataAtPts));
4344
4345 // evaluated in side domain, that is op_loop_domain_side
4346 op_loop_domain_side->getSideFEPtr()->getUserPolynomialBase() =
4347 boost::make_shared<CGGUserPolynomialBase>();
4348
4349 EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
4350 op_loop_domain_side->getOpPtrVector(), {HDIV, H1, L2},
4351 materialH1Positions, frontAdjEdges, nullptr, nullptr, nullptr);
4352 op_loop_domain_side->getOpPtrVector().push_back(
4354 piolaStress, dataAtPts->getApproxPAtPts()));
4355 op_loop_domain_side->getOpPtrVector().push_back(
4357 bubbleField, dataAtPts->getApproxPAtPts(), MBMAXTYPE));
4358 // op_loop_domain_side->getOpPtrVector().push_back(
4359 // new OpCalculateHVecTensorGradient<3, 9, 3>(
4360 // piolaStress, dataAtPts->getGradPAtPts()));
4361 // op_loop_domain_side->getOpPtrVector().push_back(
4362 // new OpCalculateHVecTensorGradient<9, 9, 3>(
4363 // bubbleField, dataAtPts->getGradPAtPts(), MBMAXTYPE));
4364
4365 op_loop_domain_side->getOpPtrVector().push_back(
4367 rotAxis, dataAtPts->getRotAxisAtPts(), MBTET));
4368 if (noStretch) {
4369 op_loop_domain_side->getOpPtrVector().push_back(
4370 physicalEquations->returnOpCalculateStretchFromStress(
4372 } else {
4373 op_loop_domain_side->getOpPtrVector().push_back(
4375 stretchTensor, dataAtPts->getLogStretchTensorAtPts(), MBTET));
4376 }
4377
4378 op_loop_domain_side->getOpPtrVector().push_back(
4380
4381 return fe_ptr;
4382 };
4383
4384 auto integrate_face_material_force_fe = [&](auto &&face_energy_fe) {
4387 dM, skeletonElement, face_energy_fe, 0, mField.get_comm_size());
4388
4389 auto face_exchange = CommInterface::createEntitiesPetscVector(
4390 mField.get_comm(), mField.get_moab(), 2, 3, Sev::inform);
4391
4392 auto print_loc_size = [this](auto v, auto str, auto sev) {
4394 int size;
4395 CHKERR VecGetLocalSize(v.second, &size);
4396 int low, high;
4397 CHKERR VecGetOwnershipRange(v.second, &low, &high);
4398 MOFEM_LOG("EPSYNC", sev) << str << " local size " << size << " ( "
4399 << low << " " << high << " ) ";
4402 };
4403 CHKERR print_loc_size(face_exchange, "material face_exchange",
4404 Sev::verbose);
4405
4407 mField.get_moab(), face_exchange, tags[ExhangeTags::MATERIALFORCE]);
4409 mField.get_moab(), faceExchange, tags[ExhangeTags::FACEPRESSURE]);
4410
4411 // #ifndef NDEBUG
4412 if (debug) {
4414 "front_skin_faces_material_force_" +
4415 std::to_string(mField.get_comm_rank()) + ".vtk",
4416 *skeletonFaces);
4417 }
4418 // #endif
4419
4421 };
4422
4423 CHKERR integrate_face_material_force_fe(get_face_material_force_fe());
4424
4426 };
4427
4428 auto calculate_front_material_force = [&](auto nb_J_integral_contours) {
4431
4432 auto get_conn = [&](auto e) {
4433 Range conn;
4434 CHK_MOAB_THROW(mField.get_moab().get_connectivity(&e, 1, conn, true),
4435 "get connectivity");
4436 return conn;
4437 };
4438
4439 auto get_conn_range = [&](auto e) {
4440 Range conn;
4441 CHK_MOAB_THROW(mField.get_moab().get_connectivity(e, conn, true),
4442 "get connectivity");
4443 return conn;
4444 };
4445
4446 auto get_adj = [&](auto e, auto dim) {
4447 Range adj;
4448 CHK_MOAB_THROW(mField.get_moab().get_adjacencies(&e, 1, dim, true, adj),
4449 "get adj");
4450 return adj;
4451 };
4452
4453 auto get_adj_range = [&](auto e, auto dim) {
4454 Range adj;
4455 CHK_MOAB_THROW(mField.get_moab().get_adjacencies(e, dim, true, adj,
4456 moab::Interface::UNION),
4457 "get adj");
4458 return adj;
4459 };
4460
4461 auto get_material_force = [&](auto r, auto th) {
4462 MatrixDouble material_forces(r.size(), 3, false);
4464 mField.get_moab().tag_get_data(th, r, material_forces.data().data()),
4465 "get data");
4466 return material_forces;
4467 };
4468
4469 if (mField.get_comm_rank() == 0) {
4470
4471 auto crack_edges = get_adj_range(*crackFaces, 1);
4472 auto front_nodes = get_conn_range(*frontEdges);
4473 auto body_edges = get_range_from_block(mField, "EDGES", 1);
4474 // auto front_block_edges = get_range_from_block(mField, "FRONT", 1);
4475 // front_block_edges = subtract(front_block_edges, crack_edges);
4476 // auto front_block_edges_conn = get_conn_range(front_block_edges);
4477
4478 // #ifndef NDEBUG
4479 Range all_skin_faces;
4480 Range all_front_faces;
4481 // #endif
4482
4483 auto calculate_edge_direction = [&](auto e) {
4484 const EntityHandle *conn;
4485 int num_nodes;
4487 mField.get_moab().get_connectivity(e, conn, num_nodes, true),
4488 "get connectivity");
4489 std::array<double, 6> coords;
4491 mField.get_moab().get_coords(conn, num_nodes, coords.data()),
4492 "get coords");
4494 &coords[0], &coords[1], &coords[2]};
4496 &coords[3], &coords[4], &coords[5]};
4499 t_dir(i) = t_p1(i) - t_p0(i);
4500 return t_dir;
4501 };
4502
4503 // take bubble tets at node, and then avarage over the edges
4504 auto calculate_force_through_node = [&]() {
4506
4511
4512 Range body_ents;
4513 CHKERR mField.get_moab().get_entities_by_dimension(0, SPACE_DIM,
4514 body_ents);
4515 auto body_skin = get_skin(mField, body_ents);
4516 auto body_skin_conn = get_conn_range(body_skin);
4517
4518 // calculate nodal material force
4519 for (auto n : front_nodes) {
4520 auto adj_tets = get_adj(n, 3);
4521 for (int ll = 0; ll < nb_J_integral_contours; ++ll) {
4522 auto conn = get_conn_range(adj_tets);
4523 adj_tets = get_adj_range(conn, 3);
4524 }
4525 auto skin_faces = get_skin(mField, adj_tets);
4526 auto material_forces = get_material_force(skin_faces, tags[0]);
4527
4528 #ifndef NDEBUG
4529 if (debug) {
4530 all_skin_faces.merge(skin_faces);
4531 }
4532 #endif
4533
4534 auto calculate_node_material_force = [&]() {
4535 auto t_face_T =
4536 getFTensor1FromPtr<SPACE_DIM>(material_forces.data().data());
4537 FTensor::Tensor1<double, SPACE_DIM> t_node_force{0., 0., 0.};
4538 for (auto face : skin_faces) {
4539
4540 FTensor::Tensor1<double, SPACE_DIM> t_face_force_tmp{0., 0., 0.};
4541 t_face_force_tmp(I) = t_face_T(I);
4542 ++t_face_T;
4543
4544 auto face_tets = intersect(get_adj(face, 3), adj_tets);
4545
4546 if (face_tets.empty()) {
4547 continue;
4548 }
4549
4550 if (face_tets.size() != 1) {
4552 "face_tets.size() != 1");
4553 }
4554
4555 int side_number, sense, offset;
4556 CHK_MOAB_THROW(mField.get_moab().side_number(face_tets[0], face,
4557 side_number, sense,
4558 offset),
4559 "moab side number");
4560 t_face_force_tmp(I) *= sense;
4561 t_node_force(I) += t_face_force_tmp(I);
4562 }
4563
4564 return t_node_force;
4565 };
4566
4567 auto calculate_crack_area_growth_direction =
4568 [&](auto n, auto &t_node_force) {
4569 // if skin is on body surface, project the direction on it
4570 FTensor::Tensor1<double, SPACE_DIM> t_project{0., 0., 0.};
4571 auto boundary_node = intersect(Range(n, n), body_skin_conn);
4572 if (boundary_node.size()) {
4573 auto faces = intersect(get_adj(n, 2), body_skin);
4574 for (auto f : faces) {
4575 FTensor::Tensor1<double, 3> t_normal_face;
4576 CHKERR mField.getInterface<Tools>()->getTriNormal(
4577 f, &t_normal_face(0));
4578 t_project(I) += t_normal_face(I);
4579 }
4580 t_project.normalize();
4581 }
4582
4583 // calculate surface projection matrix
4586 t_Q(I, J) = t_kd(I, J);
4587 if (boundary_node.size()) {
4588 t_Q(I, J) -= t_project(I) * t_project(J);
4589 }
4590
4591 auto adj_faces = intersect(get_adj(n, 2), *crackFaces);
4592 if (adj_faces.empty()) {
4593 auto adj_edges =
4594 intersect(get_adj(n, 1), unite(*frontEdges, body_edges));
4595 double l = 0;
4596 for (auto e : adj_edges) {
4597 auto t_dir = calculate_edge_direction(e);
4598 l += t_dir.l2();
4599 }
4600 l /= 2;
4601 FTensor::Tensor1<double, SPACE_DIM> t_area_dir{0., 0., 0.};
4602 FTensor::Tensor1<double, SPACE_DIM> t_node_force_tmp;
4603 t_node_force_tmp(I) = t_node_force(I);
4604 t_node_force_tmp.normalize();
4605 t_area_dir(I) = -t_node_force_tmp(I);
4606 t_area_dir(I) *= l / 2;
4607 return t_area_dir;
4608 }
4609
4610 // calculate direction
4611 auto front_edges = get_adj(n, 1);
4612 FTensor::Tensor1<double, 3> t_area_dir{0., 0., 0.};
4613 for (auto f : adj_faces) {
4614 int num_nodes;
4615 const EntityHandle *conn;
4616 CHKERR mField.get_moab().get_connectivity(f, conn, num_nodes,
4617 true);
4618 std::array<double, 9> coords;
4619 CHKERR mField.get_moab().get_coords(conn, num_nodes,
4620 coords.data());
4621 FTensor::Tensor1<double, 3> t_face_normal;
4623 CHKERR mField.getInterface<Tools>()->getTriNormal(
4624 coords.data(), &t_face_normal(0), &t_d_normal(0, 0, 0));
4625 auto n_it = std::find(conn, conn + num_nodes, n);
4626 auto n_index = std::distance(conn, n_it);
4627
4628 FTensor::Tensor2<double, 3, 3> t_face_hessian{
4629 t_d_normal(0, n_index, 0), t_d_normal(0, n_index, 1),
4630 t_d_normal(0, n_index, 2),
4631
4632 t_d_normal(1, n_index, 0), t_d_normal(1, n_index, 1),
4633 t_d_normal(1, n_index, 2),
4634
4635 t_d_normal(2, n_index, 0), t_d_normal(2, n_index, 1),
4636 t_d_normal(2, n_index, 2)};
4637
4638 FTensor::Tensor2<double, 3, 3> t_projected_hessian;
4639 t_projected_hessian(I, J) =
4640 t_Q(I, K) * (t_face_hessian(K, L) * t_Q(L, J));
4641 t_face_normal.normalize();
4642 t_area_dir(K) +=
4643 t_face_normal(I) * t_projected_hessian(I, K) / 2.;
4644 }
4645
4646 return t_area_dir;
4647 };
4648
4649 auto t_node_force = calculate_node_material_force();
4650 t_node_force(I) /= griffithEnergy; // scale all by griffith energy
4652 mField.get_moab().tag_set_data(tags[ExhangeTags::MATERIALFORCE],
4653 &n, 1, &t_node_force(0)),
4654 "set data");
4655
4656 auto get_area_dir = [&]() {
4657 FTensor::Tensor1<double, SPACE_DIM> t_area_dir{0., 0., 0.};
4658 auto adj_edges = intersect(get_adj_range(adj_tets, 1),
4659 unite(*frontEdges, body_edges));
4660 auto seed_n = get_conn_range(adj_edges);
4661 auto skin_adj_edges = get_skin(mField, adj_edges);
4662 skin_adj_edges = subtract(skin_adj_edges, body_skin_conn);
4663 seed_n = subtract(seed_n, skin_adj_edges);
4664 t_area_dir(I) = 0;
4665 for (auto sn : seed_n) {
4666 auto t_area_dir_sn =
4667 calculate_crack_area_growth_direction(sn, t_node_force);
4668 t_area_dir(I) += t_area_dir_sn(I);
4669 }
4670 for (auto sn : skin_adj_edges) {
4671 auto t_area_dir_sn =
4672 calculate_crack_area_growth_direction(sn, t_node_force);
4673 t_area_dir(I) += t_area_dir_sn(I) / 2;
4674 }
4675 return t_area_dir;
4676 };
4677
4678 auto t_area_dir = get_area_dir();
4679
4681 mField.get_moab().tag_set_data(tags[ExhangeTags::AREAGROWTH], &n,
4682 1, &t_area_dir(0)),
4683 "set data");
4684 auto griffith = -t_node_force(I) * t_area_dir(I) /
4685 (t_area_dir(K) * t_area_dir(K));
4687 mField.get_moab().tag_set_data(tags[ExhangeTags::GRIFFITHFORCE],
4688 &n, 1, &griffith),
4689 "set data");
4690 }
4691
4692 // iterate over edges, and calculate average edge material force
4693 auto ave_node_force = [&](auto th) {
4695
4696 for (auto e : *frontEdges) {
4697
4698 auto conn = get_conn(e);
4699 auto data = get_material_force(conn, th);
4700 auto t_node = getFTensor1FromPtr<SPACE_DIM>(data.data().data());
4701 FTensor::Tensor1<double, SPACE_DIM> t_edge{0., 0., 0.};
4702 for (auto n : conn) {
4703 NOT_USED(n);
4704 t_edge(I) += t_node(I);
4705 ++t_node;
4706 }
4707 t_edge(I) /= conn.size();
4708
4709 FTensor::Tensor1<double, SPACE_DIM> t_edge_direction =
4710 calculate_edge_direction(e);
4711 t_edge_direction.normalize();
4712
4717 t_cross(K) =
4718 FTensor::levi_civita(I, J, K) * t_edge_direction(I) * t_edge(J);
4719 t_edge(K) = FTensor::levi_civita(I, J, K) * t_edge_direction(J) *
4720 t_cross(I);
4721
4722 CHKERR mField.get_moab().tag_set_data(th, &e, 1, &t_edge(0));
4723 }
4725 };
4726
4727 // iterate over edges, and calculate average edge griffith energy
4728 auto ave_node_griffith_energy = [&](auto th) {
4730 for (auto e : *frontEdges) {
4732 CHKERR mField.get_moab().tag_get_data(
4733 tags[ExhangeTags::MATERIALFORCE], &e, 1, &t_edge_force(0));
4735 CHKERR mField.get_moab().tag_get_data(tags[ExhangeTags::AREAGROWTH],
4736 &e, 1, &t_edge_area_dir(0));
4737 double griffith_energy = -t_edge_force(I) * t_edge_area_dir(I) /
4738 (t_edge_area_dir(K) * t_edge_area_dir(K));
4739 CHKERR mField.get_moab().tag_set_data(th, &e, 1, &griffith_energy);
4740 }
4742 };
4743
4744 CHKERR ave_node_force(tags[ExhangeTags::MATERIALFORCE]);
4745 CHKERR ave_node_force(tags[ExhangeTags::AREAGROWTH]);
4746 CHKERR ave_node_griffith_energy(tags[ExhangeTags::GRIFFITHFORCE]);
4747
4749 };
4750
4751 CHKERR calculate_force_through_node();
4752
4753 // calculate face cross
4754 for (auto e : *frontEdges) {
4755 auto adj_faces = get_adj(e, 2);
4756 auto crack_face = intersect(get_adj(e, 2), *crackFaces);
4757
4758 // #ifndef NDEBUG
4759 if (debug) {
4760 all_front_faces.merge(adj_faces);
4761 }
4762 // #endif
4763
4765 CHKERR mField.get_moab().tag_get_data(tags[ExhangeTags::MATERIALFORCE],
4766 &e, 1, &t_edge_force(0));
4767 FTensor::Tensor1<double, SPACE_DIM> t_edge_direction =
4768 calculate_edge_direction(e);
4769 t_edge_direction.normalize();
4774 t_cross(K) = FTensor::levi_civita(I, J, K) * t_edge_direction(I) *
4775 t_edge_force(J);
4776
4777 for (auto f : adj_faces) {
4779 CHKERR mField.getInterface<Tools>()->getTriNormal(f, &t_normal(0));
4780 t_normal.normalize();
4781 int side_number, sense, offset;
4782 CHKERR mField.get_moab().side_number(f, e, side_number, sense,
4783 offset);
4784 auto dot = -sense * t_cross(I) * t_normal(I);
4785 CHK_MOAB_THROW(mField.get_moab().tag_set_data(
4786 tags[ExhangeTags::GRIFFITHFORCE], &f, 1, &dot),
4787 "set data");
4788 }
4789 }
4790
4791 #ifndef NDEBUG
4792 if (debug) {
4793 int ts_step;
4794 CHKERR TSGetStepNumber(ts, &ts_step);
4796 "front_edges_material_force_" +
4797 std::to_string(ts_step) + ".vtk",
4798 *frontEdges);
4800 "front_skin_faces_material_force_" +
4801 std::to_string(ts_step) + ".vtk",
4802 all_skin_faces);
4804 "front_faces_material_force_" +
4805 std::to_string(ts_step) + ".vtk",
4806 all_front_faces);
4807 }
4808 #endif
4809 }
4810
4811 auto edge_exchange = CommInterface::createEntitiesPetscVector(
4812 mField.get_comm(), mField.get_moab(), 1, 3, Sev::inform);
4814 mField.get_moab(), edge_exchange, tags[ExhangeTags::MATERIALFORCE]);
4816 mField.get_moab(), edge_exchange, tags[ExhangeTags::AREAGROWTH]);
4818 mField.get_moab(), edgeExchange, tags[ExhangeTags::GRIFFITHFORCE]);
4819
4821 };
4822
4823 auto print_results = [&](auto nb_J_integral_conturs) {
4825
4826 auto get_conn_range = [&](auto e) {
4827 Range conn;
4828 CHK_MOAB_THROW(mField.get_moab().get_connectivity(e, conn, true),
4829 "get connectivity");
4830 return conn;
4831 };
4832
4833 auto get_tag_data = [&](auto &ents, auto tag, auto dim) {
4834 std::vector<double> data(ents.size() * dim);
4835 CHK_MOAB_THROW(mField.get_moab().tag_get_data(tag, ents, data.data()),
4836 "get data");
4837 return data;
4838 };
4839
4840 if (mField.get_comm_rank() == 0) {
4841 auto at_nodes = [&]() {
4843 auto conn = get_conn_range(*frontEdges);
4844 auto material_force =
4845 get_tag_data(conn, tags[ExhangeTags::MATERIALFORCE], 3);
4846 auto area_growth = get_tag_data(conn, tags[ExhangeTags::AREAGROWTH], 3);
4847 auto griffith_force =
4848 get_tag_data(conn, tags[ExhangeTags::GRIFFITHFORCE], 1);
4849 std::vector<double> coords(conn.size() * 3);
4850 CHK_MOAB_THROW(mField.get_moab().get_coords(conn, coords.data()),
4851 "get coords");
4852 if (conn.size())
4853 MOFEM_LOG("EPSELF", Sev::inform) << "Material force at nodes";
4854 for (size_t i = 0; i < conn.size(); ++i) {
4855 MOFEM_LOG("EPSELF", Sev::inform)
4856 << "Node " << conn[i] << " coords " << coords[i * 3 + 0] << " "
4857 << coords[i * 3 + 1] << " " << coords[i * 3 + 2]
4858 << " material force " << material_force[i * 3 + 0] << " "
4859 << material_force[i * 3 + 1] << " " << material_force[i * 3 + 2]
4860 << " area growth " << area_growth[i * 3 + 0] << " "
4861 << area_growth[i * 3 + 1] << " " << area_growth[i * 3 + 2]
4862 << " griffith force " << std::setprecision(12)
4863 << griffith_force[i] << " contour " << nb_J_integral_conturs;
4864 }
4866 };
4867
4868 at_nodes();
4869 }
4871 };
4872
4873 CHKERR calculate_material_forces();
4874
4875 PetscBool all_conturs = PETSC_FALSE;
4876 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "",
4877 "-calculate_J_integral_all_levels", &all_conturs,
4878 PETSC_NULLPTR); // for backward compatibility
4879 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "",
4880 "-calculate_J_integral_all_contours", &all_conturs,
4881 PETSC_NULLPTR); // new name
4882
4883
4884 if (all_conturs == PETSC_TRUE) {
4885 for (int l = 0; l < nbJIntegralContours; ++l) {
4886 CHKERR calculate_front_material_force(l);
4887 CHKERR print_results(l);
4888 }
4889 }
4890
4891 CHKERR calculate_front_material_force(nbJIntegralContours);
4892 CHKERR print_results(nbJIntegralContours);
4893
4894
4895
4897}
4898
4900 bool set_orientation) {
4902
4903 // constexpr bool debug = false;
4904 constexpr auto sev = Sev::verbose;
4905
4906 Range body_ents;
4907 CHKERR mField.get_moab().get_entities_by_dimension(0, 3, body_ents);
4908 auto body_skin = get_skin(mField, body_ents);
4909 Range body_skin_edges;
4910 CHKERR mField.get_moab().get_adjacencies(body_skin, 1, false, body_skin_edges,
4911 moab::Interface::UNION);
4912 Range boundary_skin_verts;
4913 CHKERR mField.get_moab().get_connectivity(body_skin_edges,
4914 boundary_skin_verts, true);
4915
4916 auto geometry_edges = get_range_from_block(mField, "EDGES", 1);
4917 Range geometry_edges_verts;
4918 CHKERR mField.get_moab().get_connectivity(geometry_edges,
4919 geometry_edges_verts, true);
4920 Range crack_faces_verts;
4921 CHKERR mField.get_moab().get_connectivity(*crackFaces, crack_faces_verts,
4922 true);
4923 Range crack_faces_edges;
4924 CHKERR mField.get_moab().get_adjacencies(
4925 *crackFaces, 1, true, crack_faces_edges, moab::Interface::UNION);
4926 Range crack_faces_tets;
4927 CHKERR mField.get_moab().get_adjacencies(
4928 *crackFaces, 3, true, crack_faces_tets, moab::Interface::UNION);
4929
4930 Range front_verts;
4931 CHKERR mField.get_moab().get_connectivity(*frontEdges, front_verts, true);
4932 Range front_faces;
4933 CHKERR mField.get_moab().get_adjacencies(*frontEdges, 2, true, front_faces,
4934 moab::Interface::UNION);
4935 Range front_verts_edges;
4936 CHKERR mField.get_moab().get_adjacencies(
4937 front_verts, 1, true, front_verts_edges, moab::Interface::UNION);
4938
4939 auto get_tags_vec = [&](auto tag_name, int dim) {
4940 std::vector<Tag> tags(1);
4941
4942 if (dim > 3)
4944
4945 auto create_and_clean = [&]() {
4947 auto &moab = mField.get_moab();
4948 auto rval = moab.tag_get_handle(tag_name, tags[0]);
4949 if (rval == MB_SUCCESS) {
4950 moab.tag_delete(tags[0]);
4951 }
4952 double def_val[] = {0., 0., 0.};
4953 CHKERR moab.tag_get_handle(tag_name, dim, MB_TYPE_DOUBLE, tags[0],
4954 MB_TAG_CREAT | MB_TAG_SPARSE, def_val);
4956 };
4957
4958 CHK_THROW_MESSAGE(create_and_clean(), "create_and_clean");
4959
4960 return tags;
4961 };
4962
4963 auto get_adj_front = [&](bool subtract_crack) {
4964 Range adj_front;
4965 CHKERR mField.get_moab().get_adjacencies(*frontEdges, SPACE_DIM - 1, true,
4966 adj_front, moab::Interface::UNION);
4967 if (subtract_crack)
4968 adj_front = subtract(adj_front, *crackFaces);
4969 return adj_front;
4970 };
4971
4972 MOFEM_LOG_CHANNEL("SELF");
4973
4974 auto th_front_position = get_tags_vec("FrontPosition", 3);
4975 auto th_max_face_energy = get_tags_vec("MaxFaceEnergy", 1);
4976
4977 if (mField.get_comm_rank() == 0) {
4978
4979 auto get_crack_adj_tets = [&](auto r) {
4980 Range crack_faces_conn;
4981 CHKERR mField.get_moab().get_connectivity(r, crack_faces_conn);
4982 Range crack_faces_conn_tets;
4983 CHKERR mField.get_moab().get_adjacencies(crack_faces_conn, SPACE_DIM,
4984 true, crack_faces_conn_tets,
4985 moab::Interface::UNION);
4986 return crack_faces_conn_tets;
4987 };
4988
4989 auto get_layers_for_sides = [&](auto &side) {
4990 std::vector<Range> layers;
4991 auto get = [&]() {
4993
4994 auto get_adj = [&](auto &r, int dim) {
4995 Range adj;
4996 CHKERR mField.get_moab().get_adjacencies(r, dim, true, adj,
4997 moab::Interface::UNION);
4998 return adj;
4999 };
5000
5001 auto get_tets = [&](auto r) { return get_adj(r, SPACE_DIM); };
5002
5003 Range front_nodes;
5004 CHKERR mField.get_moab().get_connectivity(*frontEdges, front_nodes,
5005 true);
5006 Range front_faces = get_adj(front_nodes, 2);
5007 front_faces = subtract(front_faces, *crackFaces);
5008 auto front_tets = get_tets(front_nodes);
5009 auto front_side = intersect(side, front_tets);
5010 layers.push_back(front_side);
5011 for (;;) {
5012 auto adj_faces = get_skin(mField, layers.back());
5013 adj_faces = intersect(adj_faces, front_faces);
5014 auto adj_faces_tets = get_tets(adj_faces);
5015 adj_faces_tets = intersect(adj_faces_tets, front_tets);
5016 layers.push_back(unite(layers.back(), adj_faces_tets));
5017 if (layers.back().size() == layers[layers.size() - 2].size()) {
5018 break;
5019 }
5020 }
5022 };
5023 CHK_THROW_MESSAGE(get(), "get_layers_for_sides");
5024 return layers;
5025 };
5026
5028 auto layers_top = get_layers_for_sides(sides_pair.first);
5029 auto layers_bottom = get_layers_for_sides(sides_pair.second);
5030
5031#ifndef NDEBUG
5032 if (debug) {
5034 mField.get_moab(),
5035 "crack_tets_" +
5036 boost::lexical_cast<std::string>(mField.get_comm_rank()) + ".vtk",
5037 get_crack_adj_tets(*crackFaces));
5038 CHKERR save_range(mField.get_moab(), "sides_first.vtk", sides_pair.first);
5039 CHKERR save_range(mField.get_moab(), "sides_second.vtk",
5040 sides_pair.second);
5041 MOFEM_LOG("EP", sev) << "Nb. layers " << layers_top.size();
5042 int l = 0;
5043 for (auto &r : layers_top) {
5044 MOFEM_LOG("EP", sev) << "Layer " << l << " size " << r.size();
5046 mField.get_moab(),
5047 "layers_top_" + boost::lexical_cast<std::string>(l) + ".vtk", r);
5048 ++l;
5049 }
5050
5051 l = 0;
5052 for (auto &r : layers_bottom) {
5053 MOFEM_LOG("EP", sev) << "Layer " << l << " size " << r.size();
5055 mField.get_moab(),
5056 "layers_bottom_" + boost::lexical_cast<std::string>(l) + ".vtk", r);
5057 ++l;
5058 }
5059 }
5060#endif
5061
5062 auto get_cross = [&](auto t_dir, auto f) {
5064 CHKERR mField.getInterface<Tools>()->getTriNormal(f, &t_normal(0));
5065 t_normal.normalize();
5070 t_cross(i) = FTensor::levi_civita(i, j, k) * t_normal(j) * t_dir(k);
5071 return t_cross;
5072 };
5073
5074 auto get_sense = [&](auto f, auto e) {
5075 int side, sense, offset;
5076 CHK_MOAB_THROW(mField.get_moab().side_number(f, e, side, sense, offset),
5077 "get sense");
5078 return std::make_tuple(side, sense, offset);
5079 };
5080
5081 auto calculate_edge_direction = [&](auto e, auto normalize = true) {
5082 const EntityHandle *conn;
5083 int num_nodes;
5084 CHKERR mField.get_moab().get_connectivity(e, conn, num_nodes, true);
5085 std::array<double, 6> coords;
5086 CHKERR mField.get_moab().get_coords(conn, num_nodes, coords.data());
5088 &coords[0], &coords[1], &coords[2]};
5090 &coords[3], &coords[4], &coords[5]};
5093 t_dir(i) = t_p1(i) - t_p0(i);
5094 if (normalize)
5095 t_dir.normalize();
5096 return t_dir;
5097 };
5098
5099 auto evaluate_face_energy_and_set_orientation = [&](auto front_edges,
5100 auto front_faces,
5101 auto &sides_pair,
5102 auto th_position) {
5104
5105 Tag th_face_energy;
5106 Tag th_material_force;
5107 switch (energyReleaseSelector) {
5108 case GRIFFITH_FORCE:
5109 case GRIFFITH_SKELETON:
5110 CHKERR mField.get_moab().tag_get_handle("GriffithForce",
5111 th_face_energy);
5112 CHKERR mField.get_moab().tag_get_handle("MaterialForce",
5113 th_material_force);
5114 break;
5115 default:
5116 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
5117 "Unknown energy release selector");
5118 };
5119
5120 /**
5121 * Iterate over front edges, get adjacent faces, find maximal face energy.
5122 * Maximal face energy is stored in the edge. Maximal face energy is
5123 * magnitude of edge Griffith force.
5124 */
5125 auto find_maximal_face_energy = [&](auto front_edges, auto front_faces,
5126 auto &edge_face_max_energy_map) {
5128
5129 Range body_ents;
5130 CHKERR mField.get_moab().get_entities_by_dimension(0, 3, body_ents);
5131 auto body_skin = get_skin(mField, body_ents);
5132
5133 Range max_faces;
5134
5135 for (auto e : front_edges) {
5136
5137 double griffith_force;
5138 CHKERR mField.get_moab().tag_get_data(th_face_energy, &e, 1,
5139 &griffith_force);
5140
5141 Range faces;
5142 CHKERR mField.get_moab().get_adjacencies(&e, 1, 2, false, faces);
5143 faces = subtract(intersect(faces, front_faces), body_skin);
5144 std::vector<double> face_energy(faces.size());
5145 CHKERR mField.get_moab().tag_get_data(th_face_energy, faces,
5146 face_energy.data());
5147 auto max_energy_it =
5148 std::max_element(face_energy.begin(), face_energy.end());
5149 double max_energy =
5150 max_energy_it != face_energy.end() ? *max_energy_it : 0;
5151
5152 edge_face_max_energy_map[e] =
5153 std::make_tuple(faces[max_energy_it - face_energy.begin()],
5154 griffith_force, static_cast<double>(0));
5155 MOFEM_LOG("EP", Sev::inform)
5156 << "Edge " << e << " griffith force " << griffith_force
5157 << " max face energy " << max_energy << " factor "
5158 << max_energy / griffith_force;
5159
5160 max_faces.insert(faces[max_energy_it - face_energy.begin()]);
5161 }
5162
5163#ifndef NDEBUG
5164 if (debug) {
5166 mField.get_moab(),
5167 "max_faces_" +
5168 boost::lexical_cast<std::string>(mField.get_comm_rank()) +
5169 ".vtk",
5170 max_faces);
5171 }
5172#endif
5173
5175 };
5176
5177 /**
5178 * For each front edge, find maximal face energy and orientation. This is
5179 * by finding angle between edge material force and maximal face normal
5180 *
5181 */
5182 auto calculate_face_orientation = [&](auto &edge_face_max_energy_map) {
5184
5185 auto up_down_face = [&](
5186
5187 auto &face_angle_map_up,
5188 auto &face_angle_map_down
5189
5190 ) {
5192
5193 for (auto &m : edge_face_max_energy_map) {
5194 auto e = m.first;
5195 auto [max_face, energy, opt_angle] = m.second;
5196
5197 Range faces;
5198 CHKERR mField.get_moab().get_adjacencies(&e, 1, 2, false, faces);
5199 faces = intersect(faces, front_faces);
5200 Range adj_tets; // tetrahedrons adjacent to the face
5201 CHKERR mField.get_moab().get_adjacencies(&max_face, 1, SPACE_DIM,
5202 false, adj_tets,
5203 moab::Interface::UNION);
5204 if (adj_tets.size()) {
5205
5206 Range adj_tets; // tetrahedrons adjacent to the face
5207 CHKERR mField.get_moab().get_adjacencies(&max_face, 1, SPACE_DIM,
5208 false, adj_tets,
5209 moab::Interface::UNION);
5210 if (adj_tets.size()) {
5211
5212 Range adj_tets_faces;
5213 // get faces
5214 CHKERR mField.get_moab().get_adjacencies(
5215 adj_tets, SPACE_DIM - 1, false, adj_tets_faces,
5216 moab::Interface::UNION);
5217 adj_tets_faces = intersect(adj_tets_faces, faces);
5219
5220 // cross product of face normal and edge direction
5221 auto t_cross_max =
5222 get_cross(calculate_edge_direction(e, true), max_face);
5223 auto [side_max, sense_max, offset_max] = get_sense(max_face, e);
5224 t_cross_max(i) *= sense_max;
5225
5226 for (auto t : adj_tets) {
5227 Range adj_tets_faces;
5228 CHKERR mField.get_moab().get_adjacencies(
5229 &t, 1, SPACE_DIM - 1, false, adj_tets_faces);
5230 adj_tets_faces = intersect(adj_tets_faces, faces);
5231 adj_tets_faces =
5232 subtract(adj_tets_faces, Range(max_face, max_face));
5233
5234 if (adj_tets_faces.size() == 1) {
5235
5236 // cross product of adjacent face normal and edge
5237 // direction
5238 auto t_cross = get_cross(calculate_edge_direction(e, true),
5239 adj_tets_faces[0]);
5240 auto [side, sense, offset] =
5241 get_sense(adj_tets_faces[0], e);
5242 t_cross(i) *= sense;
5243 double dot = t_cross(i) * t_cross_max(i);
5244 auto angle = std::acos(dot);
5245
5246 double face_energy;
5247 CHKERR mField.get_moab().tag_get_data(
5248 th_face_energy, adj_tets_faces, &face_energy);
5249
5250 auto [side_face, sense_face, offset_face] =
5251 get_sense(t, max_face);
5252
5253 if (sense_face > 0) {
5254 face_angle_map_up[e] = std::make_tuple(face_energy, angle,
5255 adj_tets_faces[0]);
5256
5257 } else {
5258 face_angle_map_down[e] = std::make_tuple(
5259 face_energy, -angle, adj_tets_faces[0]);
5260 }
5261 }
5262 }
5263 }
5264 }
5265 }
5266
5268 };
5269
5270 auto calc_optimal_angle = [&](
5271
5272 auto &face_angle_map_up,
5273 auto &face_angle_map_down
5274
5275 ) {
5277
5278 for (auto &m : edge_face_max_energy_map) {
5279 auto e = m.first;
5280 auto &[max_face, e0, a0] = m.second;
5281
5282 if (std::abs(e0) > std::numeric_limits<double>::epsilon()) {
5283
5284 if (face_angle_map_up.find(e) == face_angle_map_up.end() ||
5285 face_angle_map_down.find(e) == face_angle_map_down.end()) {
5286 // Do nothing
5287 } else {
5288
5289 switch (energyReleaseSelector) {
5290 case GRIFFITH_FORCE:
5291 case GRIFFITH_SKELETON: {
5292
5293 Tag th_material_force;
5294 CHKERR mField.get_moab().tag_get_handle("MaterialForce",
5295 th_material_force);
5296 FTensor::Tensor1<double, SPACE_DIM> t_material_force;
5297 CHKERR mField.get_moab().tag_get_data(
5298 th_material_force, &e, 1, &t_material_force(0));
5299 auto material_force_magnitude = t_material_force.l2();
5300 if (material_force_magnitude <
5301 std::numeric_limits<double>::epsilon()) {
5302 a0 = 0;
5303
5304 } else {
5305
5306 auto t_edge_dir = calculate_edge_direction(e, true);
5307 auto t_cross_max = get_cross(t_edge_dir, max_face);
5308 auto [side, sense, offset] = get_sense(max_face, e);
5309 t_cross_max(sense) *= sense;
5310
5314
5315 t_material_force.normalize();
5316 t_cross_max.normalize();
5318 t_cross(I) = FTensor::levi_civita(I, J, K) *
5319 t_material_force(J) * t_cross_max(K);
5320 a0 = -std::asin(t_cross(I) * t_edge_dir(I));
5321
5322 MOFEM_LOG("EP", sev)
5323 << "Optimal angle " << a0 << " energy " << e0;
5324 }
5325 break;
5326 }
5327 default: {
5328
5329 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
5330 "Unknown energy release selector");
5331 }
5332 }
5333 }
5334 }
5335 }
5336
5338 };
5339
5340 std::map<EntityHandle, std::tuple<double, double, EntityHandle>>
5341 face_angle_map_up;
5342 std::map<EntityHandle, std::tuple<double, double, EntityHandle>>
5343 face_angle_map_down;
5344 CHKERR up_down_face(face_angle_map_up, face_angle_map_down);
5345 CHKERR calc_optimal_angle(face_angle_map_up, face_angle_map_down);
5346
5347#ifndef NDEBUG
5348 if (debug) {
5349 auto th_angle = get_tags_vec("Angle", 1);
5350 Range up;
5351 for (auto &m : face_angle_map_up) {
5352 auto [e, a, face] = m.second;
5353 up.insert(face);
5354 CHKERR mField.get_moab().tag_set_data(th_angle[0], &face, 1, &a);
5355 }
5356 Range down;
5357 for (auto &m : face_angle_map_down) {
5358 auto [e, a, face] = m.second;
5359 down.insert(face);
5360 CHKERR mField.get_moab().tag_set_data(th_angle[0], &face, 1, &a);
5361 }
5362
5363 Range max_energy_faces;
5364 for (auto &m : edge_face_max_energy_map) {
5365 auto [face, e, angle] = m.second;
5366 max_energy_faces.insert(face);
5367 CHKERR mField.get_moab().tag_set_data(th_angle[0], &face, 1,
5368 &angle);
5369 }
5370 if (mField.get_comm_rank() == 0) {
5371 CHKERR save_range(mField.get_moab(), "up_faces.vtk", up);
5372 CHKERR save_range(mField.get_moab(), "down_faces.vtk", down);
5373 CHKERR save_range(mField.get_moab(), "max_energy_faces.vtk",
5374 max_energy_faces);
5375 }
5376 }
5377#endif // NDEBUG
5378
5380 };
5381
5382 auto get_conn = [&](auto e) {
5383 Range conn;
5384 CHK_MOAB_THROW(mField.get_moab().get_connectivity(e, conn, true),
5385 "get conn");
5386 return conn;
5387 };
5388
5389 auto get_adj = [&](auto e, auto dim) {
5390 Range adj;
5391 CHK_MOAB_THROW(mField.get_moab().get_adjacencies(
5392 e, dim, false, adj, moab::Interface::UNION),
5393 "get adj");
5394 return adj;
5395 };
5396
5397 auto get_coords = [&](auto v) {
5399 CHK_MOAB_THROW(mField.get_moab().get_coords(v, &t_coords(0)),
5400 "get coords");
5401 return t_coords;
5402 };
5403
5404 // calulate normal of the max energy face
5405 auto get_rotated_normal = [&](auto e, auto f, auto angle) {
5408 auto t_edge_dir = calculate_edge_direction(e, true);
5409 auto [side, sense, offset] = get_sense(f, e);
5410 t_edge_dir(i) *= sense;
5411 t_edge_dir.normalize();
5412 t_edge_dir(i) *= angle;
5413 auto t_R = LieGroups::SO3::exp(t_edge_dir, angle);
5415 mField.getInterface<Tools>()->getTriNormal(f, &t_normal(0));
5416 FTensor::Tensor1<double, SPACE_DIM> t_rotated_normal;
5417 t_rotated_normal(i) = t_R(i, j) * t_normal(j);
5418 return std::make_tuple(t_normal, t_rotated_normal);
5419 };
5420
5421 auto set_coord = [&](auto v, auto &adj_vertex_tets_verts, auto &coords,
5422 auto &t_move, auto gamma) {
5423 auto index = adj_vertex_tets_verts.index(v);
5424 if (index >= 0) {
5425 for (auto ii : {0, 1, 2}) {
5426 coords[3 * index + ii] += gamma * t_move(ii);
5427 }
5428 return true;
5429 }
5430 return false;
5431 };
5432
5433 auto tets_quality = [&](auto quality, auto &adj_vertex_tets_verts,
5434 auto &adj_vertex_tets, auto &coords) {
5435 for (auto t : adj_vertex_tets) {
5436 const EntityHandle *conn;
5437 int num_nodes;
5438 CHKERR mField.get_moab().get_connectivity(t, conn, num_nodes, true);
5439 std::array<double, 12> tet_coords;
5440 for (auto n = 0; n != 4; ++n) {
5441 auto index = adj_vertex_tets_verts.index(conn[n]);
5442 if (index < 0) {
5444 }
5445 for (auto ii = 0; ii != 3; ++ii) {
5446 tet_coords[3 * n + ii] = coords[3 * index + ii];
5447 }
5448 }
5449 double q = Tools::volumeLengthQuality(tet_coords.data());
5450 if (!std::isnormal(q))
5451 q = -2;
5452 quality = std::min(quality, q);
5453 };
5454
5455 return quality;
5456 };
5457
5458 auto calculate_free_face_node_displacement =
5459 [&](auto &edge_face_max_energy_map) {
5460 // get edges adjacent to vertex along which nodes are moving
5461 auto get_vertex_edges = [&](auto vertex) {
5462 Range vertex_edges; // edges adjacent to vertex
5463
5464 auto impl = [&]() {
5466 CHKERR mField.get_moab().get_adjacencies(vertex, 1, false,
5467 vertex_edges);
5468 vertex_edges = subtract(vertex_edges, front_verts_edges);
5469
5470 if (boundary_skin_verts.size() &&
5471 boundary_skin_verts.find(vertex[0]) !=
5472 boundary_skin_verts.end()) {
5473 MOFEM_LOG("EP", sev) << "Boundary vertex";
5474 vertex_edges = intersect(vertex_edges, body_skin_edges);
5475 }
5476 if (geometry_edges_verts.size() &&
5477 geometry_edges_verts.find(vertex[0]) !=
5478 geometry_edges_verts.end()) {
5479 MOFEM_LOG("EP", sev) << "Geometry edge vertex";
5480 vertex_edges = intersect(vertex_edges, geometry_edges);
5481 }
5482 if (crack_faces_verts.size() &&
5483 crack_faces_verts.find(vertex[0]) !=
5484 crack_faces_verts.end()) {
5485 MOFEM_LOG("EP", sev) << "Crack face vertex";
5486 vertex_edges = intersect(vertex_edges, crack_faces_edges);
5487 }
5489 };
5490
5491 CHK_THROW_MESSAGE(impl(), "get_vertex_edges");
5492
5493 return vertex_edges;
5494 };
5495
5496 // vector of rotated faces, edge along node is moved, moved edge,
5497 // moved displacement, quality, cardinality, gamma
5498 using Bundle = std::vector<
5499
5502
5503 >;
5504 std::map<EntityHandle, Bundle> edge_bundle_map;
5505
5506 for (auto &m : edge_face_max_energy_map) {
5507
5508 auto edge = m.first;
5509 auto &[max_face, energy, opt_angle] = m.second;
5510
5511 // calculate rotation of max energy face
5512 auto [t_normal, t_rotated_normal] =
5513 get_rotated_normal(edge, max_face, opt_angle);
5514
5515 auto front_vertex = get_conn(Range(m.first, m.first));
5516 auto adj_tets = get_adj(Range(max_face, max_face), 3);
5517 auto adj_tets_faces = get_adj(adj_tets, 2);
5518 auto adj_front_faces = subtract(
5519 intersect(get_adj(Range(edge, edge), 2), adj_tets_faces),
5520 *crackFaces);
5521 if (adj_front_faces.size() > 3)
5523 "adj_front_faces.size()>3");
5524
5525 FTensor::Tensor1<double, SPACE_DIM> t_material_force;
5526 CHKERR mField.get_moab().tag_get_data(th_material_force, &edge, 1,
5527 &t_material_force(0));
5528 std::vector<double> griffith_energy(adj_front_faces.size());
5529 CHKERR mField.get_moab().tag_get_data(
5530 th_face_energy, adj_front_faces, griffith_energy.data());
5531
5532
5533 auto set_edge_bundle = [&](auto min_gamma) {
5534 for (auto rotated_f : adj_front_faces) {
5535
5536 double rotated_face_energy =
5537 griffith_energy[adj_front_faces.index(rotated_f)];
5538
5539 auto vertex = subtract(get_conn(Range(rotated_f, rotated_f)),
5540 front_vertex);
5541 if (vertex.size() != 1) {
5543 "Wrong number of vertex to move");
5544 }
5545 auto front_vertex_edges_vertex = get_conn(
5546 intersect(get_adj(front_vertex, 1), crack_faces_edges));
5547 vertex = subtract(
5548 vertex, front_vertex_edges_vertex); // vertex free to move
5549 if (vertex.empty()) {
5550 continue;
5551 }
5552
5553 auto face_cardinality = [&](auto f, auto &seen_front_edges) {
5554 auto whole_front =
5555 unite(*frontEdges,
5556 subtract(body_skin_edges, crack_faces_edges));
5557 auto faces = Range(f, f);
5558 int c = 0;
5559 for (; c < 10; ++c) {
5560 auto front_edges =
5561 subtract(get_adj(faces, 1), seen_front_edges);
5562 if (front_edges.size() == 0) {
5563 return 0;
5564 }
5565 auto front_connected_edges =
5566 intersect(front_edges, whole_front);
5567 if (front_connected_edges.size()) {
5568 seen_front_edges.merge(front_connected_edges);
5569 return c;
5570 }
5571 faces.merge(get_adj(front_edges, 2));
5572 ++c;
5573 }
5574 return c;
5575 };
5576
5577 Range seen_edges = Range(edge, edge);
5578 double rotated_face_cardinality = face_cardinality(
5579 rotated_f,
5580 seen_edges); // add cardinality of max energy
5581 // face to rotated face cardinality
5582 // rotated_face_cardinality +=
5583 // face_cardinality(max_face, seen_edges);
5584 rotated_face_cardinality = std::max(rotated_face_cardinality,
5585 1.); // at least one edge
5586
5587 auto t_vertex_coords = get_coords(vertex);
5588 auto vertex_edges = get_vertex_edges(vertex);
5589
5590 EntityHandle f0 = front_vertex[0];
5591 EntityHandle f1 = front_vertex[1];
5592 FTensor::Tensor1<double, 3> t_v_e0, t_v_e1;
5593 CHKERR mField.get_moab().get_coords(&f0, 1, &t_v_e0(0));
5594 CHKERR mField.get_moab().get_coords(&f1, 1, &t_v_e1(0));
5595
5597 for (auto e_used_to_move_detection : vertex_edges) {
5598 auto edge_conn = get_conn(Range(e_used_to_move_detection,
5599 e_used_to_move_detection));
5600 edge_conn = subtract(edge_conn, vertex);
5601 // Find displacement of the edge such that dot porduct with
5602 // normal is zero.
5603 //
5604 // { (t_v0 - t_vertex_coords) + gamma * (t_v3 -
5605 // t_vertex_coords) } * n = 0
5606 // where t_v0 is the edge vertex, t_v3 is the edge end
5607 // point, n is the rotated normal of the face gamma is the
5608 // factor by which the edge is moved
5610 t_v0(i) = (t_v_e0(i) + t_v_e1(i)) / 2;
5612 CHKERR mField.get_moab().get_coords(edge_conn, &t_v3(0));
5613 auto a =
5614 (t_v0(i) - t_vertex_coords(i)) * t_rotated_normal(i);
5615 auto b =
5616 (t_v3(i) - t_vertex_coords(i)) * t_rotated_normal(i);
5617 auto gamma = a / b;
5618
5619 constexpr double eps =
5620 std::numeric_limits<double>::epsilon();
5621 if (std::isnormal(gamma) && gamma < 1.0 - eps &&
5622 gamma > -0.1) {
5624 t_move(i) = gamma * (t_v3(i) - t_vertex_coords(i));
5625
5626 auto check_rotated_face_directoon = [&]() {
5628 t_delta(i) = t_vertex_coords(i) + t_move(i) - t_v0(i);
5629 t_delta.normalize();
5630 auto dot =
5631 (t_material_force(i) / t_material_force.l2()) *
5632 t_delta(i);
5633 return -dot > 0 ? true : false;
5634 };
5635
5636 if (check_rotated_face_directoon()) {
5637
5638 MOFEM_LOG("EP", Sev::inform)
5639 << "Crack edge " << edge << " moved face "
5640 << rotated_f
5641 << " edge: " << e_used_to_move_detection
5642 << " face direction/energy " << rotated_face_energy
5643 << " face cardinality " << rotated_face_cardinality
5644 << " gamma: " << gamma;
5645
5646 auto &bundle = edge_bundle_map[edge];
5647 bundle.emplace_back(rotated_f, e_used_to_move_detection,
5648 vertex[0], t_move, 1,
5649 rotated_face_cardinality, gamma);
5650 }
5651 }
5652 }
5653 }
5654 };
5655
5656 set_edge_bundle(std::numeric_limits<double>::epsilon());
5657 if (edge_bundle_map[edge].empty()) {
5658 set_edge_bundle(-1.);
5659 }
5660 }
5661
5662 return edge_bundle_map;
5663 };
5664
5665 auto get_sort_by_energy = [&](auto &edge_face_max_energy_map) {
5666 std::map<double, std::tuple<EntityHandle, EntityHandle, double>>
5667 sort_by_energy;
5668
5669 for (auto &m : edge_face_max_energy_map) {
5670 auto e = m.first;
5671 auto &[max_face, energy, opt_angle] = m.second;
5672 sort_by_energy[energy] = std::make_tuple(e, max_face, opt_angle);
5673 }
5674
5675 return sort_by_energy;
5676 };
5677
5678 auto set_tag = [&](auto &&adj_edges_map, auto &&sort_by_energy) {
5680
5681 Tag th_face_pressure;
5683 mField.get_moab().tag_get_handle("FacePressure", th_face_pressure),
5684 "get tag");
5685 auto get_face_pressure = [&](auto face) {
5686 double pressure;
5687 CHK_MOAB_THROW(mField.get_moab().tag_get_data(th_face_pressure, &face,
5688 1, &pressure),
5689 "get rag data");
5690 return pressure;
5691 };
5692
5693 MOFEM_LOG("EPSELF", Sev::inform)
5694 << "Number of edges to check " << sort_by_energy.size();
5695
5696 enum face_energy { POSITIVE, NEGATIVE };
5697 constexpr bool skip_negative = true;
5698
5699 for (auto fe : {face_energy::POSITIVE, face_energy::NEGATIVE}) {
5700
5701 // iterate edges wih maximal energy, and make them seed. Such edges,
5702 // will most likely will have also smallest node displacement
5703 for (auto it = sort_by_energy.rbegin(); it != sort_by_energy.rend();
5704 ++it) {
5705
5706 auto energy = it->first;
5707 auto [max_edge, max_face, opt_angle] = it->second;
5708
5709 auto face_pressure = get_face_pressure(max_face);
5710 if (skip_negative) {
5711 if (fe == face_energy::POSITIVE) {
5712 if (face_pressure < 0) {
5713 MOFEM_LOG("EPSELF", Sev::inform)
5714 << "Skip negative face " << max_face << " with energy "
5715 << energy << " and pressure " << face_pressure;
5716 continue;
5717 }
5718 }
5719 }
5720
5721 MOFEM_LOG("EPSELF", Sev::inform)
5722 << "Check face " << max_face << " edge " << max_edge
5723 << " energy " << energy << " optimal angle " << opt_angle
5724 << " face pressure " << face_pressure;
5725
5726 auto jt = adj_edges_map.find(max_edge);
5727 if (jt == adj_edges_map.end()) {
5728 MOFEM_LOG("EPSELF", Sev::warning)
5729 << "Edge " << max_edge << " not found in adj_edges_map";
5730 continue;
5731 }
5732 auto &bundle = jt->second;
5733
5734 auto find_max_in_bundle_impl = [&](auto edge, auto &bundle,
5735 auto gamma) {
5737
5738 EntityHandle vertex_max = 0;
5739 EntityHandle face_max = 0;
5740 EntityHandle move_edge_max = 0;
5741 double max_quality = -2;
5742 double max_quality_evaluated = -2;
5743 double min_cardinality = std::numeric_limits<double>::max();
5744
5745 FTensor::Tensor1<double, SPACE_DIM> t_move_last{0., 0., 0.};
5746
5747 for (auto &b : bundle) {
5748 auto &[face, move_edge, vertex, t_move, quality, cardinality,
5749 edge_gamma] = b;
5750
5751 auto adj_vertex_tets = get_adj(Range(vertex, vertex), 3);
5752 auto adj_vertex_tets_verts = get_conn(adj_vertex_tets);
5753 std::vector<double> coords(3 * adj_vertex_tets_verts.size());
5754 CHK_MOAB_THROW(mField.get_moab().get_coords(
5755 adj_vertex_tets_verts, coords.data()),
5756 "get coords");
5757
5758 set_coord(vertex, adj_vertex_tets_verts, coords, t_move, gamma);
5759 quality = tets_quality(quality, adj_vertex_tets_verts,
5760 adj_vertex_tets, coords);
5761
5762 auto eval_quality = [](auto q, auto c, auto edge_gamma) {
5763 if (q < 0) {
5764 return q;
5765 } else {
5766 return ((edge_gamma < 0) ? (q / 2) : q) / pow(c, 2);
5767 }
5768 };
5769
5770 if (eval_quality(quality, cardinality, edge_gamma) >=
5771 max_quality_evaluated) {
5772 max_quality = quality;
5773 min_cardinality = cardinality;
5774 vertex_max = vertex;
5775 face_max = face;
5776 move_edge_max = move_edge;
5777 t_move_last(i) = t_move(i);
5778 max_quality_evaluated =
5779 eval_quality(max_quality, min_cardinality, edge_gamma);
5780 }
5781 }
5782
5783 return std::make_tuple(vertex_max, face_max, t_move_last,
5784 max_quality, min_cardinality);
5785 };
5786
5787 auto find_max_in_bundle = [&](auto edge, auto &bundle) {
5788 auto b_org_bundle = bundle;
5789 auto r = find_max_in_bundle_impl(edge, bundle, 1.);
5790 auto &[vertex_max, face_max, t_move_last, max_quality,
5791 cardinality] = r;
5792 if (max_quality < 0) {
5793 for (double gamma = 0.95; gamma >= 0.45; gamma -= 0.05) {
5794 bundle = b_org_bundle;
5795 r = find_max_in_bundle_impl(edge, bundle, gamma);
5796 auto &[vertex_max, face_max, t_move_last, max_quality,
5797 cardinality] = r;
5798 MOFEM_LOG("EPSELF", Sev::warning)
5799 << "Back tracking: gamma " << gamma << " edge " << edge
5800 << " quality " << max_quality << " cardinality "
5801 << cardinality;
5802 if (max_quality > 0.01) {
5804 t_move_last(I) *= gamma;
5805 return r;
5806 }
5807 }
5809 t_move_last(I) = 0;
5810 }
5811 return r;
5812 };
5813
5814 // set tags with displacement of node and face energy
5815 auto set_tag_to_vertex_and_face = [&](auto &&r, auto &quality) {
5817 auto &[v, f, t_move, q, cardinality] = r;
5818
5819 if ((q > 0 && std::isnormal(q)) && energy > 0) {
5820
5821 MOFEM_LOG("EPSELF", Sev::inform)
5822 << "Set tag: vertex " << v << " face " << f << " "
5823 << max_edge << " move " << t_move << " energy " << energy
5824 << " quality " << q << " cardinality " << cardinality;
5825 CHKERR mField.get_moab().tag_set_data(th_position[0], &v, 1,
5826 &t_move(0));
5827 CHKERR mField.get_moab().tag_set_data(th_max_face_energy[0], &f,
5828 1, &energy);
5829 }
5830
5831 quality = q;
5833 };
5834
5835 double quality = -2;
5836 CHKERR set_tag_to_vertex_and_face(
5837
5838 find_max_in_bundle(max_edge, bundle),
5839
5840 quality
5841
5842 );
5843
5844 if (quality > 0 && std::isnormal(quality) && energy > 0) {
5845 MOFEM_LOG("EPSELF", Sev::inform)
5846 << "Crack face set with quality: " << quality;
5848 }
5849 }
5850
5851 if (!skip_negative)
5852 break;
5853 }
5854
5856 };
5857
5858 // map: {edge, {face, energy, optimal_angle}}
5859 MOFEM_LOG("EP", sev) << "Calculate orientation";
5860 std::map<EntityHandle, std::tuple<EntityHandle, double, double>>
5861 edge_face_max_energy_map;
5862 CHKERR find_maximal_face_energy(front_edges, front_faces,
5863 edge_face_max_energy_map);
5864 CHKERR calculate_face_orientation(edge_face_max_energy_map);
5865
5866 MOFEM_LOG("EP", sev) << "Calculate node positions";
5867 CHKERR set_tag(
5868
5869 calculate_free_face_node_displacement(edge_face_max_energy_map),
5870 get_sort_by_energy(edge_face_max_energy_map)
5871
5872 );
5873
5875 };
5876
5877 MOFEM_LOG("EP", sev) << "Front edges " << frontEdges->size();
5878 CHKERR evaluate_face_energy_and_set_orientation(
5879 *frontEdges, get_adj_front(false), sides_pair, th_front_position);
5880 }
5881
5882 // exchange positions and energies from processor zero to all other
5883 CHKERR VecZeroEntries(vertexExchange.second);
5884 CHKERR VecGhostUpdateBegin(vertexExchange.second, INSERT_VALUES,
5885 SCATTER_FORWARD);
5886 CHKERR VecGhostUpdateEnd(vertexExchange.second, INSERT_VALUES,
5887 SCATTER_FORWARD);
5888 CHKERR mField.getInterface<CommInterface>()->updateEntitiesPetscVector(
5889 mField.get_moab(), vertexExchange, th_front_position[0]);
5890 CHKERR VecZeroEntries(faceExchange.second);
5891 CHKERR VecGhostUpdateBegin(faceExchange.second, INSERT_VALUES,
5892 SCATTER_FORWARD);
5893 CHKERR VecGhostUpdateEnd(faceExchange.second, INSERT_VALUES, SCATTER_FORWARD);
5894 CHKERR mField.getInterface<CommInterface>()->updateEntitiesPetscVector(
5895 mField.get_moab(), faceExchange, th_max_face_energy[0]);
5896
5897 auto get_max_moved_faces = [&]() {
5898 Range max_moved_faces;
5899 auto adj_front = get_adj_front(false);
5900 std::vector<double> face_energy(adj_front.size());
5901 CHKERR mField.get_moab().tag_get_data(th_max_face_energy[0], adj_front,
5902 face_energy.data());
5903 for (int i = 0; i != adj_front.size(); ++i) {
5904 if (face_energy[i] > std::numeric_limits<double>::epsilon()) {
5905 max_moved_faces.insert(adj_front[i]);
5906 }
5907 }
5908
5909 return boost::make_shared<Range>(max_moved_faces);
5910 };
5911
5912 // move all faces with energy larger than 0
5913 maxMovedFaces = get_max_moved_faces();
5914 MOFEM_LOG("EP", sev) << "Number of of moved faces: " << maxMovedFaces->size();
5915
5916#ifndef NDEBUG
5917 if (debug) {
5919 mField.get_moab(),
5920 "max_moved_faces_" +
5921 boost::lexical_cast<std::string>(mField.get_comm_rank()) + ".vtk",
5922 *maxMovedFaces);
5923 }
5924#endif
5925
5927}
5928
5931
5932 if (!maxMovedFaces)
5934
5935 Tag th_front_position;
5936 auto rval =
5937 mField.get_moab().tag_get_handle("FrontPosition", th_front_position);
5938 if (rval == MB_SUCCESS && maxMovedFaces) {
5939 Range verts;
5940 CHKERR mField.get_moab().get_connectivity(*maxMovedFaces, verts, true);
5941 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(verts);
5942 std::vector<double> coords(3 * verts.size());
5943 CHKERR mField.get_moab().get_coords(verts, coords.data());
5944 std::vector<double> pos(3 * verts.size());
5945 CHKERR mField.get_moab().tag_get_data(th_front_position, verts, pos.data());
5946 for (int i = 0; i != 3 * verts.size(); ++i) {
5947 coords[i] += pos[i];
5948 }
5949 CHKERR mField.get_moab().set_coords(verts, coords.data());
5950 double zero[] = {0., 0., 0.};
5951 CHKERR mField.get_moab().tag_clear_data(th_front_position, verts, zero);
5952 }
5953
5954#ifndef NDEBUG
5955 constexpr bool debug = false;
5956 if (debug) {
5957
5959 mField.get_moab(),
5960 "set_coords_faces_" +
5961 boost::lexical_cast<std::string>(mField.get_comm_rank()) + ".vtk",
5962 *maxMovedFaces);
5963 }
5964#endif
5966}
5967
5970
5971 constexpr bool potential_crack_debug = false;
5972 if constexpr (potential_crack_debug) {
5973
5974 auto add_ents = get_range_from_block(mField, "POTENTIAL", SPACE_DIM - 1);
5975 Range crack_front_verts;
5976 CHKERR mField.get_moab().get_connectivity(*frontEdges, crack_front_verts,
5977 true);
5978 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
5979 crack_front_verts);
5980 Range crack_front_faces;
5981 CHKERR mField.get_moab().get_adjacencies(crack_front_verts, SPACE_DIM - 1,
5982 true, crack_front_faces,
5983 moab::Interface::UNION);
5984 crack_front_faces = intersect(crack_front_faces, add_ents);
5985 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
5986 crack_front_faces);
5987 CHKERR mField.getInterface<MeshsetsManager>()->addEntitiesToMeshset(
5988 BLOCKSET, addCrackMeshsetId, crack_front_faces);
5989 }
5990
5991 auto get_crack_faces = [&]() {
5992 if (maxMovedFaces) {
5993 return unite(*crackFaces, *maxMovedFaces);
5994 } else {
5995 return *crackFaces;
5996 }
5997 };
5998
5999 auto get_extended_crack_faces = [&]() {
6000 auto get_faces_of_crack_front_verts = [&](auto crack_faces_org) {
6001 ParallelComm *pcomm =
6002 ParallelComm::get_pcomm(&mField.get_moab(), MYPCOMM_INDEX);
6003
6004 Range crack_faces;
6005
6006 if (!pcomm->rank()) {
6007
6008 auto get_nodes = [&](auto &&e) {
6009 Range nodes;
6010 CHK_MOAB_THROW(mField.get_moab().get_connectivity(e, nodes, true),
6011 "get connectivity");
6012 return nodes;
6013 };
6014
6015 auto get_adj = [&](auto &&e, auto dim,
6016 auto t = moab::Interface::UNION) {
6017 Range adj;
6019 mField.get_moab().get_adjacencies(e, dim, true, adj, t),
6020 "get adj");
6021 return adj;
6022 };
6023
6024 Range body_ents;
6025 CHKERR mField.get_moab().get_entities_by_dimension(0, SPACE_DIM,
6026 body_ents);
6027 auto body_skin = get_skin(mField, body_ents);
6028 auto body_skin_edges = get_adj(body_skin, 1, moab::Interface::UNION);
6029 auto geometry_edges = get_range_from_block(mField, "EDGES", 1);
6030 auto front_block_edges = get_range_from_block(mField, "FRONT", 1);
6031 auto front_block_nodes = get_nodes(front_block_edges);
6032
6033 size_t s;
6034 do {
6035 s = crack_faces.size();
6036
6037 auto crack_face_nodes = get_nodes(crack_faces_org);
6038 auto crack_faces_edges =
6039 get_adj(crack_faces_org, 1, moab::Interface::UNION);
6040
6041 auto crack_skin = get_skin(mField, crack_faces_org);
6042 front_block_edges = subtract(front_block_edges, crack_skin);
6043 auto crack_skin_nodes = get_nodes(crack_skin);
6044 crack_skin_nodes.merge(front_block_nodes);
6045
6046 auto crack_skin_faces =
6047 get_adj(crack_skin, 2, moab::Interface::UNION);
6048 crack_skin_faces =
6049 subtract(subtract(crack_skin_faces, crack_faces_org), body_skin);
6050
6051 crack_faces = crack_faces_org;
6052 for (auto f : crack_skin_faces) {
6053 auto edges = intersect(
6054 get_adj(Range(f, f), 1, moab::Interface::UNION), crack_skin);
6055
6056 // if other edge is part of body skin, e.g. crack punching through
6057 // body surface
6058 if (edges.size() == 2) {
6059 edges.merge(
6060 intersect(get_adj(Range(f, f), 1, moab::Interface::UNION),
6061 body_skin_edges));
6062 }
6063
6064 if (edges.size() == 2) {
6065 auto edge_conn = get_nodes(Range(edges));
6066 auto faces = intersect(get_adj(edges, 2, moab::Interface::UNION),
6067 crack_faces_org);
6068 if (faces.size() == 2) {
6069 auto edge0_conn = get_nodes(Range(edges[0], edges[0]));
6070 auto edge1_conn = get_nodes(Range(edges[1], edges[1]));
6071 auto edges_conn = intersect(intersect(edge0_conn, edge1_conn),
6072 crack_skin_nodes); // node at apex
6073 if (edges_conn.size() == 1) {
6074
6075 auto node_edges =
6076 subtract(intersect(get_adj(edges_conn, 1,
6077 moab::Interface::INTERSECT),
6078 crack_faces_edges),
6079 crack_skin); // nodes on crack surface, but not
6080 // at the skin
6081
6082 if (node_edges.size()) {
6085 CHKERR mField.get_moab().get_coords(edges_conn, &t_v0(0));
6086
6087 auto get_t_dir = [&](auto e_conn) {
6088 auto other_node = subtract(e_conn, edges_conn);
6090 CHKERR mField.get_moab().get_coords(other_node,
6091 &t_dir(0));
6092 t_dir(i) -= t_v0(i);
6093 return t_dir;
6094 };
6095
6097 t_ave_dir(i) =
6098 get_t_dir(edge0_conn)(i) + get_t_dir(edge1_conn)(i);
6099
6100 FTensor::Tensor1<double, SPACE_DIM> t_crack_surface_ave_dir;
6101 t_crack_surface_ave_dir(i) = 0;
6102 for (auto e : node_edges) {
6103 auto e_conn = get_nodes(Range(e, e));
6104 auto t_dir = get_t_dir(e_conn);
6105 t_crack_surface_ave_dir(i) += t_dir(i);
6106 }
6107
6108 auto dot = t_ave_dir(i) * t_crack_surface_ave_dir(i);
6109 // ave edges is in opposite direction to crack surface, so
6110 // thus crack is not turning back
6111 if (dot < -std::numeric_limits<double>::epsilon()) {
6112 crack_faces.insert(f);
6113 }
6114 } else {
6115 crack_faces.insert(f);
6116 }
6117 }
6118 }
6119 } else if (edges.size() == 3) {
6120 crack_faces.insert(f);
6121 }
6122
6123 // if other edge is part of geometry edge, e.g. keyway
6124 if (edges.size() == 1) {
6125 edges.merge(
6126 intersect(get_adj(Range(f, f), 1, moab::Interface::UNION),
6127 geometry_edges));
6128 edges.merge(
6129 intersect(get_adj(Range(f, f), 1, moab::Interface::UNION),
6130 front_block_edges));
6131 if (edges.size() == 2) {
6132 crack_faces.insert(f);
6133 continue;
6134 }
6135 }
6136 }
6137
6138 crack_faces_org = crack_faces;
6139
6140 } while (s != crack_faces.size());
6141 };
6142
6143 return crack_faces; // send_type(mField, crack_faces, MBTRI);
6144 };
6145
6146 return get_faces_of_crack_front_verts(get_crack_faces());
6147 };
6148
6149 if (debug) {
6150 CHKERR save_range(mField.get_moab(), "new_crack_surface_debug.vtk",
6151 get_extended_crack_faces());
6152 }
6153
6154 auto reconstruct_crack_faces = [&](auto crack_faces) {
6155 ParallelComm *pcomm =
6156 ParallelComm::get_pcomm(&mField.get_moab(), MYPCOMM_INDEX);
6157
6158 auto impl = [&]() {
6160
6161 Range new_crack_faces;
6162 if (!pcomm->rank()) {
6163
6164 auto get_nodes = [&](auto &&e) {
6165 Range nodes;
6166 CHK_MOAB_THROW(mField.get_moab().get_connectivity(e, nodes, true),
6167 "get connectivity");
6168 return nodes;
6169 };
6170
6171 auto get_adj = [&](auto &&e, auto dim,
6172 auto t = moab::Interface::UNION) {
6173 Range adj;
6175 mField.get_moab().get_adjacencies(e, dim, true, adj, t),
6176 "get adj");
6177 return adj;
6178 };
6179
6180 auto get_test_on_crack_surface = [&]() {
6181 auto crack_faces_nodes =
6182 get_nodes(crack_faces); // nodes on crac faces
6183 auto crack_faces_tets =
6184 get_adj(crack_faces_nodes, 3,
6185 moab::Interface::UNION); // adjacent
6186 // tets to
6187 // crack
6188 // faces throug nodes
6189 auto crack_faces_tets_nodes =
6190 get_nodes(crack_faces_tets); // nodes on crack faces tets
6191 crack_faces_tets_nodes =
6192 subtract(crack_faces_tets_nodes, crack_faces_nodes);
6193 crack_faces_tets =
6194 subtract(crack_faces_tets, get_adj(crack_faces_tets_nodes, 3,
6195 moab::Interface::UNION));
6196 new_crack_faces =
6197 get_adj(crack_faces_tets, 2,
6198 moab::Interface::UNION); // adjacency faces to crack
6199 // faces through tets
6200 new_crack_faces.merge(crack_faces); // add original crack faces
6201
6202 return std::make_tuple(new_crack_faces, crack_faces_tets);
6203 };
6204
6205 auto carck_faces_test_edges = [&](auto faces, auto tets) {
6206 auto adj_tets_faces = get_adj(tets, 2, moab::Interface::UNION);
6207 auto adj_faces_edges = get_adj(subtract(faces, adj_tets_faces), 1,
6208 moab::Interface::UNION);
6209 auto adj_tets_edges = get_adj(tets, 1, moab::Interface::UNION);
6210 auto geometry_edges = get_range_from_block(mField, "EDGES", 1);
6211 auto front_block_edges = get_range_from_block(mField, "FRONT", 1);
6212 adj_faces_edges.merge(geometry_edges); // geometry edges
6213 adj_faces_edges.merge(front_block_edges); // front block edges
6214
6215 auto boundary_tets_edges = intersect(adj_tets_edges, adj_faces_edges);
6216 auto boundary_test_nodes = get_nodes(boundary_tets_edges);
6217 auto boundary_test_nodes_edges =
6218 get_adj(boundary_test_nodes, 1, moab::Interface::UNION);
6219 auto boundary_test_nodes_edges_nodes = subtract(
6220 get_nodes(boundary_test_nodes_edges), boundary_test_nodes);
6221
6222 boundary_tets_edges =
6223 subtract(boundary_test_nodes_edges,
6224 get_adj(boundary_test_nodes_edges_nodes, 1,
6225 moab::Interface::UNION));
6226
6227 Range body_ents;
6228 CHKERR mField.get_moab().get_entities_by_dimension(0, SPACE_DIM,
6229 body_ents);
6230 auto body_skin = get_skin(mField, body_ents);
6231
6232 auto body_skin_edges = get_adj(body_skin, 1, moab::Interface::UNION);
6233 body_skin_edges = intersect(get_adj(tets, 1, moab::Interface::UNION),
6234 body_skin_edges);
6235 body_skin = intersect(body_skin, adj_tets_faces);
6236 body_skin_edges = subtract(
6237 body_skin_edges, get_adj(body_skin, 1, moab::Interface::UNION));
6238
6239 save_range(mField.get_moab(), "body_skin_edges.vtk", body_skin_edges);
6240 for (auto e : body_skin_edges) {
6241 auto adj_tet = intersect(
6242 get_adj(Range(e, e), 3, moab::Interface::INTERSECT), tets);
6243 if (adj_tet.size() == 1) {
6244 boundary_tets_edges.insert(e);
6245 }
6246 }
6247
6248 return boundary_tets_edges;
6249 };
6250
6251 auto p = get_test_on_crack_surface();
6252 auto &[new_crack_faces, crack_faces_tets] = p;
6253
6254 if (debug) {
6255 CHKERR save_range(mField.get_moab(), "hole_crack_faces_debug.vtk",
6256 crack_faces);
6257 CHKERR save_range(mField.get_moab(), "new_crack_faces_debug.vtk",
6258 new_crack_faces);
6259 CHKERR save_range(mField.get_moab(), "new_crack_tets_debug.vtk",
6260 crack_faces_tets);
6261 }
6262
6263 auto boundary_tets_edges =
6264 carck_faces_test_edges(new_crack_faces, crack_faces_tets);
6265 CHKERR save_range(mField.get_moab(), "boundary_tets_edges.vtk",
6266 boundary_tets_edges);
6267
6268 auto resolve_surface = [&](auto boundary_tets_edges,
6269 auto crack_faces_tets) {
6270 auto boundary_tets_edges_nodes = get_nodes(boundary_tets_edges);
6271 auto crack_faces_tets_faces =
6272 get_adj(crack_faces_tets, 2, moab::Interface::UNION);
6273
6274 Range all_removed_faces;
6275 Range all_removed_tets;
6276 int counter = 0;
6277
6278 int size = 0;
6279 while (size != crack_faces_tets.size()) {
6280 auto tets_faces =
6281 get_adj(crack_faces_tets, 2, moab::Interface::UNION);
6282 auto skin_tets = get_skin(mField, crack_faces_tets);
6283 auto skin_skin =
6284 get_skin(mField, subtract(crack_faces_tets_faces, tets_faces));
6285 auto skin_skin_nodes = get_nodes(skin_skin);
6286
6287 size = crack_faces_tets.size();
6288 MOFEM_LOG("SELF", Sev::inform)
6289 << "Crack faces tets size " << crack_faces_tets.size()
6290 << " crack faces size " << crack_faces_tets_faces.size();
6291 auto skin_tets_nodes = subtract(
6292 get_nodes(skin_tets),
6293 boundary_tets_edges_nodes); // not remove tets which are
6294 // adjagasent to crack faces nodes
6295 skin_tets_nodes = subtract(skin_tets_nodes, skin_skin_nodes);
6296
6297 Range removed_nodes;
6298 Range tets_to_remove;
6299 Range faces_to_remove;
6300 for (auto n : skin_tets_nodes) {
6301 auto tets =
6302 intersect(get_adj(Range(n, n), 3, moab::Interface::INTERSECT),
6303 crack_faces_tets);
6304 if (tets.size() == 0) {
6305 continue;
6306 }
6307
6308 auto hole_detetction = [&]() {
6309 auto adj_tets =
6310 get_adj(Range(n, n), 3, moab::Interface::INTERSECT);
6311 adj_tets =
6312 subtract(adj_tets,
6313 crack_faces_tets); // tetst adjacent to the node
6314 // but not part of crack surface
6315 if (adj_tets.size() == 0) {
6316 return std::make_pair(
6317 intersect(
6318 get_adj(Range(n, n), 2, moab::Interface::INTERSECT),
6319 tets_faces),
6320 tets);
6321 }
6322
6323 std::vector<Range> tets_groups;
6324 auto test_adj_tets = adj_tets;
6325 while (test_adj_tets.size()) {
6326 auto seed_size = 0;
6327 Range seed = Range(test_adj_tets[0], test_adj_tets[0]);
6328 while (seed.size() != seed_size) {
6329 auto adj_faces =
6330 subtract(get_adj(seed, 2, moab::Interface::UNION),
6331 tets_faces); // edges which are not
6332 // part of the node
6333 seed_size = seed.size();
6334 seed.merge(
6335 intersect(get_adj(adj_faces, 3, moab::Interface::UNION),
6336 test_adj_tets ));
6337 }
6338 tets_groups.push_back(seed);
6339 test_adj_tets = subtract(test_adj_tets, seed);
6340 }
6341 if (tets_groups.size() == 1) {
6342
6343 return std::make_pair(
6344 intersect(
6345 get_adj(Range(n, n), 2, moab::Interface::INTERSECT),
6346 tets_faces),
6347 tets);
6348
6349 }
6350
6351 Range tets_to_remove;
6352 Range faces_to_remove;
6353 for (auto &r : tets_groups) {
6354 auto f = get_adj(r, 2, moab::Interface::UNION);
6355 auto t = intersect(get_adj(f, 3, moab::Interface::UNION),
6356 crack_faces_tets); // tets
6357
6358 if (f.size() > faces_to_remove.size() ||
6359 faces_to_remove.size() == 0) {
6360 faces_to_remove = f;
6361 tets_to_remove = t; // largest group of tets
6362 }
6363 }
6364 MOFEM_LOG("EPSELF", Sev::inform)
6365 << "Hole detection: faces to remove "
6366 << faces_to_remove.size() << " tets to remove "
6367 << tets_to_remove.size();
6368 return std::make_pair(faces_to_remove, tets_to_remove);
6369 };
6370
6371 if (tets.size() < tets_to_remove.size() ||
6372 tets_to_remove.size() == 0) {
6373 removed_nodes = Range(n, n);
6374 auto [h_faces_to_remove, h_tets_to_remove] =
6375 hole_detetction(); // find faces and tets to remove
6376 faces_to_remove = h_faces_to_remove;
6377 tets_to_remove = h_tets_to_remove;
6378
6379 // intersect(
6380 // get_adj(Range(n, n), 2, moab::Interface::INTERSECT),
6381 // tets_faces);
6382
6383 } // find tets which is largest adjacencty size, so that it is
6384 // removed first, and then faces are removed
6385 all_removed_faces.merge(faces_to_remove);
6386 all_removed_tets.merge(tets_to_remove);
6387 }
6388
6389 crack_faces_tets = subtract(crack_faces_tets, tets_to_remove);
6390 crack_faces_tets_faces =
6391 subtract(crack_faces_tets_faces, faces_to_remove);
6392
6393 if (debug) {
6395 "removed_nodes_" +
6396 boost::lexical_cast<std::string>(counter) + ".vtk",
6397 removed_nodes);
6399 "faces_to_remove_" +
6400 boost::lexical_cast<std::string>(counter) + ".vtk",
6401 faces_to_remove);
6403 "tets_to_remove_" +
6404 boost::lexical_cast<std::string>(counter) + ".vtk",
6405 tets_to_remove);
6407 "crack_faces_tets_faces_" +
6408 boost::lexical_cast<std::string>(counter) + ".vtk",
6409 crack_faces_tets_faces);
6411 "crack_faces_tets_" +
6412 boost::lexical_cast<std::string>(counter) + ".vtk",
6413 crack_faces_tets);
6414 }
6415 counter++;
6416 }
6417
6418 auto cese_internal_faces = [&]() {
6420 auto skin_tets = get_skin(mField, crack_faces_tets);
6421 auto adj_faces = get_adj(skin_tets, 2, moab::Interface::UNION);
6422 adj_faces =
6423 subtract(adj_faces, skin_tets); // remove skin tets faces
6424 auto adj_tets = get_adj(adj_faces, 3,
6425 moab::Interface::UNION); // tets which are
6426 // adjacent to skin
6427 crack_faces_tets =
6428 subtract(crack_faces_tets,
6429 adj_tets); // remove tets which are adjacent to
6430 // skin, so that they are not removed
6431 crack_faces_tets_faces =
6432 subtract(crack_faces_tets_faces, adj_faces);
6433
6434 all_removed_faces.merge(adj_faces);
6435 all_removed_tets.merge(adj_tets);
6436
6437
6438 MOFEM_LOG("EPSELF", Sev::inform)
6439 << "Remove internal faces size " << adj_faces.size()
6440 << " tets size " << adj_tets.size();
6442 };
6443
6444 auto case_only_one_free_edge = [&]() {
6446
6447 for (auto t : Range(crack_faces_tets)) {
6448
6449 auto adj_faces = get_adj(
6450 Range(t, t), 2,
6451 moab::Interface::UNION); // faces of tet which can be removed
6452 auto crack_surface_edges =
6453 get_adj(subtract(unite(crack_faces_tets_faces, crack_faces),
6454 adj_faces),
6455 1,
6456 moab::Interface::UNION); // edges not on the tet but
6457 // on crack surface
6458 auto adj_edges =
6459 subtract(get_adj(Range(t, t), 1, moab::Interface::INTERSECT),
6460 crack_surface_edges); // free edges
6461 adj_edges = subtract(
6462 adj_edges,
6463 boundary_tets_edges); // edges which are not part of gemetry
6464
6465 if (adj_edges.size() == 1) {
6466 crack_faces_tets =
6467 subtract(crack_faces_tets,
6468 Range(t, t)); // remove tets which are adjacent to
6469 // skin, so that they are not removed
6470
6471 auto faces_to_remove =
6472 get_adj(adj_edges, 2, moab::Interface::UNION); // faces
6473 // which can
6474 // be removed
6475 crack_faces_tets_faces =
6476 subtract(crack_faces_tets_faces, faces_to_remove);
6477
6478 all_removed_faces.merge(faces_to_remove);
6479 all_removed_tets.merge(Range(t, t));
6480
6481 MOFEM_LOG("EPSELF", Sev::inform) << "Remove free one edges ";
6482 }
6483 }
6484
6485 crack_faces_tets = subtract(crack_faces_tets, all_removed_tets);
6486 crack_faces_tets_faces =
6487 subtract(crack_faces_tets_faces, all_removed_faces);
6488
6490 };
6491
6492 auto cese_flat_tet = [&](auto max_adj_edges) {
6494
6495 Range body_ents;
6496 CHKERR mField.get_moab().get_entities_by_dimension(0, SPACE_DIM,
6497 body_ents);
6498 auto body_skin = get_skin(mField, body_ents);
6499 auto body_skin_edges =
6500 get_adj(body_skin, 1, moab::Interface::UNION);
6501
6502 for (auto t : Range(crack_faces_tets)) {
6503
6504 auto adj_faces = get_adj(
6505 Range(t, t), 2,
6506 moab::Interface::UNION); // faces of tet which can be removed
6507 auto crack_surface_edges =
6508 get_adj(subtract(unite(crack_faces_tets_faces, crack_faces),
6509 adj_faces),
6510 1,
6511 moab::Interface::UNION); // edges not on the tet but
6512 // on crack surface
6513 auto adj_edges =
6514 subtract(get_adj(Range(t, t), 1, moab::Interface::INTERSECT),
6515 crack_surface_edges); // free edges
6516 adj_edges = subtract(adj_edges, body_skin_edges);
6517
6518 auto tet_edges = get_adj(Range(t, t), 1,
6519 moab::Interface::UNION); // edges of
6520 // tet
6521 tet_edges = subtract(tet_edges, adj_edges);
6522
6523 for (auto e : tet_edges) {
6524 constexpr int opposite_edge[] = {5, 3, 4, 1, 2, 0};
6525 auto get_side = [&](auto e) {
6526 int side, sense, offset;
6528 mField.get_moab().side_number(t, e, side, sense, offset),
6529 "get side number failed");
6530 return side;
6531 };
6532 auto get_side_ent = [&](auto side) {
6533 EntityHandle side_edge;
6535 mField.get_moab().side_element(t, 1, side, side_edge),
6536 "get side failed");
6537 return side_edge;
6538 };
6539 adj_edges.erase(get_side_ent(opposite_edge[get_side(e)]));
6540 }
6541
6542 if (adj_edges.size() <= max_adj_edges) {
6543
6544 double dot = 1;
6545 Range faces_to_remove;
6546 for (auto e : adj_edges) {
6547 auto edge_adj_faces =
6548 get_adj(Range(e, e), 2, moab::Interface::UNION);
6549 edge_adj_faces = intersect(edge_adj_faces, adj_faces);
6550 if (edge_adj_faces.size() != 2) {
6552 "Adj faces size is not 2 for edge " +
6553 boost::lexical_cast<std::string>(e));
6554 }
6555
6556 auto get_normal = [&](auto f) {
6559 mField.getInterface<Tools>()->getTriNormal(f, &t_n(0)),
6560 "get tri normal failed");
6561 return t_n;
6562 };
6563 auto t_n0 = get_normal(edge_adj_faces[0]);
6564 auto t_n1 = get_normal(edge_adj_faces[1]);
6565 auto get_sense = [&](auto f) {
6566 int side, sense, offset;
6567 CHK_MOAB_THROW(mField.get_moab().side_number(t, f, side,
6568 sense, offset),
6569 "get side number failed");
6570 return sense;
6571 };
6572 auto sense0 = get_sense(edge_adj_faces[0]);
6573 auto sense1 = get_sense(edge_adj_faces[1]);
6574 t_n0.normalize();
6575 t_n1.normalize();
6576
6578 auto dot_e = (sense0 * sense1) * t_n0(i) * t_n1(i);
6579 if (dot_e < dot || e == adj_edges[0]) {
6580 dot = dot_e;
6581 faces_to_remove = edge_adj_faces;
6582 }
6583 }
6584
6585 all_removed_faces.merge(faces_to_remove);
6586 all_removed_tets.merge(Range(t, t));
6587
6588 MOFEM_LOG("EPSELF", Sev::inform)
6589 << "Remove free edges on flat tet, with considered nb. of "
6590 "edges "
6591 << adj_edges.size();
6592 }
6593 }
6594
6595 crack_faces_tets = subtract(crack_faces_tets, all_removed_tets);
6596 crack_faces_tets_faces =
6597 subtract(crack_faces_tets_faces, all_removed_faces);
6598
6600 };
6601
6602 CHK_THROW_MESSAGE(case_only_one_free_edge(),
6603 "Case only one free edge failed");
6604 for (auto max_adj_edges : {0, 1, 2, 3}) {
6605 CHK_THROW_MESSAGE(cese_flat_tet(max_adj_edges),
6606 "Case only one free edge failed");
6607 }
6608 CHK_THROW_MESSAGE(cese_internal_faces(),
6609 "Case internal faces failed");
6610
6611 if (debug) {
6613 "crack_faces_tets_faces_" +
6614 boost::lexical_cast<std::string>(counter) + ".vtk",
6615 crack_faces_tets_faces);
6617 "crack_faces_tets_" +
6618 boost::lexical_cast<std::string>(counter) + ".vtk",
6619 crack_faces_tets);
6620 }
6621
6622 return std::make_tuple(crack_faces_tets_faces, crack_faces_tets,
6623 all_removed_faces, all_removed_tets);
6624 };
6625
6626 auto [resolved_faces, resolved_tets, all_removed_faces,
6627 all_removed_tets] =
6628 resolve_surface(boundary_tets_edges, crack_faces_tets);
6629 resolved_faces.merge(subtract(crack_faces, all_removed_faces));
6630 if (debug) {
6631 CHKERR save_range(mField.get_moab(), "resolved_faces.vtk",
6632 resolved_faces);
6633 CHKERR save_range(mField.get_moab(), "resolved_tets.vtk",
6634 resolved_tets);
6635 }
6636
6637 crack_faces = resolved_faces;
6638 }
6639
6641 };
6642
6643 CHK_THROW_MESSAGE(impl(), "resolve new crack surfaces");
6644
6645 return crack_faces; // send_type(mField, crack_faces, MBTRI);
6646 };
6647
6648
6649 auto resolve_consisten_crack_extension = [&]() {
6651 auto crack_meshset =
6652 mField.getInterface<MeshsetsManager>()->getCubitMeshsetPtr(
6654 auto meshset = crack_meshset->getMeshset();
6655
6656
6657 if (!mField.get_comm_rank()) {
6658 Range old_crack_faces;
6659 CHKERR mField.get_moab().get_entities_by_type(meshset, MBTRI,
6660 old_crack_faces);
6661 auto extendeded_crack_faces = get_extended_crack_faces();
6662 auto reconstructed_crack_faces =
6663 subtract(reconstruct_crack_faces(extendeded_crack_faces),
6664 subtract(*crackFaces, old_crack_faces));
6665 if (nbCrackFaces >= reconstructed_crack_faces.size()) {
6666 MOFEM_LOG("EPSELF", Sev::warning)
6667 << "No new crack faces to add, skipping adding to meshset";
6668 extendeded_crack_faces = subtract(
6669 extendeded_crack_faces, subtract(*crackFaces, old_crack_faces));
6670 MOFEM_LOG("EPSELF", Sev::inform)
6671 << "Number crack faces size (extended) "
6672 << extendeded_crack_faces.size();
6673 CHKERR mField.get_moab().clear_meshset(&meshset, 1);
6674 CHKERR mField.get_moab().add_entities(meshset, extendeded_crack_faces);
6675 } else {
6676 CHKERR mField.get_moab().clear_meshset(&meshset, 1);
6677 CHKERR mField.get_moab().add_entities(meshset,
6678 reconstructed_crack_faces);
6679 MOFEM_LOG("EPSELF", Sev::inform)
6680 << "Number crack faces size (reconstructed) "
6681 << reconstructed_crack_faces.size();
6682 nbCrackFaces = reconstructed_crack_faces.size();
6683 }
6684 }
6685
6686 Range crack_faces;
6687 if (!mField.get_comm_rank()) {
6688 CHKERR mField.get_moab().get_entities_by_type(meshset, MBTRI,
6689 crack_faces);
6690 }
6691 crack_faces = send_type(mField, crack_faces, MBTRI);
6692 if (mField.get_comm_rank()) {
6693 CHKERR mField.get_moab().clear_meshset(&meshset, 1);
6694 CHKERR mField.get_moab().add_entities(meshset, crack_faces);
6695 }
6696
6698 };
6699
6700 CHKERR resolve_consisten_crack_extension();
6701
6703};
6704
6707 auto crack_faces =
6708 get_range_from_block(mField, "CRACK_COMPUTED", SPACE_DIM - 1);
6709 Range conn;
6710 CHKERR mField.get_moab().get_connectivity(crack_faces, conn, true);
6711 Range verts;
6712 CHKERR mField.get_moab().get_entities_by_type(0, MBVERTEX, verts);
6713 verts = subtract(verts, conn);
6714 std::vector<double> coords(3 * verts.size());
6715 CHKERR mField.get_moab().get_coords(verts, coords.data());
6716 double def_coords[] = {0., 0., 0.};
6717 Tag th_org_coords;
6718 CHKERR mField.get_moab().tag_get_handle(
6719 "ORG_COORDS", 3, MB_TYPE_DOUBLE, th_org_coords,
6720 MB_TAG_CREAT | MB_TAG_DENSE, def_coords);
6721 CHKERR mField.get_moab().tag_set_data(th_org_coords, verts, coords.data());
6723}
6724
6727 auto meshset_mng = mField.getInterface<MeshsetsManager>();
6728 while (meshset_mng->checkMeshset(addCrackMeshsetId, BLOCKSET))
6730 MOFEM_LOG("EP", Sev::inform)
6731 << "Crack added surface meshset " << addCrackMeshsetId;
6732 CHKERR meshset_mng->addMeshset(BLOCKSET, addCrackMeshsetId, "CRACK_COMPUTED");
6734};
6735
6736//! [Getting norms]
6739
6740 auto post_proc_norm_fe =
6741 boost::make_shared<VolumeElementForcesAndSourcesCore>(mField);
6742
6743 auto post_proc_norm_rule_hook = [](int, int, int p) -> int {
6744 return 2 * (p);
6745 };
6746 post_proc_norm_fe->getRuleHook = post_proc_norm_rule_hook;
6747
6748 post_proc_norm_fe->getUserPolynomialBase() =
6749 boost::shared_ptr<BaseFunction>(new CGGUserPolynomialBase());
6750
6751 CHKERR EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
6752 post_proc_norm_fe->getOpPtrVector(), {L2, H1, HDIV}, materialH1Positions,
6754
6755 enum NORMS { U_NORM_L2 = 0, U_NORM_H1, PIOLA_NORM, U_ERROR_L2, LAST_NORM };
6756 auto norms_vec =
6757 createVectorMPI(mField.get_comm(), LAST_NORM, PETSC_DETERMINE);
6758 CHKERR VecZeroEntries(norms_vec);
6759
6760 auto u_l2_ptr = boost::make_shared<MatrixDouble>();
6761 auto u_h1_ptr = boost::make_shared<MatrixDouble>();
6762 post_proc_norm_fe->getOpPtrVector().push_back(
6764 post_proc_norm_fe->getOpPtrVector().push_back(
6766 post_proc_norm_fe->getOpPtrVector().push_back(
6767 new OpCalcNormL2Tensor1<SPACE_DIM>(u_l2_ptr, norms_vec, U_NORM_L2));
6768 post_proc_norm_fe->getOpPtrVector().push_back(
6769 new OpCalcNormL2Tensor1<SPACE_DIM>(u_h1_ptr, norms_vec, U_NORM_H1));
6770 post_proc_norm_fe->getOpPtrVector().push_back(
6771 new OpCalcNormL2Tensor1<SPACE_DIM>(u_l2_ptr, norms_vec, U_ERROR_L2,
6772 u_h1_ptr));
6773
6774 auto piola_ptr = boost::make_shared<MatrixDouble>();
6775 post_proc_norm_fe->getOpPtrVector().push_back(
6777 post_proc_norm_fe->getOpPtrVector().push_back(
6779 MBMAXTYPE));
6780
6781 post_proc_norm_fe->getOpPtrVector().push_back(
6782 new OpCalcNormL2Tensor2<3, 3>(piola_ptr, norms_vec, PIOLA_NORM));
6783
6784 TetPolynomialBase::switchCacheBaseOn<HDIV>({post_proc_norm_fe.get()});
6786 *post_proc_norm_fe);
6787 TetPolynomialBase::switchCacheBaseOff<HDIV>({post_proc_norm_fe.get()});
6788
6789 CHKERR VecAssemblyBegin(norms_vec);
6790 CHKERR VecAssemblyEnd(norms_vec);
6791 const double *norms;
6792 CHKERR VecGetArrayRead(norms_vec, &norms);
6793 MOFEM_LOG("EP", Sev::inform) << "norm_u: " << std::sqrt(norms[U_NORM_L2]);
6794 MOFEM_LOG("EP", Sev::inform) << "norm_u_h1: " << std::sqrt(norms[U_NORM_H1]);
6795 MOFEM_LOG("EP", Sev::inform)
6796 << "norm_error_u_l2: " << std::sqrt(norms[U_ERROR_L2]);
6797 MOFEM_LOG("EP", Sev::inform)
6798 << "norm_piola: " << std::sqrt(norms[PIOLA_NORM]);
6799 CHKERR VecRestoreArrayRead(norms_vec, &norms);
6800
6802}
6803//! [Getting norms]
6804
6807
6808 auto bc_mng = mField.getInterface<BcManager>();
6810 "", piolaStress, false, false);
6811
6812 bcSpatialDispVecPtr = boost::make_shared<BcDispVec>();
6813 for (auto bc : bc_mng->getBcMapByBlockName()) {
6814 if (auto disp_bc = bc.second->dispBcPtr) {
6815
6816 auto [field_name, block_name] =
6818 MOFEM_LOG("EP", Sev::inform)
6819 << "Field name: " << field_name << " Block name: " << block_name;
6820 MOFEM_LOG("EP", Sev::noisy) << "Displacement BC: " << *disp_bc;
6821
6822 std::vector<double> block_attributes(6, 0.);
6823 if (disp_bc->data.flag1 == 1) {
6824 block_attributes[0] = disp_bc->data.value1;
6825 block_attributes[3] = 1;
6826 }
6827 if (disp_bc->data.flag2 == 1) {
6828 block_attributes[1] = disp_bc->data.value2;
6829 block_attributes[4] = 1;
6830 }
6831 if (disp_bc->data.flag3 == 1) {
6832 block_attributes[2] = disp_bc->data.value3;
6833 block_attributes[5] = 1;
6834 }
6835 auto faces = bc.second->bcEnts.subset_by_dimension(2);
6836 bcSpatialDispVecPtr->emplace_back(block_name, block_attributes, faces);
6837 }
6838 }
6839 // old way of naming blocksets for displacement BCs
6840 CHKERR getBc(bcSpatialDispVecPtr, "SPATIAL_DISP_BC", 6);
6841
6843 boost::make_shared<NormalDisplacementBcVec>();
6844 for (auto bc : bc_mng->getBcMapByBlockName()) {
6845 auto block_name = "(.*)NORMAL_DISPLACEMENT(.*)";
6846 std::regex reg_name(block_name);
6847 if (std::regex_match(bc.first, reg_name)) {
6848 auto [field_name, block_name] =
6850 MOFEM_LOG("EP", Sev::inform)
6851 << "Field name: " << field_name << " Block name: " << block_name;
6853 block_name, bc.second->bcAttributes,
6854 bc.second->bcEnts.subset_by_dimension(2));
6855 }
6856 }
6857
6859 boost::make_shared<AnalyticalDisplacementBcVec>();
6860
6861 for (auto bc : bc_mng->getBcMapByBlockName()) {
6862 auto block_name = "(.*)ANALYTICAL_DISPLACEMENT(.*)";
6863 std::regex reg_name(block_name);
6864 if (std::regex_match(bc.first, reg_name)) {
6865 auto [field_name, block_name] =
6867 MOFEM_LOG("EP", Sev::inform)
6868 << "Field name: " << field_name << " Block name: " << block_name;
6870 block_name, bc.second->bcAttributes,
6871 bc.second->bcEnts.subset_by_dimension(2));
6872 }
6873 }
6874
6875 auto ts_displacement =
6876 boost::make_shared<DynamicRelaxationTimeScale>("disp_history.txt");
6877 for (auto &bc : *bcSpatialDispVecPtr) {
6878 MOFEM_LOG("EP", Sev::noisy)
6879 << "Add time scaling displacement BC: " << bc.blockName;
6880 timeScaleMap[bc.blockName] =
6882 ts_displacement, "disp_history", ".txt", bc.blockName);
6883 }
6884
6885 auto ts_normal_displacement =
6886 boost::make_shared<DynamicRelaxationTimeScale>("normal_disp_history.txt");
6887 for (auto &bc : *bcSpatialNormalDisplacementVecPtr) {
6888 MOFEM_LOG("EP", Sev::noisy)
6889 << "Add time scaling normal displacement BC: " << bc.blockName;
6890 timeScaleMap[bc.blockName] =
6892 ts_normal_displacement, "normal_disp_history", ".txt",
6893 bc.blockName);
6894 }
6895
6897}
6898
6901
6902 auto bc_mng = mField.getInterface<BcManager>();
6904 false, false);
6905
6906 bcSpatialTractionVecPtr = boost::make_shared<TractionBcVec>();
6907
6908 for (auto bc : bc_mng->getBcMapByBlockName()) {
6909 if (auto force_bc = bc.second->forceBcPtr) {
6910
6911 auto [field_name, block_name] =
6913 MOFEM_LOG("EP", Sev::inform)
6914 << "Field name: " << field_name << " Block name: " << block_name;
6915 MOFEM_LOG("EP", Sev::noisy) << "Force BC: " << *force_bc;
6916
6917 std::vector<double> block_attributes(6, 0.);
6918 block_attributes[0] = -force_bc->data.value3 * force_bc->data.value1;
6919 block_attributes[3] = 1;
6920 block_attributes[1] = -force_bc->data.value4 * force_bc->data.value1;
6921 block_attributes[4] = 1;
6922 block_attributes[2] = -force_bc->data.value5 * force_bc->data.value1;
6923 block_attributes[5] = 1;
6924 auto faces = bc.second->bcEnts.subset_by_dimension(2);
6925 bcSpatialTractionVecPtr->emplace_back(block_name, block_attributes,
6926 faces);
6927 }
6928 }
6929 CHKERR getBc(bcSpatialTractionVecPtr, "SPATIAL_TRACTION_BC", 6);
6930
6931 bcSpatialPressureVecPtr = boost::make_shared<PressureBcVec>();
6932 for (auto bc : bc_mng->getBcMapByBlockName()) {
6933 auto block_name = "(.*)PRESSURE(.*)";
6934 std::regex reg_name(block_name);
6935 if (std::regex_match(bc.first, reg_name)) {
6936
6937 auto [field_name, block_name] =
6939 MOFEM_LOG("EP", Sev::inform)
6940 << "Field name: " << field_name << " Block name: " << block_name;
6941 bcSpatialPressureVecPtr->emplace_back(
6942 block_name, bc.second->bcAttributes,
6943 bc.second->bcEnts.subset_by_dimension(2));
6944 }
6945 }
6946
6948 boost::make_shared<AnalyticalTractionBcVec>();
6949
6950 for (auto bc : bc_mng->getBcMapByBlockName()) {
6951 auto block_name = "(.*)ANALYTICAL_TRACTION(.*)";
6952 std::regex reg_name(block_name);
6953 if (std::regex_match(bc.first, reg_name)) {
6954 auto [field_name, block_name] =
6956 MOFEM_LOG("EP", Sev::inform)
6957 << "Field name: " << field_name << " Block name: " << block_name;
6959 block_name, bc.second->bcAttributes,
6960 bc.second->bcEnts.subset_by_dimension(2));
6961 }
6962 }
6963
6964 auto ts_traction =
6965 boost::make_shared<DynamicRelaxationTimeScale>("traction_history.txt");
6966 for (auto &bc : *bcSpatialTractionVecPtr) {
6967 timeScaleMap[bc.blockName] =
6969 ts_traction, "traction_history", ".txt", bc.blockName);
6970 }
6971
6972 auto ts_pressure =
6973 boost::make_shared<DynamicRelaxationTimeScale>("pressure_history.txt");
6974 for (auto &bc : *bcSpatialPressureVecPtr) {
6975 timeScaleMap[bc.blockName] =
6977 ts_pressure, "pressure_history", ".txt", bc.blockName);
6978 }
6979
6981}
6982
6985
6986 auto getExternalStrain = [&](boost::shared_ptr<ExternalStrainVec> &ext_strain_vec_ptr,
6987 const std::string block_name,
6988 const int nb_attributes) {
6990 for (auto it : mField.getInterface<MeshsetsManager>()->getCubitMeshsetPtr(
6991 std::regex((boost::format("%s(.*)") % block_name).str()))
6992 ) {
6993 std::vector<double> block_attributes;
6994 CHKERR it->getAttributes(block_attributes);
6995 if (block_attributes.size() < nb_attributes) {
6996 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
6997 "In block %s expected %d attributes, but given %ld",
6998 it->getName().c_str(), nb_attributes, block_attributes.size());
6999 }
7000
7001 auto get_block_ents = [&]() {
7002 Range ents;
7003 CHKERR mField.get_moab().get_entities_by_handle(it->meshset, ents,
7004 true);
7005 return ents;
7006 };
7007 auto Ents = get_block_ents();
7008 ext_strain_vec_ptr->emplace_back(it->getName(), block_attributes,
7009 get_block_ents());
7010 }
7012 };
7013
7014 externalStrainVecPtr = boost::make_shared<ExternalStrainVec>();
7015 CHKERR getExternalStrain(externalStrainVecPtr, "EXTERNALSTRAIN", 2);
7016
7017 auto ts_pre_stretch =
7018 boost::make_shared<DynamicRelaxationTimeScale>("externalstrain_history.txt");
7019 for (auto &ext_strain_block: *externalStrainVecPtr) {
7020 MOFEM_LOG("EP", Sev::noisy)
7021 << "Add time scaling external strain: " << ext_strain_block.blockName;
7022 timeScaleMap[ext_strain_block.blockName] =
7024 ts_pre_stretch, "externalstrain_history", ".txt", ext_strain_block.blockName);
7025 }
7026
7028}
7029
7032
7033 auto print_loc_size = [this](auto v, auto str, auto sev) {
7035 int size;
7036 CHKERR VecGetLocalSize(v.second, &size);
7037 int low, high;
7038 CHKERR VecGetOwnershipRange(v.second, &low, &high);
7039 MOFEM_LOG("EPSYNC", sev) << str << " local size " << size << " ( " << low
7040 << " " << high << " ) ";
7043 };
7044
7046 mField.get_comm(), mField.get_moab(), 3, 1, sev);
7047 CHKERR print_loc_size(volumeExchange, "volumeExchange", sev);
7049 mField.get_comm(), mField.get_moab(), 2, 1, Sev::inform);
7050 CHKERR print_loc_size(faceExchange, "faceExchange", sev);
7052 mField.get_comm(), mField.get_moab(), 1, 1, Sev::inform);
7053 CHKERR print_loc_size(edgeExchange, "edgeExchange", sev);
7055 mField.get_comm(), mField.get_moab(), 0, 3, Sev::inform);
7056 CHKERR print_loc_size(vertexExchange, "vertexExchange", sev);
7057
7059}
7060
7062EshelbianCore::calculateCrackArea(boost::shared_ptr<double> area_ptr) {
7064
7065 if (!area_ptr) {
7066 CHK_THROW_MESSAGE(MOFEM_INVALID_DATA, "area_ptr is null");
7067 }
7068
7069 int success;
7070 *area_ptr = 0;
7071 if (mField.get_comm_rank() == 0) {
7072 MOFEM_LOG("EP", Sev::inform) << "Calculate crack area";
7073 auto crack_faces = get_range_from_block(mField, "CRACK", SPACE_DIM - 1);
7074 for (auto f : crack_faces) {
7075 *area_ptr += mField.getInterface<Tools>()->getTriArea(f);
7076 }
7077 success = MPI_Bcast(area_ptr.get(), 1, MPI_DOUBLE, 0, mField.get_comm());
7078 } else {
7079 success = MPI_Bcast(area_ptr.get(), 1, MPI_DOUBLE, 0, mField.get_comm());
7080 }
7081 if (success != MPI_SUCCESS) {
7083 }
7085}
7086
7087} // namespace EshelbianPlasticity
7088
Implementation of tonsorial bubble base div(v) = 0.
#define NBVOLUMETET_CCG_BUBBLE(P)
Bubble function for CGG H div space.
Implementation of CGGUserPolynomialBase class.
Auxilary functions for Eshelbian plasticity.
Contains definition of EshelbianMonitor class.
static auto send_type(MoFEM::Interface &m_field, Range r, const EntityType type)
static auto get_block_meshset(MoFEM::Interface &m_field, const int ms_id, const unsigned int cubit_bc_type)
static auto get_range_from_block(MoFEM::Interface &m_field, const std::string block_name, int dim)
static auto get_two_sides_of_crack_surface(MoFEM::Interface &m_field, Range crack_faces)
static auto get_range_from_block_map(MoFEM::Interface &m_field, const std::string block_name, int dim)
static auto filter_owners(MoFEM::Interface &m_field, Range skin)
static auto filter_true_skin(MoFEM::Interface &m_field, Range &&skin)
static auto get_skin(MoFEM::Interface &m_field, Range body_ents)
static auto get_crack_front_edges(MoFEM::Interface &m_field, Range crack_faces)
Eshelbian plasticity interface.
#define MOFEM_LOG_SEVERITY_SYNC(comm, severity)
Synchronise "SYNC" on curtain severity level.
#define MOFEM_LOG_C(channel, severity, format,...)
#define FTENSOR_INDEX(DIM, I)
Range get_range_from_block(MoFEM::Interface &m_field, const std::string block_name, int dim)
Definition adjoint.cpp:3283
constexpr double a
static const double eps
constexpr int SPACE_DIM
[Define dimension]
ElementsAndOps< SPACE_DIM >::BoundaryEle BoundaryEle
cholesky decomposition
Kronecker Delta class.
Tensor1< T, Tensor_Dim > normalize()
@ QUIET
@ VERBOSE
#define NOT_USED(x)
@ COL
@ ROW
@ MF_ZERO
FieldApproximationBase
approximation base
Definition definitions.h:58
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base .
Definition definitions.h:60
@ USER_BASE
user implemented approximation base
Definition definitions.h:68
@ NOBASE
Definition definitions.h:59
@ DEMKOWICZ_JACOBI_BASE
Definition definitions.h:66
#define CHK_THROW_MESSAGE(err, msg)
Check and throw MoFEM exception.
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
@ L2
field with C-1 continuity
Definition definitions.h:88
@ H1
continuous field
Definition definitions.h:85
@ HDIV
field with continuous normal traction
Definition definitions.h:87
#define MYPCOMM_INDEX
default communicator number PCOMM
@ DISCONTINUOUS
Broken continuity (No effect on L2 space)
#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.
@ BLOCKSET
@ MOFEM_OPERATION_UNSUCCESSFUL
Definition definitions.h:34
@ MOFEM_ATOM_TEST_INVALID
Definition definitions.h:40
@ MOFEM_DATA_INCONSISTENCY
Definition definitions.h:31
@ MOFEM_INVALID_DATA
Definition definitions.h:36
@ MOFEM_NOT_IMPLEMENTED
Definition definitions.h:32
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
#define MoFEMFunctionBeginHot
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
constexpr int order
Order displacement.
static const bool debug
PetscErrorCode ShapeMBTET(double *N, const double *G_X, const double *G_Y, const double *G_Z, int DIM)
calculate shape functions
Definition fem_tools.c:306
PetscErrorCode ShapeMBTRI(double *N, const double *X, const double *Y, const int G_DIM)
calculate shape functions on triangle
Definition fem_tools.c:182
@ F
constexpr auto t_kd
PetscErrorCode DMMoFEMSetIsPartitioned(DM dm, PetscBool is_partitioned)
Definition DMMoFEM.cpp:1113
PetscErrorCode DMMoFEMCreateSubDM(DM subdm, DM dm, const char problem_name[])
Must be called by user to set Sub DM MoFEM data structures.
Definition DMMoFEM.cpp:215
PetscErrorCode DMMoFEMAddElement(DM dm, std::string fe_name)
add element to dm
Definition DMMoFEM.cpp:488
PetscErrorCode DMMoFEMSetSquareProblem(DM dm, PetscBool square_problem)
set squared problem
Definition DMMoFEM.cpp:450
PetscErrorCode DMMoFEMTSSetIFunction(DM dm, const char fe_name[], MoFEM::FEMethod *method, MoFEM::BasicMethod *pre_only, MoFEM::BasicMethod *post_only)
set TS implicit function evaluation function
Definition DMMoFEM.cpp:790
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 DMoFEMPostProcessFiniteElements(DM dm, MoFEM::FEMethod *method)
execute finite element method for each element in dm (problem)
Definition DMMoFEM.cpp:546
PetscErrorCode DMoFEMMeshToLocalVector(DM dm, Vec l, InsertMode mode, ScatterMode scatter_mode)
set local (or ghosted) vector values on mesh for partition only
Definition DMMoFEM.cpp:514
PetscErrorCode DMMoFEMAddSubFieldRow(DM dm, const char field_name[])
Definition DMMoFEM.cpp:238
PetscErrorCode DMMoFEMGetTsCtx(DM dm, MoFEM::TsCtx **ts_ctx)
get MoFEM::TsCtx data structure
Definition DMMoFEM.cpp:1132
PetscErrorCode DMoFEMLoopFiniteElements(DM dm, const char fe_name[], MoFEM::FEMethod *method, CacheTupleWeakPtr cache_ptr=CacheTupleSharedPtr())
Executes FEMethod for finite elements in DM.
Definition DMMoFEM.cpp:576
PetscErrorCode DMMoFEMTSSetIJacobian(DM dm, 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 TS Jacobian evaluation function
Definition DMMoFEM.cpp:843
auto createDMVector(DM dm)
Get smart vector from DM.
Definition DMMoFEM.hpp:1234
PetscErrorCode DMMoFEMTSSetI2Jacobian(DM dm, 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 TS Jacobian evaluation function
Definition DMMoFEM.cpp:1007
PetscErrorCode DMMoFEMTSSetI2Function(DM dm, 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 TS implicit function evaluation function
Definition DMMoFEM.cpp:965
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
PetscErrorCode DMoFEMPreProcessFiniteElements(DM dm, MoFEM::FEMethod *method)
execute finite element method for each element in dm (problem)
Definition DMMoFEM.cpp:536
virtual MoFEMErrorCode add_finite_element(const std::string &fe_name, enum MoFEMTypes bh=MF_EXCL, int verb=DEFAULT_VERBOSITY)=0
add finite element
virtual MoFEMErrorCode build_finite_elements(int verb=DEFAULT_VERBOSITY)=0
Build finite elements.
virtual MoFEMErrorCode modify_finite_element_add_field_col(const std::string &fe_name, const std::string name_row)=0
set field col which finite element use
virtual MoFEMErrorCode modify_finite_element_adjacency_table(const std::string &fe_name, const EntityType type, ElementAdjacencyFunct function)=0
modify finite element table, only for advanced user
virtual MoFEMErrorCode add_ents_to_finite_element_by_type(const EntityHandle entities, const EntityType type, const std::string name, const bool recursive=true)=0
add entities to finite element
virtual MoFEMErrorCode modify_finite_element_add_field_row(const std::string &fe_name, const std::string name_row)=0
set field row which finite element use
virtual MoFEMErrorCode modify_finite_element_add_field_data(const std::string &fe_name, const std::string name_field)=0
set finite element field data
virtual const Field * get_field_structure(const std::string &name, enum MoFEMTypes bh=MF_EXIST) const =0
get field structure
virtual MoFEMErrorCode build_fields(int verb=DEFAULT_VERBOSITY)=0
virtual MoFEMErrorCode add_ents_to_field_by_dim(const Range &ents, const int dim, const std::string &name, int verb=DEFAULT_VERBOSITY)=0
Add entities to field meshset.
virtual MoFEMErrorCode set_field_order(const EntityHandle meshset, const EntityType type, const std::string &name, const ApproximationOrder order, int verb=DEFAULT_VERBOSITY)=0
Set order approximation of the entities in the field.
virtual MoFEMErrorCode add_ents_to_field_by_type(const Range &ents, const EntityType type, const std::string &name, int verb=DEFAULT_VERBOSITY)=0
Add entities to field meshset.
@ GAUSS
Gaussian quadrature integration.
#define MOFEM_LOG(channel, severity)
Log.
SeverityLevel
Severity levels.
#define MOFEM_LOG_CHANNEL(channel)
Set and reset channel.
virtual MoFEMErrorCode loop_dofs(const Problem *problem_ptr, const std::string &field_name, RowColData rc, DofMethod &method, int lower_rank, int upper_rank, int verb=DEFAULT_VERBOSITY)=0
Make a loop over dofs.
virtual MoFEMErrorCode loop_finite_elements(const std::string problem_name, const std::string &fe_name, FEMethod &method, boost::shared_ptr< NumeredEntFiniteElement_multiIndex > fe_ptr=nullptr, MoFEMTypes bh=MF_EXIST, CacheTupleWeakPtr cache_ptr=CacheTupleSharedPtr(), int verb=DEFAULT_VERBOSITY)=0
Make a loop over finite elements.
MoFEMErrorCode addMeshset(const CubitBCType cubit_bc_type, const int ms_id, const std::string name="")
Add CUBIT meshset to manager.
MoFEMErrorCode getCubitMeshsetPtr(const int ms_id, const CubitBCType cubit_bc_type, const CubitMeshSets **cubit_meshset_ptr) const
get cubit meshset
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.
#define NBVOLUMETET_L2(P)
Number of base functions on tetrahedron for L2 space.
auto bit
set bit
constexpr double a0
FTensor::Index< 'i', SPACE_DIM > i
static double lambda
const double c
speed of light (cm/ns)
const double v
phase velocity of light in medium (cm/ns)
const double n
refractive index of diffusive medium
FTensor::Index< 'J', DIM1 > J
Definition level_set.cpp:30
MoFEM::TsCtx * ts_ctx
FTensor::Index< 'l', 3 > l
FTensor::Index< 'j', 3 > j
FTensor::Index< 'k', 3 > k
constexpr std::enable_if<(Dim0<=2 &&Dim1<=2), Tensor2_Expr< Levi_Civita< T >, T, Dim0, Dim1, i, j > >::type levi_civita(const Index< i, Dim0 > &, const Index< j, Dim1 > &)
levi_civita functions to make for easy adhoc use
static MoFEMErrorCodeGeneric< moab::ErrorCode > rval
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
UBlasMatrix< double > MatrixDouble
Definition Types.hpp:77
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
PetscErrorCode TsMonitorSet(TS ts, PetscInt step, PetscReal t, Vec u, void *ctx)
Set monitor for TS solver.
Definition TsCtx.cpp:263
auto getDMTsCtx(DM dm)
Get TS context data structure used by DM.
Definition DMMoFEM.hpp:1276
PetscErrorCode DMMoFEMSetDestroyProblem(DM dm, PetscBool destroy_problem)
Definition DMMoFEM.cpp:434
MoFEMErrorCode MoFEMSNESMonitorEnergy(SNES snes, PetscInt its, PetscReal fgnorm, SnesCtx *ctx)
Sens monitor printing residual field by field.
Definition SnesCtx.cpp:652
static const bool debug
auto id_from_handle(const EntityHandle h)
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)
auto createVectorMPI(MPI_Comm comm, PetscInt n, PetscInt N)
Create MPI Vector.
PostProcBrokenMeshInMoabBaseEndImpl< PostProcBrokenMeshInMoabBase< ForcesAndSourcesCore > > PostProcBrokenMeshInMoabBaseEnd
Enable to run stack of post-processing elements. Use this to end stack.
PostProcBrokenMeshInMoabBaseBeginImpl< PostProcBrokenMeshInMoabBase< ForcesAndSourcesCore > > PostProcBrokenMeshInMoabBaseBegin
Enable to run stack of post-processing elements. Use this to begin stack.
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.
auto getDMSnesCtx(DM dm)
Get SNES context data structure used by DM.
Definition DMMoFEM.hpp:1262
auto createDM(MPI_Comm comm, const std::string dm_type_name)
Creates smart DM object.
static constexpr int edges_conn[]
auto ent_form_type_and_id(const EntityType type, const EntityID id)
get entity handle from type and id
int r
Definition sdf.py:8
constexpr IntegrationType I
constexpr AssemblyType A
[Define dimension]
OpPostProcMapInMoab< SPACE_DIM, SPACE_DIM > OpPPMap
constexpr double t
plate stiffness
Definition plate.cpp:58
constexpr auto field_name
#define QUAD_2D_TABLE_SIZE
Definition quad.h:174
#define QUAD_3D_TABLE_SIZE
Definition quad.h:186
static QUAD *const QUAD_2D_TABLE[]
Definition quad.h:175
static QUAD *const QUAD_3D_TABLE[]
Definition quad.h:187
PipelineManager::ElementsAndOpsByDim< SPACE_DIM >::FaceSideEle EleOnSide
FTensor::Index< 'm', 3 > m
CGG User Polynomial Base.
static boost::shared_ptr< SetUpSchur > createSetUpSchur(MoFEM::Interface &m_field, EshelbianCore *ep_core_ptr)
MoFEMErrorCode setElasticElementOps(const int tag)
boost::shared_ptr< ExternalStrainVec > externalStrainVecPtr
MoFEMErrorCode addVolumeFiniteElement(const EntityHandle meshset=0)
MoFEMErrorCode addFields(const EntityHandle meshset=0)
static enum StretchSelector stretchSelector
boost::shared_ptr< Range > frontAdjEdges
MoFEMErrorCode createCrackSurfaceMeshset()
MoFEMErrorCode addBoundaryFiniteElement(const EntityHandle meshset=0)
const std::string skeletonElement
static double inv_f_linear(const double v)
boost::shared_ptr< TractionBcVec > bcSpatialTractionVecPtr
boost::shared_ptr< Range > contactFaces
static double dd_f_log_e_quadratic(const double v)
static double dd_f_log(const double v)
BitRefLevel bitAdjEnt
bit ref level for parent
static boost::function< double(const double)> inv_dd_f
MoFEM::Interface & mField
const std::string spatialL2Disp
static double inv_d_f_log(const double v)
std::map< std::string, boost::shared_ptr< ScalingMethod > > timeScaleMap
static PetscBool l2UserBaseScale
SmartPetscObj< DM > dM
Coupled problem all fields.
static int internalStressInterpOrder
MoFEMErrorCode projectGeometry(const EntityHandle meshset=0)
boost::shared_ptr< TractionFreeBc > bcSpatialFreeTractionVecPtr
const std::string materialH1Positions
static int nbJIntegralContours
MoFEMErrorCode setBlockTagsOnSkin()
static PetscBool crackingOn
MoFEMErrorCode getTractionFreeBc(const EntityHandle meshset, boost::shared_ptr< TractionFreeBc > &bc_ptr, const std::string contact_set_name)
Remove all, but entities where kinematic constrains are applied.
MoFEMErrorCode setBaseVolumeElementOps(const int tag, const bool do_rhs, const bool do_lhs, const bool calc_rates, SmartPetscObj< Vec > ver_vec, boost::shared_ptr< VolumeElementForcesAndSourcesCore > fe)
MoFEMErrorCode calculateFaceMaterialForce(const int tag, TS ts)
static double griffithEnergy
Griffith energy.
MoFEMErrorCode calculateCrackArea(boost::shared_ptr< double > area_ptr)
const std::string elementVolumeName
static double dd_f_log_e(const double v)
static enum RotSelector rotSelector
static enum RotSelector gradApproximator
MoFEMErrorCode getBc(boost::shared_ptr< BC > &bc_vec_ptr, const std::string block_name, const int nb_attributes)
CommInterface::EntitiesPetscVector vertexExchange
boost::shared_ptr< BcRotVec > bcSpatialRotationVecPtr
boost::shared_ptr< Range > maxMovedFaces
static PetscBool dynamicRelaxation
const std::string spatialH1Disp
MoFEMErrorCode solveElastic(TS ts, Vec x)
static double d_f_log(const double v)
boost::shared_ptr< NormalDisplacementBcVec > bcSpatialNormalDisplacementVecPtr
static double crackingStartTime
MoFEMErrorCode getOptions()
const std::string piolaStress
MoFEMErrorCode setElasticElementToTs(DM dm)
static double inv_d_f_log_e(const double v)
MoFEMErrorCode gettingNorms()
[Getting norms]
MoFEMErrorCode setVolumeElementOps(const int tag, const bool add_elastic, const bool add_material, boost::shared_ptr< VolumeElementForcesAndSourcesCore > &fe_rhs, boost::shared_ptr< VolumeElementForcesAndSourcesCore > &fe_lhs)
MoFEMErrorCode query_interface(boost::typeindex::type_index type_index, UnknownInterface **iface) const
Getting interface of core database.
const std::string bubbleField
boost::shared_ptr< AnalyticalDisplacementBcVec > bcSpatialAnalyticalDisplacementVecPtr
MoFEMErrorCode calculateOrientation(const int tag, bool set_orientation)
static double inv_f_log(const double v)
static PetscBool noStretch
MoFEMErrorCode setNewFrontCoordinates()
boost::shared_ptr< ParentFiniteElementAdjacencyFunctionSkeleton< 2 > > parentAdjSkeletonFunctionDim2
static double exponentBase
MoFEMErrorCode setContactElementRhsOps(boost::shared_ptr< ContactTree > &fe_contact_tree)
static double dd_f_linear(const double v)
MoFEMErrorCode setFaceElementOps(const bool add_elastic, const bool add_material, boost::shared_ptr< FaceElementForcesAndSourcesCore > &fe_rhs, boost::shared_ptr< FaceElementForcesAndSourcesCore > &fe_lhs)
MoFEMErrorCode postProcessSkeletonResults(const int tag, const std::string file, Vec f_residual=PETSC_NULLPTR, std::vector< Tag > tags_to_transfer={})
boost::shared_ptr< AnalyticalExprPython > AnalyticalExprPythonPtr
boost::shared_ptr< Range > skeletonFaces
boost::shared_ptr< PhysicalEquations > physicalEquations
const std::string rotAxis
static double inv_d_f_linear(const double v)
BitRefLevel bitAdjParentMask
bit ref level for parent parent
MoFEMErrorCode solveDynamicRelaxation(TS ts, Vec x, int start_step, double start_time)
Solve problem using dynamic relaxation method.
static double inv_dd_f_log(const double v)
const std::string contactDisp
static std::string internalStressTagName
static enum SymmetrySelector symmetrySelector
CommInterface::EntitiesPetscVector edgeExchange
SmartPetscObj< DM > dmPrjSpatial
Projection spatial displacement.
static boost::function< double(const double)> f
boost::shared_ptr< BcDispVec > bcSpatialDispVecPtr
const std::string skinElement
static PetscBool internalStressVoigt
static double inv_dd_f_linear(const double v)
static double inv_dd_f_log_e(const double v)
MoFEMErrorCode getExternalStrain()
MoFEMErrorCode getSpatialTractionBc()
static PetscBool setSingularity
virtual ~EshelbianCore()
static double d_f_log_e(const double v)
boost::shared_ptr< AnalyticalTractionBcVec > bcSpatialAnalyticalTractionVecPtr
static double f_log_e_quadratic(const double v)
MoFEMErrorCode addCrackSurfaces(const bool debug=false)
MoFEMErrorCode addDMs(const BitRefLevel bit=BitRefLevel().set(0), const EntityHandle meshset=0)
MoFEMErrorCode getSpatialDispBc()
[Getting norms]
BitRefLevel bitAdjParent
bit ref level for parent
MoFEMErrorCode postProcessResults(const int tag, const std::string file, Vec f_residual=PETSC_NULLPTR, Vec var_vec=PETSC_NULLPTR, std::vector< Tag > tags_to_transfer={})
static double d_f_log_e_quadratic(const double v)
CommInterface::EntitiesPetscVector volumeExchange
MoFEMErrorCode saveOrgCoords()
const std::string naturalBcElement
static boost::function< double(const double)> dd_f
static double f_log_e(const double v)
static int addCrackMeshsetId
static double inv_f_log_e(const double v)
MoFEMErrorCode createExchangeVectors(Sev sev)
boost::shared_ptr< DataAtIntegrationPts > dataAtPts
boost::shared_ptr< Range > crackFaces
static boost::function< double(const double)> d_f
boost::shared_ptr< Range > frontVertices
static enum EnergyReleaseSelector energyReleaseSelector
static boost::function< double(const double)> inv_d_f
boost::shared_ptr< PressureBcVec > bcSpatialPressureVecPtr
static double d_f_linear(const double v)
const std::string hybridSpatialDisp
SmartPetscObj< Vec > solTSStep
static double f_log(const double v)
CommInterface::EntitiesPetscVector faceExchange
SmartPetscObj< DM > dmElastic
Elastic problem.
EshelbianCore(MoFEM::Interface &m_field)
boost::shared_ptr< Range > frontEdges
static boost::function< double(const double)> inv_f
const std::string stretchTensor
BitRefLevel bitAdjEntMask
bit ref level for parent parent
static double f_linear(const double v)
const std::string contactElement
AnalyticalDisplacementBc(std::string name, std::vector< double > attr, Range faces)
AnalyticalTractionBc(std::string name, std::vector< double > attr, Range faces)
BcRot(std::string name, std::vector< double > attr, Range faces)
ExternalStrain(std::string name, std::vector< double > attr, Range ents)
int operator()(int p_row, int p_col, int p_data) const
NormalDisplacementBc(std::string name, std::vector< double > attr, Range faces)
PressureBc(std::string name, std::vector< double > attr, Range faces)
SetIntegrationAtFrontFace(boost::shared_ptr< Range > front_nodes, boost::shared_ptr< Range > front_edges)
SetIntegrationAtFrontFace(boost::shared_ptr< Range > front_nodes, boost::shared_ptr< Range > front_edges, FunRule fun_rule)
MoFEMErrorCode operator()(ForcesAndSourcesCore *fe_raw_ptr, int order_row, int order_col, int order_data)
static std::map< long int, MatrixDouble > mapRefCoords
MoFEMErrorCode operator()(ForcesAndSourcesCore *fe_raw_ptr, int order_row, int order_col, int order_data)
static std::map< long int, MatrixDouble > mapRefCoords
SetIntegrationAtFrontVolume(boost::shared_ptr< Range > front_nodes, boost::shared_ptr< Range > front_edges)
TractionBc(std::string name, std::vector< double > attr, Range faces)
Set integration rule on element.
int operator()(int p_row, int p_col, int p_data) const
static auto setup(EshelbianCore *ep_ptr, TS ts, Vec x, bool set_ts_monitor)
static auto exp(A &&t_w_vee, B &&theta)
Definition Lie.hpp:48
multi_index_container< DofsSideMapData, indexed_by< ordered_non_unique< tag< TypeSide_mi_tag >, composite_key< DofsSideMapData, member< DofsSideMapData, EntityType, &DofsSideMapData::type >, member< DofsSideMapData, int, &DofsSideMapData::side > > >, ordered_unique< tag< EntDofIdx_mi_tag >, member< DofsSideMapData, int, &DofsSideMapData::dof > > > > DofsSideMap
Map entity stype and side to element/entity dof index.
Boundary condition manager for finite element problem setup.
static std::pair< std::string, std::string > extractStringFromBlockId(const std::string block_id, const std::string prb_name)
Extract block name and block name from block id.
Managing BitRefLevels.
Managing BitRefLevels.
static MoFEMErrorCode updateEntitiesPetscVector(moab::Interface &moab, EntitiesPetscVector &vec, Tag tag, UpdateGhosts update_gosts=defaultUpdateGhosts)
Exchange data between vector and data.
static Range getPartEntities(moab::Interface &moab, int part)
static EntitiesPetscVector createEntitiesPetscVector(MPI_Comm comm, moab::Interface &moab, int dim, const int nb_coeffs, Sev sev=Sev::verbose, int root_rank=0)
Create a ghost vector for exchanging data.
virtual int get_comm_size() const =0
virtual moab::Interface & get_moab()=0
virtual MoFEMErrorCode add_broken_field(const std::string name, const FieldSpace space, const FieldApproximationBase base, const FieldCoefficientsNumber nb_of_coefficients, const std::vector< std::pair< EntityType, std::function< MoFEMErrorCode(BaseFunction::DofsSideMap &)> > > list_dof_side_map, const TagType tag_type=MB_TAG_SPARSE, const enum MoFEMTypes bh=MF_EXCL, int verb=DEFAULT_VERBOSITY)=0
Add field.
virtual bool check_finite_element(const std::string &name) const =0
Check if finite element is in database.
virtual MoFEMErrorCode build_adjacencies(const Range &ents, int verb=DEFAULT_VERBOSITY)=0
build adjacencies
virtual MoFEMErrorCode add_field(const std::string name, const FieldSpace space, const FieldApproximationBase base, const FieldCoefficientsNumber nb_of_coefficients, const TagType tag_type=MB_TAG_SPARSE, const enum MoFEMTypes bh=MF_EXCL, int verb=DEFAULT_VERBOSITY)=0
Add field.
virtual MPI_Comm & get_comm() const =0
virtual int get_comm_rank() const =0
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)
Structure for user loop methods on finite elements.
EntityHandle getFEEntityHandle() const
Get the entity handle of the current finite element.
Basic algebra on fields.
Definition FieldBlas.hpp:21
Field data structure for finite element approximation.
Definition of the force bc data structure.
Definition BCData.hpp:135
UserDataOperator(const FieldSpace space, const char type=OPSPACE, const bool symm=true)
Constructor for operators working on finite element spaces.
structure to get information from mofem into EntitiesFieldData
MatrixDouble gaussPts
Matrix of integration points.
static boost::shared_ptr< ScalingMethod > get(boost::shared_ptr< ScalingMethod > ts, std::string file_prefix, std::string file_suffix, std::string block_name, Args &&...args)
Section manager is used to create indexes and sections.
Definition ISManager.hpp:23
Mesh refinement interface.
Interface for managing meshsets containing materials and boundary conditions.
Natural boundary conditions.
Definition Natural.hpp:57
Operator for broken loop side.
Get norm of input MatrixDouble for Tensor1.
Get norm of input MatrixDouble for Tensor2.
Calculate tenor field using tensor base, i.e. Hdiv/Hcurl.
Calculate divergence of tonsorial field using vectorial base.
Calculate tenor field using vectorial base, i.e. Hdiv/Hcurl.
Calculate trace of vector (Hdiv/Hcurl) space.
Calculate symmetric tensor field rates ant integratio pts.
Calculate symmetric tensor field values at integration pts.
Get field gradients time derivative at integration pts for scalar field rank 0, i....
Get field gradients at integration pts for scalar field rank 0, i.e. vector field.
Approximate field values for given petsc vector.
Specialization for double precision vector field values calculation.
Element used to execute operators on side of the element.
Execute "this" element in the operator.
Post post-proc data at points from hash maps.
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
std::map< std::string, boost::shared_ptr< MatrixDouble > > DataMapMat
Template struct for dimension-specific finite element types.
Problem manager is used to build and partition problems.
Projection of edge entities with one mid-node on hierarchical basis.
intrusive_ptr for managing petsc objects
Auxiliary tools.
Definition Tools.hpp:19
static RefineTrianglesReturn refineTriangle(int nb_levels)
create uniform triangle mesh of refined elements
Definition Tools.cpp:724
static constexpr std::array< double, 6 > diffShapeFunMBTRI
Definition Tools.hpp:104
static MatrixDouble refineTriangleIntegrationPts(MatrixDouble pts, RefineTrianglesReturn refined)
generate integration points for refined triangle mesh for last level
Definition Tools.cpp:791
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 tetVolume(const double *coords)
Calculate volume of tetrahedron.
Definition Tools.cpp:30
static double volumeLengthQuality(const double *coords)
Calculate tetrahedron volume length quality.
Definition Tools.cpp:15
FEMethodsSequence & getLoopsMonitor()
Get the loops to do Monitor object.
Definition TsCtx.hpp:102
base class for all interface classes
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.
MoFEMErrorCode doWork(int side, EntityType type, EntData &data)
Operator for linear form, usually to calculate values on right hand side.
Apply rotation boundary condition.
int order
Definition quad.h:28
int npoints
Definition quad.h:29
static MoFEMErrorCode postStepInitialise(EshelbianCore *ep_ptr)
static MoFEMErrorCode postStepDestroy()
static MoFEMErrorCode preStepFun(TS ts)
static MoFEMErrorCode postStepFun(TS ts)
BoundaryEle::UserDataOperator BdyEleOp
ElementsAndOps< SPACE_DIM >::SideEle SideEle
Definition plastic.cpp:61
auto save_range