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