v0.16.0
Loading...
Searching...
No Matches
insert_constraint_prisms.cpp
Go to the documentation of this file.
1/** \file insert_constraint_prisms.cpp
2 * \brief Insert prism elements between paired master/slave surface meshsets
3 *
4 * Meshsets are paired by name, using prefixes:
5 * TIE_MASTER_<suffix>
6 * TIE_SLAVE_<suffix>
7 *
8 * Current limitations:
9 * - only tetrahedral volume meshes are supported
10 * - only triangular surface meshsets are supported
11 */
12
13#include <MoFEM.hpp>
14
15using namespace MoFEM;
16
17static char help[] =
18 "Insert constraint prisms between paired master/slave triangle meshsets.\n"
19 "\n"
20 "Pairs are detected by meshset names:\n"
21 " TIE_MASTER_<suffix>\n"
22 " TIE_SLAVE_<suffix>\n"
23 "\n"
24 "Prisms are always created from the SLAVE surface.\n"
25 "\n"
26 "If the MASTER surface has more triangles than the SLAVE surface, the tool\n"
27 "only warns and suggests renaming the TIE blocks so the finer surface is\n"
28 "named SLAVE.\n"
29 "\n"
30 "Virtual refinement:\n"
31 " - -tie_ref_level N recursively refines each effective slave triangle N times\n"
32 " in-memory using 1-to-4 midpoint subdivision before ray casting\n"
33 " - -ray_length value overrides the automatic ray length\n"
34 "\n"
35 "Current limitations:\n"
36 " - only tet meshes are supported\n"
37 " - only triangle surface meshsets are supported\n\n";
38
39namespace {
40
41constexpr int SPACE_DIM = 3;
44
45struct SurfaceMeshsetData {
46 const CubitMeshSets *meshsetPtr = nullptr;
47 std::string name;
48 Range tris;
49};
50
51constexpr std::array<std::array<int, 3>, 3> TRI_PERMUTATIONS = {{
52 {{0, 1, 2}},
53 {{1, 2, 0}},
54 {{2, 0, 1}}
55}};
56
57MoFEMErrorCode set_surface_meshset_triangles(
58 moab::Interface &moab, const SurfaceMeshsetData &surface,
59 const Range &desired_tris) {
61
62 if (!surface.meshsetPtr) {
63 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
64 "Can not update triangles for null meshset pointer");
65 }
66
67 const auto meshset = surface.meshsetPtr->meshset;
68
69 // Keep TIE meshsets as pure surface meshsets. Prism-update utilities add
70 // adjacent prisms/quads to any meshset sharing the corresponding faces or
71 // edges, but for TIE detection we need these sets to contain only their
72 // designated triangles.
73 Range vols;
74 CHKERR moab.get_entities_by_dimension(meshset, 3, vols, true);
75 if (!vols.empty())
76 CHKERR moab.remove_entities(meshset, vols);
77
78 Range faces;
79 CHKERR moab.get_entities_by_dimension(meshset, 2, faces, true);
80 Range current_tris = faces.subset_by_type(MBTRI);
81 Range other_faces = subtract(faces, current_tris);
82 if (!other_faces.empty())
83 CHKERR moab.remove_entities(meshset, other_faces);
84
85 Range tris_to_remove = subtract(current_tris, desired_tris);
86 if (!tris_to_remove.empty())
87 CHKERR moab.remove_entities(meshset, tris_to_remove);
88
89 Range tris_to_add = subtract(desired_tris, current_tris);
90 if (!tris_to_add.empty())
91 CHKERR moab.add_entities(meshset, tris_to_add);
92
94}
95
96MoFEMErrorCode get_range_bbox_diag(moab::Interface &moab, const Range &ents,
97 double &diag) {
99
100 Range verts;
101 CHKERR moab.get_connectivity(ents, verts, true);
102 if (verts.empty())
103 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
104 "Can not calculate bounding box for empty vertex range");
105
106 std::vector<double> coords(3 * verts.size());
107 CHKERR moab.get_coords(verts, coords.data());
108
109 double min_c[SPACE_DIM] = {std::numeric_limits<double>::max(),
110 std::numeric_limits<double>::max(),
111 std::numeric_limits<double>::max()};
112 double max_c[SPACE_DIM] = {-std::numeric_limits<double>::max(),
113 -std::numeric_limits<double>::max(),
114 -std::numeric_limits<double>::max()};
115
116 for (size_t vv = 0; vv != verts.size(); ++vv) {
117 for (int dd = 0; dd != 3; ++dd) {
118 min_c[dd] = std::min(min_c[dd], coords[3 * vv + dd]);
119 max_c[dd] = std::max(max_c[dd], coords[3 * vv + dd]);
120 }
121 }
122
124 auto t_max_c = getFTensor1FromPtr<SPACE_DIM>(max_c);
125 auto t_min_c = getFTensor1FromPtr<SPACE_DIM>(min_c);
126 t_diag(i) = t_max_c(i) - t_min_c(i);
127 diag = t_diag.l2();
129}
130
131MoFEMErrorCode validate_surface_meshset(moab::Interface &moab,
132 const CubitMeshSets &meshset_data,
133 const Range &tet_skin,
134 SurfaceMeshsetData &surface_data) {
136
137 surface_data.meshsetPtr = &meshset_data;
138 surface_data.name = meshset_data.getName();
139
140 Range vols;
141 CHKERR moab.get_entities_by_dimension(meshset_data.meshset, 3, vols, true);
142 if (!vols.empty()) {
143 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
144 "Meshset %s contains 3D entities. Only surface meshsets are "
145 "supported",
146 surface_data.name.c_str());
147 }
148
149 Range faces;
150 CHKERR moab.get_entities_by_dimension(meshset_data.meshset, 2, faces, true);
151 if (faces.empty()) {
152 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
153 "Meshset %s does not contain surface entities",
154 surface_data.name.c_str());
155 }
156
157 surface_data.tris = faces.subset_by_type(MBTRI);
158 const Range other_faces = subtract(faces, surface_data.tris);
159 if (!other_faces.empty()) {
160 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
161 "Meshset %s contains non-triangle surface entities. Only "
162 "triangles are supported",
163 surface_data.name.c_str());
164 }
165
166 const Range skin_tris = intersect(surface_data.tris, tet_skin);
167 if (skin_tris.size() != surface_data.tris.size()) {
168 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
169 "Meshset %s contains triangles that are not on the tet skin",
170 surface_data.name.c_str());
171 }
172
174}
175
176MoFEMErrorCode get_coords_centroid(const double *coords, const int num_nodes,
177 std::array<double, 3> &centroid) {
179 centroid = {0., 0., 0.};
180 for (int nn = 0; nn != num_nodes; ++nn)
181 for (int dd = 0; dd != SPACE_DIM; ++dd)
182 centroid[dd] += coords[SPACE_DIM * nn + dd] / num_nodes;
184}
185
186MoFEMErrorCode get_skin_triangle_data(moab::Interface &moab,
187 const EntityHandle tri,
188 std::array<EntityHandle, 3> *tri_nodes,
189 std::array<double, SPACE_DIM> &outward_normal) {
191
192 const EntityHandle *conn = nullptr;
193 int num_nodes = 0;
194 CHKERR moab.get_connectivity(tri, conn, num_nodes, true);
195 if (num_nodes != 3)
196 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
197 "Only 3-node triangles are supported");
198
199 if (tri_nodes) {
200 for (int ii = 0; ii != 3; ++ii)
201 (*tri_nodes)[ii] = conn[ii];
202 }
203
204 double tri_coords[9];
205 CHKERR moab.get_coords(conn, 3, tri_coords);
206
207 std::array<double, SPACE_DIM> centroid;
208 CHKERR get_coords_centroid(tri_coords, 3, centroid);
209 auto t_centroid = getFTensor1FromPtr<SPACE_DIM>(centroid.data());
210
211 auto t_outward_normal = getFTensor1FromPtr<SPACE_DIM>(outward_normal.data());
212 CHKERR Tools::getTriNormal(tri_coords, &t_outward_normal(0));
213 const double tri_norm = t_outward_normal.l2();
214 if (tri_norm <= std::numeric_limits<double>::epsilon()) {
215 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
216 "Triangle %lu has zero normal", tri);
217 }
218 t_outward_normal(i) /= tri_norm;
219
220 Range adj_tets;
221 CHKERR moab.get_adjacencies(&tri, 1, 3, false, adj_tets);
222 adj_tets = adj_tets.subset_by_type(MBTET);
223 if (adj_tets.size() != 1) {
224 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
225 "Triangle %lu is expected to have exactly one adjacent tet", tri);
226 }
227
228 const EntityHandle tet = adj_tets[0];
229 const EntityHandle *tet_conn = nullptr;
230 int tet_num_nodes = 0;
231 CHKERR moab.get_connectivity(tet, tet_conn, tet_num_nodes, true);
232 if (tet_num_nodes != 4)
233 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
234 "Only 4-node tets are supported");
235
236 double tet_coords[12];
237 CHKERR moab.get_coords(tet_conn, 4, tet_coords);
238 std::array<double, SPACE_DIM> tet_centroid;
239 CHKERR get_coords_centroid(tet_coords, 4, tet_centroid);
240 auto t_tet_centroid = getFTensor1FromPtr<SPACE_DIM>(tet_centroid.data());
241
243 t_delta(i) = t_tet_centroid(i) - t_centroid(i);
244
245 if (t_outward_normal(i) * t_delta(i) > 0)
246 t_outward_normal(i) *= -1.;
247
249}
250
251MoFEMErrorCode get_triangle_coords(moab::Interface &moab, const EntityHandle tri,
252 std::array<double, 9> &coords) {
254 const EntityHandle *conn = nullptr;
255 int num_nodes = 0;
256 CHKERR moab.get_connectivity(tri, conn, num_nodes, true);
257 if (num_nodes != 3) {
258 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
259 "Only 3-node triangles are supported");
260 }
261 CHKERR moab.get_coords(conn, 3, coords.data());
263}
264
265MoFEMErrorCode collect_virtual_refined_triangle_centroids(
266 const int ref_level, MatrixDouble &reference_child_centroids) {
268
269 moab::Core moab_ref;
270 double base_coords[] = {0, 0, 0, 1, 0, 0, 0, 1, 0};
271 EntityHandle nodes[3];
272 for (int nn = 0; nn != 3; ++nn)
273 CHKERR moab_ref.create_vertex(&base_coords[3 * nn], nodes[nn]);
274 EntityHandle tri;
275 CHKERR moab_ref.create_element(MBTRI, nodes, 3, tri);
276
277 MoFEM::CoreTmp<-1> mofem_ref_core(moab_ref, PETSC_COMM_SELF, -2);
278 MoFEM::Interface &m_field_ref = mofem_ref_core;
279 auto *m_ref = m_field_ref.getInterface<MeshRefinement>();
280 auto *bit_ref_manager = m_field_ref.getInterface<BitRefManager>();
281
282 {
283 Range tris(tri, tri);
284 Range edges;
285 CHKERR m_field_ref.get_moab().get_adjacencies(tris, 1, true, edges,
286 moab::Interface::UNION);
287 CHKERR bit_ref_manager->setBitRefLevel(tris, BitRefLevel().set(0), false,
288 VERBOSE);
289 }
290#ifndef NDEBUG
291 const bool debug = true;
292#else
293 const bool debug = false;
294#endif
295
296 for (int ll = 0; ll != ref_level; ++ll) {
297 Range current_tris;
298 CHKERR bit_ref_manager->getEntitiesByTypeAndRefLevel(
299 BitRefLevel().set(ll), BitRefLevel().set(), MBTRI, current_tris);
300 const BitRefLevel bit = BitRefLevel().set(ll + 1);
301 Range edges;
302 CHKERR moab_ref.get_adjacencies(current_tris, 1, true, edges,
303 moab::Interface::UNION);
304 CHKERR m_ref->addVerticesInTheMiddleOfEdges(edges, bit);
305 CHKERR m_ref->refineTris(current_tris, bit, QUIET, debug);
306 }
307
308 Range refined_tris;
309 CHKERR bit_ref_manager->getEntitiesByTypeAndRefLevel(
310 BitRefLevel().set(ref_level), BitRefLevel().set(), MBTRI, refined_tris);
311 reference_child_centroids.resize(refined_tris.size(), SPACE_DIM, false);
312 int rr = 0;
313 for (auto child_tri : refined_tris) {
314 std::array<double, 9> child_coords;
315 std::array<double, 3> child_centroid;
316 CHKERR get_triangle_coords(moab_ref, child_tri, child_coords);
317 CHKERR get_coords_centroid(child_coords.data(), 3, child_centroid);
318 for (int dd = 0; dd != SPACE_DIM; ++dd)
319 reference_child_centroids(rr, dd) = child_centroid[dd];
320 ++rr;
321 }
322
324}
325
326MoFEMErrorCode map_reference_centroids_to_triangle(
327 const MatrixDouble &reference_child_centroids,
328 const std::array<double, 9> &tri_coords, MatrixDouble &child_centroids) {
330
331 child_centroids.resize(reference_child_centroids.size1(), SPACE_DIM, false);
332 std::array<double, 9> mutable_coords = tri_coords;
333 auto t_p0 = getFTensor1FromPtr<SPACE_DIM>(&mutable_coords[0]);
334 auto t_p1 = getFTensor1FromPtr<SPACE_DIM>(&mutable_coords[3]);
335 auto t_p2 = getFTensor1FromPtr<SPACE_DIM>(&mutable_coords[6]);
336
337 for (size_t rr = 0; rr != reference_child_centroids.size1(); ++rr) {
338 const double n1 = reference_child_centroids(rr, 0);
339 const double n2 = reference_child_centroids(rr, 1);
340 const double n0 = 1. - n1 - n2;
341 std::array<double, 3> child_centroid = {0., 0., 0.};
342 auto t_child_centroid =
343 getFTensor1FromPtr<SPACE_DIM>(child_centroid.data());
344 t_child_centroid(i) = n0 * t_p0(i) + n1 * t_p1(i) + n2 * t_p2(i);
345 for (int dd = 0; dd != SPACE_DIM; ++dd)
346 child_centroids(rr, dd) = child_centroid[dd];
347 }
348
350}
351
352MoFEMErrorCode collect_target_triangles(
353 OrientedBoxTreeTool &tree, const EntityHandle root_set,
354 const std::array<double, 3> &source_centroid,
355 const std::array<double, 3> &source_normal, const double ray_length,
356 const double ray_tol,
357 std::set<EntityHandle> &target_tris) {
359
360 auto collect_closest_hit = [&](const double ray_sign, EntityHandle &closest_tri,
361 double &closest_dist) {
363
364 std::vector<double> distances;
365 std::vector<EntityHandle> facets;
366 double ray_point[SPACE_DIM] = {source_centroid[0], source_centroid[1],
367 source_centroid[2]};
368 double ray_dir[SPACE_DIM] = {ray_sign * source_normal[0],
369 ray_sign * source_normal[1],
370 ray_sign * source_normal[2]};
371 double max_ray_length = ray_length;
372
373 CHKERR tree.ray_intersect_triangles(distances, facets, root_set, ray_tol,
374 ray_point, ray_dir, &max_ray_length);
375
376 closest_tri = 0;
377 closest_dist = std::numeric_limits<double>::max();
378 for (size_t ii = 0; ii != facets.size(); ++ii) {
379 const double dist = distances[ii];
380 if (dist < -ray_tol)
381 continue;
382 if (dist < closest_dist) {
383 closest_dist = dist;
384 closest_tri = facets[ii];
385 }
386 }
387
389 };
390
391 EntityHandle forward_tri = 0;
392 EntityHandle reverse_tri = 0;
393 double forward_dist = std::numeric_limits<double>::max();
394 double reverse_dist = std::numeric_limits<double>::max();
395 CHKERR collect_closest_hit(1., forward_tri, forward_dist);
396 CHKERR collect_closest_hit(-1., reverse_tri, reverse_dist);
397
398 if (forward_dist <= reverse_dist) {
399 if (forward_tri)
400 target_tris.insert(forward_tri);
401 } else if (reverse_tri) {
402 target_tris.insert(reverse_tri);
403 }
404
406}
407
408MoFEMErrorCode match_triangle_vertices(moab::Interface &moab,
409 const std::array<EntityHandle, 3> &master_nodes,
410 const std::array<EntityHandle, 3> &slave_nodes,
411 std::array<int, 3> &perm) {
413
414 double master_coords[9];
415 double slave_coords[9];
416 CHKERR moab.get_coords(master_nodes.data(), 3, master_coords);
417 CHKERR moab.get_coords(slave_nodes.data(), 3, slave_coords);
418
419 double best_score = std::numeric_limits<double>::max();
420 bool found = false;
421
422 for (const auto &candidate_perm : TRI_PERMUTATIONS) {
423 double score = 0;
424
425 for (int ii = 0; ii != 3; ++ii) {
426 auto t_master_c = getFTensor1FromPtr<3>(&master_coords[3 * ii]);
427 auto t_slave_c =
428 getFTensor1FromPtr<3>(&slave_coords[3 * candidate_perm[ii]]);
430 t_delta(j) = t_master_c(j) - t_slave_c(j);
431 score += t_delta(j) * t_delta(j);
432 }
433
434 if (score < best_score) {
435 best_score = score;
436 perm = candidate_perm;
437 found = true;
438 }
439 }
440
441 if (!found) {
442 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
443 "Could not find a vertex mapping between paired master and slave "
444 "triangles");
445 }
446
448}
449
450MoFEMErrorCode create_prism_from_triangle_pair(
451 PrismsFromSurfaceInterface &prisms_from_surface, const EntityHandle source_tri,
452 const EntityHandle target_tri, EntityHandle &prism) {
454 MoFEM::Interface &m_field = prisms_from_surface.cOre;
455 auto &moab = m_field.get_moab();
456
457 std::array<EntityHandle, 3> source_nodes;
458 std::array<double, SPACE_DIM> source_normal;
459 CHKERR get_skin_triangle_data(moab, source_tri, &source_nodes, source_normal);
460 auto t_source_normal = getFTensor1FromPtr<SPACE_DIM>(source_normal.data());
461
462 const EntityHandle *target_conn = nullptr;
463 int target_num_nodes = 0;
464 CHKERR moab.get_connectivity(target_tri, target_conn, target_num_nodes, true);
465 if (target_num_nodes != 3)
466 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
467 "Only 3-node target triangles are supported");
468
469 const EntityHandle *source_conn = nullptr;
470 int source_num_nodes = 0;
471 CHKERR moab.get_connectivity(source_tri, source_conn, source_num_nodes, true);
472 if (source_num_nodes != 3)
473 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
474 "Only 3-node source triangles are supported");
475
476 double source_coords[9];
477 CHKERR moab.get_coords(source_conn, 3, source_coords);
478 std::array<double, SPACE_DIM> raw_source_normal;
479 auto t_raw_source_normal =
480 getFTensor1FromPtr<SPACE_DIM>(raw_source_normal.data());
481 CHKERR Tools::getTriNormal(source_coords, &t_raw_source_normal(0));
482
483 std::array<EntityHandle, 3> prism_source_nodes = source_nodes;
484 if (t_raw_source_normal(i) * t_source_normal(i) < 0)
485 std::swap(prism_source_nodes[1], prism_source_nodes[2]);
486
487 std::array<EntityHandle, 3> target_nodes = {target_conn[0], target_conn[1],
488 target_conn[2]};
489 std::array<int, 3> target_perm = {0, 1, 2};
490 CHKERR match_triangle_vertices(moab, prism_source_nodes, target_nodes,
491 target_perm);
492
493 std::array<EntityHandle, 3> prism_target_nodes = {
494 target_nodes[target_perm[0]], target_nodes[target_perm[1]],
495 target_nodes[target_perm[2]]};
496
497 CHKERR prisms_from_surface.createPrism(
498 prism_source_nodes.data(), prism_target_nodes.data(),
500
501 int side_number = -1;
502 int sense = 0;
503 int offset = 0;
504
505 CHKERR moab.side_number(prism, source_tri, side_number, sense, offset);
506 if (side_number != 3) {
507 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
508 "Created prism %lu does not use source triangle %lu as side 3",
509 prism, source_tri);
510 }
511
512 CHKERR moab.side_number(prism, target_tri, side_number, sense, offset);
513 if (side_number != 4) {
514 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
515 "Created prism %lu does not use target triangle %lu as side 4",
516 prism, target_tri);
517 }
518
520}
521
522} // namespace
523
524int main(int argc, char *argv[]) {
525
526 MoFEM::Core::Initialize(&argc, &argv, (char *)0, help);
527
528 try {
529
530 char mesh_file_name[255] = "mesh.h5m";
531 char mesh_out_file[255] = "out.h5m";
532 char master_prefix[255] = "TIE_MASTER_";
533 char slave_prefix[255] = "TIE_SLAVE_";
534 PetscBool flg_my_file = PETSC_FALSE;
535 PetscBool flg_ray_length = PETSC_FALSE;
536 PetscInt ref_level = 1;
537 PetscReal ray_length_option = 0;
538
539 PetscOptionsBegin(PETSC_COMM_WORLD, "", "Insert constraint prisms", "none");
540 CHKERR PetscOptionsString("-my_file", "mesh file name", "", "mesh.h5m",
541 mesh_file_name, 255, &flg_my_file);
542 if (flg_my_file != PETSC_TRUE)
543 CHKERR PetscOptionsString("-file_name", "mesh file name", "", "mesh.h5m",
544 mesh_file_name, 255, &flg_my_file);
545 CHKERR PetscOptionsString("-output_file", "output mesh file name", "",
546 "out.h5m", mesh_out_file, 255, PETSC_NULLPTR);
547 CHKERR PetscOptionsString("-master_prefix", "master meshset name prefix",
548 "", "TIE_MASTER_", master_prefix, 255,
549 PETSC_NULLPTR);
550 CHKERR PetscOptionsString("-slave_prefix", "slave meshset name prefix", "",
551 "TIE_SLAVE_", slave_prefix, 255, PETSC_NULLPTR);
552 CHKERR PetscOptionsInt("-tie_ref_level",
553 "virtual recursive refinement level on slave "
554 "triangles",
555 "", ref_level, &ref_level, PETSC_NULLPTR);
556 CHKERR PetscOptionsReal("-ray_length", "absolute ray length", "",
557 ray_length_option, &ray_length_option,
558 &flg_ray_length);
559 PetscOptionsEnd();
560
561 if (flg_my_file != PETSC_TRUE) {
562 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
563 "error -my_file (-file_name) (mesh file needed)");
564 }
565 if (ref_level < 1) {
566 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
567 "-tie_ref_level must be greater than or equal to 1");
568 }
569 if (flg_ray_length == PETSC_TRUE && ray_length_option <= 0) {
570 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
571 "-ray_length must be greater than 0");
572 }
573
574 moab::Core mb_instance;
575 moab::Interface &moab = mb_instance;
576 ParallelComm *pcomm = ParallelComm::get_pcomm(&moab, MYPCOMM_INDEX);
577 if (pcomm == NULL)
578 pcomm = new ParallelComm(&moab, PETSC_COMM_WORLD);
579
580 CHKERR moab.load_file(mesh_file_name);
581
582 MoFEM::Core core(moab);
583 MoFEM::Interface &m_field = core;
584
585 Range tets;
586 CHKERR moab.get_entities_by_type(0, MBTET, tets, false);
587 if (tets.empty()) {
588 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
589 "No tetrahedra found. Only tet meshes are currently supported");
590 }
591
592 Range other_vols;
593 CHKERR moab.get_entities_by_dimension(0, 3, other_vols, false);
594 other_vols = subtract(other_vols, tets);
595 if (!other_vols.empty()) {
596 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
597 "Only tetrahedral volume meshes are currently supported");
598 }
599
600 Range tet_skin;
601 {
602 Skinner skinner(&moab);
603 CHKERR skinner.find_skin(0, tets, false, tet_skin);
604 tet_skin = tet_skin.subset_by_type(MBTRI);
605 }
606
607 const std::string master_prefix_str(master_prefix);
608 const std::string slave_prefix_str(slave_prefix);
609
610 std::map<std::string, const CubitMeshSets *> master_sets;
611 std::map<std::string, const CubitMeshSets *> slave_sets;
612
613 for (_IT_CUBITMESHSETS_FOR_LOOP_(m_field, it)) {
614 const std::string name = it->getName();
615
616 if (name.compare(0, master_prefix_str.size(), master_prefix_str) == 0) {
617 const auto suffix = name.substr(master_prefix_str.size());
618 if (!master_sets.emplace(suffix, &*it).second) {
619 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
620 "More than one master meshset uses suffix %s", suffix.c_str());
621 }
622 }
623
624 if (name.compare(0, slave_prefix_str.size(), slave_prefix_str) == 0) {
625 const auto suffix = name.substr(slave_prefix_str.size());
626 if (!slave_sets.emplace(suffix, &*it).second) {
627 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
628 "More than one slave meshset uses suffix %s", suffix.c_str());
629 }
630 }
631 }
632
633 if (master_sets.empty()) {
634 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_FOUND,
635 "No master meshsets found with prefix %s",
636 master_prefix_str.c_str());
637 }
638
639 for (const auto &slave_pair : slave_sets) {
640 const auto &suffix = slave_pair.first;
641 if (master_sets.find(suffix) == master_sets.end()) {
642 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
643 "Found slave meshset with suffix %s but no matching master "
644 "meshset",
645 suffix.c_str());
646 }
647 }
648
649 PrismsFromSurfaceInterface *prisms_from_surface = nullptr;
650 CHKERR m_field.getInterface(prisms_from_surface);
651
652 MatrixDouble reference_child_centroids;
653 CHKERR collect_virtual_refined_triangle_centroids(ref_level,
654 reference_child_centroids);
655
656 Range all_prisms;
657
658 for (const auto &[suffix, master_ptr] : master_sets) {
659 auto slave_it = slave_sets.find(suffix);
660 if (slave_it == slave_sets.end()) {
661 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
662 "Found master meshset with suffix %s but no matching slave "
663 "meshset",
664 suffix.c_str());
665 }
666
667 const auto *slave_ptr = slave_it->second;
668
669 if (master_ptr->getBcType() != slave_ptr->getBcType()) {
670 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
671 "Master/slave meshset types differ for suffix %s",
672 suffix.c_str());
673 }
674
675 SurfaceMeshsetData master_surface;
676 CHKERR validate_surface_meshset(moab, *master_ptr, tet_skin,
677 master_surface);
678
679 SurfaceMeshsetData slave_surface;
680 CHKERR validate_surface_meshset(moab, *slave_ptr, tet_skin, slave_surface);
681
682 const auto master_tri_count = master_surface.tris.size();
683 const auto slave_tri_count = slave_surface.tris.size();
684 double bbox_diag = 0;
685 CHKERR get_range_bbox_diag(moab,
686 unite(master_surface.tris, slave_surface.tris),
687 bbox_diag);
688
689 const double geom_eps =
690 std::max(1e-12 * std::max(1., bbox_diag), 10. *
691 std::numeric_limits<double>::epsilon());
692 const double ray_tol = geom_eps;
693 const double ray_length =
694 (flg_ray_length == PETSC_TRUE) ? ray_length_option
695 : std::max(10. * bbox_diag, 1.);
696
697 OrientedBoxTreeTool master_tree(&moab, "ROOTSET_CONSTRAINT_PRISMS", true);
698 EntityHandle master_root = 0;
699 CHKERR master_tree.build(master_surface.tris, master_root);
700
701 Range pair_prisms;
702 size_t unmatched_slave_tris = 0;
703
704 for (auto slave_tri : slave_surface.tris) {
705 std::array<double, SPACE_DIM> slave_normal;
706 CHKERR get_skin_triangle_data(moab, slave_tri, nullptr, slave_normal);
707
708 std::array<double, 9> slave_coords;
709 CHKERR get_triangle_coords(moab, slave_tri, slave_coords);
710 MatrixDouble child_centroids;
711 CHKERR map_reference_centroids_to_triangle(reference_child_centroids,
712 slave_coords,
713 child_centroids);
714
715 std::set<EntityHandle> hit_master_tris;
716 for (size_t rr = 0; rr != child_centroids.size1(); ++rr) {
717 std::array<double, 3> child_centroid = {
718 child_centroids(rr, 0), child_centroids(rr, 1),
719 child_centroids(rr, 2)};
720 CHKERR collect_target_triangles(master_tree, master_root,
721 child_centroid, slave_normal,
722 ray_length, ray_tol,
723 hit_master_tris);
724 }
725
726 if (hit_master_tris.empty()) {
727 ++unmatched_slave_tris;
728 continue;
729 }
730
731 for (auto master_tri : hit_master_tris) {
732 EntityHandle prism = 0;
733 CHKERR create_prism_from_triangle_pair(*prisms_from_surface, slave_tri,
734 master_tri, prism);
735 pair_prisms.insert(prism);
736 }
737 }
738
739 CHKERR prisms_from_surface->updateMeshestByEdgeBlock(pair_prisms);
740 CHKERR prisms_from_surface->updateMeshestByTriBlock(pair_prisms);
741
742 CHKERR set_surface_meshset_triangles(moab, master_surface,
743 master_surface.tris);
744 CHKERR set_surface_meshset_triangles(moab, slave_surface,
745 slave_surface.tris);
746
747 all_prisms.merge(pair_prisms);
748
749 MOFEM_LOG("WORLD", Sev::inform)
750 << "Inserted " << pair_prisms.size()
751 << " prisms for master/slave suffix " << suffix;
752 if (master_tri_count > slave_tri_count) {
753 MOFEM_LOG("WORLD", Sev::warning)
754 << "Master surface has more triangles than slave surface for "
755 "suffix "
756 << suffix << " (" << master_tri_count << " > "
757 << slave_tri_count
758 << "); consider renaming the TIE blocks so the finer surface is "
759 "named TIE_SLAVE_"
760 << suffix;
761 }
762 MOFEM_LOG("WORLD", Sev::warning)
763 << "Skipped " << unmatched_slave_tris
764 << " slave triangles without master hits for suffix "
765 << suffix;
766 }
767
768 MOFEM_LOG("WORLD", Sev::inform)
769 << "Inserted total " << all_prisms.size() << " constraint prisms";
770
771 CHKERR moab.write_file(mesh_out_file);
772 }
774
776
777 return 0;
778}
#define FTENSOR_INDEX(DIM, I)
int main()
constexpr int SPACE_DIM
@ QUIET
@ VERBOSE
#define CATCH_ERRORS
Catch errors.
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define MYPCOMM_INDEX
default communicator number PCOMM
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
@ MOFEM_NOT_FOUND
Definition definitions.h:33
@ 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 ...
#define MOFEM_LOG(channel, severity)
Log.
#define _IT_CUBITMESHSETS_FOR_LOOP_(MESHSET_MANAGER, IT)
Iterator that loops over all the Cubit MeshSets in a moFEM field.
auto bit
set bit
FTensor::Index< 'i', SPACE_DIM > i
static char help[]
FTensor::Index< 'j', 3 > j
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
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
static const bool debug
Managing BitRefLevels.
virtual moab::Interface & get_moab()=0
Core (interface) class.
Definition Core.hpp:83
static MoFEMErrorCode Initialize(int *argc, char ***args, const char file[], const char help[])
Initializes the MoFEM database PETSc, MOAB and MPI.
Definition Core.cpp:68
static MoFEMErrorCode Finalize()
Checks for options to be called at the conclusion of the program.
Definition Core.cpp:123
this struct keeps basic methods for moab meshset about material and boundary conditions
std::string getName() const
get name of block, sideset etc. (this is set in Cubit block properties)
Deprecated interface functions.
Mesh refinement interface.
MoFEMErrorCode createPrism(const EntityHandle tri3_nodes[3], const EntityHandle tri4_nodes[3], const SwapType swap_type, EntityHandle &prism)
Create a prism from two triangle node triplets.
MoFEMErrorCode updateMeshestByEdgeBlock(const Range &prisms)
Add quads to bockset.
MoFEMErrorCode updateMeshestByTriBlock(const Range &prisms)
Add prism to bockset.
static MoFEMErrorCode getTriNormal(const double *coords, double *normal, double *d_normal=nullptr)
Get the Tri Normal objectGet triangle normal.
Definition Tools.cpp:353
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.