v0.15.0
Loading...
Searching...
No Matches
Namespaces | Macros
CutMeshInterface.cpp File Reference

Cut mesh by surface. More...

Go to the source code of this file.

Namespaces

namespace  MoFEM
 implementation of Data Operators for Forces and Sources
 

Macros

#define CutMeshFunctionBegin
 

Detailed Description

Cut mesh by surface.

Definition in file CutMeshInterface.cpp.

Macro Definition Documentation

◆ CutMeshFunctionBegin

#define CutMeshFunctionBegin
Value:
MOFEM_LOG_CHANNEL("WORLD"); \
MOFEM_LOG_FUNCTION(); \
MOFEM_LOG_TAG("WORLD", "CutMesh");
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...

Definition at line 7 of file CutMeshInterface.cpp.

12 {
13
15CutMeshInterface::query_interface(boost::typeindex::type_index type_index,
16 UnknownInterface **iface) const {
18 *iface = const_cast<CutMeshInterface *>(this);
20}
21
22CutMeshInterface::CutMeshInterface(const Core &core)
23 : cOre(const_cast<Core &>(core)) {
24 lineSearchSteps = 10;
25 nbMaxMergingCycles = 200;
26 projectEntitiesQualityTrashold = 0.5;
27}
28
29MoFEMErrorCode CutMeshInterface::clearMap() {
31 treeSurfPtr.reset();
33}
34
35MoFEMErrorCode CutMeshInterface::setFront(const Range front) {
37 fRont = front;
39}
40
41MoFEMErrorCode CutMeshInterface::setSurface(const Range surface) {
43 sUrface = surface;
45}
46
47MoFEMErrorCode CutMeshInterface::copySurface(const Range surface, Tag th,
48 double *shift, double *origin,
49 double *transform,
50 const std::string save_mesh) {
51 CoreInterface &m_field = cOre;
52 moab::Interface &moab = m_field.get_moab();
54 sUrface.clear();
55 std::map<EntityHandle, EntityHandle> verts_map;
56 for (Range::const_iterator tit = surface.begin(); tit != surface.end();
57 tit++) {
58 int num_nodes;
59 const EntityHandle *conn;
60 CHKERR moab.get_connectivity(*tit, conn, num_nodes, true);
61 MatrixDouble coords(num_nodes, 3);
62 if (th) {
63 CHKERR moab.tag_get_data(th, conn, num_nodes, &coords(0, 0));
64 } else {
65 CHKERR moab.get_coords(conn, num_nodes, &coords(0, 0));
66 }
67 EntityHandle new_verts[num_nodes];
68 for (int nn = 0; nn != num_nodes; nn++) {
69 if (verts_map.find(conn[nn]) != verts_map.end()) {
70 new_verts[nn] = verts_map[conn[nn]];
71 } else {
72 if (transform) {
73 ublas::matrix_row<MatrixDouble> mr(coords, nn);
74 if (origin) {
75 VectorAdaptor vec_origin(
76 3, ublas::shallow_array_adaptor<double>(3, origin));
77 mr = mr - vec_origin;
78 }
79 MatrixAdaptor mat_transform = MatrixAdaptor(
80 3, 3, ublas::shallow_array_adaptor<double>(9, transform));
81 mr = prod(mat_transform, mr);
82 if (origin) {
83 VectorAdaptor vec_origin(
84 3, ublas::shallow_array_adaptor<double>(3, origin));
85 mr = mr + vec_origin;
86 }
87 }
88 if (shift) {
89 ublas::matrix_row<MatrixDouble> mr(coords, nn);
90 VectorAdaptor vec_shift(
91 3, ublas::shallow_array_adaptor<double>(3, shift));
92 mr = mr + vec_shift;
93 }
94 CHKERR moab.create_vertex(&coords(nn, 0), new_verts[nn]);
95 verts_map[conn[nn]] = new_verts[nn];
96 }
97 }
98 EntityHandle ele;
99 CHKERR moab.create_element(MBTRI, new_verts, num_nodes, ele);
100 sUrface.insert(ele);
101 }
102 if (!save_mesh.empty())
103 CHKERR SaveData(m_field.get_moab())(save_mesh, sUrface);
105}
106
107MoFEMErrorCode CutMeshInterface::setVolume(const Range volume) {
109 vOlume = volume;
111}
112
113MoFEMErrorCode CutMeshInterface::setConstrainSurface(const Range surf) {
115 constrainSurface = surf;
117}
118
119MoFEMErrorCode CutMeshInterface::mergeSurface(const Range surface) {
121 sUrface.merge(surface);
123}
124
125MoFEMErrorCode CutMeshInterface::mergeVolumes(const Range volume) {
127 vOlume.merge(volume);
129}
130
131MoFEMErrorCode CutMeshInterface::snapSurfaceSkinToEdges(const Range fixed_edges,
132 const double rel_tol,
133 const double abs_tol,
134 Tag th,
135 const bool debug) {
136 CoreInterface &m_field = cOre;
137 moab::Interface &moab = m_field.get_moab();
139
140 // Get cutting surface skin
141 Skinner skin(&moab);
142 Range surface_skin;
143 CHKERR skin.find_skin(0, sUrface, false, surface_skin);
144
145 CHKERR snapSurfaceToEdges(surface_skin, fixed_edges, rel_tol, abs_tol, th,
146 debug);
147
149}
150
151MoFEMErrorCode CutMeshInterface::snapSurfaceToEdges(const Range surface_edges,
152 const Range fixed_edges,
153 const double rel_tol,
154 const double abs_tol,
155 Tag th, const bool debug) {
156 CoreInterface &m_field = cOre;
157 moab::Interface &moab = m_field.get_moab();
158 FTensor::Index<'i', 3> i;
160
161 map<EntityHandle, double> map_verts_length;
162
163 for (auto f : surface_edges) {
164 int num_nodes;
165 const EntityHandle *conn_skin;
166 CHKERR moab.get_connectivity(f, conn_skin, num_nodes, true);
167 VectorDouble6 coords_skin(6);
168 if (th)
169 CHKERR moab.tag_get_data(th, conn_skin, num_nodes, &coords_skin[0]);
170 else
171 CHKERR moab.get_coords(conn_skin, num_nodes, &coords_skin[0]);
173 &coords_skin[0], &coords_skin[1], &coords_skin[2]);
175 &coords_skin[3], &coords_skin[4], &coords_skin[5]);
176 FTensor::Tensor1<double, 3> t_skin_delta;
177 t_skin_delta(i) = t_n1(i) - t_n0(i);
178 const double skin_edge_length = sqrt(t_skin_delta(i) * t_skin_delta(i));
179 for (int nn = 0; nn != 2; ++nn) {
180 auto it = map_verts_length.find(conn_skin[nn]);
181 if (it != map_verts_length.end())
182 it->second = std::min(it->second, skin_edge_length);
183 else
184 map_verts_length[conn_skin[nn]] = skin_edge_length;
185 }
186 }
187
188 for (auto m : map_verts_length) {
189
191 if (th)
192 CHKERR moab.tag_get_data(th, &m.first, 1, &t_n(0));
193 else
194 CHKERR moab.get_coords(&m.first, 1, &t_n(0));
195
196 double min_dist = rel_tol * m.second;
197 FTensor::Tensor1<double, 3> t_min_coords;
198 CHKERR cOre.getInterface<Tools>()->findMinDistanceFromTheEdges(
199 &t_n(0), 1, fixed_edges, &min_dist, &t_min_coords(0));
200
201 if (min_dist < rel_tol * m.second || min_dist < abs_tol) {
202 if (debug)
203 MOFEM_LOG("WORLD", Sev::noisy) << "Snap " << min_dist;
204 if (th)
205 CHKERR moab.tag_set_data(th, &m.first, 1, &t_min_coords(0));
206 else
207 CHKERR moab.set_coords(&m.first, 1, &t_min_coords(0));
208 }
209 }
210
212}
213
214MoFEMErrorCode CutMeshInterface::buildTree() {
215 CoreInterface &m_field = cOre;
216 moab::Interface &moab = m_field.get_moab();
218 treeSurfPtr = boost::shared_ptr<OrientedBoxTreeTool>(
219 new OrientedBoxTreeTool(&moab, "ROOTSETSURF", true));
220 CHKERR treeSurfPtr->build(sUrface, rootSetSurf);
222}
223
225CutMeshInterface::cutOnly(Range vol, const BitRefLevel cut_bit, Tag th,
226 const double tol_geometry, const double tol_cut_close,
227 Range *fixed_edges, Range *corner_nodes,
228 const bool update_meshsets, const bool debug) {
229 CoreInterface &m_field = cOre;
230 moab::Interface &moab = m_field.get_moab();
232
233 // cut mesh
234 CHKERR findEdgesToCut(vol, QUIET, debug);
235 CHKERR projectZeroDistanceEnts(fixed_edges, corner_nodes, tol_geometry,
236 tol_cut_close, QUIET, debug);
237 CHKERR cutEdgesInMiddle(cut_bit, cutNewVolumes, cutNewSurfaces,
238 cutNewVertices, debug);
239
240 CHKERR cOre.getInterface<BitRefManager>()->updateRangeByChildren(constrainSurface,
241 constrainSurface);
242 if (fixed_edges)
243 CHKERR cOre.getInterface<BitRefManager>()->updateRangeByChildren(*fixed_edges,
244 *fixed_edges);
245 if (corner_nodes)
246 CHKERR cOre.getInterface<BitRefManager>()->updateRangeByChildren(*corner_nodes,
247 *corner_nodes);
248 if (update_meshsets)
249 CHKERR m_field.getInterface<MeshsetsManager>()
250 ->updateAllMeshsetsByEntitiesChildren(cut_bit);
251 CHKERR moveMidNodesOnCutEdges(th);
252
253 if (debug) {
254 CHKERR saveCutEdges();
255 if (fixed_edges)
256 CHKERR SaveData(moab)("out_cut_new_fixed_edges.vtk", *fixed_edges);
257 }
258
260}
261
262MoFEMErrorCode CutMeshInterface::trimOnly(const BitRefLevel trim_bit, Tag th,
263 const double tol_trim_close,
264 Range *fixed_edges,
265 Range *corner_nodes,
266 const bool update_meshsets,
267 const bool debug) {
268 CoreInterface &m_field = cOre;
269 moab::Interface &moab = m_field.get_moab();
271
272 // trim mesh
273 CHKERR findEdgesToTrim(fixed_edges, corner_nodes, th, tol_trim_close, debug);
274 CHKERR trimEdgesInTheMiddle(trim_bit, debug);
275
276 CHKERR cOre.getInterface<BitRefManager>()->updateRangeByChildren(constrainSurface,
277 constrainSurface);
278 if (fixed_edges)
279 CHKERR cOre.getInterface<BitRefManager>()->updateRangeByChildren(*fixed_edges,
280 *fixed_edges);
281
282 if (corner_nodes)
283 CHKERR cOre.getInterface<BitRefManager>()->updateRangeByChildren(*corner_nodes,
284 *corner_nodes);
285
286 if (update_meshsets)
287 CHKERR m_field.getInterface<MeshsetsManager>()
288 ->updateAllMeshsetsByEntitiesChildren(trim_bit);
289
290 // move nodes
291 CHKERR moveMidNodesOnTrimmedEdges(th);
292
293 // remove faces
294 CHKERR trimSurface(fixed_edges, corner_nodes, tol_trim_close, th, debug);
295
296 if (debug) {
297 CHKERR saveTrimEdges();
298 Range bit2_edges;
299 CHKERR cOre.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
300 trim_bit, BitRefLevel().set(), MBEDGE, bit2_edges);
301 CHKERR SaveData(moab)("trim_fixed_edges.vtk",
302 intersect(*fixed_edges, bit2_edges));
303 }
304
306}
307
308MoFEMErrorCode CutMeshInterface::cutAndTrim(
309 int &first_bit, Tag th, const double tol_geometry,
310 const double tol_cut_close, const double tol_trim_close, Range *fixed_edges,
311 Range *corner_nodes, const bool update_meshsets, const bool debug) {
312 CoreInterface &m_field = cOre;
314
315 std::vector<BitRefLevel> bit_levels;
316
317 auto get_back_bit_levels = [&]() {
318 bit_levels.push_back(BitRefLevel());
319 bit_levels.back().set(first_bit + bit_levels.size() - 1);
320 return bit_levels.back();
321 };
322
323 BitRefLevel cut_bit = get_back_bit_levels();
324
325 CHKERR cutOnly(unite(cutSurfaceVolumes, cutFrontVolumes), cut_bit, th,
326 tol_geometry, tol_cut_close, fixed_edges, corner_nodes,
327 update_meshsets, debug);
328
329 auto get_min_quality = [&m_field](const BitRefLevel bit, Tag th) {
330 Range tets_level; // test at level
331 CHKERR m_field.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
332 bit, BitRefLevel().set(), MBTET, tets_level);
333 double min_q = 1;
334 CHKERR m_field.getInterface<Tools>()->minTetsQuality(tets_level, min_q, th);
335 return min_q;
336 };
337
338 MOFEM_LOG_C("WORLD", Sev::inform, "Min quality cut %6.4g",
339 get_min_quality(cut_bit, th));
340
341 Range starting_volume = cutNewVolumes;
342 Range starting_volume_nodes;
343 CHKERR m_field.get_moab().get_connectivity(starting_volume,
344 starting_volume_nodes, true);
345 std::vector<double> staring_volume_coords(3 * starting_volume_nodes.size());
346 CHKERR m_field.get_moab().get_coords(starting_volume_nodes,
347 &*staring_volume_coords.begin());
348
349 if (th) {
350 std::vector<double> staring_volume_th_coords(3 *
351 starting_volume_nodes.size());
352 CHKERR m_field.get_moab().tag_get_data(th, starting_volume_nodes,
353 &*staring_volume_th_coords.begin());
354 CHKERR m_field.get_moab().set_coords(starting_volume_nodes,
355 &*staring_volume_th_coords.begin());
356 }
357
358 if (th)
359 CHKERR setTagData(th);
360
361 BitRefLevel trim_bit = get_back_bit_levels();
362
363 CHKERR trimOnly(trim_bit, th, tol_trim_close, fixed_edges, corner_nodes,
364 update_meshsets, debug);
365
366 MOFEM_LOG_C("WORLD", Sev::inform, "Min quality trim %3.2g",
367 get_min_quality(trim_bit, th));
368
369 first_bit += bit_levels.size() - 1;
370
371 if (th)
372 CHKERR m_field.get_moab().set_coords(starting_volume_nodes,
373 &*staring_volume_coords.begin());
374
376}
377
378MoFEMErrorCode CutMeshInterface::cutTrimAndMerge(
379 int &first_bit, const int fraction_level, Tag th, const double tol_geometry,
380 const double tol_cut_close, const double tol_trim_close, Range &fixed_edges,
381 Range &corner_nodes, const bool update_meshsets, const bool debug) {
382 CoreInterface &m_field = cOre;
384
385 std::vector<BitRefLevel> bit_levels;
386
387 auto get_back_bit_levels = [&]() {
388 bit_levels.push_back(BitRefLevel());
389 bit_levels.back().set(first_bit + bit_levels.size() - 1);
390 return bit_levels.back();
391 };
392
393 if (debug) {
394 CHKERR cOre.getInterface<BitRefManager>()->writeEntitiesNotInDatabase(
395 "ents_not_in_database.vtk", "VTK", "");
396 }
397
398 CHKERR cutAndTrim(first_bit, th, tol_geometry, tol_cut_close, tol_trim_close,
399 &fixed_edges, &corner_nodes, update_meshsets, debug);
400 if (debug)
401 CHKERR cOre.getInterface<BitRefManager>()->writeEntitiesNotInDatabase(
402 "cut_trim_ents_not_in_database.vtk", "VTK", "");
403
404 BitRefLevel bit_level1 = BitRefLevel().set(first_bit - 1);
405 BitRefLevel bit_level2 = get_back_bit_levels();
406 BitRefLevel bit_level3 = get_back_bit_levels();
407
408 CHKERR mergeBadEdges(fraction_level, bit_level1, bit_level2, bit_level3,
409 getNewTrimSurfaces(), fixed_edges, corner_nodes, th,
410 update_meshsets, debug);
411
412 auto get_min_quality = [&m_field, debug](const BitRefLevel bit, Tag th) {
413 Range tets_level; // test at level
414 CHKERR m_field.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
415 bit, BitRefLevel().set(), MBTET, tets_level);
416 double min_q = 1;
417 CHKERR m_field.getInterface<Tools>()->minTetsQuality(tets_level, min_q, th);
418 if (min_q < 0 && debug) {
419 CHKERR m_field.getInterface<Tools>()->writeTetsWithQuality(
420 "negative_tets.vtk", "VTK", "", tets_level, th);
421 }
422 return min_q;
423 };
424
425 MOFEM_LOG_C("WORLD", Sev::inform, "Min quality node merge %6.4g",
426 get_min_quality(bit_level3, th));
427
428 CHKERR cOre.getInterface<BitRefManager>()->updateRangeByChildren(constrainSurface,
429 constrainSurface);
430 CHKERR cOre.getInterface<BitRefManager>()->updateRangeByChildren(fixed_edges,
431 fixed_edges);
432 CHKERR cOre.getInterface<BitRefManager>()->updateRangeByChildren(corner_nodes,
433 corner_nodes);
434
435 first_bit += bit_levels.size() - 1;
436
437 if (debug) {
438 CHKERR cOre.getInterface<BitRefManager>()->writeBitLevelByType(
439 bit_level3, BitRefLevel().set(), MBTET, "out_tets_merged.vtk", "VTK",
440 "");
441 CHKERR cOre.getInterface<BitRefManager>()->writeEntitiesNotInDatabase(
442 "cut_trim_merge_ents_not_in_database.vtk", "VTK", "");
443 CHKERR SaveData(m_field.get_moab())("merged_surface.vtk", mergedSurfaces);
444 }
445
447}
448
449MoFEMErrorCode CutMeshInterface::makeFront(const bool debug) {
450 CoreInterface &m_field = cOre;
451 moab::Interface &moab = m_field.get_moab();
453 Skinner skin(&moab);
454 Range tets_skin;
455 CHKERR skin.find_skin(0, vOlume, false, tets_skin);
456 Range tets_skin_edges;
457 ErrorCode tmp_result;
458 tmp_result = moab.get_adjacencies(tets_skin, 1, false, tets_skin_edges,
459 moab::Interface::UNION);
460
461 if (MB_SUCCESS != tmp_result)
462 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
463 "Duplicated edges: most likely the source of error is comming from "
464 "adding the vertices of the cracking "
465 "volume to a BLOCKSET rather than NODESET (corresponding to the "
466 "input parameter-vertex_block_set)");
467
468 Range surface_skin;
469 CHKERR skin.find_skin(0, sUrface, false, surface_skin);
470 fRont = subtract(surface_skin, tets_skin_edges);
471 if (fRont.empty()) {
472 MOFEM_LOG("WORLD", Sev::warning)
473 << "The front not found. Using edges of the cut surface";
474 CHKERR moab.get_adjacencies(sUrface, 1, true, fRont,
475 moab::Interface::UNION);
476 }
477 if (debug)
478 CHKERR SaveData(moab)("front.vtk", fRont);
480}
481
482MoFEMErrorCode CutMeshInterface::createSurfaceLevelSets(int verb,
483 const bool debug) {
484 CoreInterface &m_field = cOre;
485 moab::Interface &moab = m_field.get_moab();
487 auto tools_interface = m_field.getInterface<Tools>();
488
489 auto create_tag = [&](const std::string name, const int dim) {
490 Tag th;
491 rval = moab.tag_get_handle(name.c_str(), th);
492 if (rval == MB_SUCCESS)
493 return th;
494 std::vector<double> def_val(dim, 0);
495 CHKERR moab.tag_get_handle(name.c_str(), dim, MB_TYPE_DOUBLE, th,
496 MB_TAG_CREAT | MB_TAG_SPARSE, &*def_val.begin());
497
498 return th;
499 };
500
501 auto set_vol = [&](const Range &vol_verts, std::vector<double> &coords,
502 std::vector<double> &dist_surface_vec,
503 std::vector<double> &dist_surface_normal_vec,
504 std::vector<double> &dist_surface_signed_dist_vec) {
506
507 coords.resize(3 * vol_verts.size());
508 dist_surface_vec.resize(3 * vol_verts.size());
509 dist_surface_normal_vec.resize(3 * vol_verts.size());
510 dist_surface_signed_dist_vec.resize(vol_verts.size());
511
512 CHKERR moab.get_coords(vol_verts, &*coords.begin());
513 std::srand(0);
514
515 for (auto v : vol_verts) {
516
517 const int index = vol_verts.index(v);
518 auto point_in = getVectorAdaptor(&coords[3 * index], 3);
519 VectorDouble3 point_out(3);
520 EntityHandle facets_out;
521 CHKERR treeSurfPtr->closest_to_location(&point_in[0], rootSetSurf,
522 &point_out[0], facets_out);
523
524 VectorDouble3 delta = point_out - point_in;
525 VectorDouble3 n_first(3);
526 CHKERR tools_interface->getTriNormal(facets_out, &*n_first.begin());
527
528 // Check of only triangle in proximity of point out is one triangle, if is
529 // more than one, use normal of lager triangle to set orientation.
530 auto check_triangle_orientation = [&](auto n) {
531 int num_nodes;
532 const EntityHandle *conn;
533 CHKERR moab.get_connectivity(facets_out, conn, num_nodes, true);
534 MatrixDouble3by3 coords(3, 3);
535 CHKERR moab.get_coords(conn, 3, &coords(0, 0));
536 VectorDouble3 center(3);
537 center.clear();
538 for (auto ii : {0, 1, 2})
539 for (auto jj : {0, 1, 2})
540 center(jj) += coords(ii, jj) / 3;
541
542 std::vector<EntityHandle> triangles_out;
543 std::vector<double> distance_out;
544 auto a_max = norm_2(n);
545 VectorDouble3 ray = -n / a_max;
546 VectorDouble3 pt = center - ray * sqrt(a_max);
547 const double ray_length = 2 * sqrt(a_max);
548
549 CHKERR treeSurfPtr->ray_intersect_triangles(
550 distance_out, triangles_out, rootSetSurf,
551 std::numeric_limits<float>::epsilon(), &pt[0], &ray[0],
552 &ray_length);
553
554 if (triangles_out.size() > 1) {
555 VectorDouble3 nt(3);
556 for (auto t : triangles_out) {
557 CHKERR tools_interface->getTriNormal(t, &*nt.begin());
558 double at = norm_2(nt);
559 if (at > a_max) {
560 n = nt;
561 a_max = at;
562 }
563 }
564 }
565
566 return n;
567 };
568
569 auto n = check_triangle_orientation(n_first);
570 n /= norm_2(n);
571 const double dot = inner_prod(delta, n);
572
573
574 if (std::abs(dot) < std::numeric_limits<double>::epsilon()) {
575 if (std::rand() % 2 == 0)
576 delta += n * std::numeric_limits<double>::epsilon();
577 else
578 delta -= n * std::numeric_limits<double>::epsilon();
579 }
580
581 auto dist_vec = getVectorAdaptor(&dist_surface_vec[3 * index], 3);
582 noalias(dist_vec) = delta;
583
584 auto dist_normal_vec =
585 getVectorAdaptor(&dist_surface_normal_vec[3 * index], 3);
586
587 dist_surface_signed_dist_vec[index] = dot;
588 noalias(dist_normal_vec) = dot * n;
589 }
590
592 };
593
594 std::vector<double> coords;
595 std::vector<double> dist_surface_vec;
596 std::vector<double> dist_surface_normal_vec;
597 std::vector<double> dist_surface_signed_dist_vec;
598 Range vol_verts;
599 CHKERR moab.get_connectivity(vOlume, vol_verts, true);
600
601 CHKERR set_vol(vol_verts, coords, dist_surface_vec, dist_surface_normal_vec,
602 dist_surface_signed_dist_vec);
603
604 CHKERR moab.tag_set_data(create_tag("DIST_SURFACE_VECTOR", 3), vol_verts,
605 &*dist_surface_vec.begin());
606 CHKERR moab.tag_set_data(create_tag("DIST_SURFACE_NORMAL_VECTOR", 3),
607 vol_verts, &*dist_surface_normal_vec.begin());
608 CHKERR moab.tag_set_data(create_tag("DIST_SURFACE_NORMAL_SIGNED", 1),
609 vol_verts, &*dist_surface_signed_dist_vec.begin());
610
612}
613
614MoFEMErrorCode CutMeshInterface::createFrontLevelSets(Range vol, Tag th,
615 int verb,
616 const bool debug) {
617 CoreInterface &m_field = cOre;
618 moab::Interface &moab = m_field.get_moab();
620
621 auto create_tag = [&](const std::string name, const int dim) {
622 Tag th;
623 rval = moab.tag_get_handle(name.c_str(), th);
624 if (rval == MB_SUCCESS)
625 return th;
626 std::vector<double> def_val(dim, 0);
627 CHKERR moab.tag_get_handle(name.c_str(), dim, MB_TYPE_DOUBLE, th,
628 MB_TAG_CREAT | MB_TAG_SPARSE, &*def_val.begin());
629 return th;
630 };
631
632 Range vol_vertices;
633 CHKERR moab.get_connectivity(vol, vol_vertices, true);
634
635 std::vector<double> min_distances_from_front(vol_vertices.size(), -1);
636 std::vector<double> points_on_edges(3 * vol_vertices.size(), 0);
637 std::vector<EntityHandle> closest_edges(vol_vertices.size(), 0);
638
639 std::vector<double> coords(3 * vol_vertices.size());
640 if (th)
641 CHKERR moab.tag_get_data(th, vol_vertices, &*coords.begin());
642 else
643 CHKERR moab.get_coords(vol_vertices, &*coords.begin());
644
645 CHKERR cOre.getInterface<Tools>()->findMinDistanceFromTheEdges(
646 &*coords.begin(), vol_vertices.size(), fRont,
647 &*min_distances_from_front.begin(), &*points_on_edges.begin(),
648 &*closest_edges.begin());
649
650 if (!points_on_edges.empty()) {
651 for (int i = 0; i != min_distances_from_front.size(); ++i) {
652 Range faces;
653 CHKERR moab.get_adjacencies(&closest_edges[0], 1, 2, false, faces);
654 auto point_in = getVectorAdaptor(&coords[3 * i], 3);
655 auto point_out = getVectorAdaptor(&points_on_edges[3 * i], 3);
656 point_out -= point_in;
657 }
658 }
659
660 auto th_dist_front_vec = create_tag("DIST_FRONT_VECTOR", 3);
661 CHKERR moab.tag_set_data(th_dist_front_vec, vol_vertices,
662 &*points_on_edges.begin());
663
665}
666
667MoFEMErrorCode CutMeshInterface::findLevelSetVolumes(
668 Tag th, Range &vol_edges, const bool remove_adj_prims_edges, int verb,
669 const bool debug, const std::string edges_file_name) {
670 CoreInterface &m_field = cOre;
671 moab::Interface &moab = m_field.get_moab();
673
674 auto get_tag_dim = [&](auto th) {
675 int dim;
676 CHKERR moab.tag_get_length(th, dim);
677 return dim;
678 };
679 auto dim = get_tag_dim(th);
680
681 auto get_tag_data = [&](auto th, auto conn) {
682 const void *ptr;
683 CHKERR moab.tag_get_by_ptr(th, &conn, 1, &ptr);
684 return getVectorAdaptor(
685 const_cast<double *>(static_cast<const double *>(ptr)), 3);
686 };
687
688 auto get_edge_ray = [&](auto conn) {
689 VectorDouble6 coords(6);
690 CHKERR moab.get_coords(conn, 2, &coords[0]);
691 VectorAdaptor n0 = getVectorAdaptor(&coords[0], 3);
692 VectorAdaptor n1 = getVectorAdaptor(&coords[3], 3);
693 VectorDouble3 ray = n1 - n0;
694 return ray;
695 };
696
697 Range edges;
698 CHKERR moab.get_adjacencies(vOlume, 1, true, edges, moab::Interface::UNION);
699
700 auto remove_prisms_edges = [&](Range &edges) {
702 Range prisms;
703 CHKERR moab.get_adjacencies(edges, 3, false, prisms,
704 moab::Interface::UNION);
705 prisms = prisms.subset_by_type(MBPRISM);
706 Range prisms_verts;
707 CHKERR moab.get_connectivity(prisms, prisms_verts, true);
708 Range prism_edges;
709 CHKERR moab.get_adjacencies(prisms_verts, 1, false, prism_edges,
710 moab::Interface::UNION);
711 edges = subtract(edges, prism_edges);
713 };
714 if (remove_adj_prims_edges)
715 CHKERR remove_prisms_edges(edges);
716
717 std::vector<EntityHandle> cut_edges;
718 cut_edges.reserve(edges.size());
719
720 auto get_cut_edges_vec = [&](auto th, auto &cut_edges, auto e, auto &&conn) {
722
723 auto ray = get_edge_ray(conn);
724 const double length = norm_2(ray);
725 ray /= length;
726 const auto dist0 = get_tag_data(th, conn[0]);
727 const auto dist1 = get_tag_data(th, conn[1]);
728 const double max_dist = std::max(norm_2(dist0), norm_2(dist1));
729 if (max_dist < length) {
730 cut_edges.push_back(e);
731 }
732
734 };
735
736 auto get_cut_edges_signed_dist = [&](auto th, auto &cut_edges, auto e,
737 auto &&conn) {
739 auto get_tag_signed_dist = [&](auto conn) {
740 double dist;
741 CHKERR moab.tag_get_data(th, &conn, 1, &dist);
742 return dist;
743 };
744 const auto dist0 = get_tag_signed_dist(conn[0]);
745 const auto dist1 = get_tag_signed_dist(conn[1]);
746 const double opposite = dist0 * dist1;
747 if (opposite <= 0)
748 cut_edges.push_back(e);
750 };
751
752 auto get_conn = [&](auto e) {
753 int num_nodes;
754 const EntityHandle *conn;
755 CHKERR moab.get_connectivity(e, conn, num_nodes, true);
756 return conn;
757 };
758
759 if (dim == 3)
760 for (auto e : edges)
761 CHKERR get_cut_edges_vec(th, cut_edges, e, get_conn(e));
762 else
763 for (auto e : edges)
764 CHKERR get_cut_edges_signed_dist(th, cut_edges, e, get_conn(e));
765
766 CHKERR moab.get_adjacencies(&*cut_edges.begin(), cut_edges.size(), 3, false,
767 vol_edges, moab::Interface::UNION);
768 vol_edges = intersect(vol_edges, vOlume);
769
770 auto convert_to_ranger = [](auto &v) {
771 Range r;
772 r.insert_list(v.begin(), v.end());
773 return r;
774 };
775
776 if (debug && !edges_file_name.empty())
777 CHKERR SaveData(m_field.get_moab())(edges_file_name,
778 convert_to_ranger(cut_edges));
779
781}
782
783MoFEMErrorCode CutMeshInterface::findLevelSetVolumes(int verb,
784 const bool debug) {
785 CoreInterface &m_field = cOre;
786 moab::Interface &moab = m_field.get_moab();
788
789 CHKERR createFrontLevelSets(vOlume, nullptr, verb, debug);
790 Tag th_dist_front_vec;
791 CHKERR moab.tag_get_handle("DIST_FRONT_VECTOR", th_dist_front_vec);
792 CHKERR findLevelSetVolumes(th_dist_front_vec, cutFrontVolumes, true, verb,
793 debug, "cutFrontEdges.vtk");
794
795 CHKERR createSurfaceLevelSets(verb, debug);
796
797 Tag th_dist_surface_vec;
798 CHKERR moab.tag_get_handle("DIST_SURFACE_VECTOR", th_dist_surface_vec);
799 cutSurfaceVolumes.clear();
800 CHKERR findLevelSetVolumes(th_dist_surface_vec, cutSurfaceVolumes, true, verb,
801 debug, "cutSurfaceEdges.vtk");
802
803 if (debug)
804 CHKERR SaveData(m_field.get_moab())("level_sets.vtk", vOlume);
805 if (debug)
806 CHKERR SaveData(m_field.get_moab())("cutSurfaceVolumes.vtk",
807 cutSurfaceVolumes);
808 if (debug)
809 CHKERR SaveData(m_field.get_moab())("cutFrontVolumes.vtk", cutFrontVolumes);
810
812}
813
814MoFEMErrorCode CutMeshInterface::refineMesh(const int init_bit_level,
815 const int surf_levels,
816 const int front_levels,
817 Range *fixed_edges, int verb,
818 const bool debug) {
819 CoreInterface &m_field = cOre;
820 moab::Interface &moab = m_field.get_moab();
821 MeshRefinement *refiner;
822 BitRefManager *bit_ref_manager;
824 CHKERR m_field.getInterface(refiner);
825 CHKERR m_field.getInterface(bit_ref_manager);
826
827 auto add_bit = [&](const int bit) {
829 CHKERR bit_ref_manager->addBitRefLevel(vOlume, BitRefLevel().set(bit),
830 verb);
831 Range adj_ents;
832 for (auto d : {2, 1, 0}) {
833 CHKERR moab.get_adjacencies(vOlume, d, true, adj_ents,
834 moab::Interface::UNION);
835 CHKERR bit_ref_manager->addBitRefLevel(adj_ents, BitRefLevel().set(bit),
836 verb);
837 }
839 };
840 CHKERR add_bit(init_bit_level);
841
842 auto update_range = [&](Range *r_ptr) {
844 if (r_ptr) {
845 Range childs;
846 CHKERR bit_ref_manager->updateRangeByChildren(*r_ptr, childs);
847 r_ptr->merge(childs);
848 }
850 };
851
852 auto refine = [&](const BitRefLevel bit, const Range tets) {
854 Range verts;
855 CHKERR moab.get_connectivity(tets, verts, true);
856 Range ref_edges;
857 CHKERR moab.get_adjacencies(verts, 1, true, ref_edges,
858 moab::Interface::UNION);
859
860 CHKERR refiner->addVerticesInTheMiddleOfEdges(ref_edges, bit);
861 CHKERR refiner->refineTets(vOlume, bit, verb);
862
863 CHKERR update_range(fixed_edges);
864 CHKERR update_range(&vOlume);
865 CHKERR m_field.getInterface<MeshsetsManager>()
866 ->updateAllMeshsetsByEntitiesChildren(bit);
867
868 Range bit_tets;
869 CHKERR m_field.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
870 bit, BitRefLevel().set(), MBTET, bit_tets);
871 vOlume = intersect(vOlume, bit_tets);
872
873 Range bit_edges;
874 CHKERR m_field.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
875 bit, BitRefLevel().set(), MBEDGE, bit_edges);
876 if (fixed_edges)
877 *fixed_edges = intersect(*fixed_edges, bit_edges);
878
880 };
881
882 for (int ll = init_bit_level; ll != init_bit_level + surf_levels; ++ll) {
883 CHKERR findLevelSetVolumes(verb, debug);
884 CHKERR refine(BitRefLevel().set(ll + 1),
885 unite(cutSurfaceVolumes, cutFrontVolumes));
886 }
887
888 for (int ll = init_bit_level + surf_levels;
889 ll != init_bit_level + surf_levels + front_levels; ++ll) {
890 CHKERR findLevelSetVolumes(verb, debug);
891 CHKERR refine(BitRefLevel().set(ll + 1), cutFrontVolumes);
892 }
893
894 CHKERR findLevelSetVolumes(verb, debug);
895
896 if (debug)
897 CHKERR SaveData(m_field.get_moab())("refinedVolume.vtk", vOlume);
898
900}
901
902MoFEMErrorCode CutMeshInterface::findEdgesToCut(Range vol, int verb,
903 const bool debug) {
904 CoreInterface &m_field = cOre;
905 moab::Interface &moab = m_field.get_moab();
907
908 edgesToCut.clear();
909 cutEdges.clear();
910
911 Tag th_signed_dist;
912 CHKERR moab.tag_get_handle("DIST_SURFACE_NORMAL_SIGNED", th_signed_dist);
913
914 auto get_tag_edge_dist = [&](auto th, auto conn) {
915 std::array<double, 2> r;
916 CHKERR moab.tag_get_data(th, conn, 2, r.data());
917 return r;
918 };
919
920 auto get_conn = [&](const auto e) {
921 int num_nodes;
922 const EntityHandle *conn;
923 CHKERR moab.get_connectivity(e, conn, num_nodes, true);
924 return conn;
925 };
926
927 auto get_adj = [&moab](const Range r, const int dim) {
928 Range a;
929 if (dim)
930 CHKERR moab.get_adjacencies(r, dim, false, a, moab::Interface::UNION);
931 else
932 CHKERR moab.get_connectivity(r, a, true);
933 return a;
934 };
935
936 auto vol_edges = get_adj(vol, 1);
937
938 aveLength = 0;
939 maxLength = 0;
940 int nb_ave_length = 0;
941 for (auto e : vol_edges) {
942
943 auto conn = get_conn(e);
944 auto dist = get_tag_edge_dist(th_signed_dist, conn);
945 const auto dist_max = std::max(dist[0], dist[1]);
946 const auto dist_min = std::min(dist[0], dist[1]);
947 const auto dot = dist[0] * dist[1];
948
949 VectorDouble6 coords(6);
950 CHKERR moab.get_coords(conn, 2, &coords[0]);
951 VectorAdaptor n0 = getVectorAdaptor(&coords[0], 3);
952 VectorAdaptor n1 = getVectorAdaptor(&coords[3], 3);
953 VectorDouble3 ray = n1 - n0;
954 const double ray_length = norm_2(ray);
955 ray /= ray_length;
956
957 if (
958
959 (dot < 0 && dist_max > std::numeric_limits<double>::epsilon()) ||
960 (std::abs(dist_min) < std::numeric_limits<double>::epsilon() &&
961 dist_max > std::numeric_limits<double>::epsilon())
962
963 ) {
964
965 // Edges is on two sides of the surface
966 const double s = dist[0] / (dist[0] - dist[1]);
967 const double dist = s * ray_length;
968
969 auto add_edge = [&](auto dist) {
970 edgesToCut[e].dIst = dist;
971 edgesToCut[e].lEngth = ray_length;
972 edgesToCut[e].unitRayDir = ray;
973 edgesToCut[e].rayPoint = n0;
974 cutEdges.insert(e);
975
976 aveLength += norm_2(ray);
977 maxLength = fmax(maxLength, norm_2(ray));
978 ++nb_ave_length;
979 };
980
981 add_edge(dist);
982 }
983 }
984 aveLength /= nb_ave_length;
985
986 if (debug)
987 CHKERR SaveData(m_field.get_moab())("cut_edges.vtk", cutEdges);
988
989 if (debug)
990 CHKERR SaveData(m_field.get_moab())("cut_edges_vol.vtk",
991 get_adj(cutEdges, 3));
992
994}
995
996MoFEMErrorCode CutMeshInterface::projectZeroDistanceEnts(
997 Range *fixed_edges, Range *corner_nodes, const double geometry_tol,
998 const double close_tol, const int verb, const bool debug) {
999 CoreInterface &m_field = cOre;
1000 moab::Interface &moab = m_field.get_moab();
1001 Skinner skin(&moab);
1003
1004 auto get_ent_adj = [&moab](const EntityHandle v, const int dim) {
1005 Range a;
1006 if (dim)
1007 CHKERR moab.get_adjacencies(&v, 1, dim, true, a);
1008 return a;
1009 };
1010
1011 auto get_adj = [&moab](const Range r, const int dim) {
1012 Range a;
1013 if (dim)
1014 CHKERR moab.get_adjacencies(r, dim, false, a, moab::Interface::UNION);
1015 else
1016 CHKERR moab.get_connectivity(r, a, true);
1017 return a;
1018 };
1019
1020 auto get_skin = [&skin](const auto r) {
1021 Range s;
1022 CHKERR skin.find_skin(0, r, false, s);
1023 return s;
1024 };
1025
1026
1027 auto get_range = [](std::vector<EntityHandle> v) {
1028 Range r;
1029 r.insert_list(v.begin(), v.end());
1030 return r;
1031 };
1032
1033 auto get_coords = [&](const auto v) {
1034 VectorDouble3 coords(3);
1035 CHKERR moab.get_coords(&v, 1, &coords[0]);
1036 return coords;
1037 };
1038
1039 Tag th_normal_dist;
1040 CHKERR moab.tag_get_handle("DIST_SURFACE_NORMAL_VECTOR", th_normal_dist);
1041
1042 auto get_normal_dits = [&](const EntityHandle v) {
1043 VectorDouble3 dist_vec(3);
1044 CHKERR moab.tag_get_data(th_normal_dist, &v, 1, &*dist_vec.begin());
1045 return dist_vec;
1046 };
1047
1048 auto get_prj_point = [&](const EntityHandle v, const Range edges,
1049 const double geometry_tol) {
1050 auto get_tuple = [](const EntityHandle e, const double dist,
1051 const double l) { return std::make_tuple(e, dist, l); };
1052
1053 std::tuple<EntityHandle, double, double> min_tuple{0, 0, 0};
1054
1055 for (auto e : edges) {
1056 auto eit = edgesToCut.find(e);
1057 if (eit != edgesToCut.end()) {
1058
1059 auto get_dist = [&](auto eit) {
1060 int num_nodes;
1061 const EntityHandle *conn;
1062 CHKERR moab.get_connectivity(eit->first, conn, num_nodes, true);
1063 if (conn[0] == v)
1064 return eit->second.dIst;
1065 else if (conn[1] == v)
1066 return (eit->second.lEngth - eit->second.dIst);
1067 else
1068 THROW_MESSAGE("Data inconsistency");
1069 };
1070
1071 const auto d = get_dist(eit);
1072 if (std::get<0>(min_tuple) == 0) {
1073 min_tuple = get_tuple(e, d, eit->second.lEngth);
1074 } else if (std::get<1>(min_tuple) > d) {
1075 min_tuple = get_tuple(e, d, eit->second.lEngth);
1076 }
1077 }
1078 }
1079
1080 const auto geom_dist_vec = get_normal_dits(v);
1081 const auto geom_tol = norm_2(geom_dist_vec);
1082 const auto l = std::get<2>(min_tuple);
1083
1084 if (geom_tol < l * geometry_tol) {
1085 return std::make_pair(get_coords(v), l);
1086
1087 } else {
1088 const auto &d = edgesToCut.at(std::get<0>(min_tuple));
1089 return std::make_pair(VectorDouble3(d.rayPoint + d.dIst * d.unitRayDir),
1090 l);
1091 }
1092 };
1093
1094 auto get_in_range = [](auto v, auto &r) { return (r.find(v) != r.end()); };
1095
1096 auto project_nodes = [&](auto nodes_to_check) {
1097 if (debug)
1098 CHKERR SaveData(moab)("nodes_to_check.vtk", nodes_to_check);
1099
1100 auto get_fix_e = [](auto fixed_edges) {
1101 if (fixed_edges)
1102 return *fixed_edges;
1103 else
1104 return Range();
1105 };
1106
1107 const auto fix_e = get_fix_e(fixed_edges);
1108 const auto skin_e = get_adj(unite(get_skin(vOlume), constrainSurface), 1);
1109 const auto cut_fix = intersect(cutEdges, fix_e);
1110 const auto cut_skin = intersect(cutEdges, skin_e);
1111
1112 Range corner_n;
1113 if (corner_nodes)
1114 corner_n = intersect(*corner_nodes, nodes_to_check);
1115 auto fixe_n = intersect(get_adj(fix_e, 0), nodes_to_check);
1116 auto skin_n = intersect(get_adj(skin_e, 0), nodes_to_check);
1117
1118 std::vector<std::pair<EntityHandle, TreeData>> vertices_on_cut_edges;
1119 vertices_on_cut_edges.reserve(nodes_to_check.size());
1120
1121 auto add_zero_vertex = [&](const EntityHandle v, auto &&new_pos) {
1122 auto coords = get_coords(v);
1123 auto ray = new_pos - coords;
1124 auto l = norm_2(ray);
1125 TreeData data;
1126 data.dIst = l;
1127 if (l > std::numeric_limits<double>::epsilon()) {
1128 data.unitRayDir = ray / l;
1129 } else {
1130 data.dIst = 0;
1131 data.unitRayDir = ray;
1132 }
1133 data.rayPoint = coords;
1134 return std::make_pair(v, data);
1135 };
1136
1137 auto intersect_v = [&](const auto v, const auto r) {
1138 return intersect(r, get_ent_adj(v, 1));
1139 };
1140
1141 for (auto v : nodes_to_check) {
1142
1143 const auto e = intersect_v(v, cutEdges);
1144 if (!e.empty()) {
1145
1146 if (get_in_range(v, corner_n)) {
1147 auto p = get_prj_point(v, e, 0);
1148 if (norm_2(get_coords(v) - p.first) < close_tol * p.second) {
1149 vertices_on_cut_edges.push_back(add_zero_vertex(v, get_coords(v)));
1150 continue;
1151 }
1152
1153 } else if (get_in_range(v, fixe_n)) {
1154 const auto b = intersect_v(v, cut_fix);
1155 if (!b.empty()) {
1156 auto p = get_prj_point(v, b, geometry_tol);
1157 if (norm_2(get_coords(v) - p.first) < close_tol * p.second) {
1158 vertices_on_cut_edges.push_back(add_zero_vertex(v, p.first));
1159 continue;
1160 }
1161
1162 } else if (get_in_range(v, skin_n)) {
1163 const auto b = intersect_v(v, cut_skin);
1164 if (!b.empty()) {
1165 auto p = get_prj_point(v, b, geometry_tol);
1166 if (norm_2(get_coords(v) - p.first) < close_tol * p.second) {
1167 vertices_on_cut_edges.push_back(add_zero_vertex(v, p.first));
1168 continue;
1169 }
1170 }
1171
1172 }
1173 }
1174
1175 auto p = get_prj_point(v, e, geometry_tol);
1176 if (norm_2(get_coords(v) - p.first) < close_tol * p.second) {
1177 if (get_in_range(v, fixe_n) || get_in_range(v, skin_n))
1178 vertices_on_cut_edges.push_back(add_zero_vertex(v, get_coords(v)));
1179 else
1180 vertices_on_cut_edges.push_back(add_zero_vertex(v, p.first));
1181 }
1182 }
1183
1184 }
1185
1186 auto get_distances = [&](auto &data) {
1187 std::map<EntityHandle, double> dist_map;
1188 if (!data.empty()) {
1189 Tag th;
1190 CHKERR moab.tag_get_handle("DIST_SURFACE_NORMAL_SIGNED", th);
1191
1192 std::vector<EntityHandle> verts;
1193 verts.reserve(data.size());
1194 for (auto d : data)
1195 verts.emplace_back(d.first);
1196 std::vector<double> distances(verts.size());
1197 CHKERR moab.tag_get_data(th, &*verts.begin(), verts.size(),
1198 &*distances.begin());
1199 for (size_t i = 0; i != verts.size(); ++i)
1200 dist_map[verts[i]] = distances[i];
1201 }
1202 return dist_map;
1203 };
1204
1205 auto dist_map = get_distances(vertices_on_cut_edges);
1206 if (!dist_map.empty()) {
1207 auto cmp = [&dist_map](const auto &a, const auto &b) {
1208 return dist_map[a.first] < dist_map[b.first];
1209 };
1210 std::sort(vertices_on_cut_edges.begin(), vertices_on_cut_edges.end(),
1211 cmp);
1212 }
1213
1214 return vertices_on_cut_edges;
1215 };
1216
1217 auto get_min_quality =
1218 [&](const Range &adj_tets,
1219 const map<EntityHandle, TreeData> &vertices_on_cut_edges,
1220 const std::pair<EntityHandle, TreeData> *test_data_ptr) {
1221 double min_q = 1;
1222 for (auto t : adj_tets) {
1223 int num_nodes;
1224 const EntityHandle *conn;
1225 CHKERR m_field.get_moab().get_connectivity(t, conn, num_nodes, true);
1226 VectorDouble12 coords(12);
1227 CHKERR moab.get_coords(conn, num_nodes, &coords[0]);
1228
1229 auto set_new_coord = [](auto d) {
1230 return d.rayPoint + d.dIst * d.unitRayDir;
1231 };
1232
1233 for (auto n : {0, 1, 2, 3}) {
1234 auto n_coords = getVectorAdaptor(&coords[3 * n], 3);
1235 if (test_data_ptr) {
1236 if (test_data_ptr->first == conn[n]) {
1237 noalias(n_coords) = set_new_coord(test_data_ptr->second);
1238 }
1239 }
1240 auto mit = vertices_on_cut_edges.find(conn[n]);
1241 if (mit != vertices_on_cut_edges.end()) {
1242 noalias(n_coords) = set_new_coord(mit->second);
1243 }
1244 }
1245 min_q = std::min(min_q, Tools::volumeLengthQuality(&coords[0]));
1246 }
1247 return min_q;
1248 };
1249
1250 auto get_zero_distance_verts = [&](const auto &&vertices_on_cut_edges) {
1251 std::vector<EntityHandle> zero_dist_vec;
1252 zero_dist_vec.reserve(vertices_on_cut_edges.size());
1253 for (auto t : vertices_on_cut_edges) {
1254
1255 auto adj_tet = intersect(vOlume, get_ent_adj(t.first, 3));
1256 const double q0 = get_min_quality(adj_tet, verticesOnCutEdges, nullptr);
1257 const double q = get_min_quality(adj_tet, verticesOnCutEdges, &t);
1258 if (std::isnormal(q) && (q / q0) > projectEntitiesQualityTrashold) {
1259 verticesOnCutEdges[t.first] = t.second;
1260 zero_dist_vec.push_back(t.first);
1261 }
1262 }
1263 return zero_dist_vec;
1264 };
1265
1266 auto vol_cut_ents = intersect(vOlume, get_adj(cutEdges, 3));
1267
1268 auto get_zero_distant_ents = [&](auto bridge_ents, const int dim,
1269 const int bridge_dim) {
1270 auto ents =
1271 intersect(get_adj(bridge_ents, dim), get_adj(vol_cut_ents, dim));
1272 auto ents_to_remove =
1273 get_adj(subtract(get_adj(ents, bridge_dim), bridge_ents), dim);
1274 return subtract(ents, ents_to_remove);
1275 };
1276
1277 verticesOnCutEdges.clear();
1278 zeroDistanceVerts.clear();
1279 zeroDistanceVerts.merge(
1280 get_range(get_zero_distance_verts(project_nodes(get_adj(cutEdges, 0)))));
1281 zeroDistanceEnts = subtract(get_zero_distant_ents(zeroDistanceVerts, 2, 0),
1282 get_skin(vOlume));
1283
1284 if (debug)
1285 CHKERR SaveData(moab)("zero_distance_verts.vtk", zeroDistanceVerts);
1286 if (debug)
1287 CHKERR SaveData(moab)("zero_distance_ents.vtk", zeroDistanceEnts);
1288
1289 for (auto f : zeroDistanceVerts) {
1290 auto adj_edges = get_ent_adj(f, 1);
1291 for (auto e : adj_edges) {
1292 cutEdges.erase(e);
1293 edgesToCut.erase(e);
1294 }
1295 }
1296
1297 if (debug)
1298 CHKERR SaveData(moab)("cut_edges_to_cut.vtk", cutEdges);
1299
1301}
1302
1303MoFEMErrorCode CutMeshInterface::cutEdgesInMiddle(const BitRefLevel bit,
1304 Range &cut_vols,
1305 Range &cut_surf,
1306 Range &cut_verts,
1307 const bool debug) {
1308 CoreInterface &m_field = cOre;
1309 moab::Interface &moab = m_field.get_moab();
1310 MeshRefinement *refiner;
1311 auto ref_ents_ptr = m_field.get_ref_ents();
1313
1314 if (cutEdges.size() != edgesToCut.size())
1315 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "Data inconsistency");
1316
1317 auto refine_mesh = [&]() {
1319 CHKERR m_field.getInterface(refiner);
1320 CHKERR refiner->addVerticesInTheMiddleOfEdges(cutEdges, bit);
1321 CHKERR refiner->refineTets(vOlume, bit, QUIET, debug);
1323 };
1324
1325 CHKERR refine_mesh();
1326
1327 if (debug)
1328 if (cutEdges.size() != edgesToCut.size())
1329 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "Data inconsistency");
1330
1331 cut_vols.clear();
1332 CHKERR m_field.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
1333 bit, BitRefLevel().set(), MBTET, cut_vols);
1334 cut_surf.clear();
1335 CHKERR m_field.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
1336 bit, bit, MBTRI, cut_surf);
1337
1338 if (debug)
1339 CHKERR SaveData(moab)("cut_surf_from_bit.vtk", cut_surf);
1340
1341 // Find new vertices on cut edges
1342 cut_verts.clear();
1343 cut_verts.merge(zeroDistanceVerts);
1344
1345 for (auto &m : edgesToCut) {
1346 auto vit = ref_ents_ptr->get<Composite_ParentEnt_And_EntType_mi_tag>().find(
1347 boost::make_tuple(MBVERTEX, m.first));
1348 if (vit ==
1349 ref_ents_ptr->get<Composite_ParentEnt_And_EntType_mi_tag>().end()) {
1350 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1351 "No vertex on cut edges, that make no sense");
1352 }
1353 const boost::shared_ptr<RefEntity> &ref_ent = *vit;
1354 if ((ref_ent->getBitRefLevel() & bit).any()) {
1355 EntityHandle vert = ref_ent->getEnt();
1356 cut_verts.insert(vert);
1357 verticesOnCutEdges[vert] = m.second;
1358 } else {
1359 SETERRQ(
1360 PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1361 "Vertex has wrong bit ref level %s",
1362 boost::lexical_cast<std::string>(ref_ent->getBitRefLevel()).c_str());
1363 }
1364 }
1365
1366 // Add zero distance entities faces
1367 Range tets_skin;
1368 Skinner skin(&moab);
1369 CHKERR skin.find_skin(0, cut_vols, false, tets_skin);
1370 tets_skin.merge(constrainSurface);
1371
1372 // At that point cut_surf has all newly created faces, now take all
1373 // nodes on those faces and subtract nodes on cut edges. Faces adjacent to
1374 // nodes which left are not part of surface.
1375 cut_surf.merge(zeroDistanceEnts.subset_by_type(MBTRI));
1376 Range diff_verts;
1377 CHKERR moab.get_connectivity(cut_surf, diff_verts, true);
1378 diff_verts = subtract(diff_verts, cut_verts);
1379
1380 Range subtract_faces;
1381 CHKERR moab.get_adjacencies(diff_verts, 2, false, subtract_faces,
1382 moab::Interface::UNION);
1383 cut_surf = subtract(cut_surf, unite(subtract_faces, tets_skin));
1384
1385 cut_verts.clear();
1386 CHKERR moab.get_connectivity(cut_surf, cut_verts, true);
1387
1388 // Check non-manifolds
1389 auto check_for_non_manifold = [&]() {
1391 Range surf_edges;
1392 CHKERR moab.get_adjacencies(cut_surf, 1, false, surf_edges,
1393 moab::Interface::UNION);
1394 for (auto e : surf_edges) {
1395
1396 Range faces;
1397 CHKERR moab.get_adjacencies(&e, 1, 2, false, faces);
1398 faces = intersect(faces, cut_surf);
1399 if (faces.size() > 2) {
1400
1401 bool resolved = false;
1402
1403 // Check for haning node
1404 Range nodes;
1405 CHKERR moab.get_connectivity(faces, nodes, true);
1406 for (auto n : nodes) {
1407 Range adj_faces;
1408 CHKERR moab.get_adjacencies(&n, 1, 2, false, adj_faces);
1409 adj_faces = intersect(adj_faces, cut_surf);
1410 if (adj_faces.size() == 1) {
1411 cut_surf.erase(adj_faces[0]);
1412 resolved = true;
1413 }
1414 }
1415
1416 // Check for two edges minfold
1417 Range adj_edges;
1418 CHKERR moab.get_adjacencies(faces, 1, false, adj_edges,
1419 moab::Interface::UNION);
1420 adj_edges = intersect(adj_edges, surf_edges);
1421 adj_edges.erase(e);
1422 for (auto other_e : adj_edges) {
1423 Range other_faces;
1424 CHKERR moab.get_adjacencies(&other_e, 1, 2, false, other_faces);
1425 other_faces = intersect(other_faces, cut_surf);
1426 if (other_faces.size() > 2) {
1427 other_faces = intersect(other_faces, faces);
1428 cut_surf = subtract(cut_surf, other_faces);
1429 resolved = true;
1430 }
1431 }
1432
1433 if (!resolved && !debug)
1434 MOFEM_LOG("WORLD", Sev::warning) << "Non-mainfold surface after cut.";
1435
1436 cut_verts.clear();
1437 CHKERR moab.get_connectivity(cut_surf, cut_verts, true);
1438 }
1439 }
1441 };
1442
1443 CHKERR check_for_non_manifold();
1444
1445 if (debug)
1446 CHKERR SaveData(moab)("cut_surf.vtk", cut_surf);
1447
1449}
1450
1451MoFEMErrorCode CutMeshInterface::moveMidNodesOnCutEdges(Tag th) {
1452 CoreInterface &m_field = cOre;
1453 moab::Interface &moab = m_field.get_moab();
1455
1456 // Range out_side_vertices;
1457 for (auto m : verticesOnCutEdges) {
1458 double dist = m.second.dIst;
1459 VectorDouble3 new_coors = m.second.rayPoint + dist * m.second.unitRayDir;
1460 if (th)
1461 CHKERR moab.tag_set_data(th, &m.first, 1, &new_coors[0]);
1462 else
1463 CHKERR moab.set_coords(&m.first, 1, &new_coors[0]);
1464 }
1465
1467}
1468
1469MoFEMErrorCode CutMeshInterface::moveMidNodesOnTrimmedEdges(Tag th) {
1470 CoreInterface &m_field = cOre;
1471 moab::Interface &moab = m_field.get_moab();
1473 for (auto &v : verticesOnTrimEdges) {
1474 double dist = v.second.dIst;
1475 VectorDouble3 new_coors = v.second.rayPoint + dist * v.second.unitRayDir;
1476 if (th)
1477 CHKERR moab.tag_set_data(th, &v.first, 1, &new_coors[0]);
1478 else
1479 CHKERR moab.set_coords(&v.first, 1, &new_coors[0]);
1480 }
1482}
1483
1484MoFEMErrorCode CutMeshInterface::findEdgesToTrim(Range *fixed_edges,
1485 Range *corner_nodes, Tag th,
1486 const double tol_trim_close,
1487 const bool debug) {
1488 CoreInterface &m_field = cOre;
1489 moab::Interface &moab = m_field.get_moab();
1491
1492 // takes body skin
1493 Skinner skin(&moab);
1494 Range tets_skin;
1495 CHKERR skin.find_skin(0, cutNewVolumes, false, tets_skin);
1496 tets_skin.merge(constrainSurface);
1497
1498 // vertices on the skin
1499 Range tets_skin_verts;
1500 CHKERR moab.get_connectivity(tets_skin, tets_skin_verts, true);
1501 // edges on the skin
1502 Range tets_skin_edges;
1503 CHKERR moab.get_adjacencies(tets_skin, 1, false, tets_skin_edges,
1504 moab::Interface::UNION);
1505
1506 // get edges on new surface
1507 Range cut_surface_edges;
1508 CHKERR moab.get_adjacencies(cutNewSurfaces, 1, false, cut_surface_edges,
1509 moab::Interface::UNION);
1510 Range cut_surface_verts;
1511 CHKERR moab.get_connectivity(cutNewSurfaces, cut_surface_verts, true);
1512
1513 Range corners;
1514 if (corner_nodes)
1515 corners = *corner_nodes;
1516
1517 Range fix_edges;
1518 if (fixed_edges)
1519 fix_edges = *fixed_edges;
1520
1521 Range fixed_edges_verts;
1522 if (fixed_edges)
1523 CHKERR moab.get_connectivity(*fixed_edges, fixed_edges_verts, true);
1524
1525 Range surface_skin;
1526 if (fRont.empty())
1527 CHKERR skin.find_skin(0, sUrface, false, surface_skin);
1528 else
1529 surface_skin = fRont;
1530
1531 auto get_point_coords = [&](EntityHandle v) {
1532 VectorDouble3 point(3);
1533 if (th)
1534 CHKERR moab.tag_get_data(th, &v, 1, &point[0]);
1535 else
1536 CHKERR moab.get_coords(&v, 1, &point[0]);
1537 return point;
1538 };
1539
1540 struct VertMap {
1541 const double d;
1542 const EntityHandle v;
1543 const EntityHandle e;
1544 VertMap(const double d, const EntityHandle v, const EntityHandle e)
1545 : d(d), v(v), e(e) {}
1546 };
1547
1548 typedef multi_index_container<
1549 VertMap,
1550 indexed_by<
1551 ordered_non_unique<member<VertMap, const double, &VertMap::d>>,
1552 ordered_non_unique<member<VertMap, const EntityHandle, &VertMap::v>>,
1553 ordered_non_unique<member<VertMap, const EntityHandle, &VertMap::e>>
1554
1555 >>
1556 VertMapMultiIndex;
1557
1558 VertMapMultiIndex verts_map;
1559
1560 auto add_vert = [&](const EntityHandle v, const EntityHandle e,
1561 const double dist) {
1562 verts_map.insert(VertMap(dist, v, e));
1563 };
1564
1565 // clear data ranges
1566 trimEdges.clear();
1567 edgesToTrim.clear();
1568 verticesOnTrimEdges.clear();
1569 trimNewVertices.clear();
1570
1571 auto cut_this_edge = [&](const EntityHandle e, const double length, auto &ray,
1572 auto &ray_point) {
1573 trimEdges.insert(e);
1574 edgesToTrim[e].dIst = 1;
1575 edgesToTrim[e].lEngth = length;
1576 edgesToTrim[e].unitRayDir.resize(3, false);
1577 edgesToTrim[e].rayPoint.resize(3, false);
1578 for (int ii = 0; ii != 3; ++ii)
1579 edgesToTrim[e].unitRayDir[ii] = ray(ii);
1580 for (int ii = 0; ii != 3; ++ii)
1581 edgesToTrim[e].rayPoint[ii] = ray_point(ii);
1582 };
1583
1584 FTensor::Index<'i', 3> i;
1585 FTensor::Index<'j', 3> j;
1586 FTensor::Index<'k', 3> k;
1587
1588 int num_nodes;
1589
1590 auto get_tag_data = [&](auto th, auto conn) {
1592 CHKERR moab.tag_get_data(th, &conn, 1, &t(0));
1593 return t;
1594 };
1595
1596 double max_edge_length = 0;
1597
1598 /// Project front entities on on the cut surface plane
1599 if (!fRont.empty()) {
1600 // Calculate distances
1601 treeSurfPtr = boost::shared_ptr<OrientedBoxTreeTool>(
1602 new OrientedBoxTreeTool(&moab, "ROOTSETSURF", true));
1603 CHKERR treeSurfPtr->build(cutNewSurfaces, rootSetSurf);
1604
1605 for (auto s : surface_skin) {
1606
1607 auto project_on_surface = [&](auto &t) {
1609
1610 EntityHandle facets_out;
1611 CHKERR treeSurfPtr->closest_to_location(&t(0), rootSetSurf, &t_p(0),
1612 facets_out);
1613
1615 CHKERR m_field.getInterface<Tools>()->getTriNormal(facets_out,
1616 &t_normal(0));
1617 t_normal(i) /= sqrt(t_normal(i) * t_normal(i));
1618 const double dot = t_normal(i) * (t_p(i) - t(i));
1619 t_p(i) = t(i) + dot * t_normal(i);
1620
1621 return t_p;
1622 };
1623
1624 const EntityHandle *conn;
1625 CHKERR moab.get_connectivity(s, conn, num_nodes, true);
1626
1627 VectorDouble6 coords_front(6);
1628 CHKERR moab.get_coords(conn, num_nodes, &coords_front[0]);
1629
1630 FTensor::Tensor1<double *, 3> t_f0(&coords_front[0], &coords_front[1],
1631 &coords_front[2]);
1632 FTensor::Tensor1<double *, 3> t_f1(&coords_front[3], &coords_front[4],
1633 &coords_front[5]);
1634
1635 auto t_p_f0 = project_on_surface(t_f0);
1636 auto t_p_f1 = project_on_surface(t_f1);
1637
1638 CHKERR moab.set_coords(&conn[0], 1, &t_p_f0(0));
1639 CHKERR moab.set_coords(&conn[1], 1, &t_p_f1(0));
1640 }
1641 }
1642
1643 if (debug)
1644 CHKERR SaveData(moab)("surface_skin_to_trim.vtk", surface_skin);
1645
1646 CHKERR createFrontLevelSets(cutNewSurfaces, th, QUIET, debug);
1647 Tag th_dist_front_vec;
1648 CHKERR moab.tag_get_handle("DIST_FRONT_VECTOR", th_dist_front_vec);
1649
1650 // iterate over edges on cut surface
1651 for (auto e : cut_surface_edges) {
1652
1653 auto get_conn_edge = [&moab](auto e) {
1654 // Get edge connectivity and coords
1655 const EntityHandle *conn_edge;
1656 int num_nodes;
1657 CHKERR moab.get_connectivity(e, conn_edge, num_nodes, true);
1658 return conn_edge;
1659 };
1660
1661 auto get_coords_edge = [&moab](auto conn_edge) {
1662 std::array<double, 6> coords_edge;
1663 CHKERR moab.get_coords(conn_edge, 2, coords_edge.data());
1664 return coords_edge;
1665 };
1666
1667 auto get_ftensor_coords = [](const double *ptr) {
1668 return FTensor::Tensor1<double, 3>{ptr[0], ptr[1], ptr[2]};
1669 };
1670
1671 auto conn_edge = get_conn_edge(e);
1672 auto coords_edge = get_coords_edge(conn_edge);
1673
1674 auto t_dist0 = get_tag_data(th_dist_front_vec, conn_edge[0]);
1675 auto t_dist1 = get_tag_data(th_dist_front_vec, conn_edge[1]);
1676 auto t_e0 = get_ftensor_coords(&coords_edge[0]);
1677 auto t_e1 = get_ftensor_coords(&coords_edge[3]);
1678
1679 FTensor::Tensor1<double, 3> t_edge_delta;
1680 t_edge_delta(i) = t_e1(i) - t_e0(i);
1681 const double edge_length2 = t_edge_delta(i) * t_edge_delta(i);
1682 const double edge_length = sqrt(edge_length2);
1683 if (edge_length == 0)
1684 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "Zero edge length");
1685
1686 auto add_edge = [&](auto t_cut) {
1688 if (t_cut < 0.5) {
1689 t_ray(i) = t_cut * t_edge_delta(i);
1690 add_vert(conn_edge[0], e, fabs(t_cut));
1691 add_vert(conn_edge[1], e, fabs(t_cut - 1));
1692 cut_this_edge(e, edge_length, t_ray, t_e0);
1693 } else {
1694 FTensor::Tensor1<double, 3> t_edge_point;
1695 t_edge_point(i) = t_e0(i) + t_cut * t_edge_delta(i);
1696 t_ray(i) = t_edge_point(i) - t_e1(i);
1697 add_vert(conn_edge[0], e, fabs(t_cut));
1698 add_vert(conn_edge[1], e, fabs(t_cut - 1));
1699 cut_this_edge(e, edge_length, t_ray, t_e1);
1700 }
1701 max_edge_length = std::max(max_edge_length, edge_length);
1702 };
1703
1704 auto trim_cross_edges = [&]() {
1705 if (std::min(t_dist0(i) * t_dist0(i), t_dist1(i) * t_dist1(i)) <
1706 edge_length2) {
1707
1708 auto make_pair = [&](const double d, const double te) {
1709 return std::make_pair(d, te);
1710 };
1711
1712 auto min_pair = make_pair(-1, -1);
1713
1714 for (auto f : surface_skin) {
1715
1716 auto conn_front = get_conn_edge(f);
1717 auto coords_front = get_coords_edge(conn_front);
1718 auto t_f0 = get_ftensor_coords(&coords_front[0]);
1719 auto t_f1 = get_ftensor_coords(&coords_front[3]);
1720
1721 double te;
1722 double tf;
1723
1724 auto res = Tools::minDistanceFromSegments(
1725 &t_e0(0), &t_e1(0), &t_f0(0), &t_f1(0), &te, &tf);
1726
1727 if (res != Tools::NO_SOLUTION) {
1728
1729 auto check = [](auto v) {
1730 return (v > -std::numeric_limits<double>::epsilon() &&
1731 (v - 1) < std::numeric_limits<double>::epsilon());
1732 };
1733
1734 if (check(te) && check(tf)) {
1735
1736 FTensor::Tensor1<double, 3> t_delta, t_cross;
1737 t_delta(i) = (t_e0(i) + te * t_edge_delta(i)) -
1738 (t_f0(0) + tf * (t_f1(i) - t_f0(i)));
1739
1740 t_delta(i) /= edge_length;
1741
1742 const double dot = t_delta(i) * t_delta(i);
1743
1744 if (min_pair.first < 0 || min_pair.first > dot) {
1745
1746 if (dot < tol_trim_close * tol_trim_close)
1747 min_pair = make_pair(dot, te);
1748 }
1749 }
1750 }
1751 }
1752
1753 if (min_pair.first > -std::numeric_limits<double>::epsilon()) {
1754 add_edge(min_pair.second);
1755 return true;
1756 }
1757 }
1758
1759 return false;
1760 };
1761
1762 if (!trim_cross_edges()) {
1763
1764 const double dot = t_dist0(i) * t_dist1(i);
1765 const double dot_direction0 = t_dist0(i) * t_edge_delta(i);
1766 const double dot_direction1 = t_dist1(i) * t_edge_delta(i);
1767
1768 if (dot < std::numeric_limits<double>::epsilon() &&
1769 dot_direction0 > -std::numeric_limits<double>::epsilon() &&
1770 dot_direction1 < std::numeric_limits<double>::epsilon()) {
1771
1772 const double s0 = t_dist0(i) * t_edge_delta(i) / edge_length;
1773 const double s1 = t_dist1(i) * t_edge_delta(i) / edge_length;
1774 const double t_cut = s0 / (s0 - s1);
1775
1776 add_edge(t_cut);
1777 }
1778 }
1779 }
1780
1781 if (debug)
1782 CHKERR SaveData(moab)("edges_potentially_to_trim.vtk", cut_surface_edges);
1783
1784 if (debug)
1785 CHKERR SaveData(moab)("edges_selected_to_trim.vtk", trimEdges);
1786
1787 auto get_quality_change = [&](const Range &adj_tets, const EntityHandle &v,
1788 const VectorDouble3 &new_pos) {
1789 double q0 = 1;
1790 CHKERR m_field.getInterface<Tools>()->minTetsQuality(adj_tets, q0, th);
1791
1792 double min_q = 1;
1793 for (auto t : adj_tets) {
1794 int num_nodes;
1795 const EntityHandle *conn;
1796 CHKERR m_field.get_moab().get_connectivity(t, conn, num_nodes, true);
1797 VectorDouble12 coords(12);
1798 if (th)
1799 CHKERR moab.tag_get_data(th, conn, num_nodes, &coords[0]);
1800 else
1801 CHKERR moab.get_coords(conn, num_nodes, &coords[0]);
1802
1803 for (int n = 0; n != 4; ++n) {
1804 auto n_coords = getVectorAdaptor(&coords[3 * n], 3);
1805 if (conn[n] == v) {
1806 noalias(n_coords) = new_pos;
1807 } else {
1808 auto m = verticesOnTrimEdges.find(conn[n]);
1809 if (m != verticesOnTrimEdges.end())
1810 noalias(n_coords) =
1811 m->second.rayPoint + m->second.dIst * m->second.unitRayDir;
1812 }
1813 }
1814
1815 const double q = Tools::volumeLengthQuality(&coords[0]);
1816 if (!std::isnormal(q)) {
1817 min_q = -2;
1818 break;
1819 }
1820 min_q = std::min(min_q, q);
1821 }
1822 return min_q / q0;
1823 };
1824
1825 Range checked_verts;
1826 auto add_trim_vert = [&](const EntityHandle v, const EntityHandle e) {
1827 if (!(trimNewVertices.find(v) != trimNewVertices.end())) {
1828 auto &r = edgesToTrim.at(e);
1829 VectorDouble3 ray_point = get_point_coords(v);
1830 VectorDouble3 new_pos = r.rayPoint + r.dIst * r.unitRayDir;
1831 VectorDouble3 unit_ray_dir = ray_point - new_pos;
1832 Range adj_tets;
1833 CHKERR moab.get_adjacencies(&v, 1, 3, false, adj_tets);
1834 adj_tets = intersect(adj_tets, cutNewVolumes);
1835 double q = get_quality_change(adj_tets, v, new_pos);
1836 if (q > projectEntitiesQualityTrashold) {
1837 VectorDouble3 ray_dir = new_pos - ray_point;
1838 double dist = norm_2(ray_dir);
1839 verticesOnTrimEdges[v].dIst = 1;
1840 verticesOnTrimEdges[v].lEngth = dist;
1841 verticesOnTrimEdges[v].unitRayDir = ray_dir;
1842 verticesOnTrimEdges[v].rayPoint = ray_point;
1843 trimNewVertices.insert(v);
1844 }
1845 checked_verts.insert(v);
1846 }
1847 };
1848
1849 auto add_no_move_trim = [&](const EntityHandle v, const EntityHandle e) {
1850 if (!(trimNewVertices.find(v) != trimNewVertices.end())) {
1851 auto &m = edgesToTrim.at(e);
1852 verticesOnTrimEdges[v] = m;
1853 verticesOnTrimEdges[v].rayPoint = get_point_coords(v);
1854 verticesOnTrimEdges[v].lEngth = 0;
1855 verticesOnTrimEdges[v].dIst = 0;
1856 trimNewVertices.insert(v);
1857 checked_verts.insert(v);
1858 }
1859 };
1860
1861 // Iterate over all vertives close to surface front and check if those can
1862 // be moved
1863
1864 // filer nodes which distance is in given tolerance
1865 auto hi = verts_map.get<0>().upper_bound(tol_trim_close);
1866 verts_map.get<0>().erase(hi, verts_map.end());
1867
1868 auto remove_verts = [&](Range nodes) {
1869 for (auto n : nodes) {
1870 auto r = verts_map.get<1>().equal_range(n);
1871 verts_map.get<1>().erase(r.first, r.second);
1872 }
1873 };
1874
1875 auto trim_verts = [&](const Range verts, const bool move) {
1876 VertMapMultiIndex verts_map_tmp;
1877 for (auto p = corners.pair_begin(); p != corners.pair_end(); ++p) {
1878 auto lo = verts_map.get<1>().lower_bound(p->first);
1879 auto hi = verts_map.get<1>().upper_bound(p->second);
1880 verts_map_tmp.insert(lo, hi);
1881 }
1882 if (move) {
1883 for (auto &m : verts_map_tmp.get<0>())
1884 add_trim_vert(m.v, m.e);
1885 } else {
1886 for (auto &m : verts_map_tmp.get<0>())
1887 add_no_move_trim(m.v, m.e);
1888 }
1889 };
1890
1891 auto trim_edges = [&](const Range ents, const bool move) {
1892 VertMapMultiIndex verts_map_tmp;
1893 for (auto p = ents.pair_begin(); p != ents.pair_end(); ++p) {
1894 auto lo = verts_map.get<2>().lower_bound(p->first);
1895 auto hi = verts_map.get<2>().upper_bound(p->second);
1896 verts_map_tmp.insert(lo, hi);
1897 verts_map.get<2>().erase(lo, hi);
1898 }
1899 if (move) {
1900 for (auto &m : verts_map_tmp.get<0>())
1901 add_trim_vert(m.v, m.e);
1902 } else {
1903 for (auto &m : verts_map_tmp.get<0>())
1904 add_no_move_trim(m.v, m.e);
1905 }
1906 };
1907
1908 auto intersect_self = [&](Range &a, const Range b) { a = intersect(a, b); };
1909
1910 map<std::string, Range> range_maps;
1911
1912 // Edges on surface skin
1913 CHKERR skin.find_skin(0, cutNewSurfaces, false, range_maps["surface_skin"]);
1914 // Edges as trimmed
1915 intersect_self(range_maps["surface_skin"], trimEdges);
1916 // Edges are on fixed edges
1917 range_maps["fixed_edges_on_surface_skin"] =
1918 intersect(range_maps["surface_skin"], fix_edges);
1919
1920 // Edges adjacent to fixed edges
1921 CHKERR moab.get_adjacencies(fixed_edges_verts, 1, false,
1922 range_maps["fixed_edges_verts_edges"],
1923 moab::Interface::UNION);
1924 intersect_self(range_maps["fixed_edges_verts_edges"], trimEdges);
1925
1926 CHKERR moab.get_connectivity(
1927 range_maps["fixed_edges_verts_edges"],
1928 range_maps["fixed_edges_verts_edges_verts_on_the_skin"], false);
1929 intersect_self(range_maps["fixed_edges_verts_edges_verts_on_the_skin"],
1930 tets_skin_verts);
1931
1932 // Do not move nodes at the corners
1933 trim_verts(corners, false);
1934 remove_verts(corners);
1935
1936 // Trim edges on the body skin move
1937 trim_edges(range_maps["fixed_edges_on_surface_skin"], true);
1938 remove_verts(range_maps["fixed_edges_on_surface_skin_verts"]);
1939
1940 // Trim edges nodes on the skin but edge not on the skin do not
1941 trim_verts(range_maps["fixed_edges_verts_edges_verts_on_the_skin"], false);
1942 remove_verts(range_maps["fixed_edges_verts_edges_verts_on_the_skin"]);
1943
1944 // Trim edges on the cut skin move
1945 trim_edges(range_maps["surface_skin"], true);
1946 trim_verts(tets_skin_verts, false);
1947 remove_verts(tets_skin_verts);
1948
1949 for (auto &m : verts_map.get<0>())
1950 add_trim_vert(m.v, m.e);
1951
1952 for (auto m : verticesOnTrimEdges) {
1953 EntityHandle v = m.first;
1954 Range adj;
1955 CHKERR moab.get_adjacencies(&v, 1, 1, false, adj);
1956 for (auto e : adj) {
1957 edgesToTrim.erase(e);
1958 trimEdges.erase(e);
1959 }
1960 }
1961
1962 if (debug)
1963 if (!trimNewVertices.empty())
1964 CHKERR SaveData(moab)("trim_close_vertices.vtk", trimNewVertices);
1965
1966 if (debug)
1967 if (!trimEdges.empty())
1968 CHKERR SaveData(moab)("trim_edges.vtk", trimEdges);
1969
1971}
1972
1973MoFEMErrorCode CutMeshInterface::trimEdgesInTheMiddle(const BitRefLevel bit,
1974 const bool debug) {
1975 CoreInterface &m_field = cOre;
1976 moab::Interface &moab = m_field.get_moab();
1977 MeshRefinement *refiner;
1978 auto ref_ents_ptr = m_field.get_ref_ents();
1980
1981 CHKERR m_field.getInterface(refiner);
1982 CHKERR refiner->addVerticesInTheMiddleOfEdges(trimEdges, bit);
1983 CHKERR refiner->refineTets(cutNewVolumes, bit, QUIET, debug);
1984
1985 trimNewVolumes.clear();
1986 CHKERR m_field.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
1987 bit, BitRefLevel().set(), MBTET, trimNewVolumes);
1988
1989 for (map<EntityHandle, TreeData>::iterator mit = edgesToTrim.begin();
1990 mit != edgesToTrim.end(); mit++) {
1991 auto vit = ref_ents_ptr->get<Composite_ParentEnt_And_EntType_mi_tag>().find(
1992 boost::make_tuple(MBVERTEX, mit->first));
1993 if (vit ==
1994 ref_ents_ptr->get<Composite_ParentEnt_And_EntType_mi_tag>().end())
1995 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1996 "No vertex on trim edges, that make no sense");
1997
1998 const boost::shared_ptr<RefEntity> &ref_ent = *vit;
1999 if ((ref_ent->getBitRefLevel() & bit).any()) {
2000 EntityHandle vert = ref_ent->getEnt();
2001 trimNewVertices.insert(vert);
2002 verticesOnTrimEdges[vert] = mit->second;
2003 }
2004 }
2005
2006 // Get faces which are trimmed
2007 trimNewSurfaces.clear();
2008 CHKERR m_field.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
2009 bit, bit, MBTRI, trimNewSurfaces);
2010
2011 Range trim_new_surfaces_nodes;
2012 CHKERR moab.get_connectivity(trimNewSurfaces, trim_new_surfaces_nodes, true);
2013 trim_new_surfaces_nodes = subtract(trim_new_surfaces_nodes, trimNewVertices);
2014 trim_new_surfaces_nodes = subtract(trim_new_surfaces_nodes, cutNewVertices);
2015 Range faces_not_on_surface;
2016 CHKERR moab.get_adjacencies(trim_new_surfaces_nodes, 2, false,
2017 faces_not_on_surface, moab::Interface::UNION);
2018 trimNewSurfaces = subtract(trimNewSurfaces, faces_not_on_surface);
2019
2020 // Get surfaces which are not trimmed and add them to surface
2021 Range all_surfaces_on_bit_level;
2022 CHKERR m_field.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
2023 bit, BitRefLevel().set(), MBTRI, all_surfaces_on_bit_level);
2024 all_surfaces_on_bit_level =
2025 intersect(all_surfaces_on_bit_level, cutNewSurfaces);
2026
2027 trimNewSurfaces = unite(trimNewSurfaces, all_surfaces_on_bit_level);
2028
2030}
2031
2032MoFEMErrorCode CutMeshInterface::trimSurface(Range *fixed_edges,
2033 Range *corner_nodes,
2034 const double tol, Tag th,
2035 const bool debug) {
2036 CoreInterface &m_field = cOre;
2037 moab::Interface &moab = m_field.get_moab();
2038 Skinner skin(&moab);
2039
2040 auto get_adj = [&moab](const Range r, const int dim) {
2041 Range a;
2042 if (dim)
2043 CHKERR moab.get_adjacencies(r, dim, false, a, moab::Interface::UNION);
2044 else
2045 CHKERR moab.get_connectivity(r, a, true);
2046 return a;
2047 };
2048
2049 auto get_skin = [&skin](const auto r) {
2050 Range s;
2051 CHKERR skin.find_skin(0, r, false, s);
2052 return s;
2053 };
2054
2056
2057 auto trim_tets_skin = get_skin(trimNewVolumes);
2058 auto trim_tets_skin_edges = get_adj(trim_tets_skin, 1);
2059 auto trim_surface_edges = get_adj(trimNewSurfaces, 1);
2060
2061 auto contarain_edges =
2062 intersect(trim_surface_edges, get_adj(constrainSurface, 1));
2063 if (fixed_edges)
2064 contarain_edges.merge(
2065 intersect(fixed_edges->subset_by_type(MBEDGE), trim_surface_edges));
2066
2067 Range barrier_vertices(trimNewVertices);
2068 if (corner_nodes) {
2069 // Add nodes which re adjacent to corner nodes
2070 barrier_vertices.merge(get_adj(
2071 intersect(get_adj(intersect(*corner_nodes, barrier_vertices), 2),
2072 trimNewSurfaces),
2073 0));
2074 }
2075
2076 auto get_nodes_with_one_node_on_fixed_edge_other_not = [&]() {
2077 const auto fixed_edges_on_surface =
2078 intersect(*fixed_edges, trim_surface_edges);
2079 const auto skin_fixed_edges_on_surface = get_skin(fixed_edges_on_surface);
2080 const auto barrier_nodes = subtract(skin_fixed_edges_on_surface,
2081 get_adj(get_skin(trimNewSurfaces), 0));
2082 return barrier_nodes;
2083 };
2084
2085 if (fixed_edges)
2086 barrier_vertices.merge(get_nodes_with_one_node_on_fixed_edge_other_not());
2087
2088 auto add_close_surface_barrier = [&]() {
2090
2091 // Ten algorytm dedykuje destylarni Bowmore. Jeżeli coś pójdzie nie tak, coś
2092 // pęknie inaczej niż trzeba, to pełną odpowiedzialność ponosi Beam Suntory
2093 // UK Ltd.
2094
2095 CHKERR buildTree();
2096
2097 auto test_edges =
2098 subtract(trim_surface_edges, get_adj(constrainSurface, 1));
2099 if (fixed_edges)
2100 test_edges = subtract(test_edges, *fixed_edges);
2101 auto trim_surface_nodes = get_adj(test_edges, 0);
2102 trim_surface_nodes = subtract(trim_surface_nodes, barrier_vertices);
2103 if (fixed_edges)
2104 trim_surface_nodes =
2105 subtract(trim_surface_nodes, get_adj(*fixed_edges, 0));
2106
2107 Range trim_skin;
2108 trim_skin.merge(contarain_edges);
2109 if (fRont.empty())
2110 trim_skin.merge(get_skin(sUrface));
2111 else
2112 trim_skin.merge(fRont);
2113 if (fixed_edges)
2114 trim_skin.merge(intersect(*fixed_edges, trim_surface_edges));
2115
2116 if (debug && !trim_skin.empty())
2117 CHKERR SaveData(m_field.get_moab())("trim_skin.vtk", trim_skin);
2118
2119 VectorDouble coords(3 * trim_surface_nodes.size());
2120 if (th)
2121 CHKERR moab.tag_get_data(th, trim_surface_nodes, &*coords.begin());
2122 else
2123 CHKERR moab.get_coords(trim_surface_nodes, &*coords.begin());
2124
2125 if (!trim_skin.empty()) {
2126
2127 std::vector<double> min_distances(trim_surface_nodes.size(), -1);
2128 CHKERR cOre.getInterface<Tools>()->findMinDistanceFromTheEdges(
2129 &*coords.begin(), trim_surface_nodes.size(), trim_skin,
2130 &*min_distances.begin());
2131
2132 auto coords_ptr = &*coords.begin();
2133 auto min_dist = &*min_distances.begin();
2134
2135 std::vector<EntityHandle> add_nodes;
2136 add_nodes.reserve(trim_surface_nodes.size());
2137
2138 for (auto n : trim_surface_nodes) {
2139
2140 if ((*min_dist) > std::numeric_limits<double>::epsilon()) {
2141 VectorDouble3 point_out(3);
2142
2143 EntityHandle facets_out;
2144 CHKERR treeSurfPtr->closest_to_location(coords_ptr, rootSetSurf,
2145 &point_out[0], facets_out);
2146
2147 VectorDouble3 delta = point_out - getVectorAdaptor(coords_ptr, 3);
2148 VectorDouble3 normal(3);
2149 CHKERR m_field.getInterface<Tools>()->getTriNormal(facets_out,
2150 &normal[0]);
2151
2152 normal /= norm_2(normal);
2153 delta -= inner_prod(normal, delta) * normal;
2154
2155 double dist = norm_2(delta);
2156 if (dist < tol * (*min_dist))
2157 add_nodes.emplace_back(n);
2158 }
2159
2160 coords_ptr += 3;
2161 min_dist += 1;
2162 }
2163
2164 barrier_vertices.insert_list(add_nodes.begin(), add_nodes.end());
2165 }
2166
2168 };
2169
2170 auto remove_faces_on_skin = [&]() {
2172 Range skin_faces = intersect(trimNewSurfaces, trim_tets_skin);
2173 if (!skin_faces.empty()) {
2174 barrier_vertices.merge(get_adj(skin_faces, 0));
2175 for (auto f : skin_faces)
2176 trimNewSurfaces.erase(f);
2177 }
2179 };
2180
2181 auto get_trim_free_edges = [&]() {
2182 // get current surface skin
2183 Range trim_surf_skin;
2184 CHKERR skin.find_skin(0, trimNewSurfaces, false, trim_surf_skin);
2185 trim_surf_skin = subtract(trim_surf_skin, trim_tets_skin_edges);
2186
2187 Range trim_surf_skin_verts;
2188 CHKERR moab.get_connectivity(trim_surf_skin, trim_surf_skin_verts, true);
2189 for (auto e : barrier_vertices)
2190 trim_surf_skin_verts.erase(e);
2191
2192 Range free_edges;
2193 CHKERR moab.get_adjacencies(trim_surf_skin_verts, 1, false, free_edges,
2194 moab::Interface::UNION);
2195 free_edges =
2196 subtract(intersect(free_edges, trim_surf_skin), contarain_edges);
2197
2198 return free_edges;
2199 };
2200
2201 CHKERR remove_faces_on_skin();
2202 CHKERR add_close_surface_barrier();
2203
2204 if (debug && !barrier_vertices.empty())
2205 CHKERR SaveData(m_field.get_moab())("barrier_vertices.vtk",
2206 barrier_vertices);
2207
2208 int nn = 0;
2209 Range out_edges;
2210 while (!(out_edges = get_trim_free_edges()).empty()) {
2211
2212 if (debug && !trimNewSurfaces.empty())
2213 CHKERR SaveData(m_field.get_moab())(
2214 "trimNewSurfaces_" + boost::lexical_cast<std::string>(nn) + ".vtk",
2215 trimNewSurfaces);
2216
2217 if (debug && !out_edges.empty())
2218 CHKERR SaveData(m_field.get_moab())(
2219 "trimNewSurfacesOutsideVerts_" +
2220 boost::lexical_cast<std::string>(nn) + ".vtk",
2221 out_edges);
2222
2223 Range outside_faces;
2224 CHKERR moab.get_adjacencies(out_edges, 2, false, outside_faces,
2225 moab::Interface::UNION);
2226 trimNewSurfaces = subtract(trimNewSurfaces, outside_faces);
2227 ++nn;
2228 }
2229
2230 if (debug && !trimNewSurfaces.empty())
2231 CHKERR SaveData(m_field.get_moab())(
2232 "trimNewSurfaces_" + boost::lexical_cast<std::string>(nn) + ".vtk",
2233 trimNewSurfaces);
2234
2236}
2237
2239CutMeshInterface::removePathologicalFrontTris(const BitRefLevel split_bit,
2240 Range &ents) {
2241 CoreInterface &m_field = cOre;
2242 moab::Interface &moab = m_field.get_moab();
2243 PrismInterface *interface;
2245 CHKERR m_field.getInterface(interface);
2246 // Remove tris on surface front
2247 {
2248 Range front_tris;
2249 EntityHandle meshset;
2250 CHKERR moab.create_meshset(MESHSET_SET, meshset);
2251 CHKERR moab.add_entities(meshset, ents);
2252 CHKERR interface->findFacesWithThreeNodesOnInternalSurfaceSkin(
2253 meshset, split_bit, true, front_tris);
2254 CHKERR moab.delete_entities(&meshset, 1);
2255 ents = subtract(ents, front_tris);
2256 }
2257 // Remove entities on skin
2258 Range tets;
2259 CHKERR m_field.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
2260 split_bit, BitRefLevel().set(), MBTET, tets);
2261 // Remove entities on skin
2262 Skinner skin(&moab);
2263 Range tets_skin;
2264 CHKERR skin.find_skin(0, tets, false, tets_skin);
2265 ents = subtract(ents, tets_skin);
2266
2268}
2269
2270MoFEMErrorCode CutMeshInterface::splitSides(const BitRefLevel split_bit,
2271 const BitRefLevel bit,
2272 const Range &ents, Tag th) {
2273 CoreInterface &m_field = cOre;
2274 moab::Interface &moab = m_field.get_moab();
2275 PrismInterface *interface;
2277 CHKERR m_field.getInterface(interface);
2278 EntityHandle meshset_volume;
2279 CHKERR moab.create_meshset(MESHSET_SET, meshset_volume);
2280 CHKERR m_field.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
2281 split_bit, BitRefLevel().set(), MBTET, meshset_volume);
2282 EntityHandle meshset_surface;
2283 CHKERR moab.create_meshset(MESHSET_SET, meshset_surface);
2284 CHKERR moab.add_entities(meshset_surface, ents);
2285 CHKERR interface->getSides(meshset_surface, split_bit, true);
2286 CHKERR interface->splitSides(meshset_volume, bit, meshset_surface, true,
2287 true);
2288 CHKERR moab.delete_entities(&meshset_volume, 1);
2289 CHKERR moab.delete_entities(&meshset_surface, 1);
2290 if (th) {
2291 Range prisms;
2292 ierr = m_field.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
2293 bit, BitRefLevel().set(), MBPRISM, prisms);
2294 for (Range::iterator pit = prisms.begin(); pit != prisms.end(); pit++) {
2295 int num_nodes;
2296 const EntityHandle *conn;
2297 CHKERR moab.get_connectivity(*pit, conn, num_nodes, true);
2298 MatrixDouble data(3, 3);
2299 CHKERR moab.tag_get_data(th, conn, 3, &data(0, 0));
2300 CHKERR moab.tag_set_data(th, &conn[3], 3, &data(0, 0));
2301 }
2302 }
2304}
2305
2306MoFEMErrorCode CutMeshInterface::mergeBadEdges(
2307 const int fraction_level, const Range &tets, const Range &surface,
2308 const Range &fixed_edges, const Range &corner_nodes, Range &edges_to_merge,
2309 Range &out_tets, Range &new_surf, Tag th, const bool update_meshsets,
2310 const BitRefLevel *bit_ptr, const bool debug) {
2311 CoreInterface &m_field = cOre;
2312 moab::Interface &moab = m_field.get_moab();
2314
2315 /**
2316 * \brief Merge nodes
2317 */
2318 struct MergeNodes {
2319 CoreInterface &mField;
2320 const bool onlyIfImproveQuality;
2321 Tag tH;
2322 bool updateMehsets;
2323
2324 MergeNodes(CoreInterface &m_field, const bool only_if_improve_quality,
2325 Tag th, bool update_mehsets)
2326 : mField(m_field), onlyIfImproveQuality(only_if_improve_quality),
2327 tH(th), updateMehsets(update_mehsets) {
2328 mField.getInterface(nodeMergerPtr);
2329 }
2330 NodeMergerInterface *nodeMergerPtr;
2331 MoFEMErrorCode mergeNodes(int line_search, EntityHandle father,
2332 EntityHandle mother, Range &proc_tets,
2333 bool add_child = true) {
2334 moab::Interface &moab = mField.get_moab();
2336 const EntityHandle conn[] = {father, mother};
2337 Range vert_tets;
2338 CHKERR moab.get_adjacencies(conn, 2, 3, false, vert_tets,
2339 moab::Interface::UNION);
2340 vert_tets = intersect(vert_tets, proc_tets);
2341 Range out_tets;
2342 CHKERR nodeMergerPtr->mergeNodes(father, mother, out_tets, &vert_tets,
2343 onlyIfImproveQuality, 0, line_search,
2344 tH);
2345
2346 if (add_child && nodeMergerPtr->getSuccessMerge()) {
2347
2348 Range::iterator lo, hi = proc_tets.begin();
2349 for (auto pt = vert_tets.pair_begin(); pt != vert_tets.pair_end();
2350 ++pt) {
2351 lo = proc_tets.lower_bound(hi, proc_tets.end(), pt->first);
2352 if (lo != proc_tets.end()) {
2353 hi = proc_tets.upper_bound(lo, proc_tets.end(), pt->second);
2354 proc_tets.erase(lo, hi);
2355 } else
2356 break;
2357 }
2358 proc_tets.merge(out_tets);
2359
2360 auto &parent_child_map = nodeMergerPtr->getParentChildMap();
2361
2362 struct ChangeChild {
2363 EntityHandle child;
2364 ChangeChild(const EntityHandle child) : child(child) {}
2365 void operator()(NodeMergerInterface::ParentChild &p) {
2366 p.cHild = child;
2367 }
2368 };
2369
2370 std::vector<decltype(parentsChildMap.get<0>().begin())> it_vec;
2371 it_vec.reserve(parentsChildMap.size());
2372
2373 for (auto &p : parent_child_map) {
2374
2375 it_vec.clear();
2376 for (auto it = parentsChildMap.get<0>().equal_range(p.pArent);
2377 it.first != it.second; ++it.first)
2378 it_vec.emplace_back(it.first);
2379
2380 for (auto it = parentsChildMap.get<1>().equal_range(p.pArent);
2381 it.first != it.second; ++it.first)
2382 it_vec.emplace_back(parentsChildMap.project<0>(it.first));
2383
2384 for (auto &it : it_vec)
2385 parentsChildMap.modify(it, ChangeChild(p.cHild));
2386 }
2387
2388 parentsChildMap.insert(parent_child_map.begin(),
2389 parent_child_map.end());
2390 }
2392 }
2393
2394 MoFEMErrorCode updateRangeByChilds(Range &new_surf, Range &edges_to_merge,
2395 Range &not_merged_edges,
2396 bool add_child) {
2397 moab::Interface &moab = mField.get_moab();
2399 if (add_child) {
2400
2401 std::vector<EntityHandle> parents_ents_vec(parentsChildMap.size());
2402 for (auto &it : parentsChildMap)
2403 parents_ents_vec.emplace_back(it.pArent);
2404 Range parent_ents;
2405 parent_ents.insert_list(parents_ents_vec.begin(),
2406 parents_ents_vec.end());
2407
2408 Range surf_parent_ents = intersect(new_surf, parent_ents);
2409 new_surf = subtract(new_surf, surf_parent_ents);
2410 Range child_surf_ents;
2411 CHKERR updateRangeByChilds(parentsChildMap, surf_parent_ents,
2412 child_surf_ents);
2413 new_surf.merge(child_surf_ents);
2414
2415 Range edges_to_merge_parent_ents =
2416 intersect(edges_to_merge, parent_ents);
2417 edges_to_merge = subtract(edges_to_merge, edges_to_merge_parent_ents);
2418 Range merged_child_edge_ents;
2419 CHKERR updateRangeByChilds(parentsChildMap, edges_to_merge_parent_ents,
2420 merged_child_edge_ents);
2421
2422 Range not_merged_edges_child_ents =
2423 intersect(not_merged_edges, parent_ents);
2424 not_merged_edges =
2425 subtract(not_merged_edges, not_merged_edges_child_ents);
2426 Range not_merged_child_edge_ents;
2427 CHKERR updateRangeByChilds(parentsChildMap, not_merged_edges_child_ents,
2428 not_merged_child_edge_ents);
2429
2430 merged_child_edge_ents =
2431 subtract(merged_child_edge_ents, not_merged_child_edge_ents);
2432 edges_to_merge.merge(merged_child_edge_ents);
2433 not_merged_edges.merge(not_merged_child_edge_ents);
2434
2435 if (updateMehsets) {
2437 (*mField.getInterface<MeshsetsManager>()), cubit_it)) {
2438 EntityHandle cubit_meshset = cubit_it->meshset;
2439 Range meshset_ents;
2440 CHKERR moab.get_entities_by_handle(cubit_meshset, meshset_ents,
2441 true);
2442 Range child_ents;
2443 CHKERR updateRangeByChilds(parentsChildMap, meshset_ents,
2444 child_ents);
2445 CHKERR moab.add_entities(cubit_meshset, child_ents);
2446 }
2447 }
2448 }
2449
2451 };
2452
2453 private:
2454 NodeMergerInterface::ParentChildMap parentsChildMap;
2455 std::vector<EntityHandle> childsVec;
2456
2457 inline MoFEMErrorCode updateRangeByChilds(
2458 const NodeMergerInterface::ParentChildMap &parent_child_map,
2459 const Range &parents, Range &childs) {
2461 childsVec.clear();
2462 childsVec.reserve(parents.size());
2463 for (auto pit = parents.pair_begin(); pit != parents.pair_end(); pit++) {
2464 auto it = parent_child_map.lower_bound(pit->first);
2465 if (it != parent_child_map.end()) {
2466 for (auto hi_it = parent_child_map.upper_bound(pit->second);
2467 it != hi_it; ++it)
2468 childsVec.emplace_back(it->cHild);
2469 }
2470 }
2471 childs.insert_list(childsVec.begin(), childsVec.end());
2473 }
2474 };
2475
2476 /**
2477 * \brief Calculate edge length
2478 */
2479 struct LengthMap {
2480 Tag tH;
2481 CoreInterface &mField;
2482 moab::Interface &moab;
2483 const double maxLength;
2484 LengthMap(CoreInterface &m_field, Tag th, double max_length)
2485 : tH(th), mField(m_field), moab(m_field.get_moab()),
2486 maxLength(max_length) {
2487 gammaL = 1.;
2488 gammaQ = 3.;
2489 acceptedThrasholdMergeQuality = 0.5;
2490 }
2491
2492 double
2493 gammaL; ///< Controls importance of length when ranking edges for merge
2494 double
2495 gammaQ; ///< Controls importance of quality when ranking edges for merge
2496 double acceptedThrasholdMergeQuality; ///< Do not merge quality if quality
2497 ///< above accepted thrashold
2498
2499 MoFEMErrorCode operator()(const Range &tets, const Range &edges,
2500 LengthMapData_multi_index &length_map,
2501 double &ave) const {
2502 int num_nodes;
2503 const EntityHandle *conn;
2504 std::array<double, 12> coords;
2506 VectorAdaptor s0(3, ublas::shallow_array_adaptor<double>(3, &coords[0]));
2507 VectorAdaptor s1(3, ublas::shallow_array_adaptor<double>(3, &coords[3]));
2509
2510 struct NodeQuality {
2511 EntityHandle node;
2512 double quality;
2513 NodeQuality(const EntityHandle node) : node(node), quality(1) {}
2514 };
2515
2516 typedef multi_index_container<
2517 NodeQuality, indexed_by<
2518
2519 sequenced<>,
2520
2521 hashed_non_unique<tag<Ent_mi_tag>,
2522 member<NodeQuality, EntityHandle,
2523 &NodeQuality::node>>
2524
2525 >>
2526 NodeQuality_sequence;
2527
2528 NodeQuality_sequence node_quality_sequence;
2529
2530 Range edges_nodes;
2531 CHKERR moab.get_connectivity(tets, edges_nodes, false);
2532 Range edges_tets;
2533 CHKERR moab.get_adjacencies(edges, 3, false, edges_tets,
2534 moab::Interface::UNION);
2535 edges_tets = intersect(edges_tets, tets);
2536
2537 for (auto node : edges_nodes)
2538 node_quality_sequence.emplace_back(node);
2539
2540 for (auto tet : edges_tets) {
2541
2542 CHKERR moab.get_connectivity(tet, conn, num_nodes, true);
2543 if (tH)
2544 CHKERR moab.tag_get_data(tH, conn, num_nodes, coords.data());
2545 else
2546 CHKERR moab.get_coords(conn, num_nodes, coords.data());
2547
2548 const double q = Tools::volumeLengthQuality(coords.data());
2549
2550 for (auto n : {0, 1, 2, 3}) {
2551 auto it = node_quality_sequence.get<1>().find(conn[n]);
2552 if (it != node_quality_sequence.get<1>().end())
2553 const_cast<double &>(it->quality) = std::min(q, it->quality);
2554 }
2555 }
2556
2557 for (auto edge : edges) {
2558
2559 CHKERR moab.get_connectivity(edge, conn, num_nodes, true);
2560
2561 if (tH)
2562 CHKERR moab.tag_get_data(tH, conn, num_nodes, coords.data());
2563 else
2564 CHKERR moab.get_coords(conn, num_nodes, coords.data());
2565
2566 double q = 1;
2567 for (auto n : {0, 1}) {
2568 auto it = node_quality_sequence.get<1>().find(conn[n]);
2569 if (it != node_quality_sequence.get<1>().end())
2570 q = std::min(q, it->quality);
2571 }
2572
2573 if (q < acceptedThrasholdMergeQuality) {
2574 noalias(delta) = (s0 - s1) / maxLength;
2575 double dot = inner_prod(delta, delta);
2576 double val = pow(q, gammaQ) * pow(dot, 0.5 * gammaL);
2577 length_map.insert(LengthMapData(val, q, edge));
2578 }
2579 }
2580
2581 ave = 0;
2582 for (LengthMapData_multi_index::nth_index<0>::type::iterator mit =
2583 length_map.get<0>().begin();
2584 mit != length_map.get<0>().end(); mit++) {
2585 ave += mit->qUality;
2586 }
2587 ave /= length_map.size();
2589 }
2590 };
2591
2592 /**
2593 * \brief Topological relations
2594 */
2595 struct Toplogy {
2596
2597 CoreInterface &mField;
2598 Tag tH;
2599 Toplogy(CoreInterface &m_field, Tag th) : mField(m_field), tH(th) {}
2600
2601 enum TYPE {
2602 FREE = 0,
2603 SKIN = 1 << 0,
2604 SURFACE = 1 << 1,
2605 SURFACE_SKIN = 1 << 2,
2606 FRONT_ENDS = 1 << 3,
2607 FIX_EDGES = 1 << 4,
2608 FIX_CORNERS = 1 << 5
2609 };
2610
2611 typedef map<int, Range> SetsMap;
2612
2613 MoFEMErrorCode classifyVerts(const Range &surface, const Range &tets,
2614 const Range &fixed_edges,
2615 const Range &corner_nodes,
2616 const Range &constrain_surface,
2617 SetsMap &sets_map) const {
2618 moab::Interface &moab(mField.get_moab());
2619 Skinner skin(&moab);
2621
2622 sets_map[FIX_CORNERS].merge(corner_nodes);
2623 Range fixed_verts;
2624 CHKERR moab.get_connectivity(fixed_edges, fixed_verts, true);
2625 sets_map[FIX_EDGES].swap(fixed_verts);
2626
2627 Range tets_skin;
2628 CHKERR skin.find_skin(0, tets, false, tets_skin);
2629 Range tets_skin_edges;
2630 CHKERR moab.get_adjacencies(tets_skin, 1, false, tets_skin_edges,
2631 moab::Interface::UNION);
2632
2633 // constrain surface
2634 Range constrain_surface_verts;
2635 CHKERR moab.get_connectivity(constrain_surface, constrain_surface_verts,
2636 true);
2637 Range constrain_surface_edges;
2638 CHKERR moab.get_adjacencies(constrain_surface, 1, false,
2639 constrain_surface_edges,
2640 moab::Interface::UNION);
2641
2642 // surface skin
2643 Range surface_skin;
2644 CHKERR skin.find_skin(0, surface, false, surface_skin);
2645 Range front_in_the_body;
2646 front_in_the_body = subtract(surface_skin, tets_skin_edges);
2647 Range front_in_the_body_verts;
2648 CHKERR moab.get_connectivity(front_in_the_body, front_in_the_body_verts,
2649 true);
2650 Range front_ends;
2651 CHKERR skin.find_skin(0, front_in_the_body, false, front_ends);
2652 front_ends.merge(
2653 intersect(front_in_the_body_verts, constrain_surface_verts));
2654 sets_map[FRONT_ENDS].swap(front_ends);
2655
2656 Range surface_skin_verts;
2657 CHKERR moab.get_connectivity(surface_skin, surface_skin_verts, true);
2658 sets_map[SURFACE_SKIN].swap(surface_skin_verts);
2659
2660 // surface
2661 Range surface_verts;
2662 CHKERR moab.get_connectivity(surface, surface_verts, true);
2663 sets_map[SURFACE_SKIN].merge(
2664 intersect(constrain_surface_verts, surface_verts));
2665 sets_map[SURFACE].swap(surface_verts);
2666
2667 // skin
2668 Range tets_skin_verts;
2669 CHKERR moab.get_connectivity(tets_skin, tets_skin_verts, true);
2670 sets_map[SKIN].swap(tets_skin_verts);
2671 sets_map[SKIN].merge(constrain_surface_verts);
2672
2673 Range tets_verts;
2674 CHKERR moab.get_connectivity(tets, tets_verts, true);
2675 sets_map[FREE].swap(tets_verts);
2676
2678 }
2679
2680 MoFEMErrorCode getProcTets(const Range &tets, const Range &edges_to_merge,
2681 Range &proc_tets) const {
2682 moab::Interface &moab(mField.get_moab());
2684 Range edges_to_merge_verts;
2685 CHKERR moab.get_connectivity(edges_to_merge, edges_to_merge_verts, true);
2686 Range edges_to_merge_verts_tets;
2687 CHKERR moab.get_adjacencies(edges_to_merge_verts, 3, false,
2688 edges_to_merge_verts_tets,
2689 moab::Interface::UNION);
2690 edges_to_merge_verts_tets = intersect(edges_to_merge_verts_tets, tets);
2691 proc_tets.swap(edges_to_merge_verts_tets);
2693 }
2694
2695 MoFEMErrorCode removeBadEdges(const Range &surface, const Range &tets,
2696 const Range &fixed_edges,
2697 const Range &corner_nodes,
2698 const Range &constrain_surface,
2699 Range &edges_to_merge,
2700 Range &not_merged_edges) {
2701 moab::Interface &moab(mField.get_moab());
2703
2704 // find skin
2705 Skinner skin(&moab);
2706 Range tets_skin;
2707 CHKERR skin.find_skin(0, tets, false, tets_skin);
2708 Range surface_skin;
2709 CHKERR skin.find_skin(0, surface, false, surface_skin);
2710
2711 // constrain surface
2712 Range constrain_surface_verts;
2713 CHKERR moab.get_connectivity(constrain_surface, constrain_surface_verts,
2714 true);
2715 Range constrain_surface_edges;
2716 CHKERR moab.get_adjacencies(constrain_surface, 1, false,
2717 constrain_surface_edges,
2718 moab::Interface::UNION);
2719
2720 // end nodes
2721 Range tets_skin_edges;
2722 CHKERR moab.get_adjacencies(tets_skin, 1, false, tets_skin_edges,
2723 moab::Interface::UNION);
2724
2725 Range surface_front;
2726 surface_front = subtract(surface_skin, tets_skin_edges);
2727 Range surface_front_nodes;
2728 CHKERR moab.get_connectivity(surface_front, surface_front_nodes, true);
2729
2730 Range ends_nodes;
2731 CHKERR skin.find_skin(0, surface_front, false, ends_nodes);
2732 ends_nodes.merge(intersect(surface_front_nodes, constrain_surface_verts));
2733
2734 // remove bad merges
2735 surface_skin.merge(constrain_surface);
2736 tets_skin_edges.merge(constrain_surface_edges);
2737
2738 // get surface and body skin verts
2739 Range surface_edges;
2740 CHKERR moab.get_adjacencies(surface, 1, false, surface_edges,
2741 moab::Interface::UNION);
2742 // get nodes on the surface
2743 Range surface_edges_verts;
2744 CHKERR moab.get_connectivity(surface_edges, surface_edges_verts, true);
2745 // get vertices on the body skin
2746 Range tets_skin_edges_verts;
2747 CHKERR moab.get_connectivity(tets_skin_edges, tets_skin_edges_verts,
2748 true);
2749
2750 Range edges_to_remove;
2751
2752 // remove edges self connected to body skin
2753 {
2754 Range ents_nodes_and_edges;
2755 ents_nodes_and_edges.merge(tets_skin_edges_verts);
2756 ents_nodes_and_edges.merge(tets_skin_edges);
2757 CHKERR removeSelfConectingEdges(ents_nodes_and_edges, edges_to_remove,
2758 false);
2759 }
2760 edges_to_merge = subtract(edges_to_merge, edges_to_remove);
2761 not_merged_edges.merge(edges_to_remove);
2762
2763 // remove edges self connected to surface
2764 {
2765 Range ents_nodes_and_edges;
2766 ents_nodes_and_edges.merge(surface_edges_verts);
2767 ents_nodes_and_edges.merge(surface_edges);
2768 ents_nodes_and_edges.merge(tets_skin_edges_verts);
2769 ents_nodes_and_edges.merge(tets_skin_edges);
2770 CHKERR removeSelfConectingEdges(ents_nodes_and_edges, edges_to_remove,
2771 false);
2772 }
2773 edges_to_merge = subtract(edges_to_merge, edges_to_remove);
2774 not_merged_edges.merge(edges_to_remove);
2775
2776 // remove edges adjacent corner_nodes execpt those on fixed edges
2777 Range fixed_edges_nodes;
2778 CHKERR moab.get_connectivity(fixed_edges, fixed_edges_nodes, true);
2779 {
2780 Range ents_nodes_and_edges;
2781 ents_nodes_and_edges.merge(fixed_edges_nodes);
2782 ents_nodes_and_edges.merge(ends_nodes);
2783 ents_nodes_and_edges.merge(corner_nodes);
2784 ents_nodes_and_edges.merge(fixed_edges);
2785 CHKERR removeSelfConectingEdges(ents_nodes_and_edges, edges_to_remove,
2786 false);
2787 }
2788 edges_to_merge = subtract(edges_to_merge, edges_to_remove);
2789 not_merged_edges.merge(edges_to_remove);
2790
2791 // remove edges self connected to surface
2792 CHKERR removeSelfConectingEdges(surface_edges, edges_to_remove, false);
2793 edges_to_merge = subtract(edges_to_merge, edges_to_remove);
2794 not_merged_edges.merge(edges_to_remove);
2795
2796 // remove edges self contented on surface skin
2797 {
2798 Range ents_nodes_and_edges;
2799 ents_nodes_and_edges.merge(surface_skin);
2800 ents_nodes_and_edges.merge(fixed_edges_nodes);
2801 CHKERR removeSelfConectingEdges(ents_nodes_and_edges, edges_to_remove,
2802 false);
2803 }
2804 edges_to_merge = subtract(edges_to_merge, edges_to_remove);
2805 not_merged_edges.merge(edges_to_remove);
2806
2807 // remove edges connecting crack front and fixed edges, except those short
2808 {
2809 Range ents_nodes_and_edges;
2810 ents_nodes_and_edges.merge(surface_skin.subset_by_type(MBEDGE));
2811 ents_nodes_and_edges.merge(fixed_edges.subset_by_type(MBEDGE));
2812 CHKERR removeSelfConectingEdges(ents_nodes_and_edges, edges_to_remove,
2813 false);
2814 }
2815 edges_to_merge = subtract(edges_to_merge, edges_to_remove);
2816 not_merged_edges.merge(edges_to_remove);
2817
2818 // remove crack front nodes connected to the surface, except those short
2819 {
2820 Range ents_nodes_and_edges;
2821 ents_nodes_and_edges.merge(surface_front_nodes);
2822 ents_nodes_and_edges.merge(surface_front);
2823 ents_nodes_and_edges.merge(tets_skin_edges_verts);
2824 ents_nodes_and_edges.merge(tets_skin_edges);
2825 CHKERR removeSelfConectingEdges(ents_nodes_and_edges, edges_to_remove,
2826 false);
2827 }
2828 edges_to_merge = subtract(edges_to_merge, edges_to_remove);
2829 not_merged_edges.merge(edges_to_remove);
2830
2832 }
2833
2834 private:
2835 MoFEMErrorCode removeSelfConectingEdges(const Range &ents,
2836 Range &edges_to_remove,
2837 bool debug) const {
2838 moab::Interface &moab(mField.get_moab());
2840 // get nodes
2841 Range ents_nodes = ents.subset_by_type(MBVERTEX);
2842 if (ents_nodes.empty()) {
2843 CHKERR moab.get_connectivity(ents, ents_nodes, true);
2844 }
2845 // edges adj. to nodes
2846 Range ents_nodes_edges;
2847 CHKERR moab.get_adjacencies(ents_nodes, 1, false, ents_nodes_edges,
2848 moab::Interface::UNION);
2849 // nodes of adj. edges
2850 Range ents_nodes_edges_nodes;
2851 CHKERR moab.get_connectivity(ents_nodes_edges, ents_nodes_edges_nodes,
2852 true);
2853 // hanging nodes
2854 ents_nodes_edges_nodes = subtract(ents_nodes_edges_nodes, ents_nodes);
2855 Range ents_nodes_edges_nodes_edges;
2856 CHKERR moab.get_adjacencies(ents_nodes_edges_nodes, 1, false,
2857 ents_nodes_edges_nodes_edges,
2858 moab::Interface::UNION);
2859 // remove edges adj. to hanging edges
2860 ents_nodes_edges =
2861 subtract(ents_nodes_edges, ents_nodes_edges_nodes_edges);
2862 ents_nodes_edges =
2863 subtract(ents_nodes_edges, ents.subset_by_type(MBEDGE));
2864
2865 edges_to_remove.swap(ents_nodes_edges);
2866 if (debug) {
2867 CHKERR SaveData(moab)("edges_to_remove.vtk", edges_to_remove);
2868 }
2870 }
2871 };
2872
2873 Range not_merged_edges;
2874 CHKERR Toplogy(m_field, th)
2875 .removeBadEdges(surface, tets, fixed_edges, corner_nodes,
2876 constrainSurface, edges_to_merge, not_merged_edges);
2877 Toplogy::SetsMap sets_map;
2878 CHKERR Toplogy(m_field, th)
2879 .classifyVerts(surface, tets, fixed_edges, corner_nodes, constrainSurface,
2880 sets_map);
2881 if (debug) {
2882 for (Toplogy::SetsMap::reverse_iterator sit = sets_map.rbegin();
2883 sit != sets_map.rend(); sit++) {
2884 std::string name = "classification_verts_" +
2885 boost::lexical_cast<std::string>(sit->first) + ".vtk";
2886 if (!sit->second.empty())
2887 CHKERR SaveData(moab)(name, sit->second);
2888 }
2889 }
2890 Range proc_tets;
2891 CHKERR Toplogy(m_field, th).getProcTets(tets, edges_to_merge, proc_tets);
2892 out_tets = subtract(tets, proc_tets);
2893
2894 if (bit_ptr) {
2895 Range all_out_ents = out_tets;
2896 for (int dd = 2; dd >= 0; dd--) {
2897 CHKERR moab.get_adjacencies(out_tets, dd, false, all_out_ents,
2898 moab::Interface::UNION);
2899 }
2900 CHKERR m_field.getInterface<BitRefManager>()->addBitRefLevel(all_out_ents,
2901 *bit_ptr);
2902 }
2903
2904 int nb_nodes_merged = 0;
2905 LengthMapData_multi_index length_map;
2906 new_surf = surface;
2907
2908 auto save_merge_step = [&](const int pp, const Range collapsed_edges) {
2910 Range adj_faces;
2911 CHKERR moab.get_adjacencies(proc_tets, 2, false, adj_faces,
2912 moab::Interface::UNION);
2913 std::string name;
2914 name = "node_merge_step_" + boost::lexical_cast<std::string>(pp) + ".vtk";
2915 CHKERR SaveData(moab)(
2916 name, unite(intersect(new_surf, adj_faces), collapsed_edges));
2917 name =
2918 "edges_to_merge_step_" + boost::lexical_cast<std::string>(pp) + ".vtk";
2919 CHKERR SaveData(moab)(
2920 name, unite(intersect(new_surf, adj_faces), edges_to_merge));
2922 };
2923
2924 if (debug)
2925 CHKERR save_merge_step(0, Range());
2926
2927 double ave0 = 0, ave = 0, min = 0, min_p = 0, min_pp;
2928 for (int pp = 0; pp != nbMaxMergingCycles; ++pp) {
2929
2930 int nb_nodes_merged_p = nb_nodes_merged;
2931 length_map.clear();
2932 min_pp = min_p;
2933 min_p = min;
2934 CHKERR LengthMap(m_field, th, aveLength)(proc_tets, edges_to_merge,
2935 length_map, ave);
2936
2937 if(!length_map.empty())
2938 min = length_map.get<2>().begin()->qUality;
2939 if (pp == 0) {
2940 ave0 = ave;
2941 }
2942
2943 int nn = 0;
2944 Range collapsed_edges;
2945 MergeNodes merge_nodes(m_field, true, th, update_meshsets);
2946
2947 for (auto mit = length_map.get<0>().begin();
2948 mit != length_map.get<0>().end(); mit++, nn++) {
2949
2950 if (!mit->skip) {
2951
2952 auto get_father_and_mother =
2953 [&](EntityHandle &father, EntityHandle &mother, int &line_search) {
2955 int num_nodes;
2956 const EntityHandle *conn;
2957 CHKERR moab.get_connectivity(mit->eDge, conn, num_nodes, true);
2958 std::array<int, 2> conn_type = {0, 0};
2959 for (int nn = 0; nn != 2; nn++) {
2960 for (Toplogy::SetsMap::reverse_iterator sit = sets_map.rbegin();
2961 sit != sets_map.rend(); sit++) {
2962 if (sit->second.find(conn[nn]) != sit->second.end()) {
2963 conn_type[nn] |= sit->first;
2964 }
2965 }
2966 }
2967 int type_father, type_mother;
2968 if (conn_type[0] > conn_type[1]) {
2969 father = conn[0];
2970 mother = conn[1];
2971 type_father = conn_type[0];
2972 type_mother = conn_type[1];
2973 } else {
2974 father = conn[1];
2975 mother = conn[0];
2976 type_father = conn_type[1];
2977 type_mother = conn_type[0];
2978 }
2979 if (type_father == type_mother) {
2980 line_search = lineSearchSteps;
2981 }
2983 };
2984
2985 int line_search = 0;
2986 EntityHandle father, mother;
2987 CHKERR get_father_and_mother(father, mother, line_search);
2988 CHKERR merge_nodes.mergeNodes(line_search, father, mother, proc_tets);
2989 if (m_field.getInterface<NodeMergerInterface>()->getSuccessMerge()) {
2990 const EntityHandle father_and_mother[] = {father, mother};
2991 Range adj_tets;
2992 CHKERR moab.get_adjacencies(father_and_mother, 1, 3, false, adj_tets);
2993 Range adj_tets_nodes;
2994 CHKERR moab.get_connectivity(adj_tets, adj_tets_nodes, true);
2995 Range adj_edges;
2996 CHKERR moab.get_adjacencies(adj_tets_nodes, 1, false, adj_edges,
2997 moab::Interface::UNION);
2998 for (auto ait : adj_edges) {
2999 auto miit = length_map.get<1>().find(ait);
3000 if (miit != length_map.get<1>().end())
3001 (const_cast<LengthMapData &>(*miit)).skip = true;
3002 }
3003 nb_nodes_merged++;
3004 collapsed_edges.insert(mit->eDge);
3005 }
3006
3007 if (nn > static_cast<int>(length_map.size() / fraction_level))
3008 break;
3009 if (mit->qUality > ave)
3010 break;
3011 }
3012 }
3013
3014 CHKERR merge_nodes.updateRangeByChilds(new_surf, edges_to_merge,
3015 not_merged_edges, true);
3016
3017 MOFEM_LOG_C("WORLD", Sev::verbose,
3018 "(%d) Number of nodes merged %d ave q %3.4e min q %3.4e", pp,
3019 nb_nodes_merged, ave, min);
3020
3021 if (debug)
3022 CHKERR save_merge_step(pp + 1, collapsed_edges);
3023
3024 if (nb_nodes_merged == nb_nodes_merged_p)
3025 break;
3026 if (min > 1e-2 && min == min_pp)
3027 break;
3028 if (min > ave0)
3029 break;
3030
3031 Range adj_edges;
3032 CHKERR moab.get_adjacencies(proc_tets, 1, false, adj_edges,
3033 moab::Interface::UNION);
3034 edges_to_merge = intersect(edges_to_merge, adj_edges);
3035 CHKERR Toplogy(m_field, th)
3036 .removeBadEdges(new_surf, proc_tets, fixed_edges, corner_nodes,
3037 constrainSurface, edges_to_merge, not_merged_edges);
3038 }
3039
3040 auto reconstruct_refined_ents = [&]() {
3042 CHKERR reconstructMultiIndex(*m_field.get_ref_ents());
3044 };
3045
3046 // Add function which reconstruct core multi-index. Node merging is messy
3047 // process and entity parent could be changed without notification to
3048 // multi-index. TODO Issue has to be tracked down better, however in principle
3049 // is better not to modify multi-index each time parent is changed, that makes
3050 // code slow. Is better to do it in the bulk as below.
3051 CHKERR reconstruct_refined_ents();
3052
3053 if (bit_ptr)
3054 CHKERR m_field.getInterface<BitRefManager>()->setBitRefLevel(proc_tets,
3055 *bit_ptr);
3056
3057 out_tets.merge(proc_tets);
3058 Range adj_faces;
3059 CHKERR moab.get_adjacencies(out_tets, 2, false, adj_faces,
3060 moab::Interface::UNION);
3061 new_surf = intersect(new_surf, adj_faces);
3062
3064}
3065
3066MoFEMErrorCode CutMeshInterface::mergeBadEdges(
3067 const int fraction_level, const BitRefLevel cut_bit,
3068 const BitRefLevel trim_bit, const BitRefLevel bit, const Range &surface,
3069 const Range &fixed_edges, const Range &corner_nodes, Tag th,
3070 const bool update_meshsets, const bool debug) {
3071 CoreInterface &m_field = cOre;
3073 Range tets_level;
3074 CHKERR m_field.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
3075 trim_bit, BitRefLevel().set(), MBTET, tets_level);
3076
3077 Range edges_to_merge;
3078 CHKERR m_field.getInterface<BitRefManager>()->getEntitiesByRefLevel(
3079 trim_bit, cut_bit | trim_bit, edges_to_merge);
3080
3081 // get all entities not in database
3082 Range all_ents_not_in_database_before;
3083 CHKERR cOre.getInterface<BitRefManager>()->getAllEntitiesNotInDatabase(
3084 all_ents_not_in_database_before);
3085
3086 edges_to_merge = edges_to_merge.subset_by_type(MBEDGE);
3087 if (debug)
3088 CHKERR SaveData(m_field.get_moab())("edges_to_merge.vtk", edges_to_merge);
3089
3090 Range out_new_tets, out_new_surf;
3091 CHKERR mergeBadEdges(fraction_level, tets_level, surface, fixed_edges,
3092 corner_nodes, edges_to_merge, out_new_tets, out_new_surf,
3093 th, update_meshsets, &bit, debug);
3094
3095 // get all entities not in database after merge
3096 Range all_ents_not_in_database_after;
3097 CHKERR cOre.getInterface<BitRefManager>()->getAllEntitiesNotInDatabase(
3098 all_ents_not_in_database_after);
3099
3100 // delete hanging entities
3101 all_ents_not_in_database_after =
3102 subtract(all_ents_not_in_database_after, all_ents_not_in_database_before);
3103 Range meshsets;
3104 CHKERR m_field.get_moab().get_entities_by_type(0, MBENTITYSET, meshsets,
3105 false);
3106 for (auto m : meshsets)
3107 CHKERR m_field.get_moab().remove_entities(m,
3108 all_ents_not_in_database_after);
3109
3110 m_field.get_moab().delete_entities(all_ents_not_in_database_after);
3111
3112 mergedVolumes.swap(out_new_tets);
3113 mergedSurfaces.swap(out_new_surf);
3114
3116}
3117
3118MoFEMErrorCode CutMeshInterface::setTagData(Tag th, const BitRefLevel bit) {
3119 CoreInterface &m_field = cOre;
3120 moab::Interface &moab = m_field.get_moab();
3122 Range nodes;
3123 if (bit.none())
3124 CHKERR moab.get_entities_by_type(0, MBVERTEX, nodes);
3125 else
3126 CHKERR m_field.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
3127 bit, BitRefLevel().set(), MBVERTEX, nodes);
3128 std::vector<double> coords(3 * nodes.size());
3129 CHKERR moab.get_coords(nodes, &coords[0]);
3130 CHKERR moab.tag_set_data(th, nodes, &coords[0]);
3132}
3133
3134MoFEMErrorCode CutMeshInterface::setCoords(Tag th, const BitRefLevel bit,
3135 const BitRefLevel mask) {
3136 CoreInterface &m_field = cOre;
3137 moab::Interface &moab = m_field.get_moab();
3139 Range nodes;
3140 if (bit.none())
3141 CHKERR moab.get_entities_by_type(0, MBVERTEX, nodes);
3142 else
3143 CHKERR m_field.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
3144 bit, mask, MBVERTEX, nodes);
3145 std::vector<double> coords(3 * nodes.size());
3146 CHKERR moab.tag_get_data(th, nodes, &coords[0]);
3147 CHKERR moab.set_coords(nodes, &coords[0]);
3149}
3150
3151MoFEMErrorCode CutMeshInterface::saveCutEdges(const std::string prefix) {
3152 CoreInterface &m_field = cOre;
3153 moab::Interface &moab = m_field.get_moab();
3155 CHKERR SaveData(moab)(prefix + "out_vol.vtk", vOlume);
3156 CHKERR SaveData(moab)(prefix + "out_surface.vtk", sUrface);
3157 CHKERR SaveData(moab)(prefix + "out_cut_edges.vtk", cutEdges);
3158 CHKERR SaveData(moab)(prefix + "out_cut_new_volumes.vtk", cutNewVolumes);
3159 CHKERR SaveData(moab)(prefix + "out_cut_new_surfaces.vtk", cutNewSurfaces);
3160 CHKERR SaveData(moab)(prefix + "out_cut_zero_distance_ents.vtk",
3161 zeroDistanceEnts);
3163}
3164
3165MoFEMErrorCode CutMeshInterface::saveTrimEdges() {
3166 moab::Interface &moab = cOre.getInterface<CoreInterface>()->get_moab();
3168 CHKERR SaveData(moab)("out_trim_surface.vtk", sUrface);
3169 CHKERR SaveData(moab)("out_trim_new_volumes.vtk", trimNewVolumes);
3170 CHKERR SaveData(moab)("out_trim_new_surfaces.vtk", trimNewSurfaces);
3171 CHKERR SaveData(moab)("out_trim_edges.vtk", trimEdges);
3173}
3174
3175}
#define CutMeshFunctionBegin
static auto get_skin(MoFEM::Interface &m_field, Range body_ents)
#define MOFEM_LOG_C(channel, severity, format,...)
constexpr double a
static PetscErrorCode ierr
@ QUIET
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
@ MOFEM_DATA_INCONSISTENCY
Definition definitions.h:31
#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 THROW_MESSAGE(msg)
Throw MoFEM exception.
static const bool debug
#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
const double v
phase velocity of light in medium (cm/ns)
const double n
refractive index of diffusive medium
FTensor::Index< 'l', 3 > l
FTensor::Index< 'j', 3 > j
FTensor::Index< 'k', 3 > k
double tol
const Tensor2_symmetric_Expr< const ddTensor0< T, Dim, i, j >, typename promote< T, double >::V, Dim, i, j > dd(const Tensor0< T * > &a, const Index< i, Dim > index1, const Index< j, Dim > index2, const Tensor1< int, Dim > &d_ijk, const Tensor1< double, Dim > &d_xyz)
Definition ddTensor0.hpp:33
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
VectorBoundedArray< double, 3 > VectorDouble3
Definition Types.hpp:92
VectorBoundedArray< double, 6 > VectorDouble6
Definition Types.hpp:95
VectorShallowArrayAdaptor< double > VectorAdaptor
Definition Types.hpp:115
VectorBoundedArray< double, 12 > VectorDouble12
Definition Types.hpp:97
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
UBlasVector< double > VectorDouble
Definition Types.hpp:68
MatrixShallowArrayAdaptor< double > MatrixAdaptor
Matrix adaptor.
Definition Types.hpp:132
MatrixBoundedArray< double, 9 > MatrixDouble3by3
Definition Types.hpp:105
auto getVectorAdaptor(T1 ptr, const size_t n)
Get Vector adaptor.
Definition Templates.hpp:31
MoFEMErrorCode reconstructMultiIndex(const MI &mi, MO &&mo=Modify_change_nothing())
Template used to reconstruct multi-index.
CoreTmp< 0 > Core
Definition Core.hpp:1148
int r
Definition sdf.py:8
constexpr double t
plate stiffness
Definition plate.cpp:58
static constexpr double delta
FTensor::Index< 'm', 3 > m