v0.15.0
Loading...
Searching...
No Matches
EshelbianPlasticity.cpp
Go to the documentation of this file.
1/**
2 * \file EshelbianPlasticity.cpp
3 * \example 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 {
48 using VolumeElementForcesAndSourcesCore::UserDataOperator::UserDataOperator;
49};
52 using FaceElementForcesAndSourcesCore::UserDataOperator::UserDataOperator;
53};
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 = 4;
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 = 4;
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",
994 "", nbJIntegralLevels, &nbJIntegralLevels, PETSC_NULLPTR);
995
996 // internal stress
997 char tag_name[255] = "";
998 CHKERR PetscOptionsString("-internal_stress_tag_name",
999 "internal stress tag name", "", "", tag_name, 255,
1000 PETSC_NULLPTR);
1001 internalStressTagName = string(tag_name);
1002 CHKERR PetscOptionsInt(
1003 "-internal_stress_interp_order", "internal stress interpolation order",
1005 CHKERR PetscOptionsBool("-internal_stress_voigt", "Voigt index notation", "",
1007 PETSC_NULLPTR);
1008
1009 CHKERR PetscOptionsGetString(PETSC_NULLPTR, PETSC_NULLPTR, "-analytical_expr_file",
1010 analytical_expr_file_name, 255, PETSC_NULLPTR);
1011
1012 PetscOptionsEnd();
1013
1015 SETERRQ(PETSC_COMM_WORLD, MOFEM_NOT_IMPLEMENTED,
1016 "Unsupported internal stress interpolation order %d",
1018 }
1019
1020 if (setSingularity) {
1021 l2UserBaseScale = PETSC_TRUE;
1022 }
1023
1024 EshelbianCore::rotSelector = static_cast<RotSelector>(choice_rot);
1025 EshelbianCore::gradApproximator = static_cast<RotSelector>(choice_grad);
1026 EshelbianCore::stretchSelector = static_cast<StretchSelector>(choice_stretch);
1027 EshelbianCore::symmetrySelector = static_cast<SymmetrySelector>(choice_symm);
1029 static_cast<EnergyReleaseSelector>(choice_release);
1030
1032 case StretchSelector::LINEAR:
1039 break;
1040 case StretchSelector::LOG:
1041 if (std::fabs(EshelbianCore::exponentBase - exp(1)) >
1042 std::numeric_limits<float>::epsilon()) {
1049 } else {
1056 }
1057 break;
1058 case StretchSelector::LOG_QUADRATIC:
1062 EshelbianCore::inv_f = [](const double x) {
1064 "No logarithmic quadratic stretch for this case");
1065 return 0;
1066 };
1069 break; // no stretch, do not use stretch functions
1070 default:
1071 SETERRQ(mField.get_comm(), MOFEM_DATA_INCONSISTENCY, "Unknown stretch");
1072 break;
1073 };
1074
1075 MOFEM_LOG("EP", Sev::inform) << "spaceOrder: -space_order " << spaceOrder;
1076 MOFEM_LOG("EP", Sev::inform)
1077 << "spaceH1Order: -space_h1_order " << spaceH1Order;
1078 MOFEM_LOG("EP", Sev::inform)
1079 << "materialOrder: -material_order " << materialOrder;
1080 MOFEM_LOG("EP", Sev::inform) << "alphaU: -viscosity_alpha_u " << alphaU;
1081 MOFEM_LOG("EP", Sev::inform) << "alphaW: -viscosity_alpha_w " << alphaW;
1082 MOFEM_LOG("EP", Sev::inform)
1083 << "alphaOmega: -viscosity_alpha_omega " << alphaOmega;
1084 MOFEM_LOG("EP", Sev::inform) << "alphaRho: -density_alpha_rho " << alphaRho;
1085 MOFEM_LOG("EP", Sev::inform)
1086 << "Rotations: -rotations " << list_rots[EshelbianCore::rotSelector];
1087 MOFEM_LOG("EP", Sev::inform) << "Gradient of deformation "
1088 << list_rots[EshelbianCore::gradApproximator];
1089 MOFEM_LOG("EP", Sev::inform)
1090 << "Symmetry: -symm " << list_symm[EshelbianCore::symmetrySelector];
1091 if (exponentBase != exp(1))
1092 MOFEM_LOG("EP", Sev::inform)
1093 << "Base exponent: -exponent_base " << EshelbianCore::exponentBase;
1094 else
1095 MOFEM_LOG("EP", Sev::inform) << "Base exponent e";
1096 MOFEM_LOG("EP", Sev::inform)
1097 << "Stretch: -stretches " << list_stretches[choice_stretch];
1098 MOFEM_LOG("EP", Sev::inform) << "No stretch: -no_stretch " << (noStretch)
1099 ? "yes"
1100 : "no";
1101
1102 MOFEM_LOG("EP", Sev::inform)
1103 << "Dynamic relaxation: -dynamic_relaxation " << (dynamicRelaxation)
1104 ? "yes"
1105 : "no";
1106 MOFEM_LOG("EP", Sev::inform)
1107 << "Singularity: -set_singularity " << (setSingularity)
1108 ? "yes"
1109 : "no";
1110 MOFEM_LOG("EP", Sev::inform)
1111 << "L2 user base scale: -l2_user_base_scale " << (l2UserBaseScale)
1112 ? "yes"
1113 : "no";
1114
1115 MOFEM_LOG("EP", Sev::inform) << "Cracking on: -cracking_on " << (crackingOn)
1116 ? "yes"
1117 : "no";
1118 MOFEM_LOG("EP", Sev::inform)
1119 << "Cracking start time: -cracking_start_time " << crackingStartTime;
1120 MOFEM_LOG("EP", Sev::inform)
1121 << "Griffith energy: -griffith_energy " << griffithEnergy;
1122 MOFEM_LOG("EP", Sev::inform)
1123 << "Energy release variant: -energy_release_variant "
1124 << list_release[EshelbianCore::energyReleaseSelector];
1125 MOFEM_LOG("EP", Sev::inform)
1126 << "Number of J integral levels: -nb_J_integral_levels "
1128
1129#ifdef ENABLE_PYTHON_BINDING
1130 auto file_exists = [](std::string myfile) {
1131 std::ifstream file(myfile.c_str());
1132 if (file) {
1133 return true;
1134 }
1135 return false;
1136 };
1137
1138 if (file_exists(analytical_expr_file_name)) {
1139 MOFEM_LOG("EP", Sev::inform) << analytical_expr_file_name << " file found";
1140
1141 AnalyticalExprPythonPtr = boost::make_shared<AnalyticalExprPython>();
1142 CHKERR AnalyticalExprPythonPtr->analyticalExprInit(
1143 analytical_expr_file_name);
1144 AnalyticalExprPythonWeakPtr = AnalyticalExprPythonPtr;
1145 } else {
1146 MOFEM_LOG("EP", Sev::warning)
1147 << analytical_expr_file_name << " file NOT found";
1148 }
1149#endif
1150
1151 if (spaceH1Order == -1)
1153
1155}
1156
1159
1160 auto get_tets = [&]() {
1161 Range tets;
1162 CHKERR mField.get_moab().get_entities_by_type(meshset, MBTET, tets);
1163 return tets;
1164 };
1165
1166 auto get_tets_skin = [&]() {
1167 Range tets_skin_part;
1168 Skinner skin(&mField.get_moab());
1169 CHKERR skin.find_skin(0, get_tets(), false, tets_skin_part);
1170 ParallelComm *pcomm =
1171 ParallelComm::get_pcomm(&mField.get_moab(), MYPCOMM_INDEX);
1172 Range tets_skin;
1173 CHKERR pcomm->filter_pstatus(tets_skin_part,
1174 PSTATUS_SHARED | PSTATUS_MULTISHARED,
1175 PSTATUS_NOT, -1, &tets_skin);
1176 return tets_skin;
1177 };
1178
1179 auto subtract_boundary_conditions = [&](auto &&tets_skin) {
1180 // That mean, that hybrid field on all faces on which traction is applied,
1181 // on other faces, or enforcing displacements as
1182 // natural boundary condition.
1184 for (auto &v : *bcSpatialTractionVecPtr) {
1185 tets_skin = subtract(tets_skin, v.faces);
1186 }
1188 for (auto &v : *bcSpatialAnalyticalTractionVecPtr) {
1189 tets_skin = subtract(tets_skin, v.faces);
1190 }
1191
1193 for (auto &v : *bcSpatialPressureVecPtr) {
1194 tets_skin = subtract(tets_skin, v.faces);
1195 }
1196
1197 return tets_skin;
1198 };
1199
1200 auto add_blockset = [&](auto block_name, auto &&tets_skin) {
1201 auto crack_faces =
1202 get_range_from_block(mField, "block_name", SPACE_DIM - 1);
1203 tets_skin.merge(crack_faces);
1204 return tets_skin;
1205 };
1206
1207 auto subtract_blockset = [&](auto block_name, auto &&tets_skin) {
1208 auto contact_range =
1209 get_range_from_block(mField, block_name, SPACE_DIM - 1);
1210 tets_skin = subtract(tets_skin, contact_range);
1211 return tets_skin;
1212 };
1213
1214 auto get_stress_trace_faces = [&](auto &&tets_skin) {
1215 Range faces;
1216 CHKERR mField.get_moab().get_adjacencies(get_tets(), SPACE_DIM - 1, true,
1217 faces, moab::Interface::UNION);
1218 Range trace_faces = subtract(faces, tets_skin);
1219 return trace_faces;
1220 };
1221
1222 auto tets = get_tets();
1223
1224 // remove also contact faces, i.e. that is also kind of hybrid field but
1225 // named but used to enforce contact conditions
1226 auto trace_faces = get_stress_trace_faces(
1227
1228 subtract_blockset("CONTACT",
1229 subtract_boundary_conditions(get_tets_skin()))
1230
1231 );
1232
1233 contactFaces = boost::make_shared<Range>(intersect(
1234 trace_faces, get_range_from_block(mField, "CONTACT", SPACE_DIM - 1)));
1236 boost::make_shared<Range>(subtract(trace_faces, *contactFaces));
1237 // materialSkeletonFaces =
1238 // boost::make_shared<Range>(get_stress_trace_faces(Range()));
1239
1240#ifndef NDEBUG
1241 if (contactFaces->size())
1243 "contact_faces_" +
1244 std::to_string(mField.get_comm_rank()) + ".vtk",
1245 *contactFaces);
1246 if (skeletonFaces->size())
1248 "skeleton_faces_" +
1249 std::to_string(mField.get_comm_rank()) + ".vtk",
1250 *skeletonFaces);
1251 // if (skeletonFaces->size())
1252 // CHKERR save_range(mField.get_moab(), "material_skeleton_faces.vtk",
1253 // *materialSkeletonFaces);
1254#endif
1255
1256 auto add_broken_hdiv_field = [this, meshset](const std::string field_name,
1257 const int order) {
1259
1261
1262 auto get_side_map_hdiv = [&]() {
1263 return std::vector<
1264
1265 std::pair<EntityType,
1267
1268 >>{
1269
1270 {MBTET,
1271 [&](BaseFunction::DofsSideMap &dofs_side_map) -> MoFEMErrorCode {
1272 return TetPolynomialBase::setDofsSideMap(HDIV, DISCONTINUOUS, base,
1273 dofs_side_map);
1274 }}
1275
1276 };
1277 };
1278
1280 get_side_map_hdiv(), MB_TAG_DENSE, MF_ZERO);
1282 CHKERR mField.set_field_order(meshset, MBTET, field_name, order);
1284 };
1285
1286 auto add_l2_field = [this, meshset](const std::string field_name,
1287 const int order, const int dim) {
1290 MB_TAG_DENSE, MF_ZERO);
1292 CHKERR mField.set_field_order(meshset, MBTET, field_name, order);
1294 };
1295
1296 auto add_h1_field = [this, meshset](const std::string field_name,
1297 const int order, const int dim) {
1300 MB_TAG_DENSE, MF_ZERO);
1302 CHKERR mField.set_field_order(meshset, MBVERTEX, field_name, 1);
1303 CHKERR mField.set_field_order(meshset, MBEDGE, field_name, order);
1304 CHKERR mField.set_field_order(meshset, MBTRI, field_name, order);
1305 CHKERR mField.set_field_order(meshset, MBTET, field_name, order);
1307 };
1308
1309 auto add_l2_field_by_range = [this](const std::string field_name,
1310 const int order, const int dim,
1311 const int field_dim, Range &&r) {
1314 MB_TAG_DENSE, MF_ZERO);
1315 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(r);
1319 };
1320
1321 auto add_bubble_field = [this, meshset](const std::string field_name,
1322 const int order, const int dim) {
1324 CHKERR mField.add_field(field_name, HDIV, USER_BASE, dim, MB_TAG_DENSE,
1325 MF_ZERO);
1326 // Modify field
1327 auto field_ptr = mField.get_field_structure(field_name);
1328 auto field_order_table =
1329 const_cast<Field *>(field_ptr)->getFieldOrderTable();
1330 auto get_cgg_bubble_order_zero = [](int p) { return 0; };
1331 auto get_cgg_bubble_order_tet = [](int p) {
1332 return NBVOLUMETET_CCG_BUBBLE(p);
1333 };
1334 field_order_table[MBVERTEX] = get_cgg_bubble_order_zero;
1335 field_order_table[MBEDGE] = get_cgg_bubble_order_zero;
1336 field_order_table[MBTRI] = get_cgg_bubble_order_zero;
1337 field_order_table[MBTET] = get_cgg_bubble_order_tet;
1339 CHKERR mField.set_field_order(meshset, MBTRI, field_name, order);
1340 CHKERR mField.set_field_order(meshset, MBTET, field_name, order);
1342 };
1343
1344 auto add_user_l2_field = [this, meshset](const std::string field_name,
1345 const int order, const int dim) {
1347 CHKERR mField.add_field(field_name, L2, USER_BASE, dim, MB_TAG_DENSE,
1348 MF_ZERO);
1349 // Modify field
1350 auto field_ptr = mField.get_field_structure(field_name);
1351 auto field_order_table =
1352 const_cast<Field *>(field_ptr)->getFieldOrderTable();
1353 auto zero_dofs = [](int p) { return 0; };
1354 auto dof_l2_tet = [](int p) { return NBVOLUMETET_L2(p); };
1355 field_order_table[MBVERTEX] = zero_dofs;
1356 field_order_table[MBEDGE] = zero_dofs;
1357 field_order_table[MBTRI] = zero_dofs;
1358 field_order_table[MBTET] = dof_l2_tet;
1360 CHKERR mField.set_field_order(meshset, MBTET, field_name, order);
1362 };
1363
1364 // spatial fields
1365 CHKERR add_broken_hdiv_field(piolaStress, spaceOrder);
1366 CHKERR add_bubble_field(bubbleField, spaceOrder, 1);
1367 CHKERR add_l2_field(spatialL2Disp, spaceOrder - 1, 3);
1368 CHKERR add_l2_field(rotAxis, spaceOrder - 1, 3);
1369 CHKERR add_user_l2_field(stretchTensor, noStretch ? -1 : spaceOrder, 6);
1370
1371 if (!skeletonFaces)
1372 SETERRQ(mField.get_comm(), MOFEM_DATA_INCONSISTENCY, "No skeleton faces");
1373 if (!contactFaces)
1374 SETERRQ(mField.get_comm(), MOFEM_DATA_INCONSISTENCY, "No contact faces");
1375
1376 auto get_hybridised_disp = [&]() {
1377 auto faces = *skeletonFaces;
1378 auto skin = subtract_boundary_conditions(get_tets_skin());
1379 for (auto &bc : *bcSpatialNormalDisplacementVecPtr) {
1380 faces.merge(intersect(bc.faces, skin));
1381 }
1382 return faces;
1383 };
1384
1385 CHKERR add_l2_field_by_range(hybridSpatialDisp, spaceOrder - 1, 2, 3,
1386 get_hybridised_disp());
1387 CHKERR add_l2_field_by_range(contactDisp, spaceOrder - 1, 2, 3,
1389
1390 // spatial displacement
1391 CHKERR add_h1_field(spatialH1Disp, spaceH1Order, 3);
1392 // material positions
1393 CHKERR add_h1_field(materialH1Positions, 2, 3);
1394
1395 // Eshelby stress
1396 // CHKERR add_broken_hdiv_field(eshelbyStress, spaceOrder);
1397 // CHKERR add_l2_field(materialL2Disp, spaceOrder - 1, 3);
1398 // CHKERR add_l2_field_by_range(hybridMaterialDisp, spaceOrder - 1, 2, 3,
1399 // Range(*materialSkeletonFaces));
1400
1402
1404}
1405
1408
1409 Range meshset_ents;
1410 CHKERR mField.get_moab().get_entities_by_handle(meshset, meshset_ents);
1411
1412 auto project_ho_geometry = [&](auto field) {
1414 return mField.loop_dofs(field, ent_method);
1415 };
1416 CHKERR project_ho_geometry(materialH1Positions);
1417
1418 auto get_adj_front_edges = [&](auto &front_edges) {
1419 Range front_crack_nodes;
1420 Range crack_front_edges_with_both_nodes_not_at_front;
1421
1422 if (mField.get_comm_rank() == 0) {
1423 auto &moab = mField.get_moab();
1424 CHKERR moab.get_connectivity(front_edges, front_crack_nodes, true);
1425 Range crack_front_edges;
1426 CHKERR moab.get_adjacencies(front_crack_nodes, SPACE_DIM - 2, false,
1427 crack_front_edges, moab::Interface::UNION);
1428 crack_front_edges_with_both_nodes_not_at_front =
1429 subtract(crack_front_edges, front_edges);
1430 }
1431
1432 front_crack_nodes = send_type(mField, front_crack_nodes, MBVERTEX);
1433 crack_front_edges_with_both_nodes_not_at_front = send_type(
1434 mField, crack_front_edges_with_both_nodes_not_at_front, MBEDGE);
1435
1436 return std::make_pair(boost::make_shared<Range>(front_crack_nodes),
1437 boost::make_shared<Range>(
1438 crack_front_edges_with_both_nodes_not_at_front));
1439 };
1440
1441 crackFaces = boost::make_shared<Range>(
1442 get_range_from_block(mField, "CRACK", SPACE_DIM - 1));
1443 frontEdges =
1444 boost::make_shared<Range>(get_crack_front_edges(mField, *crackFaces));
1445 auto [front_vertices, front_adj_edges] = get_adj_front_edges(*frontEdges);
1446 frontVertices = front_vertices;
1447 frontAdjEdges = front_adj_edges;
1448
1449#ifndef NDEBUG
1450 if (crackingOn) {
1451 auto rank = mField.get_comm_rank();
1452 // CHKERR save_range(mField.get_moab(),
1453 // (boost::format("meshset_ents_%d.vtk") % rank).str(),
1454 // meshset_ents);
1456 (boost::format("crack_faces_%d.vtk") % rank).str(),
1457 *crackFaces);
1459 (boost::format("front_edges_%d.vtk") % rank).str(),
1460 *frontEdges);
1461 // CHKERR save_range(mField.get_moab(),
1462 // (boost::format("front_vertices_%d.vtk") % rank).str(),
1463 // *frontVertices);
1464 // CHKERR save_range(mField.get_moab(),
1465 // (boost::format("front_adj_edges_%d.vtk") % rank).str(),
1466 // *frontAdjEdges);
1467 }
1468#endif // NDEBUG
1469
1470 auto set_singular_dofs = [&](auto &front_adj_edges, auto &front_vertices) {
1472 auto &moab = mField.get_moab();
1473
1474 double eps = 1;
1475 double beta = 0;
1476 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "-singularity_eps", &beta,
1477 PETSC_NULLPTR);
1478 MOFEM_LOG("EP", Sev::inform) << "Singularity eps " << beta;
1479 eps -= beta;
1480
1481 for (auto edge : front_adj_edges) {
1482 int num_nodes;
1483 const EntityHandle *conn;
1484 CHKERR moab.get_connectivity(edge, conn, num_nodes, false);
1485 double coords[6];
1486 CHKERR moab.get_coords(conn, num_nodes, coords);
1487 const double dir[3] = {coords[3] - coords[0], coords[4] - coords[1],
1488 coords[5] - coords[2]};
1489 double dof[3] = {0, 0, 0};
1490 if (front_vertices.find(conn[0]) != front_vertices.end()) {
1491 for (int dd = 0; dd != 3; dd++) {
1492 dof[dd] = -dir[dd] * eps;
1493 }
1494 } else if (front_vertices.find(conn[1]) != front_vertices.end()) {
1495 for (int dd = 0; dd != 3; dd++) {
1496 dof[dd] = +dir[dd] * eps;
1497 }
1498 }
1500 mField, materialH1Positions, edge, dit)) {
1501 const int idx = dit->get()->getEntDofIdx();
1502 if (idx > 2) {
1503 dit->get()->getFieldData() = 0;
1504 } else {
1505 dit->get()->getFieldData() = dof[idx];
1506 }
1507 }
1508 }
1509
1511 };
1512
1513 if (setSingularity)
1514 CHKERR set_singular_dofs(*frontAdjEdges, *frontVertices);
1515
1517}
1518
1522
1523 // set finite element fields
1524 auto add_field_to_fe = [this](const std::string fe,
1525 const std::string field_name) {
1531 };
1532
1537
1538 CHKERR add_field_to_fe(elementVolumeName, piolaStress);
1539 CHKERR add_field_to_fe(elementVolumeName, bubbleField);
1540 if (!noStretch)
1541 CHKERR add_field_to_fe(elementVolumeName, stretchTensor);
1542 CHKERR add_field_to_fe(elementVolumeName, rotAxis);
1543 CHKERR add_field_to_fe(elementVolumeName, spatialL2Disp);
1544 CHKERR add_field_to_fe(elementVolumeName, spatialH1Disp);
1545 CHKERR add_field_to_fe(elementVolumeName, contactDisp);
1548
1549 // build finite elements data structures
1551 }
1552
1553 // if (!mField.check_finite_element(materialVolumeElement)) {
1554
1555 // Range front_edges = get_range_from_block(mField, "FRONT", SPACE_DIM - 2);
1556
1557 // Range front_elements;
1558 // for (auto l = 0; l != frontLayers; ++l) {
1559 // Range front_elements_layer;
1560 // CHKERR mField.get_moab().get_adjacencies(front_edges, SPACE_DIM, true,
1561 // front_elements_layer,
1562 // moab::Interface::UNION);
1563 // front_elements.merge(front_elements_layer);
1564 // front_edges.clear();
1565 // CHKERR mField.get_moab().get_adjacencies(front_elements_layer,
1566 // SPACE_DIM - 2, true,
1567 // front_edges,
1568 // moab::Interface::UNION);
1569 // }
1570
1571 // CHKERR mField.add_finite_element(materialVolumeElement, MF_ZERO);
1572 // CHKERR mField.add_ents_to_finite_element_by_type(front_elements, MBTET,
1573 // materialVolumeElement);
1574 // // CHKERR add_field_to_fe(materialVolumeElement, eshelbyStress);
1575 // // CHKERR add_field_to_fe(materialVolumeElement, materialL2Disp);
1576 // CHKERR mField.build_finite_elements(materialVolumeElement);
1577 // }
1578
1580}
1581
1585
1586 Range meshset_ents;
1587 CHKERR mField.get_moab().get_entities_by_handle(meshset, meshset_ents);
1588
1589 auto set_fe_adjacency = [&](auto fe_name) {
1592 boost::make_shared<ParentFiniteElementAdjacencyFunctionSkeleton<2>>(
1595 fe_name, MBTRI, *parentAdjSkeletonFunctionDim2);
1597 };
1598
1599 // set finite element fields
1600 auto add_field_to_fe = [this](const std::string fe,
1601 const std::string field_name) {
1608 };
1609
1611
1612 Range natural_bc_elements;
1613 if (bcSpatialDispVecPtr) {
1614 for (auto &v : *bcSpatialDispVecPtr) {
1615 natural_bc_elements.merge(v.faces);
1616 }
1617 }
1619 for (auto &v : *bcSpatialRotationVecPtr) {
1620 natural_bc_elements.merge(v.faces);
1621 }
1622 }
1624 for (auto &v : *bcSpatialNormalDisplacementVecPtr) {
1625 natural_bc_elements.merge(v.faces);
1626 }
1627 }
1630 natural_bc_elements.merge(v.faces);
1631 }
1632 }
1634 for (auto &v : *bcSpatialTractionVecPtr) {
1635 natural_bc_elements.merge(v.faces);
1636 }
1637 }
1639 for (auto &v : *bcSpatialAnalyticalTractionVecPtr) {
1640 natural_bc_elements.merge(v.faces);
1641 }
1642 }
1644 for (auto &v : *bcSpatialPressureVecPtr) {
1645 natural_bc_elements.merge(v.faces);
1646 }
1647 }
1648 natural_bc_elements = intersect(natural_bc_elements, meshset_ents);
1649
1651 CHKERR mField.add_ents_to_finite_element_by_type(natural_bc_elements, MBTRI,
1653 CHKERR add_field_to_fe(naturalBcElement, piolaStress);
1654 CHKERR add_field_to_fe(naturalBcElement, hybridSpatialDisp);
1655 CHKERR set_fe_adjacency(naturalBcElement);
1657 }
1658
1659 auto get_skin = [&](auto &body_ents) {
1660 Skinner skin(&mField.get_moab());
1661 Range skin_ents;
1662 CHKERR skin.find_skin(0, body_ents, false, skin_ents);
1663 return skin_ents;
1664 };
1665
1666 auto filter_true_skin = [&](auto &&skin) {
1667 Range boundary_ents;
1668 ParallelComm *pcomm =
1669 ParallelComm::get_pcomm(&mField.get_moab(), MYPCOMM_INDEX);
1670 CHKERR pcomm->filter_pstatus(skin, PSTATUS_SHARED | PSTATUS_MULTISHARED,
1671 PSTATUS_NOT, -1, &boundary_ents);
1672 return boundary_ents;
1673 };
1674
1676
1677 Range body_ents;
1678 CHKERR mField.get_moab().get_entities_by_dimension(meshset, SPACE_DIM,
1679 body_ents);
1680 auto skin = filter_true_skin(get_skin(body_ents));
1681
1689 contactDisp);
1692 // CHKERR add_field_to_fe(skinElement, hybridSpatialDisp);
1693 // CHKERR add_field_to_fe(skinElement, hybridMaterialDisp);
1694
1696 }
1697
1699 if (contactFaces) {
1700 MOFEM_LOG("EP", Sev::inform)
1701 << "Contact elements " << contactFaces->size();
1705 CHKERR add_field_to_fe(contactElement, piolaStress);
1706 CHKERR add_field_to_fe(contactElement, hybridSpatialDisp);
1707 CHKERR add_field_to_fe(contactElement, contactDisp);
1708 CHKERR add_field_to_fe(contactElement, spatialH1Disp);
1709 CHKERR set_fe_adjacency(contactElement);
1711 }
1712 }
1713
1715 if (!skeletonFaces)
1716 SETERRQ(mField.get_comm(), MOFEM_DATA_INCONSISTENCY, "No skeleton faces");
1717 MOFEM_LOG("EP", Sev::inform)
1718 << "Skeleton elements " << skeletonFaces->size();
1722 CHKERR add_field_to_fe(skeletonElement, piolaStress);
1723 CHKERR add_field_to_fe(skeletonElement, hybridSpatialDisp);
1724 CHKERR add_field_to_fe(skeletonElement, contactDisp);
1725 CHKERR add_field_to_fe(skeletonElement, spatialH1Disp);
1726 CHKERR set_fe_adjacency(skeletonElement);
1728 }
1729
1730 // if (!mField.check_finite_element(materialSkeletonElement)) {
1731
1732 // Range front_edges = get_range_from_block(mField, "FRONT", SPACE_DIM -
1733 // 2);
1734
1735 // Range front_elements;
1736 // for (auto l = 0; l != frontLayers; ++l) {
1737 // Range front_elements_layer;
1738 // CHKERR mField.get_moab().get_adjacencies(front_edges, SPACE_DIM,
1739 // true,
1740 // front_elements_layer,
1741 // moab::Interface::UNION);
1742 // front_elements.merge(front_elements_layer);
1743 // front_edges.clear();
1744 // CHKERR mField.get_moab().get_adjacencies(front_elements_layer,
1745 // SPACE_DIM - 2, true,
1746 // front_edges,
1747 // moab::Interface::UNION);
1748 // }
1749 // Range body_ents;
1750 // CHKERR mField.get_moab().get_entities_by_dimension(0, SPACE_DIM,
1751 // body_ents); Range front_elements_faces; CHKERR
1752 // mField.get_moab().get_adjacencies(front_elements, SPACE_DIM - 1,
1753 // true, front_elements_faces,
1754 // moab::Interface::UNION);
1755 // auto body_skin = filter_true_skin(get_skin(body_ents));
1756 // auto front_elements_skin = filter_true_skin(get_skin(front_elements));
1757 // Range material_skeleton_faces =
1758 // subtract(front_elements_faces, front_elements_skin);
1759 // material_skeleton_faces.merge(intersect(front_elements_skin,
1760 // body_skin));
1761
1762 // #ifndef NDEBUG
1763 // CHKERR save_range(mField.get_moab(), "front_elements.vtk",
1764 // front_elements); CHKERR save_range(mField.get_moab(),
1765 // "front_elements_skin.vtk",
1766 // front_elements_skin);
1767 // CHKERR save_range(mField.get_moab(), "material_skeleton_faces.vtk",
1768 // material_skeleton_faces);
1769 // #endif
1770
1771 // CHKERR mField.add_finite_element(materialSkeletonElement, MF_ZERO);
1772 // CHKERR mField.add_ents_to_finite_element_by_type(
1773 // material_skeleton_faces, MBTRI, materialSkeletonElement);
1774 // // CHKERR add_field_to_fe(materialSkeletonElement, eshelbyStress);
1775 // // CHKERR add_field_to_fe(materialSkeletonElement, hybridMaterialDisp);
1776 // CHKERR set_fe_adjacency(materialSkeletonElement);
1777 // CHKERR mField.build_finite_elements(materialSkeletonElement);
1778 // }
1779
1781}
1782
1784 const EntityHandle meshset) {
1786
1787 // find adjacencies between finite elements and dofs
1789
1790 // Create coupled problem
1791 dM = createDM(mField.get_comm(), "DMMOFEM");
1792 CHKERR DMMoFEMCreateMoFEM(dM, &mField, "ESHELBY_PLASTICITY", bit,
1793 BitRefLevel().set());
1794 CHKERR DMMoFEMSetDestroyProblem(dM, PETSC_TRUE);
1795 CHKERR DMMoFEMSetIsPartitioned(dM, PETSC_TRUE);
1801
1802 mField.getInterface<ProblemsManager>()->buildProblemFromFields = PETSC_TRUE;
1803 CHKERR DMSetUp(dM);
1804 mField.getInterface<ProblemsManager>()->buildProblemFromFields = PETSC_FALSE;
1805
1806 auto remove_dofs_on_broken_skin = [&](const std::string prb_name) {
1808 for (int d : {0, 1, 2}) {
1809 std::vector<boost::weak_ptr<NumeredDofEntity>> dofs_to_remove;
1811 ->getSideDofsOnBrokenSpaceEntities(
1812 dofs_to_remove, prb_name, ROW, piolaStress,
1814 // remove piola dofs, i.e. traction free boundary
1815 CHKERR mField.getInterface<ProblemsManager>()->removeDofs(prb_name, ROW,
1816 dofs_to_remove);
1817 CHKERR mField.getInterface<ProblemsManager>()->removeDofs(prb_name, COL,
1818 dofs_to_remove);
1819 }
1821 };
1822 CHKERR remove_dofs_on_broken_skin("ESHELBY_PLASTICITY");
1823
1824 // Create elastic sub-problem
1825 dmElastic = createDM(mField.get_comm(), "DMMOFEM");
1826 CHKERR DMMoFEMCreateSubDM(dmElastic, dM, "ELASTIC_PROBLEM");
1832 if (!noStretch) {
1834 }
1844 CHKERR DMSetUp(dmElastic);
1845
1846 // dmMaterial = createDM(mField.get_comm(), "DMMOFEM");
1847 // CHKERR DMMoFEMCreateSubDM(dmMaterial, dM, "MATERIAL_PROBLEM");
1848 // CHKERR DMMoFEMSetDestroyProblem(dmMaterial, PETSC_TRUE);
1849 // CHKERR DMMoFEMAddSubFieldRow(dmMaterial, eshelbyStress);
1850 // CHKERR DMMoFEMAddSubFieldRow(dmMaterial, materialL2Disp);
1851 // CHKERR DMMoFEMAddElement(dmMaterh elementVolumeName);
1852 // CHKERR DMMoFEMAddElement(dmMaterial, naturalBcElement);
1853 // CHKERR DMMoFEMAddElement(dmMaterial, skinElement);
1854 // CHKERR DMMoFEMSetSquareProblem(dmMaterial, PETSC_TRUE);
1855 // CHKERR DMMoFEMSetIsPartitioned(dmMaterial, PETSC_TRUE);
1856 // CHKERR DMSetUp(dmMaterial);
1857
1858 auto set_zero_block = [&]() {
1860 if (!noStretch) {
1861 CHKERR mField.getInterface<ProblemsManager>()->addFieldToEmptyFieldBlocks(
1862 "ELASTIC_PROBLEM", spatialL2Disp, stretchTensor);
1863 CHKERR mField.getInterface<ProblemsManager>()->addFieldToEmptyFieldBlocks(
1864 "ELASTIC_PROBLEM", stretchTensor, spatialL2Disp);
1865 }
1866 CHKERR mField.getInterface<ProblemsManager>()->addFieldToEmptyFieldBlocks(
1867 "ELASTIC_PROBLEM", spatialL2Disp, rotAxis);
1868 CHKERR mField.getInterface<ProblemsManager>()->addFieldToEmptyFieldBlocks(
1869 "ELASTIC_PROBLEM", rotAxis, spatialL2Disp);
1870 CHKERR mField.getInterface<ProblemsManager>()->addFieldToEmptyFieldBlocks(
1871 "ELASTIC_PROBLEM", spatialL2Disp, bubbleField);
1872 CHKERR mField.getInterface<ProblemsManager>()->addFieldToEmptyFieldBlocks(
1873 "ELASTIC_PROBLEM", bubbleField, spatialL2Disp);
1874 if (!noStretch) {
1875 CHKERR mField.getInterface<ProblemsManager>()->addFieldToEmptyFieldBlocks(
1876 "ELASTIC_PROBLEM", bubbleField, bubbleField);
1877 CHKERR
1878 mField.getInterface<ProblemsManager>()->addFieldToEmptyFieldBlocks(
1879 "ELASTIC_PROBLEM", piolaStress, piolaStress);
1880 CHKERR mField.getInterface<ProblemsManager>()->addFieldToEmptyFieldBlocks(
1881 "ELASTIC_PROBLEM", bubbleField, piolaStress);
1882 CHKERR mField.getInterface<ProblemsManager>()->addFieldToEmptyFieldBlocks(
1883 "ELASTIC_PROBLEM", piolaStress, bubbleField);
1884 }
1885
1888 };
1889
1890 auto set_section = [&]() {
1892 PetscSection section;
1893 CHKERR mField.getInterface<ISManager>()->sectionCreate("ELASTIC_PROBLEM",
1894 &section);
1895 CHKERR DMSetSection(dmElastic, section);
1896 CHKERR DMSetGlobalSection(dmElastic, section);
1897 CHKERR PetscSectionDestroy(&section);
1899 };
1900
1901 CHKERR set_zero_block();
1902 CHKERR set_section();
1903
1904 dmPrjSpatial = createDM(mField.get_comm(), "DMMOFEM");
1905 CHKERR DMMoFEMCreateSubDM(dmPrjSpatial, dM, "PROJECT_SPATIAL");
1911 CHKERR DMSetUp(dmPrjSpatial);
1912
1913 // CHKERR mField.getInterface<BcManager>()
1914 // ->pushMarkDOFsOnEntities<DisplacementCubitBcData>(
1915 // "PROJECT_SPATIAL", spatialH1Disp, true, false);
1916
1918}
1919
1920BcDisp::BcDisp(std::string name, std::vector<double> attr, Range faces)
1921 : blockName(name), faces(faces) {
1922 vals.resize(3, false);
1923 flags.resize(3, false);
1924 for (int ii = 0; ii != 3; ++ii) {
1925 vals[ii] = attr[ii];
1926 flags[ii] = static_cast<int>(attr[ii + 3]);
1927 }
1928
1929 MOFEM_LOG("EP", Sev::inform) << "Add BCDisp " << name;
1930 MOFEM_LOG("EP", Sev::inform)
1931 << "Add BCDisp vals " << vals[0] << " " << vals[1] << " " << vals[2];
1932 MOFEM_LOG("EP", Sev::inform)
1933 << "Add BCDisp flags " << flags[0] << " " << flags[1] << " " << flags[2];
1934 MOFEM_LOG("EP", Sev::inform) << "Add BCDisp nb. of faces " << faces.size();
1935}
1936
1937BcRot::BcRot(std::string name, std::vector<double> attr, Range faces)
1938 : blockName(name), faces(faces) {
1939 vals.resize(attr.size(), false);
1940 for (int ii = 0; ii != attr.size(); ++ii) {
1941 vals[ii] = attr[ii];
1942 }
1943 theta = attr[3];
1944}
1945
1946TractionBc::TractionBc(std::string name, std::vector<double> attr, Range faces)
1947 : blockName(name), faces(faces) {
1948 vals.resize(3, false);
1949 flags.resize(3, false);
1950 for (int ii = 0; ii != 3; ++ii) {
1951 vals[ii] = attr[ii];
1952 flags[ii] = static_cast<int>(attr[ii + 3]);
1953 }
1954
1955 MOFEM_LOG("EP", Sev::inform) << "Add BCForce " << name;
1956 MOFEM_LOG("EP", Sev::inform)
1957 << "Add BCForce vals " << vals[0] << " " << vals[1] << " " << vals[2];
1958 MOFEM_LOG("EP", Sev::inform)
1959 << "Add BCForce flags " << flags[0] << " " << flags[1] << " " << flags[2];
1960 MOFEM_LOG("EP", Sev::inform) << "Add BCForce nb. of faces " << faces.size();
1961}
1962
1964 std::vector<double> attr,
1965 Range faces)
1966 : blockName(name), faces(faces) {
1967
1968 blockName = name;
1969 if (attr.size() < 1) {
1971 "Wrong size of normal displacement BC");
1972 }
1973
1974 val = attr[0];
1975
1976 MOFEM_LOG("EP", Sev::inform) << "Add NormalDisplacementBc " << name;
1977 MOFEM_LOG("EP", Sev::inform) << "Add NormalDisplacementBc val " << val;
1978 MOFEM_LOG("EP", Sev::inform)
1979 << "Add NormalDisplacementBc nb. of faces " << faces.size();
1980}
1981
1982PressureBc::PressureBc(std::string name, std::vector<double> attr, Range faces)
1983 : blockName(name), faces(faces) {
1984
1985 blockName = name;
1986 if (attr.size() < 1) {
1988 "Wrong size of normal displacement BC");
1989 }
1990
1991 val = attr[0];
1992
1993 MOFEM_LOG("EP", Sev::inform) << "Add PressureBc " << name;
1994 MOFEM_LOG("EP", Sev::inform) << "Add PressureBc val " << val;
1995 MOFEM_LOG("EP", Sev::inform)
1996 << "Add PressureBc nb. of faces " << faces.size();
1997}
1998
1999
2000ExternalStrain::ExternalStrain(std::string name, std::vector<double> attr,
2001 Range ents)
2002 : blockName(name), ents(ents) {
2003
2004 blockName = name;
2005 if (attr.size() < 2) {
2007 "Wrong size of external strain attribute");
2008 }
2009
2010 val = attr[0];
2011 bulkModulusK = attr[1];
2012
2013 MOFEM_LOG("EP", Sev::inform) << "Add ExternalStrain " << name;
2014 MOFEM_LOG("EP", Sev::inform) << "Add ExternalStrain val " << val;
2015 MOFEM_LOG("EP", Sev::inform) << "Add ExternalStrain bulk modulus K "
2016 << bulkModulusK;
2017 MOFEM_LOG("EP", Sev::inform)
2018 << "Add ExternalStrain nb. of tets " << ents.size();
2019
2020
2021}
2022
2024 std::vector<double> attr,
2025 Range faces)
2026 : blockName(name), faces(faces) {
2027
2028 blockName = name;
2029 if (attr.size() < 3) {
2031 "Wrong size of analytical displacement BC");
2032 }
2033
2034 flags.resize(3, false);
2035 for (int ii = 0; ii != 3; ++ii) {
2036 flags[ii] = attr[ii];
2037 }
2038
2039 MOFEM_LOG("EP", Sev::inform) << "Add AnalyticalDisplacementBc " << name;
2040 MOFEM_LOG("EP", Sev::inform)
2041 << "Add AnalyticalDisplacementBc flags " << flags[0] << " " << flags[1]
2042 << " " << flags[2];
2043 MOFEM_LOG("EP", Sev::inform)
2044 << "Add AnalyticalDisplacementBc nb. of faces " << faces.size();
2045}
2046
2048 std::vector<double> attr,
2049 Range faces)
2050 : blockName(name), faces(faces) {
2051
2052 blockName = name;
2053 if (attr.size() < 3) {
2055 "Wrong size of analytical traction BC");
2056 }
2057
2058 flags.resize(3, false);
2059 for (int ii = 0; ii != 3; ++ii) {
2060 flags[ii] = attr[ii];
2061 }
2062
2063 MOFEM_LOG("EP", Sev::inform) << "Add AnalyticalTractionBc " << name;
2064 MOFEM_LOG("EP", Sev::inform)
2065 << "Add AnalyticalTractionBc flags " << flags[0] << " " << flags[1]
2066 << " " << flags[2];
2067 MOFEM_LOG("EP", Sev::inform)
2068 << "Add AnalyticalTractionBc nb. of faces " << faces.size();
2069}
2070
2071
2074 boost::shared_ptr<TractionFreeBc> &bc_ptr,
2075 const std::string contact_set_name) {
2077
2078 // get skin from all tets
2079 Range tets;
2080 CHKERR mField.get_moab().get_entities_by_type(meshset, MBTET, tets);
2081 Range tets_skin_part;
2082 Skinner skin(&mField.get_moab());
2083 CHKERR skin.find_skin(0, tets, false, tets_skin_part);
2084 ParallelComm *pcomm =
2085 ParallelComm::get_pcomm(&mField.get_moab(), MYPCOMM_INDEX);
2086 Range tets_skin;
2087 CHKERR pcomm->filter_pstatus(tets_skin_part,
2088 PSTATUS_SHARED | PSTATUS_MULTISHARED,
2089 PSTATUS_NOT, -1, &tets_skin);
2090
2091 bc_ptr->resize(3);
2092 for (int dd = 0; dd != 3; ++dd)
2093 (*bc_ptr)[dd] = tets_skin;
2094
2095 // Do not remove dofs on which traction is applied
2096 if (bcSpatialDispVecPtr)
2097 for (auto &v : *bcSpatialDispVecPtr) {
2098 if (v.flags[0])
2099 (*bc_ptr)[0] = subtract((*bc_ptr)[0], v.faces);
2100 if (v.flags[1])
2101 (*bc_ptr)[1] = subtract((*bc_ptr)[1], v.faces);
2102 if (v.flags[2])
2103 (*bc_ptr)[2] = subtract((*bc_ptr)[2], v.faces);
2104 }
2105
2106 // Do not remove dofs on which rotation is applied
2107 if (bcSpatialRotationVecPtr)
2108 for (auto &v : *bcSpatialRotationVecPtr) {
2109 (*bc_ptr)[0] = subtract((*bc_ptr)[0], v.faces);
2110 (*bc_ptr)[1] = subtract((*bc_ptr)[1], v.faces);
2111 (*bc_ptr)[2] = subtract((*bc_ptr)[2], v.faces);
2112 }
2113
2114 if (bcSpatialNormalDisplacementVecPtr)
2115 for (auto &v : *bcSpatialNormalDisplacementVecPtr) {
2116 (*bc_ptr)[0] = subtract((*bc_ptr)[0], v.faces);
2117 (*bc_ptr)[1] = subtract((*bc_ptr)[1], v.faces);
2118 (*bc_ptr)[2] = subtract((*bc_ptr)[2], v.faces);
2119 }
2120
2121 if (bcSpatialAnalyticalDisplacementVecPtr)
2122 for (auto &v : *bcSpatialAnalyticalDisplacementVecPtr) {
2123 if (v.flags[0])
2124 (*bc_ptr)[0] = subtract((*bc_ptr)[0], v.faces);
2125 if (v.flags[1])
2126 (*bc_ptr)[1] = subtract((*bc_ptr)[1], v.faces);
2127 if (v.flags[2])
2128 (*bc_ptr)[2] = subtract((*bc_ptr)[2], v.faces);
2129 }
2130
2131 if (bcSpatialTractionVecPtr)
2132 for (auto &v : *bcSpatialTractionVecPtr) {
2133 (*bc_ptr)[0] = subtract((*bc_ptr)[0], v.faces);
2134 (*bc_ptr)[1] = subtract((*bc_ptr)[1], v.faces);
2135 (*bc_ptr)[2] = subtract((*bc_ptr)[2], v.faces);
2136 }
2137
2138 if (bcSpatialAnalyticalTractionVecPtr)
2139 for (auto &v : *bcSpatialAnalyticalTractionVecPtr) {
2140 (*bc_ptr)[0] = subtract((*bc_ptr)[0], v.faces);
2141 (*bc_ptr)[1] = subtract((*bc_ptr)[1], v.faces);
2142 (*bc_ptr)[2] = subtract((*bc_ptr)[2], v.faces);
2143 }
2144
2145 if (bcSpatialPressureVecPtr)
2146 for (auto &v : *bcSpatialPressureVecPtr) {
2147 (*bc_ptr)[0] = subtract((*bc_ptr)[0], v.faces);
2148 (*bc_ptr)[1] = subtract((*bc_ptr)[1], v.faces);
2149 (*bc_ptr)[2] = subtract((*bc_ptr)[2], v.faces);
2150 }
2151
2152 // remove contact
2153 for (auto m : mField.getInterface<MeshsetsManager>()->getCubitMeshsetPtr(
2154 std::regex((boost::format("%s(.*)") % contact_set_name).str()))) {
2155 Range faces;
2156 CHKERR m->getMeshsetIdEntitiesByDimension(mField.get_moab(), 2, faces,
2157 true);
2158 (*bc_ptr)[0] = subtract((*bc_ptr)[0], faces);
2159 (*bc_ptr)[1] = subtract((*bc_ptr)[1], faces);
2160 (*bc_ptr)[2] = subtract((*bc_ptr)[2], faces);
2161 }
2162
2164}
2165
2166/**
2167 * @brief Set integration rule on element
2168 * \param order on row
2169 * \param order on column
2170 * \param order on data
2171 *
2172 * Use maximal oder on data in order to determine integration rule
2173 *
2174 */
2175struct VolRule {
2176 int operator()(int p_row, int p_col, int p_data) const {
2177 return 2 * p_data + 1;
2178 }
2179};
2180
2181struct FaceRule {
2182 int operator()(int p_row, int p_col, int p_data) const {
2183 return 2 * (p_data + 1);
2184 }
2185};
2186
2188 boost::shared_ptr<CachePhi> cache_phi_otr)
2189 : TetPolynomialBase(), cachePhiPtr(cache_phi_otr) {}
2190
2192 boost::typeindex::type_index type_index,
2193 BaseFunctionUnknownInterface **iface) const {
2194 *iface = const_cast<CGGUserPolynomialBase *>(this);
2195 return 0;
2196}
2197
2200 boost::shared_ptr<BaseFunctionCtx> ctx_ptr) {
2202
2203 this->cTx = ctx_ptr->getInterface<EntPolynomialBaseCtx>();
2204
2205 int nb_gauss_pts = pts.size2();
2206 if (!nb_gauss_pts) {
2208 }
2209
2210 if (pts.size1() < 3) {
2211 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
2212 "Wrong dimension of pts, should be at least 3 rows with "
2213 "coordinates");
2214 }
2215
2216 const auto base = this->cTx->bAse;
2217 EntitiesFieldData &data = this->cTx->dAta;
2218
2219 switch (this->cTx->sPace) {
2220 case HDIV:
2222 break;
2223 case L2:
2224 data.dataOnEntities[MBVERTEX][0].getN(base).resize(nb_gauss_pts, 4, false);
2226 &*data.dataOnEntities[MBVERTEX][0].getN(base).data().begin(),
2227 &pts(0, 0), &pts(1, 0), &pts(2, 0), nb_gauss_pts);
2228 data.dataOnEntities[MBVERTEX][0].getDiffN(base).resize(4, 3, false);
2229 std::copy(Tools::diffShapeFunMBTET.begin(), Tools::diffShapeFunMBTET.end(),
2230 data.dataOnEntities[MBVERTEX][0].getDiffN(base).data().begin());
2231 this->cTx->basePolynomialsType0 = Legendre_polynomials;
2232 CHKERR getValueL2AinsworthBase(pts);
2233 break;
2234 default:
2235 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED, "Not yet implemented");
2236 }
2237
2239}
2240
2244
2245 // This should be used only in case USER_BASE is selected
2246 if (this->cTx->bAse != USER_BASE) {
2247 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
2248 "Wrong base, should be USER_BASE");
2249 }
2250 // get access to data structures on element
2251 EntitiesFieldData &data = this->cTx->dAta;
2252 // Get approximation order on element. Note that bubble functions are only
2253 // on tetrahedron.
2254 const int order = data.dataOnEntities[MBTET][0].getOrder();
2255 /// number of integration points
2256 const int nb_gauss_pts = pts.size2();
2257
2258 auto check_cache = [this](int order, int nb_gauss_pts) -> bool {
2259 if (cachePhiPtr) {
2260 return cachePhiPtr->get<0>() == order &&
2261 cachePhiPtr->get<1>() == nb_gauss_pts;
2262 } else {
2263 return false;
2264 }
2265 };
2266
2267 if (check_cache(order, nb_gauss_pts)) {
2268 auto &mat = cachePhiPtr->get<2>();
2269 auto &phi = data.dataOnEntities[MBTET][0].getN(USER_BASE);
2270 phi.resize(mat.size1(), mat.size2(), false);
2271 noalias(phi) = mat;
2272
2273 } else {
2274 // calculate shape functions, i.e. barycentric coordinates
2275 shapeFun.resize(nb_gauss_pts, 4, false);
2276 CHKERR ShapeMBTET(&*shapeFun.data().begin(), &pts(0, 0), &pts(1, 0),
2277 &pts(2, 0), nb_gauss_pts);
2278 // derivatives of shape functions
2279 double diff_shape_fun[12];
2280 CHKERR ShapeDiffMBTET(diff_shape_fun);
2281
2282 const int nb_base_functions = NBVOLUMETET_CCG_BUBBLE(order);
2283 // get base functions and set size
2284 MatrixDouble &phi = data.dataOnEntities[MBTET][0].getN(USER_BASE);
2285 phi.resize(nb_gauss_pts, 9 * nb_base_functions, false);
2286 // finally calculate base functions
2288 &phi(0, 0), &phi(0, 1), &phi(0, 2),
2289
2290 &phi(0, 3), &phi(0, 4), &phi(0, 5),
2291
2292 &phi(0, 6), &phi(0, 7), &phi(0, 8));
2293 CHKERR CGG_BubbleBase_MBTET(order, &shapeFun(0, 0), diff_shape_fun, t_phi,
2294 nb_gauss_pts);
2295
2296 if (cachePhiPtr) {
2297 cachePhiPtr->get<0>() = order;
2298 cachePhiPtr->get<1>() = nb_gauss_pts;
2299 cachePhiPtr->get<2>().resize(phi.size1(), phi.size2(), false);
2300 noalias(cachePhiPtr->get<2>()) = phi;
2301 }
2302 }
2303
2305}
2306
2308 const int tag, const bool do_rhs, const bool do_lhs, const bool calc_rates,
2309 SmartPetscObj<Vec> var_vec,
2310 boost::shared_ptr<VolumeElementForcesAndSourcesCore> fe) {
2312
2313 auto bubble_cache =
2314 boost::make_shared<CGGUserPolynomialBase::CachePhi>(0, 0, MatrixDouble());
2315 fe->getUserPolynomialBase() =
2316 boost::make_shared<CGGUserPolynomialBase>(bubble_cache);
2317 EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
2318 fe->getOpPtrVector(), {HDIV, H1, L2}, materialH1Positions, frontAdjEdges);
2319
2320 // set integration rule
2321 fe->getRuleHook = [](int, int, int) { return -1; };
2322 fe->setRuleHook = SetIntegrationAtFrontVolume(frontVertices, frontAdjEdges);
2323 // fe->getRuleHook = VolRule();
2324
2325 if (!dataAtPts) {
2326 dataAtPts =
2327 boost::shared_ptr<DataAtIntegrationPts>(new DataAtIntegrationPts());
2328 dataAtPts->physicsPtr = physicalEquations;
2329 }
2330
2331 // calculate fields values
2332 fe->getOpPtrVector().push_back(new OpCalculateHVecTensorField<3, 3>(
2333 piolaStress, dataAtPts->getApproxPAtPts()));
2334 fe->getOpPtrVector().push_back(new OpCalculateHTensorTensorField<3, 3>(
2335 bubbleField, dataAtPts->getApproxPAtPts(), MBMAXTYPE));
2336 fe->getOpPtrVector().push_back(new OpCalculateHVecTensorDivergence<3, 3>(
2337 piolaStress, dataAtPts->getDivPAtPts()));
2338
2339 if (noStretch) {
2340 fe->getOpPtrVector().push_back(
2341 physicalEquations->returnOpCalculateStretchFromStress(
2342 dataAtPts, physicalEquations));
2343 } else {
2344 fe->getOpPtrVector().push_back(
2346 stretchTensor, dataAtPts->getLogStretchTensorAtPts(), MBTET));
2347 }
2348
2349 fe->getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
2350 rotAxis, dataAtPts->getRotAxisAtPts(), MBTET));
2351 fe->getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
2352 rotAxis, dataAtPts->getRotAxis0AtPts(), solTSStep, MBTET));
2353 fe->getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
2354 spatialL2Disp, dataAtPts->getSmallWL2AtPts(), MBTET));
2355
2356 // H1 displacements
2357 fe->getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
2358 spatialH1Disp, dataAtPts->getSmallWH1AtPts()));
2359 fe->getOpPtrVector().push_back(new OpCalculateVectorFieldGradient<3, 3>(
2360 spatialH1Disp, dataAtPts->getSmallWGradH1AtPts()));
2361
2362 // velocities
2363 if (calc_rates) {
2364 fe->getOpPtrVector().push_back(new OpCalculateVectorFieldValuesDot<3>(
2365 spatialL2Disp, dataAtPts->getSmallWL2DotAtPts(), MBTET));
2366 if (noStretch) {
2367 } else {
2368 fe->getOpPtrVector().push_back(
2370 stretchTensor, dataAtPts->getLogStretchDotTensorAtPts(), MBTET));
2371 fe->getOpPtrVector().push_back(
2373 stretchTensor, dataAtPts->getGradLogStretchDotTensorAtPts(),
2374 MBTET));
2375 }
2376 fe->getOpPtrVector().push_back(new OpCalculateVectorFieldValuesDot<3>(
2377 rotAxis, dataAtPts->getRotAxisDotAtPts(), MBTET));
2378 fe->getOpPtrVector().push_back(new OpCalculateVectorFieldGradientDot<3, 3>(
2379 rotAxis, dataAtPts->getRotAxisGradDotAtPts(), MBTET));
2380
2381 // acceleration
2382 if (std::abs(alphaRho) > std::numeric_limits<double>::epsilon()) {
2383 fe->getOpPtrVector().push_back(new OpCalculateVectorFieldValuesDotDot<3>(
2384 spatialL2Disp, dataAtPts->getSmallWL2DotDotAtPts(), MBTET));
2385 }
2386 }
2387
2388 // variations
2389 if (var_vec.use_count()) {
2390 fe->getOpPtrVector().push_back(new OpCalculateHVecTensorField<3, 3>(
2391 piolaStress, dataAtPts->getVarPiolaPts(), boost::make_shared<double>(1),
2392 var_vec));
2393 fe->getOpPtrVector().push_back(new OpCalculateHTensorTensorField<3, 3>(
2394 bubbleField, dataAtPts->getVarPiolaPts(), boost::make_shared<double>(1),
2395 var_vec, MBMAXTYPE));
2396 fe->getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
2397 rotAxis, dataAtPts->getVarRotAxisPts(), var_vec, MBTET));
2398 fe->getOpPtrVector().push_back(new OpCalculateHVecTensorDivergence<3, 3>(
2399 piolaStress, dataAtPts->getDivVarPiolaPts(), var_vec));
2400 fe->getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
2401 spatialL2Disp, dataAtPts->getVarWL2Pts(), var_vec, MBTET));
2402
2403 if (noStretch) {
2404 fe->getOpPtrVector().push_back(
2405 physicalEquations->returnOpCalculateVarStretchFromStress(
2406 dataAtPts, physicalEquations));
2407 } else {
2408 fe->getOpPtrVector().push_back(
2410 stretchTensor, dataAtPts->getVarLogStreachPts(), var_vec, MBTET));
2411 }
2412 }
2413
2414 // calculate other derived quantities
2415 fe->getOpPtrVector().push_back(new OpCalculateRotationAndSpatialGradient(
2416 dataAtPts, ((do_rhs || do_lhs) && calc_rates) ? alphaOmega : 0.));
2417
2418 // evaluate integration points
2419 if (noStretch) {
2420 } else {
2421 fe->getOpPtrVector().push_back(physicalEquations->returnOpJacobian(
2422 tag, do_rhs, do_lhs, dataAtPts, physicalEquations));
2423 }
2424
2426}
2427
2429 const int tag, const bool add_elastic, const bool add_material,
2430 boost::shared_ptr<VolumeElementForcesAndSourcesCore> &fe_rhs,
2431 boost::shared_ptr<VolumeElementForcesAndSourcesCore> &fe_lhs) {
2433
2434 /** Contact requires that body is marked */
2435 auto get_body_range = [this](auto name, int dim) {
2436 std::map<int, Range> map;
2437
2438 for (auto m_ptr :
2439 mField.getInterface<MeshsetsManager>()->getCubitMeshsetPtr(std::regex(
2440
2441 (boost::format("%s(.*)") % name).str()
2442
2443 ))
2444
2445 ) {
2446 Range ents;
2447 CHK_MOAB_THROW(m_ptr->getMeshsetIdEntitiesByDimension(mField.get_moab(),
2448 dim, ents, true),
2449 "by dim");
2450 map[m_ptr->getMeshsetId()] = ents;
2451 }
2452
2453 return map;
2454 };
2455
2456 auto rule_contact = [](int, int, int o) { return -1; };
2457 auto refine = Tools::refineTriangle(contactRefinementLevels);
2458
2459 auto set_rule_contact = [refine](
2460
2461 ForcesAndSourcesCore *fe_raw_ptr, int order_row,
2462 int order_col, int order_data
2463
2464 ) {
2466 auto rule = 2 * order_data;
2467 fe_raw_ptr->gaussPts = Tools::refineTriangleIntegrationPts(rule, refine);
2469 };
2470
2471 // Right hand side
2472 fe_rhs = boost::make_shared<VolumeElementForcesAndSourcesCore>(mField);
2473 CHKERR setBaseVolumeElementOps(tag, true, false, true, SmartPetscObj<Vec>(),
2474 fe_rhs);
2475
2476 // elastic
2477 if (add_elastic) {
2478
2479 fe_rhs->getOpPtrVector().push_back(
2480 new OpSpatialEquilibrium(spatialL2Disp, dataAtPts, alphaW, alphaRho));
2481 fe_rhs->getOpPtrVector().push_back(
2482 new OpSpatialRotation(rotAxis, dataAtPts, alphaOmega));
2483 if (noStretch) {
2484 // do nothing - no stretch approximation
2485 } else {
2486 if (!internalStressTagName.empty()) {
2487 switch (internalStressInterpOrder) {
2488 case 0:
2489 fe_rhs->getOpPtrVector().push_back(
2490 new OpGetInternalStress<0>(dataAtPts, internalStressTagName));
2491 break;
2492 case 1:
2493 fe_rhs->getOpPtrVector().push_back(
2494 new OpGetInternalStress<1>(dataAtPts, internalStressTagName));
2495 break;
2496 default:
2497 SETERRQ(PETSC_COMM_WORLD, MOFEM_NOT_IMPLEMENTED,
2498 "Unsupported internal stress interpolation order %d",
2499 internalStressInterpOrder);
2500 }
2501 if (internalStressVoigt) {
2502 fe_rhs->getOpPtrVector().push_back(
2503 new OpSpatialPhysicalInternalStress<true>(stretchTensor,
2504 dataAtPts));
2505 } else {
2506 fe_rhs->getOpPtrVector().push_back(
2508 dataAtPts));
2509 }
2510 }
2511 if (auto op = physicalEquations->returnOpSpatialPhysicalExternalStrain(
2512 stretchTensor, dataAtPts, externalStrainVecPtr, timeScaleMap)) {
2513 fe_rhs->getOpPtrVector().push_back(op);
2514 } else if (externalStrainVecPtr && !externalStrainVecPtr->empty()) {
2515 SETERRQ(PETSC_COMM_WORLD, MOFEM_NOT_IMPLEMENTED,
2516 "OpSpatialPhysicalExternalStrain not implemented for this "
2517 "material");
2518 }
2519
2520 fe_rhs->getOpPtrVector().push_back(
2521 physicalEquations->returnOpSpatialPhysical(stretchTensor, dataAtPts,
2522 alphaU));
2523 }
2524 fe_rhs->getOpPtrVector().push_back(
2525 new OpSpatialConsistencyP(piolaStress, dataAtPts));
2526 fe_rhs->getOpPtrVector().push_back(
2527 new OpSpatialConsistencyBubble(bubbleField, dataAtPts));
2528 fe_rhs->getOpPtrVector().push_back(
2529 new OpSpatialConsistencyDivTerm(piolaStress, dataAtPts));
2530
2531 auto set_hybridisation = [&](auto &pip) {
2533
2534 using BoundaryEle =
2536 using EleOnSide =
2538 using SideEleOp = EleOnSide::UserDataOperator;
2539 using BdyEleOp = BoundaryEle::UserDataOperator;
2540
2541 // First: Iterate over skeleton FEs adjacent to Domain FEs
2542 // Note: BoundaryEle, i.e. uses skeleton interation rule
2543 auto op_loop_skeleton_side = new OpLoopSide<BoundaryEle>(
2544 mField, skeletonElement, SPACE_DIM - 1, Sev::noisy);
2545 // op_loop_skeleton_side->getSideFEPtr()->getRuleHook = FaceRule();
2546 op_loop_skeleton_side->getSideFEPtr()->getRuleHook = [](int, int, int) {
2547 return -1;
2548 };
2549 op_loop_skeleton_side->getSideFEPtr()->setRuleHook =
2550 SetIntegrationAtFrontFace(frontVertices, frontAdjEdges);
2551
2552 CHKERR EshelbianPlasticity::
2553 AddHOOps<SPACE_DIM - 1, SPACE_DIM, SPACE_DIM>::add(
2554 op_loop_skeleton_side->getOpPtrVector(), {L2},
2555 materialH1Positions, frontAdjEdges);
2556
2557 // Second: Iterate over domain FEs adjacent to skelton, particularly one
2558 // domain element.
2559 auto broken_data_ptr =
2560 boost::make_shared<std::vector<BrokenBaseSideData>>();
2561 // Note: EleOnSide, i.e. uses on domain projected skeleton rule
2562 auto op_loop_domain_side = new OpBrokenLoopSide<EleOnSide>(
2563 mField, elementVolumeName, SPACE_DIM, Sev::noisy);
2564 op_loop_domain_side->getSideFEPtr()->getUserPolynomialBase() =
2565 boost::make_shared<CGGUserPolynomialBase>();
2566 CHKERR
2567 EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
2568 op_loop_domain_side->getOpPtrVector(), {HDIV, H1, L2},
2569 materialH1Positions, frontAdjEdges);
2570 op_loop_domain_side->getOpPtrVector().push_back(
2571 new OpGetBrokenBaseSideData<SideEleOp>(piolaStress, broken_data_ptr));
2572 auto flux_mat_ptr = boost::make_shared<MatrixDouble>();
2573 op_loop_domain_side->getOpPtrVector().push_back(
2575 flux_mat_ptr));
2576 op_loop_domain_side->getOpPtrVector().push_back(
2577 new OpSetFlux<SideEleOp>(broken_data_ptr, flux_mat_ptr));
2578
2579 // Assemble on skeleton
2580 op_loop_skeleton_side->getOpPtrVector().push_back(op_loop_domain_side);
2582 GAUSS>::OpBrokenSpaceConstrainDHybrid<SPACE_DIM>;
2584 GAUSS>::OpBrokenSpaceConstrainDFlux<SPACE_DIM>;
2585 op_loop_skeleton_side->getOpPtrVector().push_back(new OpC_dHybrid(
2586 hybridSpatialDisp, broken_data_ptr, boost::make_shared<double>(1.0)));
2587 auto hybrid_ptr = boost::make_shared<MatrixDouble>();
2588 op_loop_skeleton_side->getOpPtrVector().push_back(
2589 new OpCalculateVectorFieldValues<SPACE_DIM>(hybridSpatialDisp,
2590 hybrid_ptr));
2591 op_loop_skeleton_side->getOpPtrVector().push_back(new OpC_dBroken(
2592 broken_data_ptr, hybrid_ptr, boost::make_shared<double>(1.0)));
2593
2594 // Add skeleton to domain pipeline
2595 pip.push_back(op_loop_skeleton_side);
2596
2598 };
2599
2600 auto set_contact = [&](auto &pip) {
2602
2603 using BoundaryEle =
2605 using EleOnSide =
2607 using SideEleOp = EleOnSide::UserDataOperator;
2608 using BdyEleOp = BoundaryEle::UserDataOperator;
2609
2610 // First: Iterate over skeleton FEs adjacent to Domain FEs
2611 // Note: BoundaryEle, i.e. uses skeleton interation rule
2612 auto op_loop_skeleton_side = new OpLoopSide<BoundaryEle>(
2613 mField, contactElement, SPACE_DIM - 1, Sev::noisy);
2614
2615 op_loop_skeleton_side->getSideFEPtr()->getRuleHook = rule_contact;
2616 op_loop_skeleton_side->getSideFEPtr()->setRuleHook = set_rule_contact;
2617 CHKERR EshelbianPlasticity::
2618 AddHOOps<SPACE_DIM - 1, SPACE_DIM, SPACE_DIM>::add(
2619 op_loop_skeleton_side->getOpPtrVector(), {L2},
2620 materialH1Positions, frontAdjEdges);
2621
2622 // Second: Iterate over domain FEs adjacent to skelton, particularly
2623 // one domain element.
2624 auto broken_data_ptr =
2625 boost::make_shared<std::vector<BrokenBaseSideData>>();
2626
2627 // Data storing contact fields
2628 auto contact_common_data_ptr =
2629 boost::make_shared<ContactOps::CommonData>();
2630
2631 auto add_ops_domain_side = [&](auto &pip) {
2633 // Note: EleOnSide, i.e. uses on domain projected skeleton rule
2634 auto op_loop_domain_side = new OpBrokenLoopSide<EleOnSide>(
2635 mField, elementVolumeName, SPACE_DIM, Sev::noisy);
2636 op_loop_domain_side->getSideFEPtr()->getUserPolynomialBase() =
2637 boost::make_shared<CGGUserPolynomialBase>();
2638 CHKERR
2639 EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
2640 op_loop_domain_side->getOpPtrVector(), {HDIV, H1, L2},
2641 materialH1Positions, frontAdjEdges);
2642 op_loop_domain_side->getOpPtrVector().push_back(
2643 new OpGetBrokenBaseSideData<SideEleOp>(piolaStress,
2644 broken_data_ptr));
2645 op_loop_domain_side->getOpPtrVector().push_back(
2647 piolaStress, contact_common_data_ptr->contactTractionPtr()));
2648 pip.push_back(op_loop_domain_side);
2650 };
2651
2652 auto add_ops_contact_rhs = [&](auto &pip) {
2654 // get body id and SDF range
2655 auto contact_sfd_map_range_ptr =
2656 boost::make_shared<std::map<int, Range>>(
2657 get_body_range("CONTACT_SDF", SPACE_DIM - 1));
2658
2659 pip.push_back(new OpCalculateVectorFieldValues<3>(
2660 contactDisp, contact_common_data_ptr->contactDispPtr()));
2661 auto u_h1_ptr = boost::make_shared<MatrixDouble>();
2662 pip.push_back(
2663 new OpCalculateVectorFieldValues<3>(spatialH1Disp, u_h1_ptr));
2664 pip.push_back(new OpTreeSearch(
2665 contactTreeRhs, contact_common_data_ptr, u_h1_ptr,
2666 get_range_from_block(mField, "CONTACT", SPACE_DIM - 1), nullptr,
2667 nullptr));
2669 contactDisp, contact_common_data_ptr, contactTreeRhs,
2670 contact_sfd_map_range_ptr));
2671 pip.push_back(
2673 broken_data_ptr, contact_common_data_ptr, contactTreeRhs));
2674
2676 };
2677
2678 // push ops to face/side pipeline
2679 CHKERR add_ops_domain_side(op_loop_skeleton_side->getOpPtrVector());
2680 CHKERR add_ops_contact_rhs(op_loop_skeleton_side->getOpPtrVector());
2681
2682 // Add skeleton to domain pipeline
2683 pip.push_back(op_loop_skeleton_side);
2684
2686 };
2687
2688 CHKERR set_hybridisation(fe_rhs->getOpPtrVector());
2689 CHKERR set_contact(fe_rhs->getOpPtrVector());
2690
2691 // Body forces
2692 using BodyNaturalBC =
2694 Assembly<PETSC>::LinearForm<GAUSS>;
2695 using OpBodyForce =
2696 BodyNaturalBC::OpFlux<NaturalMeshsetType<BLOCKSET>, 1, 3>;
2697
2698 auto body_time_scale =
2699 boost::make_shared<DynamicRelaxationTimeScale>("body_force.txt");
2700 CHKERR BodyNaturalBC::AddFluxToPipeline<OpBodyForce>::add(
2701 fe_rhs->getOpPtrVector(), mField, spatialL2Disp, {body_time_scale},
2702 "BODY_FORCE", Sev::inform);
2703 }
2704
2705 // Left hand side
2706 fe_lhs = boost::make_shared<VolumeElementForcesAndSourcesCore>(mField);
2707 CHKERR setBaseVolumeElementOps(tag, true, true, true, SmartPetscObj<Vec>(),
2708 fe_lhs);
2709
2710 // elastic
2711 if (add_elastic) {
2712
2713 if (noStretch) {
2714 fe_lhs->getOpPtrVector().push_back(
2715 new OpSpatialConsistency_dP_dP(piolaStress, piolaStress, dataAtPts));
2716 fe_lhs->getOpPtrVector().push_back(new OpSpatialConsistency_dBubble_dP(
2717 bubbleField, piolaStress, dataAtPts));
2718 fe_lhs->getOpPtrVector().push_back(
2719 new OpSpatialConsistency_dBubble_dBubble(bubbleField, bubbleField,
2720 dataAtPts));
2721 } else {
2722 fe_lhs->getOpPtrVector().push_back(
2723 physicalEquations->returnOpSpatialPhysical_du_du(
2724 stretchTensor, stretchTensor, dataAtPts, alphaU));
2725 fe_lhs->getOpPtrVector().push_back(new OpSpatialPhysical_du_dP(
2726 stretchTensor, piolaStress, dataAtPts, true));
2727 fe_lhs->getOpPtrVector().push_back(new OpSpatialPhysical_du_dBubble(
2728 stretchTensor, bubbleField, dataAtPts, true));
2729 fe_lhs->getOpPtrVector().push_back(new OpSpatialPhysical_du_domega(
2730 stretchTensor, rotAxis, dataAtPts,
2731 symmetrySelector == SYMMETRIC ? true : false));
2732 }
2733
2734 fe_lhs->getOpPtrVector().push_back(new OpSpatialEquilibrium_dw_dP(
2735 spatialL2Disp, piolaStress, dataAtPts, true));
2736 fe_lhs->getOpPtrVector().push_back(new OpSpatialEquilibrium_dw_dw(
2737 spatialL2Disp, spatialL2Disp, dataAtPts, alphaW, alphaRho));
2738
2739 fe_lhs->getOpPtrVector().push_back(new OpSpatialConsistency_dP_domega(
2740 piolaStress, rotAxis, dataAtPts,
2741 symmetrySelector == SYMMETRIC ? true : false));
2742 fe_lhs->getOpPtrVector().push_back(new OpSpatialConsistency_dBubble_domega(
2743 bubbleField, rotAxis, dataAtPts,
2744 symmetrySelector == SYMMETRIC ? true : false));
2745
2746 if (symmetrySelector > SYMMETRIC) {
2747 if (!noStretch) {
2748 fe_lhs->getOpPtrVector().push_back(new OpSpatialRotation_domega_du(
2749 rotAxis, stretchTensor, dataAtPts, false));
2750 }
2751 fe_lhs->getOpPtrVector().push_back(new OpSpatialRotation_domega_dP(
2752 rotAxis, piolaStress, dataAtPts, false));
2753 fe_lhs->getOpPtrVector().push_back(new OpSpatialRotation_domega_dBubble(
2754 rotAxis, bubbleField, dataAtPts, false));
2755 }
2756 fe_lhs->getOpPtrVector().push_back(new OpSpatialRotation_domega_domega(
2757 rotAxis, rotAxis, dataAtPts, alphaOmega));
2758
2759 // stabilise
2760 fe_lhs->getOpPtrVector().push_back(new OpAssembleVolumeStabilize());
2761
2762
2763 auto set_hybridisation = [&](auto &pip) {
2765
2766 using BoundaryEle =
2768 using EleOnSide =
2770 using SideEleOp = EleOnSide::UserDataOperator;
2771 using BdyEleOp = BoundaryEle::UserDataOperator;
2772
2773 // First: Iterate over skeleton FEs adjacent to Domain FEs
2774 // Note: BoundaryEle, i.e. uses skeleton interation rule
2775 auto op_loop_skeleton_side = new OpLoopSide<BoundaryEle>(
2776 mField, skeletonElement, SPACE_DIM - 1, Sev::noisy);
2777 // op_loop_skeleton_side->getSideFEPtr()->getRuleHook = FaceRule();
2778 op_loop_skeleton_side->getSideFEPtr()->getRuleHook = [](int, int, int) {
2779 return -1;
2780 };
2781 op_loop_skeleton_side->getSideFEPtr()->setRuleHook =
2782 SetIntegrationAtFrontFace(frontVertices, frontAdjEdges);
2783 CHKERR EshelbianPlasticity::
2784 AddHOOps<SPACE_DIM - 1, SPACE_DIM, SPACE_DIM>::add(
2785 op_loop_skeleton_side->getOpPtrVector(), {L2},
2786 materialH1Positions, frontAdjEdges);
2787
2788 // Second: Iterate over domain FEs adjacent to skelton, particularly one
2789 // domain element.
2790 auto broken_data_ptr =
2791 boost::make_shared<std::vector<BrokenBaseSideData>>();
2792 // Note: EleOnSide, i.e. uses on domain projected skeleton rule
2793 auto op_loop_domain_side = new OpBrokenLoopSide<EleOnSide>(
2794 mField, elementVolumeName, SPACE_DIM, Sev::noisy);
2795 op_loop_domain_side->getSideFEPtr()->getUserPolynomialBase() =
2796 boost::make_shared<CGGUserPolynomialBase>();
2797 CHKERR
2798 EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
2799 op_loop_domain_side->getOpPtrVector(), {HDIV, H1, L2},
2800 materialH1Positions, frontAdjEdges);
2801 op_loop_domain_side->getOpPtrVector().push_back(
2802 new OpGetBrokenBaseSideData<SideEleOp>(piolaStress, broken_data_ptr));
2803
2804 op_loop_skeleton_side->getOpPtrVector().push_back(op_loop_domain_side);
2806 GAUSS>::OpBrokenSpaceConstrain<SPACE_DIM>;
2807 op_loop_skeleton_side->getOpPtrVector().push_back(
2808 new OpC(hybridSpatialDisp, broken_data_ptr,
2809 boost::make_shared<double>(1.0), true, false));
2810
2811 pip.push_back(op_loop_skeleton_side);
2812
2814 };
2815
2816 auto set_contact = [&](auto &pip) {
2818
2819 using BoundaryEle =
2821 using EleOnSide =
2823 using SideEleOp = EleOnSide::UserDataOperator;
2824 using BdyEleOp = BoundaryEle::UserDataOperator;
2825
2826 // First: Iterate over skeleton FEs adjacent to Domain FEs
2827 // Note: BoundaryEle, i.e. uses skeleton interation rule
2828 auto op_loop_skeleton_side = new OpLoopSide<BoundaryEle>(
2829 mField, contactElement, SPACE_DIM - 1, Sev::noisy);
2830
2831 op_loop_skeleton_side->getSideFEPtr()->getRuleHook = rule_contact;
2832 op_loop_skeleton_side->getSideFEPtr()->setRuleHook = set_rule_contact;
2833 CHKERR EshelbianPlasticity::
2834 AddHOOps<SPACE_DIM - 1, SPACE_DIM, SPACE_DIM>::add(
2835 op_loop_skeleton_side->getOpPtrVector(), {L2},
2836 materialH1Positions, frontAdjEdges);
2837
2838 // Second: Iterate over domain FEs adjacent to skelton, particularly
2839 // one domain element.
2840 auto broken_data_ptr =
2841 boost::make_shared<std::vector<BrokenBaseSideData>>();
2842
2843 // Data storing contact fields
2844 auto contact_common_data_ptr =
2845 boost::make_shared<ContactOps::CommonData>();
2846
2847 auto add_ops_domain_side = [&](auto &pip) {
2849 // Note: EleOnSide, i.e. uses on domain projected skeleton rule
2850 auto op_loop_domain_side = new OpBrokenLoopSide<EleOnSide>(
2851 mField, elementVolumeName, SPACE_DIM, Sev::noisy);
2852 op_loop_domain_side->getSideFEPtr()->getUserPolynomialBase() =
2853 boost::make_shared<CGGUserPolynomialBase>();
2854 CHKERR
2855 EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
2856 op_loop_domain_side->getOpPtrVector(), {HDIV, H1, L2},
2857 materialH1Positions, frontAdjEdges);
2858 op_loop_domain_side->getOpPtrVector().push_back(
2859 new OpGetBrokenBaseSideData<SideEleOp>(piolaStress,
2860 broken_data_ptr));
2861 op_loop_domain_side->getOpPtrVector().push_back(
2863 piolaStress, contact_common_data_ptr->contactTractionPtr()));
2864 pip.push_back(op_loop_domain_side);
2866 };
2867
2868 auto add_ops_contact_lhs = [&](auto &pip) {
2870 pip.push_back(new OpCalculateVectorFieldValues<3>(
2871 contactDisp, contact_common_data_ptr->contactDispPtr()));
2872 auto u_h1_ptr = boost::make_shared<MatrixDouble>();
2873 pip.push_back(
2874 new OpCalculateVectorFieldValues<3>(spatialH1Disp, u_h1_ptr));
2875 pip.push_back(new OpTreeSearch(
2876 contactTreeRhs, contact_common_data_ptr, u_h1_ptr,
2877 get_range_from_block(mField, "CONTACT", SPACE_DIM - 1), nullptr,
2878 nullptr));
2879
2880 // get body id and SDF range
2881 auto contact_sfd_map_range_ptr =
2882 boost::make_shared<std::map<int, Range>>(
2883 get_body_range("CONTACT_SDF", SPACE_DIM - 1));
2884
2886 contactDisp, contactDisp, contact_common_data_ptr, contactTreeRhs,
2887 contact_sfd_map_range_ptr));
2888 pip.push_back(
2890 contactDisp, broken_data_ptr, contact_common_data_ptr,
2891 contactTreeRhs, contact_sfd_map_range_ptr));
2892 pip.push_back(
2894 broken_data_ptr, contactDisp, contact_common_data_ptr,
2895 contactTreeRhs));
2896
2898 };
2899
2900 // push ops to face/side pipeline
2901 CHKERR add_ops_domain_side(op_loop_skeleton_side->getOpPtrVector());
2902 CHKERR add_ops_contact_lhs(op_loop_skeleton_side->getOpPtrVector());
2903
2904 // Add skeleton to domain pipeline
2905 pip.push_back(op_loop_skeleton_side);
2906
2908 };
2909
2910 CHKERR set_hybridisation(fe_lhs->getOpPtrVector());
2911 CHKERR set_contact(fe_lhs->getOpPtrVector());
2912 }
2913
2914 if (add_material) {
2915 }
2916
2918}
2919
2921 const bool add_elastic, const bool add_material,
2922 boost::shared_ptr<FaceElementForcesAndSourcesCore> &fe_rhs,
2923 boost::shared_ptr<FaceElementForcesAndSourcesCore> &fe_lhs) {
2925
2926 fe_rhs = boost::make_shared<FaceElementForcesAndSourcesCore>(mField);
2927 fe_lhs = boost::make_shared<FaceElementForcesAndSourcesCore>(mField);
2928
2929 // set integration rule
2930 // fe_rhs->getRuleHook = [](int, int, int p) { return 2 * (p + 1); };
2931 // fe_lhs->getRuleHook = [](int, int, int p) { return 2 * (p + 1); };
2932 fe_rhs->getRuleHook = [](int, int, int) { return -1; };
2933 fe_lhs->getRuleHook = [](int, int, int) { return -1; };
2934 fe_rhs->setRuleHook = SetIntegrationAtFrontFace(frontVertices, frontAdjEdges);
2935 fe_lhs->setRuleHook = SetIntegrationAtFrontFace(frontVertices, frontAdjEdges);
2936
2937 CHKERR
2938 EshelbianPlasticity::AddHOOps<SPACE_DIM - 1, SPACE_DIM, SPACE_DIM>::add(
2939 fe_rhs->getOpPtrVector(), {L2}, materialH1Positions, frontAdjEdges);
2940 CHKERR
2941 EshelbianPlasticity::AddHOOps<SPACE_DIM - 1, SPACE_DIM, SPACE_DIM>::add(
2942 fe_lhs->getOpPtrVector(), {L2}, materialH1Positions, frontAdjEdges);
2943
2944 if (add_elastic) {
2945
2946 auto get_broken_op_side = [this](auto &pip) {
2947 using EleOnSide =
2949 using SideEleOp = EleOnSide::UserDataOperator;
2950 // Iterate over domain FEs adjacent to boundary.
2951 auto broken_data_ptr =
2952 boost::make_shared<std::vector<BrokenBaseSideData>>();
2953 // Note: EleOnSide, i.e. uses on domain projected skeleton rule
2954 auto op_loop_domain_side = new OpLoopSide<EleOnSide>(
2955 mField, elementVolumeName, SPACE_DIM, Sev::noisy);
2956 op_loop_domain_side->getSideFEPtr()->getUserPolynomialBase() =
2957 boost::make_shared<CGGUserPolynomialBase>();
2958 CHKERR
2959 EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
2960 op_loop_domain_side->getOpPtrVector(), {HDIV, H1, L2},
2961 materialH1Positions, frontAdjEdges);
2962 op_loop_domain_side->getOpPtrVector().push_back(
2963 new OpGetBrokenBaseSideData<SideEleOp>(piolaStress, broken_data_ptr));
2964 boost::shared_ptr<double> piola_scale_ptr(new double);
2965 op_loop_domain_side->getOpPtrVector().push_back(
2966 physicalEquations->returnOpSetScale(piola_scale_ptr,
2967 physicalEquations));
2968
2969 auto piola_stress_mat_ptr = boost::make_shared<MatrixDouble>();
2970 op_loop_domain_side->getOpPtrVector().push_back(
2971 new OpCalculateHVecTensorField<3, 3>(piolaStress,
2972 piola_stress_mat_ptr));
2973 pip.push_back(op_loop_domain_side);
2974 return std::make_tuple(broken_data_ptr, piola_scale_ptr,
2975 piola_stress_mat_ptr);
2976 };
2977
2978 auto set_rhs = [&]() {
2980
2981 auto [broken_data_ptr, piola_scale_ptr, piola_stress_mat_ptr] =
2982 get_broken_op_side(fe_rhs->getOpPtrVector());
2983
2984 fe_rhs->getOpPtrVector().push_back(
2985 new OpDispBc(broken_data_ptr, bcSpatialDispVecPtr, timeScaleMap));
2986 fe_rhs->getOpPtrVector().push_back(new OpAnalyticalDispBc(
2987 broken_data_ptr, bcSpatialAnalyticalDisplacementVecPtr,
2988 timeScaleMap));
2989 fe_rhs->getOpPtrVector().push_back(new OpRotationBc(
2990 broken_data_ptr, bcSpatialRotationVecPtr, timeScaleMap));
2991
2992 fe_rhs->getOpPtrVector().push_back(
2993 new OpBrokenTractionBc(hybridSpatialDisp, bcSpatialTractionVecPtr,
2994 piola_scale_ptr, timeScaleMap));
2995 auto hybrid_grad_ptr = boost::make_shared<MatrixDouble>();
2996 // if you push gradient of L2 base to physical element, it will not work.
2997 fe_rhs->getOpPtrVector().push_back(
2999 hybridSpatialDisp, hybrid_grad_ptr));
3000 fe_rhs->getOpPtrVector().push_back(new OpBrokenPressureBc(
3001 hybridSpatialDisp, bcSpatialPressureVecPtr, piola_scale_ptr,
3002 hybrid_grad_ptr, timeScaleMap));
3003 fe_rhs->getOpPtrVector().push_back(new OpBrokenAnalyticalTractionBc(
3004 hybridSpatialDisp, bcSpatialAnalyticalTractionVecPtr, piola_scale_ptr,
3005 timeScaleMap));
3006
3007 auto hybrid_ptr = boost::make_shared<MatrixDouble>();
3008 fe_rhs->getOpPtrVector().push_back(
3009 new OpCalculateVectorFieldValues<SPACE_DIM>(hybridSpatialDisp,
3010 hybrid_ptr));
3011 fe_rhs->getOpPtrVector().push_back(new OpNormalDispRhsBc(
3012 hybridSpatialDisp, hybrid_ptr, piola_stress_mat_ptr,
3013 bcSpatialNormalDisplacementVecPtr, timeScaleMap));
3014
3015 auto get_normal_disp_bc_faces = [&]() {
3016 auto faces =
3017 get_range_from_block(mField, "NORMAL_DISPLACEMENT", SPACE_DIM - 1);
3018 return boost::make_shared<Range>(faces);
3019 };
3020
3021 using BoundaryEle =
3023 using BdyEleOp = BoundaryEle::UserDataOperator;
3025 GAUSS>::OpBrokenSpaceConstrainDFlux<SPACE_DIM>;
3026 fe_rhs->getOpPtrVector().push_back(new OpC_dBroken(
3027 broken_data_ptr, hybrid_ptr, boost::make_shared<double>(1.0),
3028 get_normal_disp_bc_faces()));
3029
3031 };
3032
3033 auto set_lhs = [&]() {
3035
3036 auto [broken_data_ptr, piola_scale_ptr, piola_stress_mat_ptr] =
3037 get_broken_op_side(fe_lhs->getOpPtrVector());
3038
3039 fe_lhs->getOpPtrVector().push_back(new OpNormalDispLhsBc_dU(
3040 hybridSpatialDisp, bcSpatialNormalDisplacementVecPtr, timeScaleMap));
3041 fe_lhs->getOpPtrVector().push_back(new OpNormalDispLhsBc_dP(
3042 hybridSpatialDisp, broken_data_ptr, bcSpatialNormalDisplacementVecPtr,
3043 timeScaleMap));
3044
3045 auto hybrid_grad_ptr = boost::make_shared<MatrixDouble>();
3046 // if you push gradient of L2 base to physical element, it will not work.
3047 fe_rhs->getOpPtrVector().push_back(
3049 hybridSpatialDisp, hybrid_grad_ptr));
3050 fe_lhs->getOpPtrVector().push_back(new OpBrokenPressureBcLhs_dU(
3051 hybridSpatialDisp, bcSpatialPressureVecPtr, hybrid_grad_ptr,
3052 timeScaleMap));
3053
3054 auto get_normal_disp_bc_faces = [&]() {
3055 auto faces =
3056 get_range_from_block(mField, "NORMAL_DISPLACEMENT", SPACE_DIM - 1);
3057 return boost::make_shared<Range>(faces);
3058 };
3059
3060 using BoundaryEle =
3062 using BdyEleOp = BoundaryEle::UserDataOperator;
3064 GAUSS>::OpBrokenSpaceConstrain<SPACE_DIM>;
3065 fe_lhs->getOpPtrVector().push_back(new OpC(
3066 hybridSpatialDisp, broken_data_ptr, boost::make_shared<double>(1.0),
3067 true, true, get_normal_disp_bc_faces()));
3068
3070 };
3071
3072 CHKERR set_rhs();
3073 CHKERR set_lhs();
3074 }
3075
3077}
3078
3080
3081 boost::shared_ptr<ContactTree> &fe_contact_tree
3082
3083) {
3085
3086 /** Contact requires that body is marked */
3087 auto get_body_range = [this](auto name, int dim, auto sev) {
3088 std::map<int, Range> map;
3089
3090 for (auto m_ptr :
3091 mField.getInterface<MeshsetsManager>()->getCubitMeshsetPtr(std::regex(
3092
3093 (boost::format("%s(.*)") % name).str()
3094
3095 ))
3096
3097 ) {
3098 Range ents;
3099 CHK_MOAB_THROW(m_ptr->getMeshsetIdEntitiesByDimension(mField.get_moab(),
3100 dim, ents, true),
3101 "by dim");
3102 map[m_ptr->getMeshsetId()] = ents;
3103 MOFEM_LOG("EPSYNC", sev) << "Meshset: " << m_ptr->getMeshsetId() << " "
3104 << ents.size() << " entities";
3105 }
3106
3107 MOFEM_LOG_SEVERITY_SYNC(mField.get_comm(), sev);
3108 return map;
3109 };
3110
3111 auto get_map_skin = [this](auto &&map) {
3112 ParallelComm *pcomm =
3113 ParallelComm::get_pcomm(&mField.get_moab(), MYPCOMM_INDEX);
3114
3115 Skinner skin(&mField.get_moab());
3116 for (auto &m : map) {
3117 Range skin_faces;
3118 CHKERR skin.find_skin(0, m.second, false, skin_faces);
3119 CHK_MOAB_THROW(pcomm->filter_pstatus(skin_faces,
3120 PSTATUS_SHARED | PSTATUS_MULTISHARED,
3121 PSTATUS_NOT, -1, nullptr),
3122 "filter");
3123 m.second.swap(skin_faces);
3124 }
3125 return map;
3126 };
3127
3128 /* The above code is written in C++ and it appears to be defining and using
3129 various operations on boundary elements and side elements. */
3131 using BoundaryEleOp = BoundaryEle::UserDataOperator;
3132
3133 auto contact_common_data_ptr = boost::make_shared<ContactOps::CommonData>();
3134
3135 auto calcs_side_traction = [&](auto &pip) {
3137 using EleOnSide =
3139 using SideEleOp = EleOnSide::UserDataOperator;
3140 auto op_loop_domain_side = new OpLoopSide<EleOnSide>(
3141 mField, elementVolumeName, SPACE_DIM, Sev::noisy);
3142 op_loop_domain_side->getSideFEPtr()->getUserPolynomialBase() =
3143 boost::make_shared<CGGUserPolynomialBase>();
3144 EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
3145 op_loop_domain_side->getOpPtrVector(), {HDIV, H1, L2},
3146 materialH1Positions, frontAdjEdges);
3147 op_loop_domain_side->getOpPtrVector().push_back(
3149 piolaStress, contact_common_data_ptr->contactTractionPtr(),
3150 boost::make_shared<double>(1.0)));
3151 pip.push_back(op_loop_domain_side);
3153 };
3154
3155 auto add_contact_three = [&]() {
3157 auto tree_moab_ptr = boost::make_shared<moab::Core>();
3158 fe_contact_tree = boost::make_shared<ContactTree>(
3159 mField, tree_moab_ptr, spaceOrder,
3160 get_body_range("CONTACT", SPACE_DIM - 1, Sev::inform));
3161 fe_contact_tree->getOpPtrVector().push_back(
3163 contactDisp, contact_common_data_ptr->contactDispPtr()));
3164 CHKERR calcs_side_traction(fe_contact_tree->getOpPtrVector());
3165 auto u_h1_ptr = boost::make_shared<MatrixDouble>();
3166 fe_contact_tree->getOpPtrVector().push_back(
3167 new OpCalculateVectorFieldValues<3>(spatialH1Disp, u_h1_ptr));
3168 fe_contact_tree->getOpPtrVector().push_back(
3169 new OpMoveNode(fe_contact_tree, contact_common_data_ptr, u_h1_ptr));
3171 };
3172
3173 CHKERR add_contact_three();
3174
3176}
3177
3180
3181 // Add contact operators. Note that only for rhs. THe lhs is assembled with
3182 // volume element, to enable schur complement evaluation.
3183 CHKERR setContactElementRhsOps(contactTreeRhs);
3184
3185 CHKERR setVolumeElementOps(tag, true, false, elasticFeRhs, elasticFeLhs);
3186 CHKERR setFaceElementOps(true, false, elasticBcRhs, elasticBcLhs);
3187
3188 auto adj_cache =
3189 boost::make_shared<ForcesAndSourcesCore::UserDataOperator::AdjCache>();
3190
3191 auto get_op_contact_bc = [&]() {
3193 auto op_loop_side = new OpLoopSide<SideEle>(
3194 mField, contactElement, SPACE_DIM - 1, Sev::noisy, adj_cache);
3195 return op_loop_side;
3196 };
3197
3199}
3200
3203 boost::shared_ptr<FEMethod> null;
3204
3205 if (std::abs(alphaRho) > std::numeric_limits<double>::epsilon()) {
3206
3207 CHKERR DMMoFEMTSSetI2Function(dm, elementVolumeName, elasticFeRhs, null,
3208 null);
3209 CHKERR DMMoFEMTSSetI2Function(dm, naturalBcElement, elasticBcRhs, null,
3210 null);
3211 CHKERR DMMoFEMTSSetI2Jacobian(dm, elementVolumeName, elasticFeLhs, null,
3212 null);
3213 CHKERR DMMoFEMTSSetI2Jacobian(dm, naturalBcElement, elasticBcLhs, null,
3214 null);
3215
3216 } else {
3217 CHKERR DMMoFEMTSSetIFunction(dm, elementVolumeName, elasticFeRhs, null,
3218 null);
3219 CHKERR DMMoFEMTSSetIFunction(dm, naturalBcElement, elasticBcRhs, null,
3220 null);
3221 CHKERR DMMoFEMTSSetIJacobian(dm, elementVolumeName, elasticFeLhs, null,
3222 null);
3223 CHKERR DMMoFEMTSSetIJacobian(dm, naturalBcElement, elasticBcLhs, null,
3224 null);
3225 }
3226
3228}
3229
3231#include "impl/SetUpSchurImpl.cpp"
3233
3235
3236 inline static auto setup(EshelbianCore *ep_ptr, TS ts, Vec x,
3237 bool set_ts_monitor) {
3238
3239#ifdef ENABLE_PYTHON_BINDING
3240 auto setup_sdf = [&]() {
3241 boost::shared_ptr<ContactOps::SDFPython> sdf_python_ptr;
3242
3243 auto file_exists = [](std::string myfile) {
3244 std::ifstream file(myfile.c_str());
3245 if (file) {
3246 return true;
3247 }
3248 return false;
3249 };
3250
3251 char sdf_file_name[255] = "sdf.py";
3252 CHKERR PetscOptionsGetString(PETSC_NULLPTR, PETSC_NULLPTR, "-sdf_file",
3253 sdf_file_name, 255, PETSC_NULLPTR);
3254
3255 if (file_exists(sdf_file_name)) {
3256 MOFEM_LOG("EP", Sev::inform) << sdf_file_name << " file found";
3257 sdf_python_ptr = boost::make_shared<ContactOps::SDFPython>();
3258 CHKERR sdf_python_ptr->sdfInit(sdf_file_name);
3259 ContactOps::sdfPythonWeakPtr = sdf_python_ptr;
3260 MOFEM_LOG("EP", Sev::inform) << "SdfPython initialized";
3261 } else {
3262 MOFEM_LOG("EP", Sev::warning) << sdf_file_name << " file NOT found";
3263 }
3264 return sdf_python_ptr;
3265 };
3266 auto sdf_python_ptr = setup_sdf();
3267#endif
3268
3269 auto setup_ts_monitor = [&]() {
3270 boost::shared_ptr<TsCtx> ts_ctx;
3272 if (set_ts_monitor) {
3273 CHKERR TSMonitorSet(ts, TsMonitorSet, ts_ctx.get(), PETSC_NULLPTR);
3274 auto monitor_ptr = boost::make_shared<EshelbianMonitor>(*ep_ptr);
3275 ts_ctx->getLoopsMonitor().push_back(
3276 TsCtx::PairNameFEMethodPtr(ep_ptr->elementVolumeName, monitor_ptr));
3277 }
3278 MOFEM_LOG("EP", Sev::inform) << "TS monitor setup";
3279 return std::make_tuple(ts_ctx);
3280 };
3281
3282 auto setup_snes_monitor = [&]() {
3284 SNES snes;
3285 CHKERR TSGetSNES(ts, &snes);
3286 auto snes_ctx = getDMSnesCtx(ep_ptr->dmElastic);
3287 CHKERR SNESMonitorSet(snes,
3288 (MoFEMErrorCode (*)(SNES, PetscInt, PetscReal,
3289 void *))MoFEMSNESMonitorEnergy,
3290 (void *)(snes_ctx.get()), PETSC_NULLPTR);
3291 MOFEM_LOG("EP", Sev::inform) << "SNES monitor setup";
3293 };
3294
3295 auto setup_snes_conergence_test = [&]() {
3297
3298 auto snes_convergence_test = [](SNES snes, PetscInt it, PetscReal xnorm,
3299 PetscReal snorm, PetscReal fnorm,
3300 SNESConvergedReason *reason, void *cctx) {
3302 EshelbianCore *ep_ptr = (EshelbianCore *)cctx;
3303 CHKERR SNESConvergedDefault(snes, it, xnorm, snorm, fnorm, reason,
3304 PETSC_NULLPTR);
3305
3306 Vec x_update, r;
3307 CHKERR SNESGetSolutionUpdate(snes, &x_update);
3308 CHKERR SNESGetFunction(snes, &r, PETSC_NULLPTR, PETSC_NULLPTR);
3309
3310 // *reason = SNES_CONVERGED_ITERATING;
3311 // if (!it) {
3312 // /* set parameter for default relative tolerance convergence test */
3313 // snes->ttol = fnorm * snes->rtol;
3314 // snes->rnorm0 = fnorm;
3315 // }
3316 // if (PetscIsInfOrNanReal(fnorm)) {
3317 // MOFEM_LOG("EP", Sev::error)
3318 // << "SNES convergence test: function norm is NaN";
3319 // *reason = SNES_DIVERGED_FNORM_NAN;
3320 // } else if (fnorm < snes->abstol && (it || !snes->forceiteration)) {
3321 // MOFEM_LOG("EP", Sev::inform)
3322 // << "SNES convergence test: Converged due to function norm "
3323 // << std::setw(14) << std::setprecision(12) << std::scientific
3324 // << fnorm << " < " << std::setw(14) << std::setprecision(12)
3325 // << std::scientific << snes->abstol;
3326
3327 // PetscCall(PetscInfo(
3328 // snes, "Converged due to function norm %14.12e < %14.12e\n",
3329 // (double)fnorm, (double)snes->abstol));
3330 // *reason = SNES_CONVERGED_FNORM_ABS;
3331 // } else if (snes->nfuncs >= snes->max_funcs && snes->max_funcs >= 0) {
3332 // PetscCall(PetscInfo(
3333 // snes,
3334 // "Exceeded maximum number of function evaluations: %" PetscInt_FMT
3335 // " > %" PetscInt_FMT "\n",
3336 // snes->nfuncs, snes->max_funcs));
3337 // *reason = SNES_DIVERGED_FUNCTION_COUNT;
3338 // }
3339
3340 // if (it && !*reason) {
3341 // if (fnorm <= snes->ttol) {
3342 // PetscCall(PetscInfo(snes,
3343 // "Converged due to function norm %14.12e < "
3344 // "%14.12e (relative tolerance)\n",
3345 // (double)fnorm, (double)snes->ttol));
3346 // *reason = SNES_CONVERGED_FNORM_RELATIVE;
3347 // } else if (snorm < snes->stol * xnorm) {
3348 // PetscCall(PetscInfo(snes,
3349 // "Converged due to small update length: %14.12e "
3350 // "< %14.12e * %14.12e\n",
3351 // (double)snorm, (double)snes->stol,
3352 // (double)xnorm));
3353 // *reason = SNES_CONVERGED_SNORM_RELATIVE;
3354 // } else if (snes->divtol != PETSC_UNLIMITED &&
3355 // (fnorm > snes->divtol * snes->rnorm0)) {
3356 // PetscCall(PetscInfo(snes,
3357 // "Diverged due to increase in function norm: "
3358 // "%14.12e > %14.12e * %14.12e\n",
3359 // (double)fnorm, (double)snes->divtol,
3360 // (double)snes->rnorm0));
3361 // *reason = SNES_DIVERGED_DTOL;
3362 // }
3363 // }
3364
3366 };
3367
3368 // SNES snes;
3369 // CHKERR TSGetSNES(ts, &snes);
3370 // CHKERR SNESSetConvergenceTest(snes, snes_convergence_test, ep_ptr,
3371 // PETSC_NULLPTR);
3372 // MOFEM_LOG("EP", Sev::inform) << "SNES convergence test setup";
3374 };
3375
3376 auto setup_section = [&]() {
3377 PetscSection section_raw;
3378 CHKERR DMGetSection(ep_ptr->dmElastic, &section_raw);
3379 int num_fields;
3380 CHKERR PetscSectionGetNumFields(section_raw, &num_fields);
3381 for (int ff = 0; ff != num_fields; ff++) {
3382 const char *field_name;
3383 CHKERR PetscSectionGetFieldName(section_raw, ff, &field_name);
3384 MOFEM_LOG_C("EP", Sev::inform, "Field %d name %s", ff, field_name);
3385 }
3386 return section_raw;
3387 };
3388
3389 auto set_vector_on_mesh = [&]() {
3391 CHKERR DMoFEMMeshToLocalVector(ep_ptr->dmElastic, x, INSERT_VALUES,
3392 SCATTER_FORWARD);
3393 CHKERR VecGhostUpdateBegin(x, INSERT_VALUES, SCATTER_FORWARD);
3394 CHKERR VecGhostUpdateEnd(x, INSERT_VALUES, SCATTER_FORWARD);
3395 MOFEM_LOG("EP", Sev::inform) << "Vector set on mesh";
3397 };
3398
3399 auto setup_schur_block_solver = [&]() {
3400 MOFEM_LOG("EP", Sev::inform) << "Setting up Schur block solver";
3401 CHKERR TSAppendOptionsPrefix(ts, "elastic_");
3402 CHKERR TSSetFromOptions(ts);
3403 CHKERR TSSetDM(ts, ep_ptr->dmElastic);
3404 // Adding field split solver
3405 boost::shared_ptr<EshelbianCore::SetUpSchur> schur_ptr;
3406 if constexpr (A == AssemblyType::BLOCK_MAT) {
3407 schur_ptr =
3409 CHK_THROW_MESSAGE(schur_ptr->setUp(ts), "setup schur");
3410 }
3411 MOFEM_LOG("EP", Sev::inform) << "Setting up Schur block solver done";
3412 return schur_ptr;
3413 };
3414
3415 // Warning: sequence of construction is not guaranteed for tuple. You have
3416 // to enforce order by proper packaging.
3417
3418#ifdef ENABLE_PYTHON_BINDING
3419 return std::make_tuple(setup_sdf(), setup_ts_monitor(),
3420 setup_snes_monitor(), setup_snes_conergence_test(),
3421 setup_section(), set_vector_on_mesh(),
3422 setup_schur_block_solver());
3423#else
3424 return std::make_tuple(setup_ts_monitor(), setup_snes_monitor(),
3425 setup_snes_conergence_test(), setup_section(),
3426 set_vector_on_mesh(), setup_schur_block_solver());
3427#endif
3428 }
3429};
3430
3433
3434 PetscBool debug_model = PETSC_FALSE;
3435 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-debug_model", &debug_model,
3436 PETSC_NULLPTR);
3437
3438 if (debug_model == PETSC_TRUE) {
3439 auto ts_ctx_ptr = getDMTsCtx(dmElastic);
3440 auto post_proc = [&](TS ts, PetscReal t, Vec u, Vec u_t, Vec u_tt, Vec F,
3441 void *ctx) {
3443
3444 SNES snes;
3445 CHKERR TSGetSNES(ts, &snes);
3446 int it;
3447 CHKERR SNESGetIterationNumber(snes, &it);
3448 std::string file_name = "snes_iteration_" + std::to_string(it) + ".h5m";
3449 CHKERR postProcessResults(1, file_name, F, u_t);
3450 std::string file_skel_name =
3451 "snes_iteration_skel_" + std::to_string(it) + ".h5m";
3452
3453 auto get_material_force_tag = [&]() {
3454 auto &moab = mField.get_moab();
3455 Tag tag;
3456 CHK_MOAB_THROW(moab.tag_get_handle("MaterialForce", tag),
3457 "can't get tag");
3458 return tag;
3459 };
3460
3461 CHKERR calculateFaceMaterialForce(1, ts);
3462 CHKERR postProcessSkeletonResults(1, file_skel_name, F,
3463 {get_material_force_tag()});
3464
3466 };
3467 ts_ctx_ptr->tsDebugHook = post_proc;
3468 }
3469
3470 auto storage = solve_elastic_setup::setup(this, ts, x, true);
3471
3472 if (std::abs(alphaRho) > std::numeric_limits<double>::epsilon()) {
3473 Vec xx;
3474 CHKERR VecDuplicate(x, &xx);
3475 CHKERR VecZeroEntries(xx);
3476 CHKERR TS2SetSolution(ts, x, xx);
3477 CHKERR VecDestroy(&xx);
3478 } else {
3479 CHKERR TSSetSolution(ts, x);
3480 }
3481
3482 TetPolynomialBase::switchCacheBaseOn<HDIV>(
3483 {elasticFeLhs.get(), elasticFeRhs.get()});
3484 CHKERR TSSetUp(ts);
3485 CHKERR TSSetPreStep(ts, TSElasticPostStep::preStepFun);
3486 CHKERR TSSetPostStep(ts, TSElasticPostStep::postStepFun);
3488 CHKERR TSSolve(ts, PETSC_NULLPTR);
3490 TetPolynomialBase::switchCacheBaseOff<HDIV>(
3491 {elasticFeLhs.get(), elasticFeRhs.get()});
3492
3493 SNES snes;
3494 CHKERR TSGetSNES(ts, &snes);
3495 int lin_solver_iterations;
3496 CHKERR SNESGetLinearSolveIterations(snes, &lin_solver_iterations);
3497 MOFEM_LOG("EP", Sev::inform)
3498 << "Number of linear solver iterations " << lin_solver_iterations;
3499
3500 PetscBool test_cook_flg = PETSC_FALSE;
3501 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-test_cook", &test_cook_flg,
3502 PETSC_NULLPTR);
3503 if (test_cook_flg) {
3504 constexpr int expected_lin_solver_iterations = 11;
3505 if (lin_solver_iterations > expected_lin_solver_iterations)
3506 SETERRQ(
3507 PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
3508 "Expected number of iterations is different than expected %d > %d",
3509 lin_solver_iterations, expected_lin_solver_iterations);
3510 }
3511
3512 PetscBool test_sslv116_flag = PETSC_FALSE;
3513 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-test_sslv116",
3514 &test_sslv116_flag, PETSC_NULLPTR);
3515
3516 if (test_sslv116_flag) {
3517 double max_val = 0.0;
3518 double min_val = 0.0;
3519 auto field_min_max = [&](boost::shared_ptr<FieldEntity> ent_ptr) {
3521 auto ent_type = ent_ptr->getEntType();
3522 if (ent_type == MBVERTEX) {
3523 max_val = std::max(ent_ptr->getEntFieldData()[SPACE_DIM - 1], max_val);
3524 min_val = std::min(ent_ptr->getEntFieldData()[SPACE_DIM - 1], min_val);
3525 }
3527 };
3528 CHKERR mField.getInterface<FieldBlas>()->fieldLambdaOnEntities(
3529 field_min_max, spatialH1Disp);
3530
3531 double global_max_val = 0.0;
3532 double global_min_val = 0.0;
3533 MPI_Allreduce(&max_val, &global_max_val, 1, MPI_DOUBLE, MPI_MAX,
3534 mField.get_comm());
3535 MPI_Allreduce(&min_val, &global_min_val, 1, MPI_DOUBLE, MPI_MIN,
3536 mField.get_comm());
3537 MOFEM_LOG("EP", Sev::inform)
3538 << "Max " << spatialH1Disp << " value: " << global_max_val;
3539 MOFEM_LOG("EP", Sev::inform)
3540 << "Min " << spatialH1Disp << " value: " << global_min_val;
3541
3542 double ref_max_val = 0.00767;
3543 double ref_min_val = -0.00329;
3544 if (std::abs(global_max_val - ref_max_val) > 1e-5) {
3545 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
3546 "Incorrect max value of the displacement field: %f != %f",
3547 global_max_val, ref_max_val);
3548 }
3549 if (std::abs(global_min_val - ref_min_val) > 4e-5) {
3550 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
3551 "Incorrect min value of the displacement field: %f != %f",
3552 global_min_val, ref_min_val);
3553 }
3554 }
3555
3556 CHKERR gettingNorms();
3557
3559}
3560
3563
3564 auto storage = solve_elastic_setup::setup(this, ts, x, false);
3565
3566 double final_time = 1;
3567 double delta_time = 0.1;
3568 int max_it = 10;
3569 PetscBool ts_h1_update = PETSC_FALSE;
3570
3571 PetscOptionsBegin(PETSC_COMM_WORLD, "", "Dynamic Relaxation Options",
3572 "none");
3573
3574 CHKERR PetscOptionsScalar("-dynamic_final_time",
3575 "dynamic relaxation final time", "", final_time,
3576 &final_time, PETSC_NULLPTR);
3577 CHKERR PetscOptionsScalar("-dynamic_delta_time",
3578 "dynamic relaxation final time", "", delta_time,
3579 &delta_time, PETSC_NULLPTR);
3580 CHKERR PetscOptionsInt("-dynamic_max_it", "dynamic relaxation iterations", "",
3581 max_it, &max_it, PETSC_NULLPTR);
3582 CHKERR PetscOptionsBool("-dynamic_h1_update", "update each ts step", "",
3583 ts_h1_update, &ts_h1_update, PETSC_NULLPTR);
3584
3585 PetscOptionsEnd();
3586
3587 auto setup_ts_monitor = [&]() {
3588 auto monitor_ptr = boost::make_shared<EshelbianMonitor>(*this);
3589 return monitor_ptr;
3590 };
3591 auto monitor_ptr = setup_ts_monitor();
3592
3593 TetPolynomialBase::switchCacheBaseOn<HDIV>(
3594 {elasticFeLhs.get(), elasticFeRhs.get()});
3595 CHKERR TSSetUp(ts);
3597
3598 double ts_delta_time;
3599 CHKERR TSGetTimeStep(ts, &ts_delta_time);
3600
3601 if (ts_h1_update) {
3602 CHKERR TSSetPreStep(ts, TSElasticPostStep::preStepFun);
3603 CHKERR TSSetPostStep(ts, TSElasticPostStep::postStepFun);
3604 }
3605
3608
3609 dynamicTime = 0;
3610 dynamicStep = 0;
3611 monitor_ptr->ts_u = PETSC_NULLPTR;
3612 monitor_ptr->ts_t = dynamicTime;
3613 monitor_ptr->ts_step = dynamicStep;
3614 CHKERR DMoFEMLoopFiniteElements(dmElastic, elementVolumeName, monitor_ptr);
3615 MOFEM_LOG("EP", Sev::inform) << "IT " << dynamicStep << " Time "
3616 << dynamicTime << " delta time " << delta_time;
3617 dynamicTime += delta_time;
3618 ++dynamicStep;
3619
3620 for (; dynamicTime < final_time; dynamicTime += delta_time) {
3621 MOFEM_LOG("EP", Sev::inform) << "IT " << dynamicStep << " Time "
3622 << dynamicTime << " delta time " << delta_time;
3623
3624 CHKERR TSSetStepNumber(ts, 0);
3625 CHKERR TSSetTime(ts, 0);
3626 CHKERR TSSetTimeStep(ts, ts_delta_time);
3627 if (!ts_h1_update) {
3629 }
3630 CHKERR TSSolve(ts, PETSC_NULLPTR);
3631 if (!ts_h1_update) {
3633 }
3634
3635 monitor_ptr->ts_u = PETSC_NULLPTR;
3636 monitor_ptr->ts_t = dynamicTime;
3637 monitor_ptr->ts_step = dynamicStep;
3638 CHKERR DMoFEMLoopFiniteElements(dmElastic, elementVolumeName, monitor_ptr);
3639
3640 ++dynamicStep;
3641 if (dynamicStep > max_it)
3642 break;
3643 }
3644
3646 TetPolynomialBase::switchCacheBaseOff<HDIV>(
3647 {elasticFeLhs.get(), elasticFeRhs.get()});
3648
3650}
3651
3654
3655 auto set_block = [&](auto name, int dim) {
3656 std::map<int, Range> map;
3657 auto set_tag_impl = [&](auto name) {
3659 auto mesh_mng = mField.getInterface<MeshsetsManager>();
3660 auto bcs = mesh_mng->getCubitMeshsetPtr(
3661
3662 std::regex((boost::format("%s(.*)") % name).str())
3663
3664 );
3665 for (auto bc : bcs) {
3666 Range r;
3667 CHKERR bc->getMeshsetIdEntitiesByDimension(mField.get_moab(), dim, r,
3668 true);
3669 map[bc->getMeshsetId()] = r;
3670 }
3672 };
3673
3674 CHKERR set_tag_impl(name);
3675
3676 return std::make_pair(name, map);
3677 };
3678
3679 auto set_skin = [&](auto &&map) {
3680 for (auto &m : map.second) {
3681 auto s = filter_true_skin(mField, get_skin(mField, m.second));
3682 m.second.swap(s);
3683 }
3684 return map;
3685 };
3686
3687 auto set_tag = [&](auto &&map) {
3688 Tag th;
3689 auto name = map.first;
3690 int def_val[] = {-1};
3692 mField.get_moab().tag_get_handle(name, 1, MB_TYPE_INTEGER, th,
3693 MB_TAG_SPARSE | MB_TAG_CREAT, def_val),
3694 "create tag");
3695 for (auto &m : map.second) {
3696 int id = m.first;
3697 CHK_MOAB_THROW(mField.get_moab().tag_clear_data(th, m.second, &id),
3698 "clear tag");
3699 }
3700 return th;
3701 };
3702
3703 listTagsToTransfer.push_back(set_tag(set_skin(set_block("BODY", 3))));
3704 listTagsToTransfer.push_back(set_tag(set_skin(set_block("MAT_ELASTIC", 3))));
3705 listTagsToTransfer.push_back(
3706 set_tag(set_skin(set_block("MAT_NEOHOOKEAN", 3))));
3707 listTagsToTransfer.push_back(set_tag(set_block("CONTACT", 2)));
3708
3710}
3711
3713EshelbianCore::postProcessResults(const int tag, const std::string file,
3714 Vec f_residual, Vec var_vector,
3715 std::vector<Tag> tags_to_transfer) {
3717
3718 // mark crack surface
3719 if (crackingOn) {
3720 Tag th;
3721 rval = mField.get_moab().tag_get_handle("CRACK", th);
3722 if (rval == MB_SUCCESS) {
3723 CHKERR mField.get_moab().tag_delete(th);
3724 }
3725 int def_val[] = {0};
3726 CHKERR mField.get_moab().tag_get_handle(
3727 "CRACK", 1, MB_TYPE_INTEGER, th, MB_TAG_SPARSE | MB_TAG_CREAT, def_val);
3728 int mark[] = {1};
3729 CHKERR mField.get_moab().tag_clear_data(th, *crackFaces, mark);
3730 tags_to_transfer.push_back(th);
3731
3732 auto get_tag = [&](auto name, auto dim) {
3733 auto &mob = mField.get_moab();
3734 Tag tag;
3735 double def_val[] = {0., 0., 0.};
3736 CHK_MOAB_THROW(mob.tag_get_handle(name, dim, MB_TYPE_DOUBLE, tag,
3737 MB_TAG_CREAT | MB_TAG_SPARSE, def_val),
3738 "create tag");
3739 return tag;
3740 };
3741
3742 tags_to_transfer.push_back(get_tag("MaterialForce", 3));
3743 // tags_to_transfer.push_back(get_tag("GriffithForce", 1));
3744 }
3745
3746 // add tags to transfer
3747 for (auto t : listTagsToTransfer) {
3748 tags_to_transfer.push_back(t);
3749 }
3750
3751 if (!dataAtPts) {
3752 dataAtPts =
3753 boost::shared_ptr<DataAtIntegrationPts>(new DataAtIntegrationPts());
3754 }
3755
3756 struct exclude_sdf {
3757 exclude_sdf(Range &&r) : map(r) {}
3758 bool operator()(FEMethod *fe_method_ptr) {
3759 auto ent = fe_method_ptr->getFEEntityHandle();
3760 if (map.find(ent) != map.end()) {
3761 return false;
3762 }
3763 return true;
3764 }
3765
3766 private:
3767 Range map;
3768 };
3769
3770 contactTreeRhs->exeTestHook =
3771 exclude_sdf(get_range_from_block(mField, "CONTACT_SDF", SPACE_DIM - 1));
3772
3773 CHKERR DMoFEMLoopFiniteElements(dM, contactElement, contactTreeRhs);
3774
3775 auto get_post_proc = [&](auto &post_proc_mesh, auto sense) {
3777 auto post_proc_ptr =
3778 boost::make_shared<PostProcBrokenMeshInMoabBaseCont<FaceEle>>(
3779 mField, post_proc_mesh);
3780 EshelbianPlasticity::AddHOOps<SPACE_DIM - 1, SPACE_DIM, SPACE_DIM>::add(
3781 post_proc_ptr->getOpPtrVector(), {L2}, materialH1Positions,
3782 frontAdjEdges);
3783
3784 auto domain_ops = [&](auto &fe, int sense) {
3786 fe.getUserPolynomialBase() =
3787 boost::shared_ptr<BaseFunction>(new CGGUserPolynomialBase());
3788 EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
3789 fe.getOpPtrVector(), {HDIV, H1, L2}, materialH1Positions,
3790 frontAdjEdges);
3791 auto piola_scale_ptr = boost::make_shared<double>(1.0);
3792 fe.getOpPtrVector().push_back(physicalEquations->returnOpSetScale(
3793 piola_scale_ptr, physicalEquations));
3794 fe.getOpPtrVector().push_back(new OpCalculateHVecTensorField<3, 3>(
3795 piolaStress, dataAtPts->getApproxPAtPts(), piola_scale_ptr));
3796 fe.getOpPtrVector().push_back(new OpCalculateHTensorTensorField<3, 3>(
3797 bubbleField, dataAtPts->getApproxPAtPts(), piola_scale_ptr,
3798 SmartPetscObj<Vec>(), MBMAXTYPE));
3799 if (noStretch) {
3800 fe.getOpPtrVector().push_back(
3801 physicalEquations->returnOpCalculateStretchFromStress(
3802 dataAtPts, physicalEquations));
3803 } else {
3804 fe.getOpPtrVector().push_back(
3806 stretchTensor, dataAtPts->getLogStretchTensorAtPts(), MBTET));
3807 }
3808 if (var_vector) {
3809 auto vec = SmartPetscObj<Vec>(var_vector, true);
3810 fe.getOpPtrVector().push_back(new OpCalculateHVecTensorField<3, 3>(
3811 piolaStress, dataAtPts->getVarPiolaPts(),
3812 boost::make_shared<double>(1), vec));
3813 fe.getOpPtrVector().push_back(new OpCalculateHTensorTensorField<3, 3>(
3814 bubbleField, dataAtPts->getVarPiolaPts(),
3815 boost::make_shared<double>(1), vec, MBMAXTYPE));
3816 fe.getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
3817 rotAxis, dataAtPts->getVarRotAxisPts(), vec, MBTET));
3818 if (noStretch) {
3819 fe.getOpPtrVector().push_back(
3820 physicalEquations->returnOpCalculateVarStretchFromStress(
3821 dataAtPts, physicalEquations));
3822 } else {
3823 fe.getOpPtrVector().push_back(
3825 stretchTensor, dataAtPts->getVarLogStreachPts(), vec, MBTET));
3826 }
3827 }
3828
3829 fe.getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
3830 rotAxis, dataAtPts->getRotAxisAtPts(), MBTET));
3831 fe.getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
3832 rotAxis, dataAtPts->getRotAxis0AtPts(), solTSStep, MBTET));
3833
3834 fe.getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
3835 spatialL2Disp, dataAtPts->getSmallWL2AtPts(), MBTET));
3836 fe.getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
3837 spatialH1Disp, dataAtPts->getSmallWH1AtPts()));
3838 fe.getOpPtrVector().push_back(new OpCalculateVectorFieldGradient<3, 3>(
3839 spatialH1Disp, dataAtPts->getSmallWGradH1AtPts()));
3840 // evaluate derived quantities
3841 fe.getOpPtrVector().push_back(
3843
3844 // evaluate integration points
3845 fe.getOpPtrVector().push_back(physicalEquations->returnOpJacobian(
3846 tag, true, false, dataAtPts, physicalEquations));
3847 if (auto op =
3848 physicalEquations->returnOpCalculateEnergy(dataAtPts, nullptr)) {
3849 fe.getOpPtrVector().push_back(op);
3850 fe.getOpPtrVector().push_back(new OpCalculateEshelbyStress(dataAtPts));
3851 }
3852
3853 // // post-proc
3857
3858 struct OpSidePPMap : public OpPPMap {
3859 OpSidePPMap(moab::Interface &post_proc_mesh,
3860 std::vector<EntityHandle> &map_gauss_pts,
3861 DataMapVec data_map_scalar, DataMapMat data_map_vec,
3862 DataMapMat data_map_mat, DataMapMat data_symm_map_mat,
3863 int sense)
3864 : OpPPMap(post_proc_mesh, map_gauss_pts, data_map_scalar,
3865 data_map_vec, data_map_mat, data_symm_map_mat),
3866 tagSense(sense) {}
3867
3868 MoFEMErrorCode doWork(int side, EntityType type,
3871
3872 if (tagSense != OpPPMap::getSkeletonSense())
3874
3875 CHKERR OpPPMap::doWork(side, type, data);
3877 }
3878
3879 private:
3880 int tagSense;
3881 };
3882
3883 OpPPMap::DataMapMat vec_fields;
3884 vec_fields["SpatialDisplacementL2"] = dataAtPts->getSmallWL2AtPts();
3885 vec_fields["SpatialDisplacementH1"] = dataAtPts->getSmallWH1AtPts();
3886 vec_fields["Omega"] = dataAtPts->getRotAxisAtPts();
3887 vec_fields["ContactDisplacement"] = dataAtPts->getContactL2AtPts();
3888 vec_fields["AngularMomentum"] = dataAtPts->getLeviKirchhoffAtPts();
3889 vec_fields["X"] = dataAtPts->getLargeXH1AtPts();
3890 if (!noStretch) {
3891 vec_fields["EiegnLogStreach"] = dataAtPts->getEigenValsAtPts();
3892 }
3893 if (var_vector) {
3894 auto vec = SmartPetscObj<Vec>(var_vector, true);
3895 vec_fields["VarOmega"] = dataAtPts->getVarRotAxisPts();
3896 vec_fields["VarSpatialDisplacementL2"] =
3897 boost::make_shared<MatrixDouble>();
3898 fe.getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
3899 spatialL2Disp, vec_fields["VarSpatialDisplacementL2"], vec, MBTET));
3900 }
3901 if (f_residual) {
3902 auto vec = SmartPetscObj<Vec>(f_residual, true);
3903 vec_fields["ResSpatialDisplacementL2"] =
3904 boost::make_shared<MatrixDouble>();
3905 fe.getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
3906 spatialL2Disp, vec_fields["ResSpatialDisplacementL2"], vec, MBTET));
3907 vec_fields["ResOmega"] = boost::make_shared<MatrixDouble>();
3908 fe.getOpPtrVector().push_back(new OpCalculateVectorFieldValues<3>(
3909 rotAxis, vec_fields["ResOmega"], vec, MBTET));
3910 }
3911
3912 OpPPMap::DataMapMat mat_fields;
3913 mat_fields["PiolaStress"] = dataAtPts->getApproxPAtPts();
3914 if (var_vector) {
3915 mat_fields["VarPiolaStress"] = dataAtPts->getVarPiolaPts();
3916 }
3917 if (f_residual) {
3918 auto vec = SmartPetscObj<Vec>(f_residual, true);
3919 mat_fields["ResPiolaStress"] = boost::make_shared<MatrixDouble>();
3920 fe.getOpPtrVector().push_back(new OpCalculateHVecTensorField<3, 3>(
3921 piolaStress, mat_fields["ResPiolaStress"],
3922 boost::make_shared<double>(1), vec));
3923 fe.getOpPtrVector().push_back(new OpCalculateHTensorTensorField<3, 3>(
3924 bubbleField, mat_fields["ResPiolaStress"],
3925 boost::make_shared<double>(1), vec, MBMAXTYPE));
3926 }
3927 if (!internalStressTagName.empty()) {
3928 mat_fields[internalStressTagName] = dataAtPts->getInternalStressAtPts();
3929 switch (internalStressInterpOrder) {
3930 case 0:
3931 fe.getOpPtrVector().push_back(
3932 new OpGetInternalStress<0>(dataAtPts, internalStressTagName));
3933 break;
3934 case 1:
3935 fe.getOpPtrVector().push_back(
3936 new OpGetInternalStress<1>(dataAtPts, internalStressTagName));
3937 break;
3938 default:
3939 SETERRQ(PETSC_COMM_WORLD, MOFEM_NOT_IMPLEMENTED,
3940 "Unsupported internal stress interpolation order %d",
3941 internalStressInterpOrder);
3942 }
3943 }
3944
3945 OpPPMap::DataMapMat mat_fields_symm;
3946 mat_fields_symm["LogSpatialStretch"] =
3947 dataAtPts->getLogStretchTensorAtPts();
3948 mat_fields_symm["SpatialStretch"] = dataAtPts->getStretchTensorAtPts();
3949 if (var_vector) {
3950 mat_fields_symm["VarLogSpatialStretch"] =
3951 dataAtPts->getVarLogStreachPts();
3952 }
3953 if (f_residual) {
3954 auto vec = SmartPetscObj<Vec>(f_residual, true);
3955 if (!noStretch) {
3956 mat_fields_symm["ResLogSpatialStretch"] =
3957 boost::make_shared<MatrixDouble>();
3958 fe.getOpPtrVector().push_back(
3960 stretchTensor, mat_fields_symm["ResLogSpatialStretch"], vec,
3961 MBTET));
3962 }
3963 }
3964
3965 fe.getOpPtrVector().push_back(
3966
3967 new OpSidePPMap(
3968
3969 post_proc_ptr->getPostProcMesh(), post_proc_ptr->getMapGaussPts(),
3970
3971 {},
3972
3973 vec_fields,
3974
3975 mat_fields,
3976
3977 mat_fields_symm,
3978
3979 sense
3980
3981 )
3982
3983 );
3984
3985 fe.getOpPtrVector().push_back(new OpPostProcDataStructure(
3986 post_proc_ptr->getPostProcMesh(), post_proc_ptr->getMapGaussPts(),
3987 dataAtPts, sense));
3988
3990 };
3991
3992 post_proc_ptr->getOpPtrVector().push_back(
3993 new OpCalculateVectorFieldValues<3>(contactDisp,
3994 dataAtPts->getContactL2AtPts()));
3995
3996 auto X_h1_ptr = boost::make_shared<MatrixDouble>();
3997 // H1 material positions
3998 post_proc_ptr->getOpPtrVector().push_back(
3999 new OpCalculateVectorFieldValues<3>(materialH1Positions,
4000 dataAtPts->getLargeXH1AtPts()));
4001
4002 // domain
4004 mField, elementVolumeName, SPACE_DIM);
4005 domain_ops(*(op_loop_side->getSideFEPtr()), sense);
4006 post_proc_ptr->getOpPtrVector().push_back(op_loop_side);
4007
4008 return post_proc_ptr;
4009 };
4010
4011 // contact
4012 auto calcs_side_traction_and_displacements = [&](auto &post_proc_ptr,
4013 auto &pip) {
4015 auto contact_common_data_ptr = boost::make_shared<ContactOps::CommonData>();
4016 // evaluate traction
4017 using EleOnSide =
4019 using SideEleOp = EleOnSide::UserDataOperator;
4020 auto op_loop_domain_side = new OpLoopSide<EleOnSide>(
4021 mField, elementVolumeName, SPACE_DIM, Sev::noisy);
4022 op_loop_domain_side->getSideFEPtr()->getUserPolynomialBase() =
4023 boost::shared_ptr<BaseFunction>(new CGGUserPolynomialBase());
4024 EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
4025 op_loop_domain_side->getOpPtrVector(), {HDIV, H1, L2},
4026 materialH1Positions, frontAdjEdges);
4027 op_loop_domain_side->getOpPtrVector().push_back(
4029 piolaStress, contact_common_data_ptr->contactTractionPtr(),
4030 boost::make_shared<double>(1.0)));
4031 pip.push_back(op_loop_domain_side);
4032 // evaluate contact displacement and contact conditions
4033 auto u_h1_ptr = boost::make_shared<MatrixDouble>();
4034 pip.push_back(new OpCalculateVectorFieldValues<3>(spatialH1Disp, u_h1_ptr));
4036 contactDisp, contact_common_data_ptr->contactDispPtr()));
4037 pip.push_back(new OpTreeSearch(
4038 contactTreeRhs, contact_common_data_ptr, u_h1_ptr,
4039 get_range_from_block(mField, "CONTACT", SPACE_DIM - 1),
4040 &post_proc_ptr->getPostProcMesh(), &post_proc_ptr->getMapGaussPts()));
4041
4042 if (f_residual) {
4043
4044 using BoundaryEle =
4046 auto op_this = new OpLoopThis<BoundaryEle>(mField, contactElement);
4047 pip.push_back(op_this);
4048 auto contact_residual = boost::make_shared<MatrixDouble>();
4049 op_this->getOpPtrVector().push_back(
4051 contactDisp, contact_residual,
4052 SmartPetscObj<Vec>(f_residual, true)));
4054 op_this->getOpPtrVector().push_back(
4055
4056 new OpPPMap(
4057
4058 post_proc_ptr->getPostProcMesh(), post_proc_ptr->getMapGaussPts(),
4059
4060 {},
4061
4062 {{"res_contact", contact_residual}},
4063
4064 {},
4065
4066 {}
4067
4068 )
4069
4070 );
4071 }
4072
4074 };
4075
4076 auto post_proc_mesh = boost::make_shared<moab::Core>();
4077 auto post_proc_ptr = get_post_proc(post_proc_mesh, 1);
4078 auto post_proc_negative_sense_ptr = get_post_proc(post_proc_mesh, -1);
4079 CHKERR calcs_side_traction_and_displacements(post_proc_ptr,
4080 post_proc_ptr->getOpPtrVector());
4081
4082 auto own_tets =
4083 CommInterface::getPartEntities(mField.get_moab(), mField.get_comm_rank())
4084 .subset_by_dimension(SPACE_DIM);
4085 Range own_faces;
4086 CHKERR mField.get_moab().get_adjacencies(own_tets, SPACE_DIM - 1, true,
4087 own_faces, moab::Interface::UNION);
4088
4089 auto get_post_negative = [&](auto &&ents) {
4090 auto crack_faces_pos = ents;
4091 auto crack_faces_neg = crack_faces_pos;
4092 auto skin = get_skin(mField, own_tets);
4093 auto crack_on_proc_skin = intersect(crack_faces_pos, skin);
4094 for (auto f : crack_on_proc_skin) {
4095 Range tet;
4096 CHKERR mField.get_moab().get_adjacencies(&f, 1, SPACE_DIM, false, tet);
4097 tet = intersect(tet, own_tets);
4098 int side_number, sense, offset;
4099 CHKERR mField.get_moab().side_number(tet[0], f, side_number, sense,
4100 offset);
4101 if (sense == 1) {
4102 crack_faces_neg.erase(f);
4103 } else {
4104 crack_faces_pos.erase(f);
4105 }
4106 }
4107 return std::make_pair(crack_faces_pos, crack_faces_neg);
4108 };
4109
4110 auto get_crack_faces = [&](auto crack_faces) {
4111 auto get_adj = [&](auto e, auto dim) {
4112 Range adj;
4113 CHKERR mField.get_moab().get_adjacencies(e, dim, true, adj,
4114 moab::Interface::UNION);
4115 return adj;
4116 };
4117 auto tets = get_adj(crack_faces, 3);
4118 auto faces = subtract(get_adj(tets, 2), crack_faces);
4119 tets = subtract(tets, get_adj(faces, 3));
4120 return subtract(crack_faces, get_adj(tets, 2));
4121 };
4122
4123 auto [crack_faces_pos, crack_faces_neg] =
4124 get_post_negative(intersect(own_faces, get_crack_faces(*crackFaces)));
4125
4126 auto only_crack_faces = [&](FEMethod *fe_method_ptr) {
4127 auto ent = fe_method_ptr->getFEEntityHandle();
4128 if (crack_faces_pos.find(ent) == crack_faces_pos.end()) {
4129 return false;
4130 }
4131 return true;
4132 };
4133
4134 auto only_negative_crack_faces = [&](FEMethod *fe_method_ptr) {
4135 auto ent = fe_method_ptr->getFEEntityHandle();
4136 if (crack_faces_neg.find(ent) == crack_faces_neg.end()) {
4137 return false;
4138 }
4139 return true;
4140 };
4141
4142 auto get_adj_front = [&]() {
4143 auto skeleton_faces = *skeletonFaces;
4144 Range adj_front;
4145 CHKERR mField.get_moab().get_adjacencies(*frontEdges, 2, true, adj_front,
4146 moab::Interface::UNION);
4147
4148 adj_front = intersect(adj_front, skeleton_faces);
4149 adj_front = subtract(adj_front, *crackFaces);
4150 adj_front = intersect(own_faces, adj_front);
4151 return adj_front;
4152 };
4153
4154 post_proc_ptr->setTagsToTransfer(tags_to_transfer);
4155 post_proc_negative_sense_ptr->setTagsToTransfer(tags_to_transfer);
4156
4157 auto post_proc_begin =
4158 PostProcBrokenMeshInMoabBaseBegin(mField, post_proc_mesh);
4159 CHKERR DMoFEMPreProcessFiniteElements(dM, post_proc_begin.getFEMethod());
4160 CHKERR DMoFEMLoopFiniteElements(dM, skinElement, post_proc_ptr);
4161 post_proc_ptr->exeTestHook = only_crack_faces;
4162 post_proc_negative_sense_ptr->exeTestHook = only_negative_crack_faces;
4164 dM, skeletonElement, post_proc_ptr, 0, mField.get_comm_size());
4165 CHKERR DMoFEMLoopFiniteElementsUpAndLowRank(dM, skeletonElement,
4166 post_proc_negative_sense_ptr, 0,
4167 mField.get_comm_size());
4168
4169 constexpr bool debug = false;
4170 if (debug) {
4171
4172 auto [adj_front_pos, adj_front_neg] =
4173 get_post_negative(filter_owners(mField, get_adj_front()));
4174
4175 auto only_front_faces_pos = [adj_front_pos](FEMethod *fe_method_ptr) {
4176 auto ent = fe_method_ptr->getFEEntityHandle();
4177 if (adj_front_pos.find(ent) == adj_front_pos.end()) {
4178 return false;
4179 }
4180 return true;
4181 };
4182
4183 auto only_front_faces_neg = [adj_front_neg](FEMethod *fe_method_ptr) {
4184 auto ent = fe_method_ptr->getFEEntityHandle();
4185 if (adj_front_neg.find(ent) == adj_front_neg.end()) {
4186 return false;
4187 }
4188 return true;
4189 };
4190
4191 post_proc_ptr->exeTestHook = only_front_faces_pos;
4193 dM, skeletonElement, post_proc_ptr, 0, mField.get_comm_size());
4194 post_proc_negative_sense_ptr->exeTestHook = only_front_faces_neg;
4195 CHKERR DMoFEMLoopFiniteElementsUpAndLowRank(dM, skeletonElement,
4196 post_proc_negative_sense_ptr, 0,
4197 mField.get_comm_size());
4198 }
4199 auto post_proc_end = PostProcBrokenMeshInMoabBaseEnd(mField, post_proc_mesh);
4200 CHKERR DMoFEMPostProcessFiniteElements(dM, post_proc_end.getFEMethod());
4201
4202 CHKERR post_proc_end.writeFile(file.c_str());
4204}
4205
4207EshelbianCore::postProcessSkeletonResults(const int tag, const std::string file,
4208 Vec f_residual,
4209 std::vector<Tag> tags_to_transfer) {
4211
4213
4214 auto post_proc_mesh = boost::make_shared<moab::Core>();
4215 auto post_proc_ptr =
4216 boost::make_shared<PostProcBrokenMeshInMoabBaseCont<FaceEle>>(
4217 mField, post_proc_mesh);
4218 EshelbianPlasticity::AddHOOps<SPACE_DIM - 1, SPACE_DIM - 1, SPACE_DIM>::add(
4219 post_proc_ptr->getOpPtrVector(), {L2}, materialH1Positions,
4221
4222 auto hybrid_disp = boost::make_shared<MatrixDouble>();
4223 post_proc_ptr->getOpPtrVector().push_back(
4225 post_proc_ptr->getOpPtrVector().push_back(
4227 hybridSpatialDisp, dataAtPts->getGradHybridDispAtPts()));
4228
4229 auto op_loop_domain_side =
4231 mField, elementVolumeName, SPACE_DIM, Sev::noisy);
4232 post_proc_ptr->getOpPtrVector().push_back(op_loop_domain_side);
4233
4234 // evaluated in side domain, that is op_loop_domain_side
4235 op_loop_domain_side->getSideFEPtr()->getUserPolynomialBase() =
4236 boost::make_shared<CGGUserPolynomialBase>();
4237 EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
4238 op_loop_domain_side->getOpPtrVector(), {HDIV, H1, L2},
4240 op_loop_domain_side->getOpPtrVector().push_back(
4242 piolaStress, dataAtPts->getApproxPAtPts()));
4243 op_loop_domain_side->getOpPtrVector().push_back(
4245 bubbleField, dataAtPts->getApproxPAtPts(), MBMAXTYPE));
4246 op_loop_domain_side->getOpPtrVector().push_back(
4248 rotAxis, dataAtPts->getRotAxisAtPts(), MBTET));
4249 if (noStretch) {
4250 op_loop_domain_side->getOpPtrVector().push_back(
4251 physicalEquations->returnOpCalculateStretchFromStress(
4253 } else {
4254 op_loop_domain_side->getOpPtrVector().push_back(
4256 stretchTensor, dataAtPts->getLogStretchTensorAtPts(), MBTET));
4257 }
4258
4260
4261 OpPPMap::DataMapMat vec_fields;
4262 vec_fields["HybridDisplacement"] = hybrid_disp;
4263 vec_fields["Omega"] = dataAtPts->getRotAxisAtPts();
4264 OpPPMap::DataMapMat mat_fields;
4265 mat_fields["PiolaStress"] = dataAtPts->getApproxPAtPts();
4266 mat_fields["HybridDisplacementGradient"] =
4267 dataAtPts->getGradHybridDispAtPts();
4268 OpPPMap::DataMapMat mat_fields_symm;
4269 mat_fields_symm["LogSpatialStretch"] = dataAtPts->getLogStretchTensorAtPts();
4270
4271 post_proc_ptr->getOpPtrVector().push_back(
4272
4273 new OpPPMap(
4274
4275 post_proc_ptr->getPostProcMesh(), post_proc_ptr->getMapGaussPts(),
4276
4277 {},
4278
4279 vec_fields,
4280
4281 mat_fields,
4282
4283 mat_fields_symm
4284
4285 )
4286
4287 );
4288
4289 if (f_residual) {
4290 auto hybrid_res = boost::make_shared<MatrixDouble>();
4291 post_proc_ptr->getOpPtrVector().push_back(
4293 hybridSpatialDisp, hybrid_res,
4294 SmartPetscObj<Vec>(f_residual, true)));
4296 post_proc_ptr->getOpPtrVector().push_back(
4297
4298 new OpPPMap(
4299
4300 post_proc_ptr->getPostProcMesh(), post_proc_ptr->getMapGaussPts(),
4301
4302 {},
4303
4304 {{"res_hybrid", hybrid_res}},
4305
4306 {},
4307
4308 {}
4309
4310 )
4311
4312 );
4313 }
4314
4315 post_proc_ptr->setTagsToTransfer(tags_to_transfer);
4316
4317 auto post_proc_begin =
4318 PostProcBrokenMeshInMoabBaseBegin(mField, post_proc_mesh);
4319 CHKERR DMoFEMPreProcessFiniteElements(dM, post_proc_begin.getFEMethod());
4320 CHKERR DMoFEMLoopFiniteElements(dM, skeletonElement, post_proc_ptr);
4321 auto post_proc_end = PostProcBrokenMeshInMoabBaseEnd(mField, post_proc_mesh);
4322 CHKERR DMoFEMPostProcessFiniteElements(dM, post_proc_end.getFEMethod());
4323
4324 CHKERR post_proc_end.writeFile(file.c_str());
4325
4327}
4328
4331
4332 constexpr bool debug = false;
4333
4334 auto get_tags_vec = [&](std::vector<std::pair<std::string, int>> names) {
4335 std::vector<Tag> tags;
4336 tags.reserve(names.size());
4337 auto create_and_clean = [&]() {
4339 for (auto n : names) {
4340 tags.push_back(Tag());
4341 auto &tag = tags.back();
4342 auto &moab = mField.get_moab();
4343 auto rval = moab.tag_get_handle(n.first.c_str(), tag);
4344 if (rval == MB_SUCCESS) {
4345 moab.tag_delete(tag);
4346 }
4347 double def_val[] = {0., 0., 0.};
4348 CHKERR moab.tag_get_handle(n.first.c_str(), n.second, MB_TYPE_DOUBLE,
4349 tag, MB_TAG_CREAT | MB_TAG_SPARSE, def_val);
4350 }
4352 };
4353 CHK_THROW_MESSAGE(create_and_clean(), "create_and_clean");
4354 return tags;
4355 };
4356
4357 enum ExhangeTags { MATERIALFORCE, AREAGROWTH, GRIFFITHFORCE, FACEPRESSURE };
4358
4359 auto tags = get_tags_vec({{"MaterialForce", 3},
4360 {"AreaGrowth", 3},
4361 {"GriffithForce", 1},
4362 {"FacePressure", 1}});
4363
4364 auto calculate_material_forces = [&]() {
4366
4367 /**
4368 * @brief Create element to integration faces energies
4369 */
4370 auto get_face_material_force_fe = [&]() {
4372 auto fe_ptr = boost::make_shared<FaceEle>(mField);
4373 fe_ptr->getRuleHook = [](int, int, int) { return -1; };
4374 fe_ptr->setRuleHook =
4375 SetIntegrationAtFrontFace(frontVertices, frontAdjEdges);
4376
4377 // hybrid disp, evalated on face first
4378 EshelbianPlasticity::AddHOOps<2, 2, 3>::add(
4379 fe_ptr->getOpPtrVector(), {L2}, materialH1Positions, frontAdjEdges);
4380 fe_ptr->getOpPtrVector().push_back(
4382 hybridSpatialDisp, dataAtPts->getGradHybridDispAtPts()));
4383 auto op_loop_domain_side =
4385 mField, elementVolumeName, SPACE_DIM, Sev::noisy);
4386 fe_ptr->getOpPtrVector().push_back(op_loop_domain_side);
4387 fe_ptr->getOpPtrVector().push_back(new OpFaceMaterialForce(dataAtPts));
4388
4389 // evaluated in side domain, that is op_loop_domain_side
4390 op_loop_domain_side->getSideFEPtr()->getUserPolynomialBase() =
4391 boost::make_shared<CGGUserPolynomialBase>();
4392 EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
4393 op_loop_domain_side->getOpPtrVector(), {HDIV, H1, L2},
4395 op_loop_domain_side->getOpPtrVector().push_back(
4397 piolaStress, dataAtPts->getApproxPAtPts()));
4398 op_loop_domain_side->getOpPtrVector().push_back(
4400 bubbleField, dataAtPts->getApproxPAtPts(), MBMAXTYPE));
4401 op_loop_domain_side->getOpPtrVector().push_back(
4403 rotAxis, dataAtPts->getRotAxisAtPts(), MBTET));
4404 if (noStretch) {
4405 op_loop_domain_side->getOpPtrVector().push_back(
4406 physicalEquations->returnOpCalculateStretchFromStress(
4408 } else {
4409 op_loop_domain_side->getOpPtrVector().push_back(
4411 stretchTensor, dataAtPts->getLogStretchTensorAtPts(), MBTET));
4412 }
4413 op_loop_domain_side->getOpPtrVector().push_back(
4415
4416 return fe_ptr;
4417 };
4418
4419 auto integrate_face_material_force_fe = [&](auto &&face_energy_fe) {
4422 dM, skeletonElement, face_energy_fe, 0, mField.get_comm_size());
4423
4424 auto face_exchange = CommInterface::createEntitiesPetscVector(
4425 mField.get_comm(), mField.get_moab(), 2, 3, Sev::inform);
4426
4427 auto print_loc_size = [this](auto v, auto str, auto sev) {
4429 int size;
4430 CHKERR VecGetLocalSize(v.second, &size);
4431 int low, high;
4432 CHKERR VecGetOwnershipRange(v.second, &low, &high);
4433 MOFEM_LOG("EPSYNC", sev) << str << " local size " << size << " ( "
4434 << low << " " << high << " ) ";
4437 };
4438 CHKERR print_loc_size(face_exchange, "material face_exchange",
4439 Sev::verbose);
4440
4442 mField.get_moab(), face_exchange, tags[ExhangeTags::MATERIALFORCE]);
4444 mField.get_moab(), faceExchange, tags[ExhangeTags::FACEPRESSURE]);
4445
4446 // #ifndef NDEBUG
4447 if (debug) {
4449 "front_skin_faces_material_force_" +
4450 std::to_string(mField.get_comm_rank()) + ".vtk",
4451 *skeletonFaces);
4452 }
4453 // #endif
4454
4456 };
4457
4458 CHKERR integrate_face_material_force_fe(get_face_material_force_fe());
4459
4461 };
4462
4463 auto calculate_front_material_force = [&]() {
4466
4467 auto get_conn = [&](auto e) {
4468 Range conn;
4469 CHK_MOAB_THROW(mField.get_moab().get_connectivity(&e, 1, conn, true),
4470 "get connectivity");
4471 return conn;
4472 };
4473
4474 auto get_conn_range = [&](auto e) {
4475 Range conn;
4476 CHK_MOAB_THROW(mField.get_moab().get_connectivity(e, conn, true),
4477 "get connectivity");
4478 return conn;
4479 };
4480
4481 auto get_adj = [&](auto e, auto dim) {
4482 Range adj;
4483 CHK_MOAB_THROW(mField.get_moab().get_adjacencies(&e, 1, dim, true, adj),
4484 "get adj");
4485 return adj;
4486 };
4487
4488 auto get_adj_range = [&](auto e, auto dim) {
4489 Range adj;
4490 CHK_MOAB_THROW(mField.get_moab().get_adjacencies(e, dim, true, adj,
4491 moab::Interface::UNION),
4492 "get adj");
4493 return adj;
4494 };
4495
4496 auto get_material_force = [&](auto r, auto th) {
4497 MatrixDouble material_forces(r.size(), 3, false);
4499 mField.get_moab().tag_get_data(th, r, material_forces.data().data()),
4500 "get data");
4501 return material_forces;
4502 };
4503
4504 if (mField.get_comm_rank() == 0) {
4505
4506 auto crack_edges = get_adj_range(*crackFaces, 1);
4507 auto front_nodes = get_conn_range(*frontEdges);
4508 auto body_edges = get_range_from_block(mField, "EDGES", 1);
4509 // auto front_block_edges = get_range_from_block(mField, "FRONT", 1);
4510 // front_block_edges = subtract(front_block_edges, crack_edges);
4511 // auto front_block_edges_conn = get_conn_range(front_block_edges);
4512
4513 // #ifndef NDEBUG
4514 Range all_skin_faces;
4515 Range all_front_faces;
4516 // #endif
4517
4518 auto calculate_edge_direction = [&](auto e) {
4519 const EntityHandle *conn;
4520 int num_nodes;
4522 mField.get_moab().get_connectivity(e, conn, num_nodes, true),
4523 "get connectivity");
4524 std::array<double, 6> coords;
4526 mField.get_moab().get_coords(conn, num_nodes, coords.data()),
4527 "get coords");
4529 &coords[0], &coords[1], &coords[2]};
4531 &coords[3], &coords[4], &coords[5]};
4534 t_dir(i) = t_p1(i) - t_p0(i);
4535 return t_dir;
4536 };
4537
4538 // take bubble tets at node, and then avarage over the edges
4539 auto calculate_force_through_node = [&]() {
4541
4546
4547 Range body_ents;
4548 CHKERR mField.get_moab().get_entities_by_dimension(0, SPACE_DIM,
4549 body_ents);
4550 auto body_skin = get_skin(mField, body_ents);
4551 auto body_skin_conn = get_conn_range(body_skin);
4552
4553 // calculate nodal material force
4554 for (auto n : front_nodes) {
4555 auto adj_tets = get_adj(n, 3);
4556 for (int ll = 0; ll < nbJIntegralLevels; ++ll) {
4557 auto conn = get_conn_range(adj_tets);
4558 adj_tets = get_adj_range(conn, 3);
4559 }
4560 auto skin_faces = get_skin(mField, adj_tets);
4561 auto material_forces = get_material_force(skin_faces, tags[0]);
4562
4563 // #ifndef NDEBUG
4564 if (debug) {
4565 all_skin_faces.merge(skin_faces);
4566 }
4567 // #endif
4568
4569 auto calculate_node_material_force = [&]() {
4570 auto t_face_T =
4571 getFTensor1FromPtr<SPACE_DIM>(material_forces.data().data());
4572 FTensor::Tensor1<double, SPACE_DIM> t_node_force{0., 0., 0.};
4573 for (auto face : skin_faces) {
4574
4575 FTensor::Tensor1<double, SPACE_DIM> t_face_force_tmp{0., 0., 0.};
4576 t_face_force_tmp(I) = t_face_T(I);
4577 ++t_face_T;
4578
4579 auto face_tets = intersect(get_adj(face, 3), adj_tets);
4580
4581 if (face_tets.empty()) {
4582 continue;
4583 }
4584
4585 if (face_tets.size() != 1) {
4587 "face_tets.size() != 1");
4588 }
4589
4590 int side_number, sense, offset;
4591 CHK_MOAB_THROW(mField.get_moab().side_number(face_tets[0], face,
4592 side_number, sense,
4593 offset),
4594 "moab side number");
4595 t_face_force_tmp(I) *= sense;
4596 t_node_force(I) += t_face_force_tmp(I);
4597 }
4598
4599 return t_node_force;
4600 };
4601
4602 auto calculate_crack_area_growth_direction =
4603 [&](auto n, auto &t_node_force) {
4604 // if skin is on body surface, project the direction on it
4605 FTensor::Tensor1<double, SPACE_DIM> t_project{0., 0., 0.};
4606 auto boundary_node = intersect(Range(n, n), body_skin_conn);
4607 if (boundary_node.size()) {
4608 auto faces = intersect(get_adj(n, 2), body_skin);
4609 for (auto f : faces) {
4610 FTensor::Tensor1<double, 3> t_normal_face;
4611 CHKERR mField.getInterface<Tools>()->getTriNormal(
4612 f, &t_normal_face(0));
4613 t_project(I) += t_normal_face(I);
4614 }
4615 t_project.normalize();
4616 }
4617
4618 // calculate surface projection matrix
4621 t_Q(I, J) = t_kd(I, J);
4622 if (boundary_node.size()) {
4623 t_Q(I, J) -= t_project(I) * t_project(J);
4624 }
4625
4626 auto adj_faces = intersect(get_adj(n, 2), *crackFaces);
4627 if (adj_faces.empty()) {
4628 auto adj_edges =
4629 intersect(get_adj(n, 1), unite(*frontEdges, body_edges));
4630 double l = 0;
4631 for (auto e : adj_edges) {
4632 auto t_dir = calculate_edge_direction(e);
4633 l += t_dir.l2();
4634 }
4635 l /= 2;
4636 FTensor::Tensor1<double, SPACE_DIM> t_area_dir{0., 0., 0.};
4637 FTensor::Tensor1<double, SPACE_DIM> t_node_force_tmp;
4638 t_node_force_tmp(I) = t_node_force(I);
4639 t_node_force_tmp.normalize();
4640 t_area_dir(I) = -t_node_force_tmp(I);
4641 t_area_dir(I) *= l / 2;
4642 return t_area_dir;
4643 }
4644
4645 // calculate direction
4646 auto front_edges = get_adj(n, 1);
4647 FTensor::Tensor1<double, 3> t_area_dir{0., 0., 0.};
4648 for (auto f : adj_faces) {
4649 int num_nodes;
4650 const EntityHandle *conn;
4651 CHKERR mField.get_moab().get_connectivity(f, conn, num_nodes,
4652 true);
4653 std::array<double, 9> coords;
4654 CHKERR mField.get_moab().get_coords(conn, num_nodes,
4655 coords.data());
4656 FTensor::Tensor1<double, 3> t_face_normal;
4658 CHKERR mField.getInterface<Tools>()->getTriNormal(
4659 coords.data(), &t_face_normal(0), &t_d_normal(0, 0, 0));
4660 auto n_it = std::find(conn, conn + num_nodes, n);
4661 auto n_index = std::distance(conn, n_it);
4662
4663 FTensor::Tensor2<double, 3, 3> t_face_hessian{
4664 t_d_normal(0, n_index, 0), t_d_normal(0, n_index, 1),
4665 t_d_normal(0, n_index, 2),
4666
4667 t_d_normal(1, n_index, 0), t_d_normal(1, n_index, 1),
4668 t_d_normal(1, n_index, 2),
4669
4670 t_d_normal(2, n_index, 0), t_d_normal(2, n_index, 1),
4671 t_d_normal(2, n_index, 2)};
4672
4673 FTensor::Tensor2<double, 3, 3> t_projected_hessian;
4674 t_projected_hessian(I, J) =
4675 t_Q(I, K) * (t_face_hessian(K, L) * t_Q(L, J));
4676 t_face_normal.normalize();
4677 t_area_dir(K) +=
4678 t_face_normal(I) * t_projected_hessian(I, K) / 2.;
4679 }
4680
4681 return t_area_dir;
4682 };
4683
4684 auto t_node_force = calculate_node_material_force();
4685 t_node_force(I) /= griffithEnergy; // scale all by griffith energy
4687 mField.get_moab().tag_set_data(tags[ExhangeTags::MATERIALFORCE],
4688 &n, 1, &t_node_force(0)),
4689 "set data");
4690
4691 auto get_area_dir = [&]() {
4692 auto adj_faces = get_adj_range(adj_tets, 2);
4693 auto t_area_dir = calculate_crack_area_growth_direction(
4694 n, t_node_force);
4695 if (nbJIntegralLevels) {
4696 auto adj_edges = intersect(get_adj_range(adj_tets, 1),
4697 unite(*frontEdges, body_edges));
4698 auto seed_n = get_conn_range(adj_edges);
4699 auto skin_adj_edges = get_skin(mField, adj_edges);
4700 skin_adj_edges = subtract(skin_adj_edges, body_skin_conn);
4701 seed_n = subtract(seed_n, skin_adj_edges);
4702 t_area_dir(I) = 0;
4703 for (auto sn : seed_n) {
4704 auto t_area_dir_sn = calculate_crack_area_growth_direction(
4705 sn, t_node_force);
4706 t_area_dir(I) += t_area_dir_sn(I);
4707 }
4708 for (auto sn : skin_adj_edges) {
4709 auto t_area_dir_sn = calculate_crack_area_growth_direction(
4710 sn, t_node_force);
4711 t_area_dir(I) += t_area_dir_sn(I) / 2;
4712 }
4713 }
4714
4715 return t_area_dir;
4716 };
4717
4718 auto t_area_dir = get_area_dir();
4719
4721 mField.get_moab().tag_set_data(tags[ExhangeTags::AREAGROWTH], &n,
4722 1, &t_area_dir(0)),
4723 "set data");
4724 auto griffith = -t_node_force(I) * t_area_dir(I) /
4725 (t_area_dir(K) * t_area_dir(K));
4727 mField.get_moab().tag_set_data(tags[ExhangeTags::GRIFFITHFORCE],
4728 &n, 1, &griffith),
4729 "set data");
4730 }
4731
4732 // iterate over edges, and calculate average edge material force
4733 auto ave_node_force = [&](auto th) {
4735
4736 for (auto e : *frontEdges) {
4737
4738 auto conn = get_conn(e);
4739 auto data = get_material_force(conn, th);
4740 auto t_node = getFTensor1FromPtr<SPACE_DIM>(data.data().data());
4741 FTensor::Tensor1<double, SPACE_DIM> t_edge{0., 0., 0.};
4742 for (auto n : conn) {
4743 t_edge(I) += t_node(I);
4744 ++t_node;
4745 }
4746 t_edge(I) /= conn.size();
4747
4748 FTensor::Tensor1<double, SPACE_DIM> t_edge_direction =
4749 calculate_edge_direction(e);
4750 t_edge_direction.normalize();
4751
4756 t_cross(K) =
4757 FTensor::levi_civita(I, J, K) * t_edge_direction(I) * t_edge(J);
4758 t_edge(K) = FTensor::levi_civita(I, J, K) * t_edge_direction(J) *
4759 t_cross(I);
4760
4761 CHKERR mField.get_moab().tag_set_data(th, &e, 1, &t_edge(0));
4762 }
4764 };
4765
4766 // iterate over edges, and calculate average edge griffith energy
4767 auto ave_node_griffith_energy = [&](auto th) {
4769 for (auto e : *frontEdges) {
4771 CHKERR mField.get_moab().tag_get_data(
4772 tags[ExhangeTags::MATERIALFORCE], &e, 1, &t_edge_force(0));
4774 CHKERR mField.get_moab().tag_get_data(tags[ExhangeTags::AREAGROWTH],
4775 &e, 1, &t_edge_area_dir(0));
4776 double griffith_energy = -t_edge_force(I) * t_edge_area_dir(I) /
4777 (t_edge_area_dir(K) * t_edge_area_dir(K));
4778 CHKERR mField.get_moab().tag_set_data(th, &e, 1, &griffith_energy);
4779 }
4781 };
4782
4783 CHKERR ave_node_force(tags[ExhangeTags::MATERIALFORCE]);
4784 CHKERR ave_node_force(tags[ExhangeTags::AREAGROWTH]);
4785 CHKERR ave_node_griffith_energy(tags[ExhangeTags::GRIFFITHFORCE]);
4786
4788 };
4789
4790 CHKERR calculate_force_through_node();
4791
4792 // calculate face cross
4793 for (auto e : *frontEdges) {
4794 auto adj_faces = get_adj(e, 2);
4795 auto crack_face = intersect(get_adj(e, 2), *crackFaces);
4796
4797 // #ifndef NDEBUG
4798 if (debug) {
4799 all_front_faces.merge(adj_faces);
4800 }
4801 // #endif
4802
4804 CHKERR mField.get_moab().tag_get_data(tags[ExhangeTags::MATERIALFORCE],
4805 &e, 1, &t_edge_force(0));
4806 FTensor::Tensor1<double, SPACE_DIM> t_edge_direction =
4807 calculate_edge_direction(e);
4808 t_edge_direction.normalize();
4813 t_cross(K) = FTensor::levi_civita(I, J, K) * t_edge_direction(I) *
4814 t_edge_force(J);
4815
4816 for (auto f : adj_faces) {
4818 CHKERR mField.getInterface<Tools>()->getTriNormal(f, &t_normal(0));
4819 t_normal.normalize();
4820 int side_number, sense, offset;
4821 CHKERR mField.get_moab().side_number(f, e, side_number, sense,
4822 offset);
4823 auto dot = -sense * t_cross(I) * t_normal(I);
4824 CHK_MOAB_THROW(mField.get_moab().tag_set_data(
4825 tags[ExhangeTags::GRIFFITHFORCE], &f, 1, &dot),
4826 "set data");
4827 }
4828 }
4829
4830 // #ifndef NDEBUG
4831 if (debug) {
4832 int ts_step;
4833 CHKERR TSGetStepNumber(ts, &ts_step);
4835 "front_edges_material_force_" +
4836 std::to_string(ts_step) + ".vtk",
4837 *frontEdges);
4839 "front_skin_faces_material_force_" +
4840 std::to_string(ts_step) + ".vtk",
4841 all_skin_faces);
4843 "front_faces_material_force_" +
4844 std::to_string(ts_step) + ".vtk",
4845 all_front_faces);
4846 }
4847 // #endif
4848 }
4849
4850 auto edge_exchange = CommInterface::createEntitiesPetscVector(
4851 mField.get_comm(), mField.get_moab(), 1, 3, Sev::inform);
4853 mField.get_moab(), edge_exchange, tags[ExhangeTags::MATERIALFORCE]);
4855 mField.get_moab(), edge_exchange, tags[ExhangeTags::AREAGROWTH]);
4857 mField.get_moab(), edgeExchange, tags[ExhangeTags::GRIFFITHFORCE]);
4858
4860 };
4861
4862 auto print_results = [&]() {
4864
4865 auto get_conn_range = [&](auto e) {
4866 Range conn;
4867 CHK_MOAB_THROW(mField.get_moab().get_connectivity(e, conn, true),
4868 "get connectivity");
4869 return conn;
4870 };
4871
4872 auto get_tag_data = [&](auto &ents, auto tag, auto dim) {
4873 std::vector<double> data(ents.size() * dim);
4874 CHK_MOAB_THROW(mField.get_moab().tag_get_data(tag, ents, data.data()),
4875 "get data");
4876 return data;
4877 };
4878
4879 if (mField.get_comm_rank() == 0) {
4880 auto at_nodes = [&]() {
4882 auto conn = get_conn_range(*frontEdges);
4883 auto material_force =
4884 get_tag_data(conn, tags[ExhangeTags::MATERIALFORCE], 3);
4885 auto area_growth = get_tag_data(conn, tags[ExhangeTags::AREAGROWTH], 3);
4886 auto griffith_force =
4887 get_tag_data(conn, tags[ExhangeTags::GRIFFITHFORCE], 1);
4888 std::vector<double> coords(conn.size() * 3);
4889 CHK_MOAB_THROW(mField.get_moab().get_coords(conn, coords.data()),
4890 "get coords");
4891 if (conn.size())
4892 MOFEM_LOG("EPSELF", Sev::inform) << "Material force at nodes";
4893 for (size_t i = 0; i < conn.size(); ++i) {
4894 MOFEM_LOG("EPSELF", Sev::inform)
4895 << "Node " << conn[i] << " coords "
4896 << coords[i * 3 + 0] << " " << coords[i * 3 + 1] << " "
4897 << coords[i * 3 + 2] << " material force "
4898 << material_force[i * 3 + 0] << " "
4899 << material_force[i * 3 + 1] << " "
4900 << material_force[i * 3 + 2] << " area growth "
4901 << area_growth[i * 3 + 0] << " " << area_growth[i * 3 + 1]
4902 << " " << area_growth[i * 3 + 2] << " griffith force "
4903 << griffith_force[i];
4904 }
4906 };
4907
4908 at_nodes();
4909 }
4911 };
4912
4913 CHKERR calculate_material_forces();
4914 CHKERR calculate_front_material_force();
4915 CHKERR print_results();
4916
4918}
4919
4921 bool set_orientation) {
4923
4924 constexpr bool debug = false;
4925 constexpr auto sev = Sev::verbose;
4926
4927 Range body_ents;
4928 CHKERR mField.get_moab().get_entities_by_dimension(0, 3, body_ents);
4929 auto body_skin = get_skin(mField, body_ents);
4930 Range body_skin_edges;
4931 CHKERR mField.get_moab().get_adjacencies(body_skin, 1, false, body_skin_edges,
4932 moab::Interface::UNION);
4933 Range boundary_skin_verts;
4934 CHKERR mField.get_moab().get_connectivity(body_skin_edges,
4935 boundary_skin_verts, true);
4936
4937 auto geometry_edges = get_range_from_block(mField, "EDGES", 1);
4938 Range geometry_edges_verts;
4939 CHKERR mField.get_moab().get_connectivity(geometry_edges,
4940 geometry_edges_verts, true);
4941 Range crack_faces_verts;
4942 CHKERR mField.get_moab().get_connectivity(*crackFaces, crack_faces_verts,
4943 true);
4944 Range crack_faces_edges;
4945 CHKERR mField.get_moab().get_adjacencies(
4946 *crackFaces, 1, true, crack_faces_edges, moab::Interface::UNION);
4947 Range crack_faces_tets;
4948 CHKERR mField.get_moab().get_adjacencies(
4949 *crackFaces, 3, true, crack_faces_tets, moab::Interface::UNION);
4950
4951 Range front_verts;
4952 CHKERR mField.get_moab().get_connectivity(*frontEdges, front_verts, true);
4953 Range front_faces;
4954 CHKERR mField.get_moab().get_adjacencies(*frontEdges, 2, true, front_faces,
4955 moab::Interface::UNION);
4956 Range front_verts_edges;
4957 CHKERR mField.get_moab().get_adjacencies(
4958 front_verts, 1, true, front_verts_edges, moab::Interface::UNION);
4959
4960 auto get_tags_vec = [&](auto tag_name, int dim) {
4961 std::vector<Tag> tags(1);
4962
4963 if (dim > 3)
4965
4966 auto create_and_clean = [&]() {
4968 auto &moab = mField.get_moab();
4969 auto rval = moab.tag_get_handle(tag_name, tags[0]);
4970 if (rval == MB_SUCCESS) {
4971 moab.tag_delete(tags[0]);
4972 }
4973 double def_val[] = {0., 0., 0.};
4974 CHKERR moab.tag_get_handle(tag_name, dim, MB_TYPE_DOUBLE, tags[0],
4975 MB_TAG_CREAT | MB_TAG_SPARSE, def_val);
4977 };
4978
4979 CHK_THROW_MESSAGE(create_and_clean(), "create_and_clean");
4980
4981 return tags;
4982 };
4983
4984 auto get_adj_front = [&](bool subtract_crack) {
4985 Range adj_front;
4986 CHKERR mField.get_moab().get_adjacencies(*frontEdges, SPACE_DIM - 1, true,
4987 adj_front, moab::Interface::UNION);
4988 if (subtract_crack)
4989 adj_front = subtract(adj_front, *crackFaces);
4990 return adj_front;
4991 };
4992
4993 MOFEM_LOG_CHANNEL("SELF");
4994
4995 auto th_front_position = get_tags_vec("FrontPosition", 3);
4996 auto th_max_face_energy = get_tags_vec("MaxFaceEnergy", 1);
4997
4998 if (mField.get_comm_rank() == 0) {
4999
5000 auto get_crack_adj_tets = [&](auto r) {
5001 Range crack_faces_conn;
5002 CHKERR mField.get_moab().get_connectivity(r, crack_faces_conn);
5003 Range crack_faces_conn_tets;
5004 CHKERR mField.get_moab().get_adjacencies(crack_faces_conn, SPACE_DIM,
5005 true, crack_faces_conn_tets,
5006 moab::Interface::UNION);
5007 return crack_faces_conn_tets;
5008 };
5009
5010 auto get_layers_for_sides = [&](auto &side) {
5011 std::vector<Range> layers;
5012 auto get = [&]() {
5014
5015 auto get_adj = [&](auto &r, int dim) {
5016 Range adj;
5017 CHKERR mField.get_moab().get_adjacencies(r, dim, true, adj,
5018 moab::Interface::UNION);
5019 return adj;
5020 };
5021
5022 auto get_tets = [&](auto r) { return get_adj(r, SPACE_DIM); };
5023
5024 Range front_nodes;
5025 CHKERR mField.get_moab().get_connectivity(*frontEdges, front_nodes,
5026 true);
5027 Range front_faces = get_adj(front_nodes, 2);
5028 front_faces = subtract(front_faces, *crackFaces);
5029 auto front_tets = get_tets(front_nodes);
5030 auto front_side = intersect(side, front_tets);
5031 layers.push_back(front_side);
5032 for (;;) {
5033 auto adj_faces = get_skin(mField, layers.back());
5034 adj_faces = intersect(adj_faces, front_faces);
5035 auto adj_faces_tets = get_tets(adj_faces);
5036 adj_faces_tets = intersect(adj_faces_tets, front_tets);
5037 layers.push_back(unite(layers.back(), adj_faces_tets));
5038 if (layers.back().size() == layers[layers.size() - 2].size()) {
5039 break;
5040 }
5041 }
5043 };
5044 CHK_THROW_MESSAGE(get(), "get_layers_for_sides");
5045 return layers;
5046 };
5047
5049 auto layers_top = get_layers_for_sides(sides_pair.first);
5050 auto layers_bottom = get_layers_for_sides(sides_pair.second);
5051
5052#ifndef NDEBUG
5053 if (debug) {
5055 mField.get_moab(),
5056 "crack_tets_" +
5057 boost::lexical_cast<std::string>(mField.get_comm_rank()) + ".vtk",
5058 get_crack_adj_tets(*crackFaces));
5059 CHKERR save_range(mField.get_moab(), "sides_first.vtk", sides_pair.first);
5060 CHKERR save_range(mField.get_moab(), "sides_second.vtk",
5061 sides_pair.second);
5062 MOFEM_LOG("EP", sev) << "Nb. layers " << layers_top.size();
5063 int l = 0;
5064 for (auto &r : layers_top) {
5065 MOFEM_LOG("EP", sev) << "Layer " << l << " size " << r.size();
5067 mField.get_moab(),
5068 "layers_top_" + boost::lexical_cast<std::string>(l) + ".vtk", r);
5069 ++l;
5070 }
5071
5072 l = 0;
5073 for (auto &r : layers_bottom) {
5074 MOFEM_LOG("EP", sev) << "Layer " << l << " size " << r.size();
5076 mField.get_moab(),
5077 "layers_bottom_" + boost::lexical_cast<std::string>(l) + ".vtk", r);
5078 ++l;
5079 }
5080 }
5081#endif
5082
5083 auto get_cross = [&](auto t_dir, auto f) {
5085 CHKERR mField.getInterface<Tools>()->getTriNormal(f, &t_normal(0));
5086 t_normal.normalize();
5091 t_cross(i) = FTensor::levi_civita(i, j, k) * t_normal(j) * t_dir(k);
5092 return t_cross;
5093 };
5094
5095 auto get_sense = [&](auto f, auto e) {
5096 int side, sense, offset;
5097 CHK_MOAB_THROW(mField.get_moab().side_number(f, e, side, sense, offset),
5098 "get sense");
5099 return std::make_tuple(side, sense, offset);
5100 };
5101
5102 auto calculate_edge_direction = [&](auto e, auto normalize = true) {
5103 const EntityHandle *conn;
5104 int num_nodes;
5105 CHKERR mField.get_moab().get_connectivity(e, conn, num_nodes, true);
5106 std::array<double, 6> coords;
5107 CHKERR mField.get_moab().get_coords(conn, num_nodes, coords.data());
5109 &coords[0], &coords[1], &coords[2]};
5111 &coords[3], &coords[4], &coords[5]};
5114 t_dir(i) = t_p1(i) - t_p0(i);
5115 if (normalize)
5116 t_dir.normalize();
5117 return t_dir;
5118 };
5119
5120 auto evaluate_face_energy_and_set_orientation = [&](auto front_edges,
5121 auto front_faces,
5122 auto &sides_pair,
5123 auto th_position) {
5125
5126 Tag th_face_energy;
5127 Tag th_material_force;
5128 switch (energyReleaseSelector) {
5129 case GRIFFITH_FORCE:
5130 case GRIFFITH_SKELETON:
5131 CHKERR mField.get_moab().tag_get_handle("GriffithForce",
5132 th_face_energy);
5133 CHKERR mField.get_moab().tag_get_handle("MaterialForce",
5134 th_material_force);
5135 break;
5136 default:
5137 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
5138 "Unknown energy release selector");
5139 };
5140
5141 /**
5142 * Iterate over front edges, get adjacent faces, find maximal face energy.
5143 * Maximal face energy is stored in the edge. Maximal face energy is
5144 * magnitude of edge Griffith force.
5145 */
5146 auto find_maximal_face_energy = [&](auto front_edges, auto front_faces,
5147 auto &edge_face_max_energy_map) {
5149
5150 Range body_ents;
5151 CHKERR mField.get_moab().get_entities_by_dimension(0, 3, body_ents);
5152 auto body_skin = get_skin(mField, body_ents);
5153
5154 Range max_faces;
5155
5156 for (auto e : front_edges) {
5157
5158 double griffith_force;
5159 CHKERR mField.get_moab().tag_get_data(th_face_energy, &e, 1,
5160 &griffith_force);
5161
5162 Range faces;
5163 CHKERR mField.get_moab().get_adjacencies(&e, 1, 2, false, faces);
5164 faces = subtract(intersect(faces, front_faces), body_skin);
5165 std::vector<double> face_energy(faces.size());
5166 CHKERR mField.get_moab().tag_get_data(th_face_energy, faces,
5167 face_energy.data());
5168 auto max_energy_it =
5169 std::max_element(face_energy.begin(), face_energy.end());
5170 double max_energy =
5171 max_energy_it != face_energy.end() ? *max_energy_it : 0;
5172
5173 edge_face_max_energy_map[e] =
5174 std::make_tuple(faces[max_energy_it - face_energy.begin()],
5175 griffith_force, static_cast<double>(0));
5176 MOFEM_LOG("EP", Sev::inform)
5177 << "Edge " << e << " griffith force " << griffith_force
5178 << " max face energy " << max_energy << " factor "
5179 << max_energy / griffith_force;
5180
5181 max_faces.insert(faces[max_energy_it - face_energy.begin()]);
5182 }
5183
5184#ifndef NDEBUG
5185 if (debug) {
5187 mField.get_moab(),
5188 "max_faces_" +
5189 boost::lexical_cast<std::string>(mField.get_comm_rank()) +
5190 ".vtk",
5191 max_faces);
5192 }
5193#endif
5194
5196 };
5197
5198 /**
5199 * For each front edge, find maximal face energy and orientation. This is
5200 * by finding angle between edge material force and maximal face normal
5201 *
5202 */
5203 auto calculate_face_orientation = [&](auto &edge_face_max_energy_map) {
5205
5206 auto up_down_face = [&](
5207
5208 auto &face_angle_map_up,
5209 auto &face_angle_map_down
5210
5211 ) {
5213
5214 for (auto &m : edge_face_max_energy_map) {
5215 auto e = m.first;
5216 auto [max_face, energy, opt_angle] = m.second;
5217
5218 Range faces;
5219 CHKERR mField.get_moab().get_adjacencies(&e, 1, 2, false, faces);
5220 faces = intersect(faces, front_faces);
5221 Range adj_tets; // tetrahedrons adjacent to the face
5222 CHKERR mField.get_moab().get_adjacencies(&max_face, 1, SPACE_DIM,
5223 false, adj_tets,
5224 moab::Interface::UNION);
5225 if (adj_tets.size()) {
5226
5227 Range adj_tets; // tetrahedrons adjacent to the face
5228 CHKERR mField.get_moab().get_adjacencies(&max_face, 1, SPACE_DIM,
5229 false, adj_tets,
5230 moab::Interface::UNION);
5231 if (adj_tets.size()) {
5232
5233 Range adj_tets_faces;
5234 // get faces
5235 CHKERR mField.get_moab().get_adjacencies(
5236 adj_tets, SPACE_DIM - 1, false, adj_tets_faces,
5237 moab::Interface::UNION);
5238 adj_tets_faces = intersect(adj_tets_faces, faces);
5240
5241 // cross product of face normal and edge direction
5242 auto t_cross_max =
5243 get_cross(calculate_edge_direction(e, true), max_face);
5244 auto [side_max, sense_max, offset_max] = get_sense(max_face, e);
5245 t_cross_max(i) *= sense_max;
5246
5247 for (auto t : adj_tets) {
5248 Range adj_tets_faces;
5249 CHKERR mField.get_moab().get_adjacencies(
5250 &t, 1, SPACE_DIM - 1, false, adj_tets_faces);
5251 adj_tets_faces = intersect(adj_tets_faces, faces);
5252 adj_tets_faces =
5253 subtract(adj_tets_faces, Range(max_face, max_face));
5254
5255 if (adj_tets_faces.size() == 1) {
5256
5257 // cross product of adjacent face normal and edge
5258 // direction
5259 auto t_cross = get_cross(calculate_edge_direction(e, true),
5260 adj_tets_faces[0]);
5261 auto [side, sense, offset] =
5262 get_sense(adj_tets_faces[0], e);
5263 t_cross(i) *= sense;
5264 double dot = t_cross(i) * t_cross_max(i);
5265 auto angle = std::acos(dot);
5266
5267 double face_energy;
5268 CHKERR mField.get_moab().tag_get_data(
5269 th_face_energy, adj_tets_faces, &face_energy);
5270
5271 auto [side_face, sense_face, offset_face] =
5272 get_sense(t, max_face);
5273
5274 if (sense_face > 0) {
5275 face_angle_map_up[e] = std::make_tuple(face_energy, angle,
5276 adj_tets_faces[0]);
5277
5278 } else {
5279 face_angle_map_down[e] = std::make_tuple(
5280 face_energy, -angle, adj_tets_faces[0]);
5281 }
5282 }
5283 }
5284 }
5285 }
5286 }
5287
5289 };
5290
5291 auto calc_optimal_angle = [&](
5292
5293 auto &face_angle_map_up,
5294 auto &face_angle_map_down
5295
5296 ) {
5298
5299 for (auto &m : edge_face_max_energy_map) {
5300 auto e = m.first;
5301 auto &[max_face, e0, a0] = m.second;
5302
5303 if (std::abs(e0) > std::numeric_limits<double>::epsilon()) {
5304
5305 if (face_angle_map_up.find(e) == face_angle_map_up.end() ||
5306 face_angle_map_down.find(e) == face_angle_map_down.end()) {
5307 // Do nothing
5308 } else {
5309
5310 switch (energyReleaseSelector) {
5311 case GRIFFITH_FORCE:
5312 case GRIFFITH_SKELETON: {
5313
5314 Tag th_material_force;
5315 CHKERR mField.get_moab().tag_get_handle("MaterialForce",
5316 th_material_force);
5317 FTensor::Tensor1<double, SPACE_DIM> t_material_force;
5318 CHKERR mField.get_moab().tag_get_data(
5319 th_material_force, &e, 1, &t_material_force(0));
5320 auto material_force_magnitude = t_material_force.l2();
5321 if (material_force_magnitude <
5322 std::numeric_limits<double>::epsilon()) {
5323 a0 = 0;
5324
5325 } else {
5326
5327 auto t_edge_dir = calculate_edge_direction(e, true);
5328 auto t_cross_max = get_cross(t_edge_dir, max_face);
5329 auto [side, sense, offset] = get_sense(max_face, e);
5330 t_cross_max(sense) *= sense;
5331
5335
5336 t_material_force.normalize();
5337 t_cross_max.normalize();
5339 t_cross(I) = FTensor::levi_civita(I, J, K) *
5340 t_material_force(J) * t_cross_max(K);
5341 a0 = -std::asin(t_cross(I) * t_edge_dir(I));
5342
5343 MOFEM_LOG("EP", sev)
5344 << "Optimal angle " << a0 << " energy " << e0;
5345 }
5346 break;
5347 }
5348 default: {
5349
5350 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
5351 "Unknown energy release selector");
5352 }
5353 }
5354 }
5355 }
5356 }
5357
5359 };
5360
5361 std::map<EntityHandle, std::tuple<double, double, EntityHandle>>
5362 face_angle_map_up;
5363 std::map<EntityHandle, std::tuple<double, double, EntityHandle>>
5364 face_angle_map_down;
5365 CHKERR up_down_face(face_angle_map_up, face_angle_map_down);
5366 CHKERR calc_optimal_angle(face_angle_map_up, face_angle_map_down);
5367
5368#ifndef NDEBUG
5369 if (debug) {
5370 auto th_angle = get_tags_vec("Angle", 1);
5371 Range up;
5372 for (auto &m : face_angle_map_up) {
5373 auto [e, a, face] = m.second;
5374 up.insert(face);
5375 CHKERR mField.get_moab().tag_set_data(th_angle[0], &face, 1, &a);
5376 }
5377 Range down;
5378 for (auto &m : face_angle_map_down) {
5379 auto [e, a, face] = m.second;
5380 down.insert(face);
5381 CHKERR mField.get_moab().tag_set_data(th_angle[0], &face, 1, &a);
5382 }
5383
5384 Range max_energy_faces;
5385 for (auto &m : edge_face_max_energy_map) {
5386 auto [face, e, angle] = m.second;
5387 max_energy_faces.insert(face);
5388 CHKERR mField.get_moab().tag_set_data(th_angle[0], &face, 1,
5389 &angle);
5390 }
5391 if (mField.get_comm_rank() == 0) {
5392 CHKERR save_range(mField.get_moab(), "up_faces.vtk", up);
5393 CHKERR save_range(mField.get_moab(), "down_faces.vtk", down);
5394 CHKERR save_range(mField.get_moab(), "max_energy_faces.vtk",
5395 max_energy_faces);
5396 }
5397 }
5398#endif // NDEBUG
5399
5401 };
5402
5403 auto get_conn = [&](auto e) {
5404 Range conn;
5405 CHK_MOAB_THROW(mField.get_moab().get_connectivity(e, conn, true),
5406 "get conn");
5407 return conn;
5408 };
5409
5410 auto get_adj = [&](auto e, auto dim) {
5411 Range adj;
5412 CHK_MOAB_THROW(mField.get_moab().get_adjacencies(
5413 e, dim, false, adj, moab::Interface::UNION),
5414 "get adj");
5415 return adj;
5416 };
5417
5418 auto get_coords = [&](auto v) {
5420 CHK_MOAB_THROW(mField.get_moab().get_coords(v, &t_coords(0)),
5421 "get coords");
5422 return t_coords;
5423 };
5424
5425 // calulate normal of the max energy face
5426 auto get_rotated_normal = [&](auto e, auto f, auto angle) {
5429 auto t_edge_dir = calculate_edge_direction(e, true);
5430 auto [side, sense, offset] = get_sense(f, e);
5431 t_edge_dir(i) *= sense;
5432 t_edge_dir.normalize();
5433 t_edge_dir(i) *= angle;
5434 auto t_R = LieGroups::SO3::exp(t_edge_dir, angle);
5436 mField.getInterface<Tools>()->getTriNormal(f, &t_normal(0));
5437 FTensor::Tensor1<double, SPACE_DIM> t_rotated_normal;
5438 t_rotated_normal(i) = t_R(i, j) * t_normal(j);
5439 return std::make_tuple(t_normal, t_rotated_normal);
5440 };
5441
5442 auto set_coord = [&](auto v, auto &adj_vertex_tets_verts, auto &coords,
5443 auto &t_move, auto gamma) {
5444 auto index = adj_vertex_tets_verts.index(v);
5445 if (index >= 0) {
5446 for (auto ii : {0, 1, 2}) {
5447 coords[3 * index + ii] += gamma * t_move(ii);
5448 }
5449 return true;
5450 }
5451 return false;
5452 };
5453
5454 auto tets_quality = [&](auto quality, auto &adj_vertex_tets_verts,
5455 auto &adj_vertex_tets, auto &coords) {
5456 for (auto t : adj_vertex_tets) {
5457 const EntityHandle *conn;
5458 int num_nodes;
5459 CHKERR mField.get_moab().get_connectivity(t, conn, num_nodes, true);
5460 std::array<double, 12> tet_coords;
5461 for (auto n = 0; n != 4; ++n) {
5462 auto index = adj_vertex_tets_verts.index(conn[n]);
5463 if (index < 0) {
5465 }
5466 for (auto ii = 0; ii != 3; ++ii) {
5467 tet_coords[3 * n + ii] = coords[3 * index + ii];
5468 }
5469 }
5470 double q = Tools::volumeLengthQuality(tet_coords.data());
5471 if (!std::isnormal(q))
5472 q = -2;
5473 quality = std::min(quality, q);
5474 };
5475
5476 return quality;
5477 };
5478
5479 auto calculate_free_face_node_displacement =
5480 [&](auto &edge_face_max_energy_map) {
5481 // get edges adjacent to vertex along which nodes are moving
5482 auto get_vertex_edges = [&](auto vertex) {
5483 Range vertex_edges; // edges adjacent to vertex
5484
5485 auto impl = [&]() {
5487 CHKERR mField.get_moab().get_adjacencies(vertex, 1, false,
5488 vertex_edges);
5489 vertex_edges = subtract(vertex_edges, front_verts_edges);
5490
5491 if (boundary_skin_verts.size() &&
5492 boundary_skin_verts.find(vertex[0]) !=
5493 boundary_skin_verts.end()) {
5494 MOFEM_LOG("EP", sev) << "Boundary vertex";
5495 vertex_edges = intersect(vertex_edges, body_skin_edges);
5496 }
5497 if (geometry_edges_verts.size() &&
5498 geometry_edges_verts.find(vertex[0]) !=
5499 geometry_edges_verts.end()) {
5500 MOFEM_LOG("EP", sev) << "Geometry edge vertex";
5501 vertex_edges = intersect(vertex_edges, geometry_edges);
5502 }
5503 if (crack_faces_verts.size() &&
5504 crack_faces_verts.find(vertex[0]) !=
5505 crack_faces_verts.end()) {
5506 MOFEM_LOG("EP", sev) << "Crack face vertex";
5507 vertex_edges = intersect(vertex_edges, crack_faces_edges);
5508 }
5510 };
5511
5512 CHK_THROW_MESSAGE(impl(), "get_vertex_edges");
5513
5514 return vertex_edges;
5515 };
5516
5517 // vector of rotated faces, edge along node is moved, moved edge,
5518 // moved displacement, quality, cardinality, gamma
5519 using Bundle = std::vector<
5520
5523
5524 >;
5525 std::map<EntityHandle, Bundle> edge_bundle_map;
5526
5527 for (auto &m : edge_face_max_energy_map) {
5528
5529 auto edge = m.first;
5530 auto &[max_face, energy, opt_angle] = m.second;
5531
5532 // calculate rotation of max energy face
5533 auto [t_normal, t_rotated_normal] =
5534 get_rotated_normal(edge, max_face, opt_angle);
5535
5536 auto front_vertex = get_conn(Range(m.first, m.first));
5537 auto adj_tets = get_adj(Range(max_face, max_face), 3);
5538 auto adj_tets_faces = get_adj(adj_tets, 2);
5539 auto adj_front_faces = subtract(
5540 intersect(get_adj(Range(edge, edge), 2), adj_tets_faces),
5541 *crackFaces);
5542 if (adj_front_faces.size() > 3)
5544 "adj_front_faces.size()>3");
5545
5546 FTensor::Tensor1<double, SPACE_DIM> t_material_force;
5547 CHKERR mField.get_moab().tag_get_data(th_material_force, &edge, 1,
5548 &t_material_force(0));
5549 std::vector<double> griffith_energy(adj_front_faces.size());
5550 CHKERR mField.get_moab().tag_get_data(
5551 th_face_energy, adj_front_faces, griffith_energy.data());
5552
5553
5554 auto set_edge_bundle = [&](auto min_gamma) {
5555 for (auto rotated_f : adj_front_faces) {
5556
5557 double rotated_face_energy =
5558 griffith_energy[adj_front_faces.index(rotated_f)];
5559
5560 auto vertex = subtract(get_conn(Range(rotated_f, rotated_f)),
5561 front_vertex);
5562 if (vertex.size() != 1) {
5564 "Wrong number of vertex to move");
5565 }
5566 auto front_vertex_edges_vertex = get_conn(
5567 intersect(get_adj(front_vertex, 1), crack_faces_edges));
5568 vertex = subtract(
5569 vertex, front_vertex_edges_vertex); // vertex free to move
5570 if (vertex.empty()) {
5571 continue;
5572 }
5573
5574 auto face_cardinality = [&](auto f, auto &seen_front_edges) {
5575 auto whole_front =
5576 unite(*frontEdges,
5577 subtract(body_skin_edges, crack_faces_edges));
5578 auto faces = Range(f, f);
5579 int c = 0;
5580 for (; c < 10; ++c) {
5581 auto front_edges =
5582 subtract(get_adj(faces, 1), seen_front_edges);
5583 if (front_edges.size() == 0) {
5584 return 0;
5585 }
5586 auto front_connected_edges =
5587 intersect(front_edges, whole_front);
5588 if (front_connected_edges.size()) {
5589 seen_front_edges.merge(front_connected_edges);
5590 return c;
5591 }
5592 faces.merge(get_adj(front_edges, 2));
5593 ++c;
5594 }
5595 return c;
5596 };
5597
5598 Range seen_edges = Range(edge, edge);
5599 double rotated_face_cardinality = face_cardinality(
5600 rotated_f,
5601 seen_edges); // add cardinality of max energy
5602 // face to rotated face cardinality
5603 // rotated_face_cardinality +=
5604 // face_cardinality(max_face, seen_edges);
5605 rotated_face_cardinality = std::max(rotated_face_cardinality,
5606 1.); // at least one edge
5607
5608 auto t_vertex_coords = get_coords(vertex);
5609 auto vertex_edges = get_vertex_edges(vertex);
5610
5611 EntityHandle f0 = front_vertex[0];
5612 EntityHandle f1 = front_vertex[1];
5613 FTensor::Tensor1<double, 3> t_v_e0, t_v_e1;
5614 CHKERR mField.get_moab().get_coords(&f0, 1, &t_v_e0(0));
5615 CHKERR mField.get_moab().get_coords(&f1, 1, &t_v_e1(0));
5616
5618 for (auto e_used_to_move_detection : vertex_edges) {
5619 auto edge_conn = get_conn(Range(e_used_to_move_detection,
5620 e_used_to_move_detection));
5621 edge_conn = subtract(edge_conn, vertex);
5622 // Find displacement of the edge such that dot porduct with
5623 // normal is zero.
5624 //
5625 // { (t_v0 - t_vertex_coords) + gamma * (t_v3 -
5626 // t_vertex_coords) } * n = 0
5627 // where t_v0 is the edge vertex, t_v3 is the edge end
5628 // point, n is the rotated normal of the face gamma is the
5629 // factor by which the edge is moved
5631 t_v0(i) = (t_v_e0(i) + t_v_e1(i)) / 2;
5633 CHKERR mField.get_moab().get_coords(edge_conn, &t_v3(0));
5634 auto a =
5635 (t_v0(i) - t_vertex_coords(i)) * t_rotated_normal(i);
5636 auto b =
5637 (t_v3(i) - t_vertex_coords(i)) * t_rotated_normal(i);
5638 auto gamma = a / b;
5639
5640 constexpr double eps =
5641 std::numeric_limits<double>::epsilon();
5642 if (std::isnormal(gamma) && gamma < 1.0 - eps &&
5643 gamma > -0.1) {
5645 t_move(i) = gamma * (t_v3(i) - t_vertex_coords(i));
5646
5647 auto check_rotated_face_directoon = [&]() {
5649 t_delta(i) = t_vertex_coords(i) + t_move(i) - t_v0(i);
5650 t_delta.normalize();
5651 auto dot =
5652 (t_material_force(i) / t_material_force.l2()) *
5653 t_delta(i);
5654 return -dot > 0 ? true : false;
5655 };
5656
5657 if (check_rotated_face_directoon()) {
5658
5659 MOFEM_LOG("EP", Sev::inform)
5660 << "Crack edge " << edge << " moved face "
5661 << rotated_f
5662 << " edge: " << e_used_to_move_detection
5663 << " face direction/energy " << rotated_face_energy
5664 << " face cardinality " << rotated_face_cardinality
5665 << " gamma: " << gamma;
5666
5667 auto &bundle = edge_bundle_map[edge];
5668 bundle.emplace_back(rotated_f, e_used_to_move_detection,
5669 vertex[0], t_move, 1,
5670 rotated_face_cardinality, gamma);
5671 }
5672 }
5673 }
5674 }
5675 };
5676
5677 set_edge_bundle(std::numeric_limits<double>::epsilon());
5678 if (edge_bundle_map[edge].empty()) {
5679 set_edge_bundle(-1.);
5680 }
5681 }
5682
5683 return edge_bundle_map;
5684 };
5685
5686 auto get_sort_by_energy = [&](auto &edge_face_max_energy_map) {
5687 std::map<double, std::tuple<EntityHandle, EntityHandle, double>>
5688 sort_by_energy;
5689
5690 for (auto &m : edge_face_max_energy_map) {
5691 auto e = m.first;
5692 auto &[max_face, energy, opt_angle] = m.second;
5693 sort_by_energy[energy] = std::make_tuple(e, max_face, opt_angle);
5694 }
5695
5696 return sort_by_energy;
5697 };
5698
5699 auto set_tag = [&](auto &&adj_edges_map, auto &&sort_by_energy) {
5701
5702 Tag th_face_pressure;
5704 mField.get_moab().tag_get_handle("FacePressure", th_face_pressure),
5705 "get tag");
5706 auto get_face_pressure = [&](auto face) {
5707 double pressure;
5708 CHK_MOAB_THROW(mField.get_moab().tag_get_data(th_face_pressure, &face,
5709 1, &pressure),
5710 "get rag data");
5711 return pressure;
5712 };
5713
5714 MOFEM_LOG("EPSELF", Sev::inform)
5715 << "Number of edges to check " << sort_by_energy.size();
5716
5717 enum face_energy { POSITIVE, NEGATIVE };
5718 constexpr bool skip_negative = true;
5719
5720 for (auto fe : {face_energy::POSITIVE, face_energy::NEGATIVE}) {
5721
5722 // iterate edges wih maximal energy, and make them seed. Such edges,
5723 // will most likely will have also smallest node displacement
5724 for (auto it = sort_by_energy.rbegin(); it != sort_by_energy.rend();
5725 ++it) {
5726
5727 auto energy = it->first;
5728 auto [max_edge, max_face, opt_angle] = it->second;
5729
5730 auto face_pressure = get_face_pressure(max_face);
5731 if (skip_negative) {
5732 if (fe == face_energy::POSITIVE) {
5733 if (face_pressure < 0) {
5734 MOFEM_LOG("EPSELF", Sev::inform)
5735 << "Skip negative face " << max_face << " with energy "
5736 << energy << " and pressure " << face_pressure;
5737 continue;
5738 }
5739 }
5740 }
5741
5742 MOFEM_LOG("EPSELF", Sev::inform)
5743 << "Check face " << max_face << " edge " << max_edge
5744 << " energy " << energy << " optimal angle " << opt_angle
5745 << " face pressure " << face_pressure;
5746
5747 auto jt = adj_edges_map.find(max_edge);
5748 if (jt == adj_edges_map.end()) {
5749 MOFEM_LOG("EPSELF", Sev::warning)
5750 << "Edge " << max_edge << " not found in adj_edges_map";
5751 continue;
5752 }
5753 auto &bundle = jt->second;
5754
5755 auto find_max_in_bundle_impl = [&](auto edge, auto &bundle,
5756 auto gamma) {
5758
5759 EntityHandle vertex_max = 0;
5760 EntityHandle face_max = 0;
5761 EntityHandle move_edge_max = 0;
5762 double max_quality = -2;
5763 double max_quality_evaluated = -2;
5764 double min_cardinality = std::numeric_limits<double>::max();
5765
5766 FTensor::Tensor1<double, SPACE_DIM> t_move_last{0., 0., 0.};
5767
5768 for (auto &b : bundle) {
5769 auto &[face, move_edge, vertex, t_move, quality, cardinality,
5770 edge_gamma] = b;
5771
5772 auto adj_vertex_tets = get_adj(Range(vertex, vertex), 3);
5773 auto adj_vertex_tets_verts = get_conn(adj_vertex_tets);
5774 std::vector<double> coords(3 * adj_vertex_tets_verts.size());
5775 CHK_MOAB_THROW(mField.get_moab().get_coords(
5776 adj_vertex_tets_verts, coords.data()),
5777 "get coords");
5778
5779 set_coord(vertex, adj_vertex_tets_verts, coords, t_move, gamma);
5780 quality = tets_quality(quality, adj_vertex_tets_verts,
5781 adj_vertex_tets, coords);
5782
5783 auto eval_quality = [](auto q, auto c, auto edge_gamma) {
5784 if (q < 0) {
5785 return q;
5786 } else {
5787 return ((edge_gamma < 0) ? (q / 2) : q) / pow(c, 2);
5788 }
5789 };
5790
5791 if (eval_quality(quality, cardinality, edge_gamma) >=
5792 max_quality_evaluated) {
5793 max_quality = quality;
5794 min_cardinality = cardinality;
5795 vertex_max = vertex;
5796 face_max = face;
5797 move_edge_max = move_edge;
5798 t_move_last(i) = t_move(i);
5799 max_quality_evaluated =
5800 eval_quality(max_quality, min_cardinality, edge_gamma);
5801 }
5802 }
5803
5804 return std::make_tuple(vertex_max, face_max, t_move_last,
5805 max_quality, min_cardinality);
5806 };
5807
5808 auto find_max_in_bundle = [&](auto edge, auto &bundle) {
5809 auto b_org_bundle = bundle;
5810 auto r = find_max_in_bundle_impl(edge, bundle, 1.);
5811 auto &[vertex_max, face_max, t_move_last, max_quality,
5812 cardinality] = r;
5813 if (max_quality < 0) {
5814 for (double gamma = 0.95; gamma >= 0.45; gamma -= 0.05) {
5815 bundle = b_org_bundle;
5816 r = find_max_in_bundle_impl(edge, bundle, gamma);
5817 auto &[vertex_max, face_max, t_move_last, max_quality,
5818 cardinality] = r;
5819 MOFEM_LOG("EPSELF", Sev::warning)
5820 << "Back tracking: gamma " << gamma << " edge " << edge
5821 << " quality " << max_quality << " cardinality "
5822 << cardinality;
5823 if (max_quality > 0.01) {
5825 t_move_last(I) *= gamma;
5826 return r;
5827 }
5828 }
5830 t_move_last(I) = 0;
5831 }
5832 return r;
5833 };
5834
5835 // set tags with displacement of node and face energy
5836 auto set_tag_to_vertex_and_face = [&](auto &&r, auto &quality) {
5838 auto &[v, f, t_move, q, cardinality] = r;
5839
5840 if ((q > 0 && std::isnormal(q)) && energy > 0) {
5841
5842 MOFEM_LOG("EPSELF", Sev::inform)
5843 << "Set tag: vertex " << v << " face " << f << " "
5844 << max_edge << " move " << t_move << " energy " << energy
5845 << " quality " << q << " cardinality " << cardinality;
5846 CHKERR mField.get_moab().tag_set_data(th_position[0], &v, 1,
5847 &t_move(0));
5848 CHKERR mField.get_moab().tag_set_data(th_max_face_energy[0], &f,
5849 1, &energy);
5850 }
5851
5852 quality = q;
5854 };
5855
5856 double quality = -2;
5857 CHKERR set_tag_to_vertex_and_face(
5858
5859 find_max_in_bundle(max_edge, bundle),
5860
5861 quality
5862
5863 );
5864
5865 if (quality > 0 && std::isnormal(quality) && energy > 0) {
5866 MOFEM_LOG("EPSELF", Sev::inform)
5867 << "Crack face set with quality: " << quality;
5869 }
5870 }
5871
5872 if (!skip_negative)
5873 break;
5874 }
5875
5877 };
5878
5879 // map: {edge, {face, energy, optimal_angle}}
5880 MOFEM_LOG("EP", sev) << "Calculate orientation";
5881 std::map<EntityHandle, std::tuple<EntityHandle, double, double>>
5882 edge_face_max_energy_map;
5883 CHKERR find_maximal_face_energy(front_edges, front_faces,
5884 edge_face_max_energy_map);
5885 CHKERR calculate_face_orientation(edge_face_max_energy_map);
5886
5887 MOFEM_LOG("EP", sev) << "Calculate node positions";
5888 CHKERR set_tag(
5889
5890 calculate_free_face_node_displacement(edge_face_max_energy_map),
5891 get_sort_by_energy(edge_face_max_energy_map)
5892
5893 );
5894
5896 };
5897
5898 MOFEM_LOG("EP", sev) << "Front edges " << frontEdges->size();
5899 CHKERR evaluate_face_energy_and_set_orientation(
5900 *frontEdges, get_adj_front(false), sides_pair, th_front_position);
5901 }
5902
5903 // exchange positions and energies from processor zero to all other
5904 CHKERR VecZeroEntries(vertexExchange.second);
5905 CHKERR VecGhostUpdateBegin(vertexExchange.second, INSERT_VALUES,
5906 SCATTER_FORWARD);
5907 CHKERR VecGhostUpdateEnd(vertexExchange.second, INSERT_VALUES,
5908 SCATTER_FORWARD);
5909 CHKERR mField.getInterface<CommInterface>()->updateEntitiesPetscVector(
5910 mField.get_moab(), vertexExchange, th_front_position[0]);
5911 CHKERR VecZeroEntries(faceExchange.second);
5912 CHKERR VecGhostUpdateBegin(faceExchange.second, INSERT_VALUES,
5913 SCATTER_FORWARD);
5914 CHKERR VecGhostUpdateEnd(faceExchange.second, INSERT_VALUES, SCATTER_FORWARD);
5915 CHKERR mField.getInterface<CommInterface>()->updateEntitiesPetscVector(
5916 mField.get_moab(), faceExchange, th_max_face_energy[0]);
5917
5918 auto get_max_moved_faces = [&]() {
5919 Range max_moved_faces;
5920 auto adj_front = get_adj_front(false);
5921 std::vector<double> face_energy(adj_front.size());
5922 CHKERR mField.get_moab().tag_get_data(th_max_face_energy[0], adj_front,
5923 face_energy.data());
5924 for (int i = 0; i != adj_front.size(); ++i) {
5925 if (face_energy[i] > std::numeric_limits<double>::epsilon()) {
5926 max_moved_faces.insert(adj_front[i]);
5927 }
5928 }
5929
5930 return boost::make_shared<Range>(max_moved_faces);
5931 };
5932
5933 // move all faces with energy larger than 0
5934 maxMovedFaces = get_max_moved_faces();
5935 MOFEM_LOG("EP", sev) << "Number of of moved faces: " << maxMovedFaces->size();
5936
5937#ifndef NDEBUG
5938 if (debug) {
5940 mField.get_moab(),
5941 "max_moved_faces_" +
5942 boost::lexical_cast<std::string>(mField.get_comm_rank()) + ".vtk",
5943 *maxMovedFaces);
5944 }
5945#endif
5946
5948}
5949
5952
5953 if (!maxMovedFaces)
5955
5956 Tag th_front_position;
5957 auto rval =
5958 mField.get_moab().tag_get_handle("FrontPosition", th_front_position);
5959 if (rval == MB_SUCCESS && maxMovedFaces) {
5960 Range verts;
5961 CHKERR mField.get_moab().get_connectivity(*maxMovedFaces, verts, true);
5962 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(verts);
5963 std::vector<double> coords(3 * verts.size());
5964 CHKERR mField.get_moab().get_coords(verts, coords.data());
5965 std::vector<double> pos(3 * verts.size());
5966 CHKERR mField.get_moab().tag_get_data(th_front_position, verts, pos.data());
5967 for (int i = 0; i != 3 * verts.size(); ++i) {
5968 coords[i] += pos[i];
5969 }
5970 CHKERR mField.get_moab().set_coords(verts, coords.data());
5971 double zero[] = {0., 0., 0.};
5972 CHKERR mField.get_moab().tag_clear_data(th_front_position, verts, zero);
5973 }
5974
5975#ifndef NDEBUG
5976 constexpr bool debug = false;
5977 if (debug) {
5978
5980 mField.get_moab(),
5981 "set_coords_faces_" +
5982 boost::lexical_cast<std::string>(mField.get_comm_rank()) + ".vtk",
5983 *maxMovedFaces);
5984 }
5985#endif
5987}
5988
5991
5992 constexpr bool potential_crack_debug = false;
5993 if constexpr (potential_crack_debug) {
5994
5995 auto add_ents = get_range_from_block(mField, "POTENTIAL", SPACE_DIM - 1);
5996 Range crack_front_verts;
5997 CHKERR mField.get_moab().get_connectivity(*frontEdges, crack_front_verts,
5998 true);
5999 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
6000 crack_front_verts);
6001 Range crack_front_faces;
6002 CHKERR mField.get_moab().get_adjacencies(crack_front_verts, SPACE_DIM - 1,
6003 true, crack_front_faces,
6004 moab::Interface::UNION);
6005 crack_front_faces = intersect(crack_front_faces, add_ents);
6006 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
6007 crack_front_faces);
6008 CHKERR mField.getInterface<MeshsetsManager>()->addEntitiesToMeshset(
6009 BLOCKSET, addCrackMeshsetId, crack_front_faces);
6010 }
6011
6012 auto get_crack_faces = [&]() {
6013 if (maxMovedFaces) {
6014 return unite(*crackFaces, *maxMovedFaces);
6015 } else {
6016 return *crackFaces;
6017 }
6018 };
6019
6020 auto get_extended_crack_faces = [&]() {
6021 auto get_faces_of_crack_front_verts = [&](auto crack_faces_org) {
6022 ParallelComm *pcomm =
6023 ParallelComm::get_pcomm(&mField.get_moab(), MYPCOMM_INDEX);
6024
6025 Range crack_faces;
6026
6027 if (!pcomm->rank()) {
6028
6029 auto get_nodes = [&](auto &&e) {
6030 Range nodes;
6031 CHK_MOAB_THROW(mField.get_moab().get_connectivity(e, nodes, true),
6032 "get connectivity");
6033 return nodes;
6034 };
6035
6036 auto get_adj = [&](auto &&e, auto dim,
6037 auto t = moab::Interface::UNION) {
6038 Range adj;
6040 mField.get_moab().get_adjacencies(e, dim, true, adj, t),
6041 "get adj");
6042 return adj;
6043 };
6044
6045 Range body_ents;
6046 CHKERR mField.get_moab().get_entities_by_dimension(0, SPACE_DIM,
6047 body_ents);
6048 auto body_skin = get_skin(mField, body_ents);
6049 auto body_skin_edges = get_adj(body_skin, 1, moab::Interface::UNION);
6050 auto geometry_edges = get_range_from_block(mField, "EDGES", 1);
6051 auto front_block_edges = get_range_from_block(mField, "FRONT", 1);
6052 auto front_block_nodes = get_nodes(front_block_edges);
6053
6054 size_t s;
6055 do {
6056 s = crack_faces.size();
6057
6058 auto crack_face_nodes = get_nodes(crack_faces_org);
6059 auto crack_faces_edges =
6060 get_adj(crack_faces_org, 1, moab::Interface::UNION);
6061
6062 auto crack_skin = get_skin(mField, crack_faces_org);
6063 front_block_edges = subtract(front_block_edges, crack_skin);
6064 auto crack_skin_nodes = get_nodes(crack_skin);
6065 crack_skin_nodes.merge(front_block_nodes);
6066
6067 auto crack_skin_faces =
6068 get_adj(crack_skin, 2, moab::Interface::UNION);
6069 crack_skin_faces =
6070 subtract(subtract(crack_skin_faces, crack_faces_org), body_skin);
6071
6072 crack_faces = crack_faces_org;
6073 for (auto f : crack_skin_faces) {
6074 auto edges = intersect(
6075 get_adj(Range(f, f), 1, moab::Interface::UNION), crack_skin);
6076
6077 // if other edge is part of body skin, e.g. crack punching through
6078 // body surface
6079 if (edges.size() == 2) {
6080 edges.merge(
6081 intersect(get_adj(Range(f, f), 1, moab::Interface::UNION),
6082 body_skin_edges));
6083 }
6084
6085 if (edges.size() == 2) {
6086 auto edge_conn = get_nodes(Range(edges));
6087 auto faces = intersect(get_adj(edges, 2, moab::Interface::UNION),
6088 crack_faces_org);
6089 if (faces.size() == 2) {
6090 auto edge0_conn = get_nodes(Range(edges[0], edges[0]));
6091 auto edge1_conn = get_nodes(Range(edges[1], edges[1]));
6092 auto edges_conn = intersect(intersect(edge0_conn, edge1_conn),
6093 crack_skin_nodes); // node at apex
6094 if (edges_conn.size() == 1) {
6095
6096 auto node_edges =
6097 subtract(intersect(get_adj(edges_conn, 1,
6098 moab::Interface::INTERSECT),
6099 crack_faces_edges),
6100 crack_skin); // nodes on crack surface, but not
6101 // at the skin
6102
6103 if (node_edges.size()) {
6106 CHKERR mField.get_moab().get_coords(edges_conn, &t_v0(0));
6107
6108 auto get_t_dir = [&](auto e_conn) {
6109 auto other_node = subtract(e_conn, edges_conn);
6111 CHKERR mField.get_moab().get_coords(other_node,
6112 &t_dir(0));
6113 t_dir(i) -= t_v0(i);
6114 return t_dir;
6115 };
6116
6118 t_ave_dir(i) =
6119 get_t_dir(edge0_conn)(i) + get_t_dir(edge1_conn)(i);
6120
6121 FTensor::Tensor1<double, SPACE_DIM> t_crack_surface_ave_dir;
6122 t_crack_surface_ave_dir(i) = 0;
6123 for (auto e : node_edges) {
6124 auto e_conn = get_nodes(Range(e, e));
6125 auto t_dir = get_t_dir(e_conn);
6126 t_crack_surface_ave_dir(i) += t_dir(i);
6127 }
6128
6129 auto dot = t_ave_dir(i) * t_crack_surface_ave_dir(i);
6130 // ave edges is in opposite direction to crack surface, so
6131 // thus crack is not turning back
6132 if (dot < -std::numeric_limits<double>::epsilon()) {
6133 crack_faces.insert(f);
6134 }
6135 } else {
6136 crack_faces.insert(f);
6137 }
6138 }
6139 }
6140 } else if (edges.size() == 3) {
6141 crack_faces.insert(f);
6142 }
6143
6144 // if other edge is part of geometry edge, e.g. keyway
6145 if (edges.size() == 1) {
6146 edges.merge(
6147 intersect(get_adj(Range(f, f), 1, moab::Interface::UNION),
6148 geometry_edges));
6149 edges.merge(
6150 intersect(get_adj(Range(f, f), 1, moab::Interface::UNION),
6151 front_block_edges));
6152 if (edges.size() == 2) {
6153 crack_faces.insert(f);
6154 continue;
6155 }
6156 }
6157 }
6158
6159 crack_faces_org = crack_faces;
6160
6161 } while (s != crack_faces.size());
6162 };
6163
6164 return crack_faces; // send_type(mField, crack_faces, MBTRI);
6165 };
6166
6167 return get_faces_of_crack_front_verts(get_crack_faces());
6168 };
6169
6170 if (debug) {
6171 CHKERR save_range(mField.get_moab(), "new_crack_surface_debug.vtk",
6172 get_extended_crack_faces());
6173 }
6174
6175 auto reconstruct_crack_faces = [&](auto crack_faces) {
6176 ParallelComm *pcomm =
6177 ParallelComm::get_pcomm(&mField.get_moab(), MYPCOMM_INDEX);
6178
6179 auto impl = [&]() {
6181
6182 Range new_crack_faces;
6183 if (!pcomm->rank()) {
6184
6185 auto get_nodes = [&](auto &&e) {
6186 Range nodes;
6187 CHK_MOAB_THROW(mField.get_moab().get_connectivity(e, nodes, true),
6188 "get connectivity");
6189 return nodes;
6190 };
6191
6192 auto get_adj = [&](auto &&e, auto dim,
6193 auto t = moab::Interface::UNION) {
6194 Range adj;
6196 mField.get_moab().get_adjacencies(e, dim, true, adj, t),
6197 "get adj");
6198 return adj;
6199 };
6200
6201 auto get_test_on_crack_surface = [&]() {
6202 auto crack_faces_nodes =
6203 get_nodes(crack_faces); // nodes on crac faces
6204 auto crack_faces_tets =
6205 get_adj(crack_faces_nodes, 3,
6206 moab::Interface::UNION); // adjacent
6207 // tets to
6208 // crack
6209 // faces throug nodes
6210 auto crack_faces_tets_nodes =
6211 get_nodes(crack_faces_tets); // nodes on crack faces tets
6212 crack_faces_tets_nodes =
6213 subtract(crack_faces_tets_nodes, crack_faces_nodes);
6214 crack_faces_tets =
6215 subtract(crack_faces_tets, get_adj(crack_faces_tets_nodes, 3,
6216 moab::Interface::UNION));
6217 new_crack_faces =
6218 get_adj(crack_faces_tets, 2,
6219 moab::Interface::UNION); // adjacency faces to crack
6220 // faces through tets
6221 new_crack_faces.merge(crack_faces); // add original crack faces
6222
6223 return std::make_tuple(new_crack_faces, crack_faces_tets);
6224 };
6225
6226 auto carck_faces_test_edges = [&](auto faces, auto tets) {
6227 auto adj_tets_faces = get_adj(tets, 2, moab::Interface::UNION);
6228 auto adj_faces_edges = get_adj(subtract(faces, adj_tets_faces), 1,
6229 moab::Interface::UNION);
6230 auto adj_tets_edges = get_adj(tets, 1, moab::Interface::UNION);
6231 auto geometry_edges = get_range_from_block(mField, "EDGES", 1);
6232 auto front_block_edges = get_range_from_block(mField, "FRONT", 1);
6233 adj_faces_edges.merge(geometry_edges); // geometry edges
6234 adj_faces_edges.merge(front_block_edges); // front block edges
6235
6236 auto boundary_tets_edges = intersect(adj_tets_edges, adj_faces_edges);
6237 auto boundary_test_nodes = get_nodes(boundary_tets_edges);
6238 auto boundary_test_nodes_edges =
6239 get_adj(boundary_test_nodes, 1, moab::Interface::UNION);
6240 auto boundary_test_nodes_edges_nodes = subtract(
6241 get_nodes(boundary_test_nodes_edges), boundary_test_nodes);
6242
6243 boundary_tets_edges =
6244 subtract(boundary_test_nodes_edges,
6245 get_adj(boundary_test_nodes_edges_nodes, 1,
6246 moab::Interface::UNION));
6247
6248 Range body_ents;
6249 CHKERR mField.get_moab().get_entities_by_dimension(0, SPACE_DIM,
6250 body_ents);
6251 auto body_skin = get_skin(mField, body_ents);
6252
6253 auto body_skin_edges = get_adj(body_skin, 1, moab::Interface::UNION);
6254 body_skin_edges = intersect(get_adj(tets, 1, moab::Interface::UNION),
6255 body_skin_edges);
6256 body_skin = intersect(body_skin, adj_tets_faces);
6257 body_skin_edges = subtract(
6258 body_skin_edges, get_adj(body_skin, 1, moab::Interface::UNION));
6259
6260 save_range(mField.get_moab(), "body_skin_edges.vtk", body_skin_edges);
6261 for (auto e : body_skin_edges) {
6262 auto adj_tet = intersect(
6263 get_adj(Range(e, e), 3, moab::Interface::INTERSECT), tets);
6264 if (adj_tet.size() == 1) {
6265 boundary_tets_edges.insert(e);
6266 }
6267 }
6268
6269 return boundary_tets_edges;
6270 };
6271
6272 auto p = get_test_on_crack_surface();
6273 auto &[new_crack_faces, crack_faces_tets] = p;
6274
6275 if (debug) {
6276 CHKERR save_range(mField.get_moab(), "hole_crack_faces_debug.vtk",
6277 crack_faces);
6278 CHKERR save_range(mField.get_moab(), "new_crack_faces_debug.vtk",
6279 new_crack_faces);
6280 CHKERR save_range(mField.get_moab(), "new_crack_tets_debug.vtk",
6281 crack_faces_tets);
6282 }
6283
6284 auto boundary_tets_edges =
6285 carck_faces_test_edges(new_crack_faces, crack_faces_tets);
6286 CHKERR save_range(mField.get_moab(), "boundary_tets_edges.vtk",
6287 boundary_tets_edges);
6288
6289 auto resolve_surface = [&](auto boundary_tets_edges,
6290 auto crack_faces_tets) {
6291 auto boundary_tets_edges_nodes = get_nodes(boundary_tets_edges);
6292 auto crack_faces_tets_faces =
6293 get_adj(crack_faces_tets, 2, moab::Interface::UNION);
6294
6295 Range all_removed_faces;
6296 Range all_removed_tets;
6297 int counter = 0;
6298
6299 int size = 0;
6300 while (size != crack_faces_tets.size()) {
6301 auto tets_faces =
6302 get_adj(crack_faces_tets, 2, moab::Interface::UNION);
6303 auto skin_tets = get_skin(mField, crack_faces_tets);
6304 auto skin_skin =
6305 get_skin(mField, subtract(crack_faces_tets_faces, tets_faces));
6306 auto skin_skin_nodes = get_nodes(skin_skin);
6307
6308 size = crack_faces_tets.size();
6309 MOFEM_LOG("SELF", Sev::inform)
6310 << "Crack faces tets size " << crack_faces_tets.size()
6311 << " crack faces size " << crack_faces_tets_faces.size();
6312 auto skin_tets_nodes = subtract(
6313 get_nodes(skin_tets),
6314 boundary_tets_edges_nodes); // not remove tets which are
6315 // adjagasent to crack faces nodes
6316 skin_tets_nodes = subtract(skin_tets_nodes, skin_skin_nodes);
6317
6318 Range removed_nodes;
6319 Range tets_to_remove;
6320 Range faces_to_remove;
6321 for (auto n : skin_tets_nodes) {
6322 auto tets =
6323 intersect(get_adj(Range(n, n), 3, moab::Interface::INTERSECT),
6324 crack_faces_tets);
6325 if (tets.size() == 0) {
6326 continue;
6327 }
6328
6329 auto hole_detetction = [&]() {
6330 auto adj_tets =
6331 get_adj(Range(n, n), 3, moab::Interface::INTERSECT);
6332 adj_tets =
6333 subtract(adj_tets,
6334 crack_faces_tets); // tetst adjacent to the node
6335 // but not part of crack surface
6336 if (adj_tets.size() == 0) {
6337 return std::make_pair(
6338 intersect(
6339 get_adj(Range(n, n), 2, moab::Interface::INTERSECT),
6340 tets_faces),
6341 tets);
6342 }
6343
6344 std::vector<Range> tets_groups;
6345 auto test_adj_tets = adj_tets;
6346 while (test_adj_tets.size()) {
6347 auto seed_size = 0;
6348 Range seed = Range(test_adj_tets[0], test_adj_tets[0]);
6349 while (seed.size() != seed_size) {
6350 auto adj_faces =
6351 subtract(get_adj(seed, 2, moab::Interface::UNION),
6352 tets_faces); // edges which are not
6353 // part of the node
6354 seed_size = seed.size();
6355 seed.merge(
6356 intersect(get_adj(adj_faces, 3, moab::Interface::UNION),
6357 test_adj_tets ));
6358 }
6359 tets_groups.push_back(seed);
6360 test_adj_tets = subtract(test_adj_tets, seed);
6361 }
6362 if (tets_groups.size() == 1) {
6363
6364 return std::make_pair(
6365 intersect(
6366 get_adj(Range(n, n), 2, moab::Interface::INTERSECT),
6367 tets_faces),
6368 tets);
6369
6370 }
6371
6372 Range tets_to_remove;
6373 Range faces_to_remove;
6374 for (auto &r : tets_groups) {
6375 auto f = get_adj(r, 2, moab::Interface::UNION);
6376 auto t = intersect(get_adj(f, 3, moab::Interface::UNION),
6377 crack_faces_tets); // tets
6378
6379 if (f.size() > faces_to_remove.size() ||
6380 faces_to_remove.size() == 0) {
6381 faces_to_remove = f;
6382 tets_to_remove = t; // largest group of tets
6383 }
6384 }
6385 MOFEM_LOG("EPSELF", Sev::inform)
6386 << "Hole detection: faces to remove "
6387 << faces_to_remove.size() << " tets to remove "
6388 << tets_to_remove.size();
6389 return std::make_pair(faces_to_remove, tets_to_remove);
6390 };
6391
6392 if (tets.size() < tets_to_remove.size() ||
6393 tets_to_remove.size() == 0) {
6394 removed_nodes = Range(n, n);
6395 auto [h_faces_to_remove, h_tets_to_remove] =
6396 hole_detetction(); // find faces and tets to remove
6397 faces_to_remove = h_faces_to_remove;
6398 tets_to_remove = h_tets_to_remove;
6399
6400 // intersect(
6401 // get_adj(Range(n, n), 2, moab::Interface::INTERSECT),
6402 // tets_faces);
6403
6404 } // find tets which is largest adjacencty size, so that it is
6405 // removed first, and then faces are removed
6406 all_removed_faces.merge(faces_to_remove);
6407 all_removed_tets.merge(tets_to_remove);
6408 }
6409
6410 crack_faces_tets = subtract(crack_faces_tets, tets_to_remove);
6411 crack_faces_tets_faces =
6412 subtract(crack_faces_tets_faces, faces_to_remove);
6413
6414 if (debug) {
6416 "removed_nodes_" +
6417 boost::lexical_cast<std::string>(counter) + ".vtk",
6418 removed_nodes);
6420 "faces_to_remove_" +
6421 boost::lexical_cast<std::string>(counter) + ".vtk",
6422 faces_to_remove);
6424 "tets_to_remove_" +
6425 boost::lexical_cast<std::string>(counter) + ".vtk",
6426 tets_to_remove);
6428 "crack_faces_tets_faces_" +
6429 boost::lexical_cast<std::string>(counter) + ".vtk",
6430 crack_faces_tets_faces);
6432 "crack_faces_tets_" +
6433 boost::lexical_cast<std::string>(counter) + ".vtk",
6434 crack_faces_tets);
6435 }
6436 counter++;
6437 }
6438
6439 auto cese_internal_faces = [&]() {
6441 auto skin_tets = get_skin(mField, crack_faces_tets);
6442 auto adj_faces = get_adj(skin_tets, 2, moab::Interface::UNION);
6443 adj_faces =
6444 subtract(adj_faces, skin_tets); // remove skin tets faces
6445 auto adj_tets = get_adj(adj_faces, 3,
6446 moab::Interface::UNION); // tets which are
6447 // adjacent to skin
6448 crack_faces_tets =
6449 subtract(crack_faces_tets,
6450 adj_tets); // remove tets which are adjacent to
6451 // skin, so that they are not removed
6452 crack_faces_tets_faces =
6453 subtract(crack_faces_tets_faces, adj_faces);
6454
6455 all_removed_faces.merge(adj_faces);
6456 all_removed_tets.merge(adj_tets);
6457
6458
6459 MOFEM_LOG("EPSELF", Sev::inform)
6460 << "Remove internal faces size " << adj_faces.size()
6461 << " tets size " << adj_tets.size();
6463 };
6464
6465 auto case_only_one_free_edge = [&]() {
6467
6468 for (auto t : Range(crack_faces_tets)) {
6469
6470 auto adj_faces = get_adj(
6471 Range(t, t), 2,
6472 moab::Interface::UNION); // faces of tet which can be removed
6473 auto crack_surface_edges =
6474 get_adj(subtract(unite(crack_faces_tets_faces, crack_faces),
6475 adj_faces),
6476 1,
6477 moab::Interface::UNION); // edges not on the tet but
6478 // on crack surface
6479 auto adj_edges =
6480 subtract(get_adj(Range(t, t), 1, moab::Interface::INTERSECT),
6481 crack_surface_edges); // free edges
6482 adj_edges = subtract(
6483 adj_edges,
6484 boundary_tets_edges); // edges which are not part of gemetry
6485
6486 if (adj_edges.size() == 1) {
6487 crack_faces_tets =
6488 subtract(crack_faces_tets,
6489 Range(t, t)); // remove tets which are adjacent to
6490 // skin, so that they are not removed
6491
6492 auto faces_to_remove =
6493 get_adj(adj_edges, 2, moab::Interface::UNION); // faces
6494 // which can
6495 // be removed
6496 crack_faces_tets_faces =
6497 subtract(crack_faces_tets_faces, faces_to_remove);
6498
6499 all_removed_faces.merge(faces_to_remove);
6500 all_removed_tets.merge(Range(t, t));
6501
6502 MOFEM_LOG("EPSELF", Sev::inform) << "Remove free one edges ";
6503 }
6504 }
6505
6506 crack_faces_tets = subtract(crack_faces_tets, all_removed_tets);
6507 crack_faces_tets_faces =
6508 subtract(crack_faces_tets_faces, all_removed_faces);
6509
6511 };
6512
6513 auto cese_flat_tet = [&](auto max_adj_edges) {
6515
6516 Range body_ents;
6517 CHKERR mField.get_moab().get_entities_by_dimension(0, SPACE_DIM,
6518 body_ents);
6519 auto body_skin = get_skin(mField, body_ents);
6520 auto body_skin_edges =
6521 get_adj(body_skin, 1, moab::Interface::UNION);
6522
6523 for (auto t : Range(crack_faces_tets)) {
6524
6525 auto adj_faces = get_adj(
6526 Range(t, t), 2,
6527 moab::Interface::UNION); // faces of tet which can be removed
6528 auto crack_surface_edges =
6529 get_adj(subtract(unite(crack_faces_tets_faces, crack_faces),
6530 adj_faces),
6531 1,
6532 moab::Interface::UNION); // edges not on the tet but
6533 // on crack surface
6534 auto adj_edges =
6535 subtract(get_adj(Range(t, t), 1, moab::Interface::INTERSECT),
6536 crack_surface_edges); // free edges
6537 adj_edges = subtract(adj_edges, body_skin_edges);
6538
6539 auto tet_edges = get_adj(Range(t, t), 1,
6540 moab::Interface::UNION); // edges of
6541 // tet
6542 tet_edges = subtract(tet_edges, adj_edges);
6543
6544 for (auto e : tet_edges) {
6545 constexpr int opposite_edge[] = {5, 3, 4, 1, 2, 0};
6546 auto get_side = [&](auto e) {
6547 int side, sense, offset;
6549 mField.get_moab().side_number(t, e, side, sense, offset),
6550 "get side number failed");
6551 return side;
6552 };
6553 auto get_side_ent = [&](auto side) {
6554 EntityHandle side_edge;
6556 mField.get_moab().side_element(t, 1, side, side_edge),
6557 "get side failed");
6558 return side_edge;
6559 };
6560 adj_edges.erase(get_side_ent(opposite_edge[get_side(e)]));
6561 }
6562
6563 if (adj_edges.size() <= max_adj_edges) {
6564
6565 double dot = 1;
6566 Range faces_to_remove;
6567 for (auto e : adj_edges) {
6568 auto edge_adj_faces =
6569 get_adj(Range(e, e), 2, moab::Interface::UNION);
6570 edge_adj_faces = intersect(edge_adj_faces, adj_faces);
6571 if (edge_adj_faces.size() != 2) {
6573 "Adj faces size is not 2 for edge " +
6574 boost::lexical_cast<std::string>(e));
6575 }
6576
6577 auto get_normal = [&](auto f) {
6580 mField.getInterface<Tools>()->getTriNormal(f, &t_n(0)),
6581 "get tri normal failed");
6582 return t_n;
6583 };
6584 auto t_n0 = get_normal(edge_adj_faces[0]);
6585 auto t_n1 = get_normal(edge_adj_faces[1]);
6586 auto get_sense = [&](auto f) {
6587 int side, sense, offset;
6588 CHK_MOAB_THROW(mField.get_moab().side_number(t, f, side,
6589 sense, offset),
6590 "get side number failed");
6591 return sense;
6592 };
6593 auto sense0 = get_sense(edge_adj_faces[0]);
6594 auto sense1 = get_sense(edge_adj_faces[1]);
6595 t_n0.normalize();
6596 t_n1.normalize();
6597
6599 auto dot_e = (sense0 * sense1) * t_n0(i) * t_n1(i);
6600 if (dot_e < dot || e == adj_edges[0]) {
6601 dot = dot_e;
6602 faces_to_remove = edge_adj_faces;
6603 }
6604 }
6605
6606 all_removed_faces.merge(faces_to_remove);
6607 all_removed_tets.merge(Range(t, t));
6608
6609 MOFEM_LOG("EPSELF", Sev::inform)
6610 << "Remove free edges on flat tet, with considered nb. of "
6611 "edges "
6612 << adj_edges.size();
6613 }
6614 }
6615
6616 crack_faces_tets = subtract(crack_faces_tets, all_removed_tets);
6617 crack_faces_tets_faces =
6618 subtract(crack_faces_tets_faces, all_removed_faces);
6619
6621 };
6622
6623 CHK_THROW_MESSAGE(case_only_one_free_edge(),
6624 "Case only one free edge failed");
6625 for (auto max_adj_edges : {0, 1, 2, 3}) {
6626 CHK_THROW_MESSAGE(cese_flat_tet(max_adj_edges),
6627 "Case only one free edge failed");
6628 }
6629 CHK_THROW_MESSAGE(cese_internal_faces(),
6630 "Case internal faces failed");
6631
6632 if (debug) {
6634 "crack_faces_tets_faces_" +
6635 boost::lexical_cast<std::string>(counter) + ".vtk",
6636 crack_faces_tets_faces);
6638 "crack_faces_tets_" +
6639 boost::lexical_cast<std::string>(counter) + ".vtk",
6640 crack_faces_tets);
6641 }
6642
6643 return std::make_tuple(crack_faces_tets_faces, crack_faces_tets,
6644 all_removed_faces, all_removed_tets);
6645 };
6646
6647 auto [resolved_faces, resolved_tets, all_removed_faces,
6648 all_removed_tets] =
6649 resolve_surface(boundary_tets_edges, crack_faces_tets);
6650 resolved_faces.merge(subtract(crack_faces, all_removed_faces));
6651 if (debug) {
6652 CHKERR save_range(mField.get_moab(), "resolved_faces.vtk",
6653 resolved_faces);
6654 CHKERR save_range(mField.get_moab(), "resolved_tets.vtk",
6655 resolved_tets);
6656 }
6657
6658 crack_faces = resolved_faces;
6659 }
6660
6662 };
6663
6664 CHK_THROW_MESSAGE(impl(), "resolve new crack surfaces");
6665
6666 return crack_faces; // send_type(mField, crack_faces, MBTRI);
6667 };
6668
6669
6670 auto resolve_consisten_crack_extension = [&]() {
6672 auto crack_meshset =
6673 mField.getInterface<MeshsetsManager>()->getCubitMeshsetPtr(
6675 auto meshset = crack_meshset->getMeshset();
6676
6677
6678 if (!mField.get_comm_rank()) {
6679 Range old_crack_faces;
6680 CHKERR mField.get_moab().get_entities_by_type(meshset, MBTRI,
6681 old_crack_faces);
6682 auto extendeded_crack_faces = get_extended_crack_faces();
6683 auto reconstructed_crack_faces =
6684 subtract(reconstruct_crack_faces(extendeded_crack_faces),
6685 subtract(*crackFaces, old_crack_faces));
6686 if (nbCrackFaces >= reconstructed_crack_faces.size()) {
6687 MOFEM_LOG("EPSELF", Sev::warning)
6688 << "No new crack faces to add, skipping adding to meshset";
6689 extendeded_crack_faces = subtract(
6690 extendeded_crack_faces, subtract(*crackFaces, old_crack_faces));
6691 MOFEM_LOG("EPSELF", Sev::inform)
6692 << "Number crack faces size (extended) "
6693 << extendeded_crack_faces.size();
6694 CHKERR mField.get_moab().clear_meshset(&meshset, 1);
6695 CHKERR mField.get_moab().add_entities(meshset, extendeded_crack_faces);
6696 } else {
6697 CHKERR mField.get_moab().clear_meshset(&meshset, 1);
6698 CHKERR mField.get_moab().add_entities(meshset,
6699 reconstructed_crack_faces);
6700 MOFEM_LOG("EPSELF", Sev::inform)
6701 << "Number crack faces size (reconstructed) "
6702 << reconstructed_crack_faces.size();
6703 nbCrackFaces = reconstructed_crack_faces.size();
6704 }
6705 }
6706
6707 Range crack_faces;
6708 if (!mField.get_comm_rank()) {
6709 CHKERR mField.get_moab().get_entities_by_type(meshset, MBTRI,
6710 crack_faces);
6711 }
6712 crack_faces = send_type(mField, crack_faces, MBTRI);
6713 if (mField.get_comm_rank()) {
6714 CHKERR mField.get_moab().clear_meshset(&meshset, 1);
6715 CHKERR mField.get_moab().add_entities(meshset, crack_faces);
6716 }
6717
6719 };
6720
6721 CHKERR resolve_consisten_crack_extension();
6722
6724};
6725
6728 auto crack_faces =
6729 get_range_from_block(mField, "CRACK_COMPUTED", SPACE_DIM - 1);
6730 Range conn;
6731 CHKERR mField.get_moab().get_connectivity(crack_faces, conn, true);
6732 Range verts;
6733 CHKERR mField.get_moab().get_entities_by_type(0, MBVERTEX, verts);
6734 verts = subtract(verts, conn);
6735 std::vector<double> coords(3 * verts.size());
6736 CHKERR mField.get_moab().get_coords(verts, coords.data());
6737 double def_coords[] = {0., 0., 0.};
6738 Tag th_org_coords;
6739 CHKERR mField.get_moab().tag_get_handle(
6740 "ORG_COORDS", 3, MB_TYPE_DOUBLE, th_org_coords,
6741 MB_TAG_CREAT | MB_TAG_DENSE, def_coords);
6742 CHKERR mField.get_moab().tag_set_data(th_org_coords, verts, coords.data());
6744}
6745
6748 auto meshset_mng = mField.getInterface<MeshsetsManager>();
6749 while (meshset_mng->checkMeshset(addCrackMeshsetId, BLOCKSET))
6751 MOFEM_LOG("EP", Sev::inform)
6752 << "Crack added surface meshset " << addCrackMeshsetId;
6753 CHKERR meshset_mng->addMeshset(BLOCKSET, addCrackMeshsetId, "CRACK_COMPUTED");
6755};
6756
6757//! [Getting norms]
6760
6761 auto post_proc_norm_fe =
6762 boost::make_shared<VolumeElementForcesAndSourcesCore>(mField);
6763
6764 auto post_proc_norm_rule_hook = [](int, int, int p) -> int {
6765 return 2 * (p);
6766 };
6767 post_proc_norm_fe->getRuleHook = post_proc_norm_rule_hook;
6768
6769 post_proc_norm_fe->getUserPolynomialBase() =
6770 boost::shared_ptr<BaseFunction>(new CGGUserPolynomialBase());
6771
6772 CHKERR EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
6773 post_proc_norm_fe->getOpPtrVector(), {L2, H1, HDIV}, materialH1Positions,
6775
6776 enum NORMS { U_NORM_L2 = 0, U_NORM_H1, PIOLA_NORM, U_ERROR_L2, LAST_NORM };
6777 auto norms_vec =
6778 createVectorMPI(mField.get_comm(), LAST_NORM, PETSC_DETERMINE);
6779 CHKERR VecZeroEntries(norms_vec);
6780
6781 auto u_l2_ptr = boost::make_shared<MatrixDouble>();
6782 auto u_h1_ptr = boost::make_shared<MatrixDouble>();
6783 post_proc_norm_fe->getOpPtrVector().push_back(
6785 post_proc_norm_fe->getOpPtrVector().push_back(
6787 post_proc_norm_fe->getOpPtrVector().push_back(
6788 new OpCalcNormL2Tensor1<SPACE_DIM>(u_l2_ptr, norms_vec, U_NORM_L2));
6789 post_proc_norm_fe->getOpPtrVector().push_back(
6790 new OpCalcNormL2Tensor1<SPACE_DIM>(u_h1_ptr, norms_vec, U_NORM_H1));
6791 post_proc_norm_fe->getOpPtrVector().push_back(
6792 new OpCalcNormL2Tensor1<SPACE_DIM>(u_l2_ptr, norms_vec, U_ERROR_L2,
6793 u_h1_ptr));
6794
6795 auto piola_ptr = boost::make_shared<MatrixDouble>();
6796 post_proc_norm_fe->getOpPtrVector().push_back(
6798 post_proc_norm_fe->getOpPtrVector().push_back(
6800 MBMAXTYPE));
6801
6802 post_proc_norm_fe->getOpPtrVector().push_back(
6803 new OpCalcNormL2Tensor2<3, 3>(piola_ptr, norms_vec, PIOLA_NORM));
6804
6805 TetPolynomialBase::switchCacheBaseOn<HDIV>({post_proc_norm_fe.get()});
6807 *post_proc_norm_fe);
6808 TetPolynomialBase::switchCacheBaseOff<HDIV>({post_proc_norm_fe.get()});
6809
6810 CHKERR VecAssemblyBegin(norms_vec);
6811 CHKERR VecAssemblyEnd(norms_vec);
6812 const double *norms;
6813 CHKERR VecGetArrayRead(norms_vec, &norms);
6814 MOFEM_LOG("EP", Sev::inform) << "norm_u: " << std::sqrt(norms[U_NORM_L2]);
6815 MOFEM_LOG("EP", Sev::inform) << "norm_u_h1: " << std::sqrt(norms[U_NORM_H1]);
6816 MOFEM_LOG("EP", Sev::inform)
6817 << "norm_error_u_l2: " << std::sqrt(norms[U_ERROR_L2]);
6818 MOFEM_LOG("EP", Sev::inform)
6819 << "norm_piola: " << std::sqrt(norms[PIOLA_NORM]);
6820 CHKERR VecRestoreArrayRead(norms_vec, &norms);
6821
6823}
6824//! [Getting norms]
6825
6828
6829 auto bc_mng = mField.getInterface<BcManager>();
6831 "", piolaStress, false, false);
6832
6833 bcSpatialDispVecPtr = boost::make_shared<BcDispVec>();
6834 for (auto bc : bc_mng->getBcMapByBlockName()) {
6835 if (auto disp_bc = bc.second->dispBcPtr) {
6836
6837 auto [field_name, block_name] =
6839 MOFEM_LOG("EP", Sev::inform)
6840 << "Field name: " << field_name << " Block name: " << block_name;
6841 MOFEM_LOG("EP", Sev::noisy) << "Displacement BC: " << *disp_bc;
6842
6843 std::vector<double> block_attributes(6, 0.);
6844 if (disp_bc->data.flag1 == 1) {
6845 block_attributes[0] = disp_bc->data.value1;
6846 block_attributes[3] = 1;
6847 }
6848 if (disp_bc->data.flag2 == 1) {
6849 block_attributes[1] = disp_bc->data.value2;
6850 block_attributes[4] = 1;
6851 }
6852 if (disp_bc->data.flag3 == 1) {
6853 block_attributes[2] = disp_bc->data.value3;
6854 block_attributes[5] = 1;
6855 }
6856 auto faces = bc.second->bcEnts.subset_by_dimension(2);
6857 bcSpatialDispVecPtr->emplace_back(block_name, block_attributes, faces);
6858 }
6859 }
6860 // old way of naming blocksets for displacement BCs
6861 CHKERR getBc(bcSpatialDispVecPtr, "SPATIAL_DISP_BC", 6);
6862
6864 boost::make_shared<NormalDisplacementBcVec>();
6865 for (auto bc : bc_mng->getBcMapByBlockName()) {
6866 auto block_name = "(.*)NORMAL_DISPLACEMENT(.*)";
6867 std::regex reg_name(block_name);
6868 if (std::regex_match(bc.first, reg_name)) {
6869 auto [field_name, block_name] =
6871 MOFEM_LOG("EP", Sev::inform)
6872 << "Field name: " << field_name << " Block name: " << block_name;
6874 block_name, bc.second->bcAttributes,
6875 bc.second->bcEnts.subset_by_dimension(2));
6876 }
6877 }
6878
6880 boost::make_shared<AnalyticalDisplacementBcVec>();
6881
6882 for (auto bc : bc_mng->getBcMapByBlockName()) {
6883 auto block_name = "(.*)ANALYTICAL_DISPLACEMENT(.*)";
6884 std::regex reg_name(block_name);
6885 if (std::regex_match(bc.first, reg_name)) {
6886 auto [field_name, block_name] =
6888 MOFEM_LOG("EP", Sev::inform)
6889 << "Field name: " << field_name << " Block name: " << block_name;
6891 block_name, bc.second->bcAttributes,
6892 bc.second->bcEnts.subset_by_dimension(2));
6893 }
6894 }
6895
6896 auto ts_displacement =
6897 boost::make_shared<DynamicRelaxationTimeScale>("disp_history.txt");
6898 for (auto &bc : *bcSpatialDispVecPtr) {
6899 MOFEM_LOG("EP", Sev::noisy)
6900 << "Add time scaling displacement BC: " << bc.blockName;
6901 timeScaleMap[bc.blockName] =
6903 ts_displacement, "disp_history", ".txt", bc.blockName);
6904 }
6905
6906 auto ts_normal_displacement =
6907 boost::make_shared<DynamicRelaxationTimeScale>("normal_disp_history.txt");
6908 for (auto &bc : *bcSpatialNormalDisplacementVecPtr) {
6909 MOFEM_LOG("EP", Sev::noisy)
6910 << "Add time scaling normal displacement BC: " << bc.blockName;
6911 timeScaleMap[bc.blockName] =
6913 ts_normal_displacement, "normal_disp_history", ".txt",
6914 bc.blockName);
6915 }
6916
6918}
6919
6922
6923 auto bc_mng = mField.getInterface<BcManager>();
6925 false, false);
6926
6927 bcSpatialTractionVecPtr = boost::make_shared<TractionBcVec>();
6928
6929 for (auto bc : bc_mng->getBcMapByBlockName()) {
6930 if (auto force_bc = bc.second->forceBcPtr) {
6931
6932 auto [field_name, block_name] =
6934 MOFEM_LOG("EP", Sev::inform)
6935 << "Field name: " << field_name << " Block name: " << block_name;
6936 MOFEM_LOG("EP", Sev::noisy) << "Force BC: " << *force_bc;
6937
6938 std::vector<double> block_attributes(6, 0.);
6939 block_attributes[0] = -force_bc->data.value3 * force_bc->data.value1;
6940 block_attributes[3] = 1;
6941 block_attributes[1] = -force_bc->data.value4 * force_bc->data.value1;
6942 block_attributes[4] = 1;
6943 block_attributes[2] = -force_bc->data.value5 * force_bc->data.value1;
6944 block_attributes[5] = 1;
6945 auto faces = bc.second->bcEnts.subset_by_dimension(2);
6946 bcSpatialTractionVecPtr->emplace_back(block_name, block_attributes,
6947 faces);
6948 }
6949 }
6950 CHKERR getBc(bcSpatialTractionVecPtr, "SPATIAL_TRACTION_BC", 6);
6951
6952 bcSpatialPressureVecPtr = boost::make_shared<PressureBcVec>();
6953 for (auto bc : bc_mng->getBcMapByBlockName()) {
6954 auto block_name = "(.*)PRESSURE(.*)";
6955 std::regex reg_name(block_name);
6956 if (std::regex_match(bc.first, reg_name)) {
6957
6958 auto [field_name, block_name] =
6960 MOFEM_LOG("EP", Sev::inform)
6961 << "Field name: " << field_name << " Block name: " << block_name;
6962 bcSpatialPressureVecPtr->emplace_back(
6963 block_name, bc.second->bcAttributes,
6964 bc.second->bcEnts.subset_by_dimension(2));
6965 }
6966 }
6967
6969 boost::make_shared<AnalyticalTractionBcVec>();
6970
6971 for (auto bc : bc_mng->getBcMapByBlockName()) {
6972 auto block_name = "(.*)ANALYTICAL_TRACTION(.*)";
6973 std::regex reg_name(block_name);
6974 if (std::regex_match(bc.first, reg_name)) {
6975 auto [field_name, block_name] =
6977 MOFEM_LOG("EP", Sev::inform)
6978 << "Field name: " << field_name << " Block name: " << block_name;
6980 block_name, bc.second->bcAttributes,
6981 bc.second->bcEnts.subset_by_dimension(2));
6982 }
6983 }
6984
6985 auto ts_traction =
6986 boost::make_shared<DynamicRelaxationTimeScale>("traction_history.txt");
6987 for (auto &bc : *bcSpatialTractionVecPtr) {
6988 timeScaleMap[bc.blockName] =
6990 ts_traction, "traction_history", ".txt", bc.blockName);
6991 }
6992
6993 auto ts_pressure =
6994 boost::make_shared<DynamicRelaxationTimeScale>("pressure_history.txt");
6995 for (auto &bc : *bcSpatialPressureVecPtr) {
6996 timeScaleMap[bc.blockName] =
6998 ts_pressure, "pressure_history", ".txt", bc.blockName);
6999 }
7000
7002}
7003
7006
7007 auto getExternalStrain = [&](boost::shared_ptr<ExternalStrainVec> &ext_strain_vec_ptr,
7008 const std::string block_name,
7009 const int nb_attributes) {
7011 for (auto it : mField.getInterface<MeshsetsManager>()->getCubitMeshsetPtr(
7012 std::regex((boost::format("%s(.*)") % block_name).str()))
7013 ) {
7014 std::vector<double> block_attributes;
7015 CHKERR it->getAttributes(block_attributes);
7016 if (block_attributes.size() < nb_attributes) {
7017 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
7018 "In block %s expected %d attributes, but given %ld",
7019 it->getName().c_str(), nb_attributes, block_attributes.size());
7020 }
7021
7022 auto get_block_ents = [&]() {
7023 Range ents;
7024 CHKERR mField.get_moab().get_entities_by_handle(it->meshset, ents,
7025 true);
7026 return ents;
7027 };
7028 auto Ents = get_block_ents();
7029 ext_strain_vec_ptr->emplace_back(it->getName(), block_attributes,
7030 get_block_ents());
7031 }
7033 };
7034
7035 externalStrainVecPtr = boost::make_shared<ExternalStrainVec>();
7036 CHKERR getExternalStrain(externalStrainVecPtr, "EXTERNALSTRAIN", 2);
7037
7038 auto ts_pre_stretch =
7039 boost::make_shared<DynamicRelaxationTimeScale>("externalstrain_history.txt");
7040 for (auto &ext_strain_block: *externalStrainVecPtr) {
7041 MOFEM_LOG("EP", Sev::noisy)
7042 << "Add time scaling external strain: " << ext_strain_block.blockName;
7043 timeScaleMap[ext_strain_block.blockName] =
7045 ts_pre_stretch, "externalstrain_history", ".txt", ext_strain_block.blockName);
7046 }
7047
7049}
7050
7053
7054 auto print_loc_size = [this](auto v, auto str, auto sev) {
7056 int size;
7057 CHKERR VecGetLocalSize(v.second, &size);
7058 int low, high;
7059 CHKERR VecGetOwnershipRange(v.second, &low, &high);
7060 MOFEM_LOG("EPSYNC", sev) << str << " local size " << size << " ( " << low
7061 << " " << high << " ) ";
7064 };
7065
7067 mField.get_comm(), mField.get_moab(), 3, 1, sev);
7068 CHKERR print_loc_size(volumeExchange, "volumeExchange", sev);
7070 mField.get_comm(), mField.get_moab(), 2, 1, Sev::inform);
7071 CHKERR print_loc_size(faceExchange, "faceExchange", sev);
7073 mField.get_comm(), mField.get_moab(), 1, 1, Sev::inform);
7074 CHKERR print_loc_size(edgeExchange, "edgeExchange", sev);
7076 mField.get_comm(), mField.get_moab(), 0, 3, Sev::inform);
7077 CHKERR print_loc_size(vertexExchange, "vertexExchange", sev);
7078
7080}
7081
7083EshelbianCore::calculateCrackArea(boost::shared_ptr<double> area_ptr) {
7085
7086 if (!area_ptr) {
7087 CHK_THROW_MESSAGE(MOFEM_INVALID_DATA, "area_ptr is null");
7088 }
7089
7090 int success;
7091 *area_ptr = 0;
7092 if (mField.get_comm_rank() == 0) {
7093 MOFEM_LOG("EP", Sev::inform) << "Calculate crack area";
7094 auto crack_faces = get_range_from_block(mField, "CRACK", SPACE_DIM - 1);
7095 for (auto f : crack_faces) {
7096 *area_ptr += mField.getInterface<Tools>()->getTriArea(f);
7097 }
7098 success = MPI_Bcast(area_ptr.get(), 1, MPI_DOUBLE, 0, mField.get_comm());
7099 } else {
7100 success = MPI_Bcast(area_ptr.get(), 1, MPI_DOUBLE, 0, mField.get_comm());
7101 }
7102 if (success != MPI_SUCCESS) {
7104 }
7106}
7107
7108} // namespace EshelbianPlasticity
7109
Implementation of tonsorial bubble base div(v) = 0.
#define NBVOLUMETET_CCG_BUBBLE(P)
Bubble function for CGG H div space.
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:2579
constexpr double a
static const double eps
constexpr int SPACE_DIM
ElementsAndOps< SPACE_DIM >::BoundaryEle BoundaryEle
cholesky decomposition
Kronecker Delta class.
Tensor1< T, Tensor_Dim > normalize()
@ QUIET
@ VERBOSE
@ 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
static const bool debug
PetscErrorCode ShapeDiffMBTET(double *diffN)
calculate derivatives of shape functions
Definition fem_tools.c:319
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:1119
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
#define _IT_GET_DOFS_FIELD_BY_NAME_AND_ENT_FOR_LOOP_(MFIELD, NAME, ENT, IT)
loop over all dofs from a moFEM field and particular field
PetscErrorCode Legendre_polynomials(int p, double s, double *diff_s, double *L, double *diffL, const int dim)
Calculate Legendre approximation basis.
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.
#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
MoFEMErrorCode getCubitMeshsetPtr(const int ms_id, const CubitBCType cubit_bc_type, const CubitMeshSets **cubit_meshset_ptr) const
get cubit meshset
#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
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
MoFEMErrorCode CGG_BubbleBase_MBTET(const int p, const double *N, const double *diffN, FTensor::Tensor2< FTensor::PackPtr< double *, 9 >, 3, 3 > &phi, const int gdim)
Calculate CGGT tonsorial bubble base.
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:1161
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:648
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:1147
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
OpPostProcMapInMoab< SPACE_DIM, SPACE_DIM > OpPPMap
ElementsAndOps< SPACE_DIM >::SideEle SideEle
Definition plastic.cpp:61
constexpr double t
plate stiffness
Definition plate.cpp:58
static double phi
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
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
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
MoFEMErrorCode solveDynamicRelaxation(TS ts, Vec x)
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
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)
static int nbJIntegralLevels
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)
CGGUserPolynomialBase(boost::shared_ptr< CachePhi > cache_phi=nullptr)
MoFEMErrorCode getValueHdivForCGGBubble(MatrixDouble &pts)
MoFEMErrorCode getValue(MatrixDouble &pts, boost::shared_ptr< BaseFunctionCtx > ctx_ptr)
MoFEMErrorCode query_interface(boost::typeindex::type_index type_index, BaseFunctionUnknownInterface **iface) const
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.
Simple interface for fast problem set-up.
Definition BcManager.hpp:29
static std::pair< std::string, std::string > extractStringFromBlockId(const std::string block_id, const std::string prb_name)
Extract block name and block name form block id.
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 block DOFs.
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
Class used to pass element data to calculate base functions on tet,triangle,edge.
Data on single entity (This is passed as argument to DataOperator::doWork)
data structure for finite element entity
std::array< boost::ptr_vector< EntData >, MBMAXTYPE > dataOnEntities
structure for User Loop Methods on finite elements
EntityHandle getFEEntityHandle() const
Basic algebra on fields.
Definition FieldBlas.hpp:21
Provide data structure for (tensor) field approximation.
Definition of the force bc data structure.
Definition BCData.hpp:135
structure to get information form 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.
Get values at integration pts for tensor field rank 1, i.e. vector field.
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
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
Calculate base functions on tetrahedral.
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 MoFEMErrorCode shapeFunMBTET(double *shape, const double *ksi, const double *eta, const double *zeta, const double nb)
Calculate shape functions on tetrahedron.
Definition Tools.hpp:747
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
static constexpr std::array< double, 12 > diffShapeFunMBTET
Definition Tools.hpp:271
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)
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
auto save_range