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