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