7 #include "GmshConfig.h"
28 #if defined(HAVE_BLOSSOM)
29 extern "C" struct CCdatagroup;
30 extern "C" int perfect_match(
int ncount, CCdatagroup *dat,
int ecount,
31 int **elist,
int **elen,
char *blo_filename,
32 char *mat_filename,
int just_fractional,
33 int no_fractional,
int use_all_trees,
34 int partialprice,
double *totalzeit);
95 double ErrDir = std::min(fabs(
dot(
t1,
t2)), n.
norm());
116 double a[3] = {p1->
x() - p2->
x(), p1->
y() - p2->
y(), p1->
z() - p2->
z()};
117 double b[3] = {p1->
x() - p3->
x(), p1->
y() - p3->
y(), p1->
z() - p3->
z()};
118 c1[2] = a[0] * b[1] - a[1] * b[0];
119 c1[1] = -a[0] * b[2] + a[2] * b[0];
120 c1[0] = a[1] * b[2] - a[2] * b[1];
126 double a[3] = {p1->
x() - p2->
x(), p1->
y() - p2->
y(), p1->
z() - p2->
z()};
127 double b[3] = {p1->
x() - p3->
x(), p1->
y() - p3->
y(), p1->
z() - p3->
z()};
128 c2[2] = a[0] * b[1] - a[1] * b[0];
129 c2[1] = -a[0] * b[2] + a[2] * b[0];
130 c2[0] = a[1] * b[2] - a[2] * b[1];
136 double const sina =
norme(c3);
137 angle = std::atan2(sina, cosa);
143 for(
int i = 0; i < 3; i++) {
144 for(
int j = i + 1; j < 3; j++) {
156 for(
int i = 0; i < 3; i++) {
157 for(
int j = i + 1; j < 3; j++) {
161 double dx = vi->
x() - vj->
x();
162 double dy = vi->
y() - vj->
y();
163 double dz = vi->
z() - vj->
z();
164 double l = sqrt(dx * dx + dy * dy + dz * dz);
165 auto iti = vSizes.find(vi);
166 auto itj = vSizes.find(vj);
167 if(iti->second < 0 || iti->second > l) iti->second = l;
168 if(itj->second < 0 || itj->second > l) itj->second = l;
177 std::map<MVertex *, double> vSizesMap;
179 for(std::size_t i = 0; i < gf->
triangles.size(); i++)
182 auto itfind = vSizesMap.find(
nullptr);
183 if(itfind != vSizesMap.end()) {
184 Msg::Error(
"Some NULL points exist in 2D mesh");
188 for(std::size_t i = 0; i < gf->
triangles.size(); i++)
192 std::set<MVertex *> embeddedVertices;
195 auto itvx = emb_vertx.begin();
196 while(itvx != emb_vertx.end()) {
197 if((*itvx)->mesh_vertices.size()) {
198 MVertex *v = *((*itvx)->mesh_vertices.begin());
200 std::min(vSizesMap[v], (*itvx)->prescribedMeshSizeAtVertex());
201 embeddedVertices.insert(v);
210 auto ite = embedded_edges.begin();
211 while(ite != embedded_edges.end()) {
212 if(!(*ite)->isMeshDegenerated()) {
213 for(std::size_t i = 0; i < (*ite)->lines.size(); i++)
215 (*ite)->lines[i]->getVertex(1)));
223 std::vector<GEdge *> _edges = gf->
edges();
224 auto ite = _edges.begin();
225 while(ite != _edges.end()) {
226 if(!(*ite)->isMeshDegenerated()) {
227 for(std::size_t i = 0; i < (*ite)->lines.size(); i++) {
228 double d =
distance((*ite)->lines[i]->getVertex(0),
229 (*ite)->lines[i]->getVertex(1));
230 double d0 = vSizesMap[(*ite)->lines[i]->getVertex(0)];
231 double d1 = vSizesMap[(*ite)->lines[i]->getVertex(1)];
232 if(d0 < .5 * d) vSizesMap[(*ite)->lines[i]->getVertex(0)] = .5 * d;
233 if(d1 < .5 * d) vSizesMap[(*ite)->lines[i]->getVertex(1)] = .5 * d;
240 for(
auto it = vSizesMap.begin(); it != vSizesMap.end(); ++it) {
245 const double lcBGM = (embeddedVertices.count(it->first) > 0) ?
247 it->first->y(), it->first->z()) :
249 data.
addVertex(it->first, param[0], param[1], it->second, lcBGM);
251 for(std::size_t i = 0; i < gf->
triangles.size(); i++) {
252 double lc = 0.3333333333 *
263 AllTris.insert(
new MTri3(gf->
triangles[i], LL,
nullptr, &data, gf));
274 std::vector<MTriangle *> newT;
275 for(std::size_t i = 0; i < gf->
triangles.size(); i++) {
278 for(
int j = 0; j < 3; j++) {
281 if(it != data.
equivalence->end()) { v[j] = it->second; }
283 if(v[0] != v[1] && v[0] != v[2] && v[2] != v[1])
284 newT.push_back(
new MTriangle(v[0], v[1], v[2]));
297 for(
int i = 0; i < 3; i++) {
299 auto it = equivalence->find(v);
300 if(it == equivalence->end())
305 std::sort(
_v,
_v + 3);
309 for(
int i = 0; i < 3; i++) {
310 if(other.
_v[i] >
_v[i])
return true;
311 if(other.
_v[i] <
_v[i])
return false;
318 std::map<MVertex *, MVertex *> *equivalence)
320 if(!equivalence)
return false;
321 std::vector<MTriangle *> WTF;
322 if(!equivalence)
return false;
323 std::set<equivalentTriangle> eqTs;
324 for(std::size_t i = 0; i < gf->
triangles.size(); i++) {
326 auto iteq = eqTs.find(et);
327 if(iteq == eqTs.end())
330 WTF.push_back(iteq->_t);
336 Msg::Info(
"%d triangles are equivalent", WTF.size());
337 for(std::size_t i = 0; i < WTF.size(); i++) {}
349 std::set<MTri3 *, compareTri3Ptr> &AllTris,
353 if(AllTris.begin() == AllTris.end())
break;
354 MTri3 *worst = *AllTris.begin();
360 AllTris.erase(AllTris.begin());
382 data.
Vs[index1], 0., data.
Us[index2], data.
Vs[index2], 0.,
388 v2->x(), v2->y(), v2->z(), n1);
390 for(std::size_t j = 1; j < gf->
triangles.size(); j++) {
400 data.
Vs[index1], 0., data.
Us[index2], data.
Vs[index2], 0.,
406 v2->x(), v2->y(), v2->z(), n2);
419 for(std::size_t i = 0; i < elements.size(); i++) {
421 for(
int j = 0; j < t->getNumEdges(); j++) {
422 MEdge e = t->getEdge(j);
423 auto it = adj.find(e);
424 if(it == adj.end()) {
425 std::pair<MElement *, MElement *> one =
426 std::make_pair(t, (
MElement *)
nullptr);
430 it->second.second = t;
456 std::vector<edge_angle> &edges_lonly)
458 auto it = adj.begin();
459 for(; it != adj.end(); ++it) {
460 if(it->second.second)
461 edges_detected.push_back(
edge_angle(it->first.getVertex(0),
462 it->first.getVertex(1),
463 it->second.first, it->second.second));
465 edges_lonly.push_back(
edge_angle(it->first.getVertex(0),
466 it->first.getVertex(1), it->second.first,
469 std::sort(edges_detected.begin(), edges_detected.end());
473 double v[4],
MVertex *close =
nullptr)
491 Msg::Warning(
"surfaceFaceUV only for first order elements");
499 fabs((u[1] - u[0]) * (v[2] - v[0]) - (u[2] - u[0]) * (v[1] - v[0]));
503 fabs((u[1] - u[0]) * (v[2] - v[0]) - (u[2] - u[0]) * (v[1] - v[0])) +
504 0.5 * fabs((u[3] - u[2]) * (v[0] - v[2]) - (u[0] - u[2]) * (v[3] - v[2]));
507 fabs((u[2] - u[1]) * (v[3] - v[1]) - (u[3] - u[1]) * (v[2] - v[1])) +
508 0.5 * fabs((u[0] - u[3]) * (v[1] - v[3]) - (u[1] - u[3]) * (v[0] - v[3]));
509 return maximal ? std::max(
a2,
a1) : std::min(
a2,
a1);
518 auto it = adj.begin();
519 std::set<MElement *> touched;
520 std::set<MVertex *> vtouched;
521 while(it != adj.end()) {
523 if(it->second.size() == 2 && v->
onWhat() == gf) {
527 touched.find(q1) == touched.end() &&
528 touched.find(q2) == touched.end()) {
530 for(
int i = 0; i < 4; i++) {
540 for(
int i = 0; i < 4; i++) {
548 Msg::Error(
"Bug in removeTwoQuadsNodes %p,%p,%p", v1, v2, v3);
549 q1->
writePOS(stdout,
true,
false,
false,
false,
false,
false);
550 q2->
writePOS(stdout,
true,
false,
false,
false,
false,
false);
562 std::vector<MQuadrangle *> quadrangles2;
563 quadrangles2.reserve(gf->
quadrangles.size() - touched.size());
564 for(std::size_t i = 0; i < gf->
quadrangles.size(); i++) {
565 if(touched.find(gf->
quadrangles[i]) == touched.end()) {
574 std::vector<MVertex *> mesh_vertices2;
575 mesh_vertices2.reserve(gf->
mesh_vertices.size() - vtouched.size());
586 return vtouched.size();
597 Msg::Debug(
"%i two-quadrangles nodes removed", nbRemove);
602 std::vector<MElement *> &e2,
MElement *q,
605 std::vector<MElement *> e = e1;
606 e.insert(e.end(), e2.begin(), e2.end());
617 double initialGuess[2] = {0, 0};
619 SPoint3(0.5 * (x1 + x2), 0.5 * (y1 + y2), 0.5 * (z1 + z2)), initialGuess);
621 double worst_quality_old = 1.0;
622 double worst_quality_new = 1.0;
625 for(std::size_t j = 0; j < e.size(); ++j) {
628 worst_quality_old = std::min(worst_quality_old, e[j]->etaShapeMeasure());
635 worst_quality_new = std::min(worst_quality_new, e[j]->etaShapeMeasure());
645 if(worst_quality_new > worst_quality_old) {
649 for(std::size_t j = 0; j < e.size(); ++j) {
651 for(
int k = 0; k < 4; k++) {
652 if(e[j]->getVertex(k) == v2) { e[j]->setVertex(k, v1); }
663 std::vector<MElement *> &e2,
MElement *q,
666 std::vector<MElement *> e = e1;
667 e.insert(e.end(), e2.begin(), e2.end());
686 GPoint pp = gf->
point(0.5 * (uu1 + uu2), 0.5 * (vv1 + vv2));
687 double worst_quality_old = 1.0;
688 double worst_quality_new = 1.0;
690 for(std::size_t j = 0; j < e.size(); ++j) {
693 worst_quality_old = std::min(worst_quality_old, e[j]->etaShapeMeasure());
704 worst_quality_new = std::min(worst_quality_new, e[j]->etaShapeMeasure());
718 if(worst_quality_new > worst_quality_old) {
724 for(std::size_t j = 0; j < e.size(); ++j) {
726 for(
int k = 0; k < 4; k++) {
727 if(e[j]->getVertex(k) == v2) { e[j]->setVertex(k, v1); }
737 const std::vector<MElement *> &e1,
741 double surface_old = 0;
742 double surface_new = 0;
750 for(std::size_t j = 0; j < e1.size(); ++j) {
752 minq = std::min(e1[j]->etaShapeMeasure(), minq);
757 v1->
setXYZ(pafter.
x(), pafter.
y(), pafter.
z());
759 double minq_new = 1.0;
760 for(std::size_t j = 0; j < e1.size(); ++j) {
762 minq_new = std::min(e1[j]->etaShapeMeasure(), minq_new);
767 v1->
setXYZ(pbefore.
x(), pbefore.
y(), pbefore.
z());
768 if((1. + 1.e-10) * surface_old < surface_new || minq_new < minq) {
777 return touched.find(v1) == touched.end() &&
778 touched.find(v2) == touched.end() &&
779 touched.find(v3) == touched.end() && touched.find(v4) == touched.end();
789 template <
class InputIterator>
792 return iterator1->second.size() == 3 && iterator2->second.size() == 3;
800 std::vector<MElement *> diamonds;
801 std::set<MVertex *> touched;
802 std::vector<MVertex *> deleted;
804 std::vector<MQuadrangle *> quadrangles2;
807 for(std::size_t i = 0; i < gf->
triangles.size(); i++) {
808 touched.insert(gf->
triangles[i]->getVertex(0));
809 touched.insert(gf->
triangles[i]->getVertex(1));
810 touched.insert(gf->
triangles[i]->getVertex(2));
813 for(std::size_t i = 0; i < gf->
quadrangles.size(); i++) {
822 auto it1 = adj.find(v1);
823 auto it2 = adj.find(v2);
824 auto it3 = adj.find(v3);
825 auto it4 = adj.find(v4);
834 deleted.push_back(v3);
836 diamonds.push_back(q);
847 deleted.push_back(v4);
849 diamonds.push_back(q);
852 quadrangles2.push_back(q);
856 quadrangles2.push_back(q);
859 std::sort(deleted.begin(), deleted.end());
860 deleted.erase(std::unique(deleted.begin(), deleted.end()), deleted.end());
864 std::vector<MVertex *> mesh_vertices2;
868 if(!std::binary_search(deleted.begin(), deleted.end(),
878 std::sort(diamonds.begin(), diamonds.end());
881 std::unique(diamonds.begin(), diamonds.end()));
886 std::size_t nbRemove = 0;
892 Msg::Debug(
"%i diamond quads removed", nbRemove);
901 const std::vector<MElement *> <)
903 if(ver->
onWhat() != gf)
return;
912 std::map<MVertex *, SPoint2, MVertexPtrLessThan> pts;
913 for(std::size_t i = 0; i < lt.size(); i++) {
914 for(
int j = 0; j < lt[i]->getNumEdges(); j++) {
915 MEdge e = lt[i]->getEdge(j);
934 for(
auto it = pts.begin(); it != pts.end(); ++it) {
936 SVector3 d(adj.
x() - before.
x(), adj.
y() - before.
y(), 0.0);
940 sqrt(metric[0] * d.
x() * d.
x() + 2 * metric[1] * d.
x() * d.
y() +
941 metric[2] * d.
y() * d.
y());
945 after *= (1.0 / COUNT);
947 const int MAXITER = 5;
949 for(
int ITER = 0; ITER < MAXITER; ITER++) {
950 SPoint2 trial = after * FACTOR + before * (1. - FACTOR);
971 if(!_columns)
return;
972 for(
auto it = _columns->
_data.begin(); it != _columns->
_data.end(); it++) {
974 for(
size_t i = 0; i < data.
_column.size(); i++) vs.insert(data.
_column[i]);
984 "Surface mesh smoothing only valid for first order mesh (use the high-"
985 "order optimization tools for high-order meshes)");
993 std::set<MVertex *> vs;
998 for(
int i = 0; i < niter; i++) {
999 auto it = adj.begin();
1000 while(it != adj.end()) {
1001 if(vs.find(it->first) == vs.end()) {
1014 std::vector<MVertex *> emb_edgeverts;
1017 auto ite = emb_edges.begin();
1018 while(ite != emb_edges.end()) {
1019 if(!(*ite)->isMeshDegenerated()) {
1020 emb_edgeverts.insert(emb_edgeverts.end(), (*ite)->mesh_vertices.begin(),
1021 (*ite)->mesh_vertices.end());
1022 if((*ite)->getBeginVertex())
1023 emb_edgeverts.insert(emb_edgeverts.end(),
1024 (*ite)->getBeginVertex()->mesh_vertices.begin(),
1025 (*ite)->getBeginVertex()->mesh_vertices.end());
1026 if((*ite)->getEndVertex())
1027 emb_edgeverts.insert(emb_edgeverts.end(),
1028 (*ite)->getEndVertex()->mesh_vertices.begin(),
1029 (*ite)->getEndVertex()->mesh_vertices.end());
1036 std::vector<GEdge *>
const &_edges = gf->
edges();
1037 auto ite = _edges.begin();
1038 while(ite != _edges.end()) {
1039 if(!(*ite)->isMeshDegenerated()) {
1040 if((*ite)->isSeam(gf)) {
1041 emb_edgeverts.insert(emb_edgeverts.end(),
1042 (*ite)->mesh_vertices.begin(),
1043 (*ite)->mesh_vertices.end());
1044 if((*ite)->getBeginVertex())
1045 emb_edgeverts.insert(
1046 emb_edgeverts.end(),
1047 (*ite)->getBeginVertex()->mesh_vertices.begin(),
1048 (*ite)->getBeginVertex()->mesh_vertices.end());
1049 if((*ite)->getEndVertex())
1050 emb_edgeverts.insert(emb_edgeverts.end(),
1051 (*ite)->getEndVertex()->mesh_vertices.begin(),
1052 (*ite)->getEndVertex()->mesh_vertices.end());
1060 std::sort(emb_edgeverts.begin(), emb_edgeverts.end());
1061 emb_edgeverts.erase(std::unique(emb_edgeverts.begin(), emb_edgeverts.end()),
1062 emb_edgeverts.end());
1068 Field *cross_field = NULL;
1078 std::vector<RecombineTriangle> pairs;
1080 std::map<MVertex *, std::pair<MElement *, MElement *> > makeGraphPeriodic;
1082 for(
auto it = adj.begin(); it != adj.end(); ++it) {
1083 if(it->second.second && it->second.first->getNumVertices() == 3 &&
1084 it->second.second->getNumVertices() == 3 &&
1085 (!std::binary_search(emb_edgeverts.begin(), emb_edgeverts.end(),
1086 it->first.getVertex(0)) ||
1087 !std::binary_search(emb_edgeverts.begin(), emb_edgeverts.end(),
1088 it->first.getVertex(1)))) {
1090 it->second.second, cross_field));
1092 else if(!it->second.second && it->second.first->getNumVertices() == 3) {
1093 for(
int i = 0; i < 2; i++) {
1094 MVertex *
const v = it->first.getVertex(i);
1095 auto itv = makeGraphPeriodic.find(v);
1096 if(itv == makeGraphPeriodic.end()) {
1097 makeGraphPeriodic[v] =
1098 std::make_pair(it->second.first,
static_cast<MElement *
>(
nullptr));
1101 if(itv->second.first != it->second.first)
1102 itv->second.second = it->second.first;
1104 makeGraphPeriodic.erase(itv);
1110 std::sort(pairs.begin(), pairs.end());
1111 std::set<MElement *> touched;
1114 #if defined(HAVE_BLOSSOM)
1116 if(ncount % 2 != 0) {
1117 Msg::Warning(
"Cannot apply Blossom: odd number of triangles (%d) in "
1123 cubicGraph ? (pairs.size() + makeGraphPeriodic.size()) : pairs.size();
1124 Msg::Info(
"Blossom: %d internal %d closed", (
int)pairs.size(),
1125 (
int)makeGraphPeriodic.size());
1126 Msg::Debug(
"Perfect Match Starts %d edges %d nodes", ecount, ncount);
1127 std::map<MElement *, int> t2n;
1128 std::map<int, MElement *> n2t;
1129 for(std::size_t i = 0; i < gf->
triangles.size(); ++i) {
1135 int *elist = (
int *)malloc(
sizeof(
int) * 2 * ecount);
1136 int *elen = (
int *)malloc(
sizeof(
int) * ecount);
1138 for(std::size_t i = 0; i < pairs.size(); ++i) {
1139 elist[2 * i] = t2n[pairs[i].t1];
1140 elist[2 * i + 1] = t2n[pairs[i].t2];
1141 elen[i] = (int)1000 * std::exp(-pairs[i].
angle);
1143 if(pairs[i].n1->onWhat()->dim() < 2) NB++;
1144 if(pairs[i].n2->onWhat()->dim() < 2) NB++;
1145 if(pairs[i].n3->onWhat()->dim() < 2) NB++;
1146 if(pairs[i].n4->onWhat()->dim() < 2) NB++;
1147 if(elen[i] >
static_cast<int>(1000 * std::exp(0.1)) && NB > 2) {
1150 else if(elen[i] >= 1000 && NB > 2) {
1156 auto itv = makeGraphPeriodic.begin();
1157 std::size_t CC = pairs.size();
1158 for(; itv != makeGraphPeriodic.end(); ++itv) {
1159 elist[2 * CC] = t2n[itv->second.first];
1160 elist[2 * CC + 1] = t2n[itv->second.second];
1161 elen[CC++] = 100000;
1165 double matzeit = 0.0;
1166 char MATCHFILE[256];
1167 sprintf(MATCHFILE,
".face.match");
1168 if(perfect_match(ncount,
nullptr, ecount, &elist, &elen,
nullptr,
1169 MATCHFILE, 0, 0, 0, 0, &matzeit)) {
1171 "Perfect Match failed in quadrangulation, try something else");
1177 for(
int k = 0; k < elist[0]; k++) {
1178 int i1 = elist[1 + 3 * k], i2 = elist[1 + 3 * k + 1],
1179 an = elist[1 + 3 * k + 2];
1193 for(
int i = 0; i < 3; i++) {
1202 for(
int i = 0; i < 3; i++) {
1218 Msg::Debug(
"Perfect Match Succeeded in Quadrangulation (%g sec)",
1223 Msg::Warning(
"Gmsh should be compiled with the Blossom IV code and "
1224 " CONCORDE in order to allow the Blossom optimization");
1229 auto itp = pairs.begin();
1230 while(itp != pairs.end()) {
1234 if(touched.find(t1) == touched.end() &&
1235 touched.find(t2) == touched.end()) {
1238 int orientation = 0;
1239 for(
int i = 0; i < 3; i++) {
1241 if(t1->
getVertex((i + 1) % 3) == itp->n2)
1249 new MQuadrangle(itp->n1, orientation < 0 ? itp->n3 : itp->n4, itp->n2,
1250 orientation < 0 ? itp->n4 : itp->n3));
1256 std::vector<MTriangle *> triangles2;
1257 triangles2.reserve(gf->
triangles.size());
1258 for(std::size_t i = 0; i < gf->
triangles.size(); i++) {
1259 if(touched.find(gf->
triangles[i]) == touched.end()) {
1275 for(std::size_t i = 0; i < gf->
quadrangles.size(); i++) {
1277 if(Q <= 0.0) nbInv++;
1278 if(Q <= 0.1) nbBad++;
1280 Qmin = std::min(Q, Qmin);
1283 "%s: %d quads, %d triangles, %d invalid quads, %d quads with Q < 0.1, "
1284 "avg Q = %g, min Q = %g",
1303 if(!ge)
return false;
1304 if(ge->
dim() == 2 && ge != gf)
return false;
1312 bool nodeRepositioning,
double minqual)
1325 if(haveParam && nodeRepositioning) {
1331 #pragma omp critical
1333 if(topologicalOptiPasses > 0) {
1336 (
"Skipping topological optimization - mesh topology is not complete");
1339 int iter = 0, nbTwoQuadNodes = 1, nbDiamonds = 1;
1340 while(nbTwoQuadNodes || nbDiamonds) {
1341 Msg::Debug(
"Topological optimization of quad mesh: pass %d", iter);
1345 if(haveParam && nodeRepositioning)
1348 if(iter > topologicalOptiPasses)
break;
1361 if(haveParam && nodeRepositioning)
1367 sprintf(name,
"%s recombination completed (Wall %gs, CPU %gs)",
1368 blossom ?
"Blossom" :
"Simple", w2 -
w1, t2 - t1);
1376 std::vector<MQuadrangle *> qds;
1377 std::map<MElement *, std::pair<MElement *, MElement *> > change;
1378 for(std::size_t i = 0; i < gf->
quadrangles.size(); i++) {
1396 if(qual1 > qual2 || ori2 < 0) {
1399 change[q] = std::make_pair(t11, t12);
1406 change[q] = std::make_pair(t21, t22);
1419 if(!_columns)
return;
1426 std::map<MElement *, std::vector<MElement *> > newElemColumns;
1431 auto it2 = change.find(firstEl);
1432 if(it2 != change.end()) firstEl = it2->second.first;
1435 std::vector<MElement *> &newColumn = newElemColumns[firstEl];
1436 std::vector<MElement *> &oldColumn = it->second;
1438 for(std::size_t i = 0; i < oldColumn.size(); i++) {
1440 it2 = change.find(oldEl);
1441 if(it2 == change.end()) {
1442 newColumn.push_back(oldEl);
1443 _columns->
_toFirst[oldEl] = firstEl;
1446 newColumn.push_back(it2->second.first);
1447 newColumn.push_back(it2->second.second);
1449 _columns->
_toFirst[it2->second.first] = firstEl;
1450 _columns->
_toFirst[it2->second.second] = firstEl;
1464 for(
int i = 0; i < n; ++i) {
1466 if(bl_field ==
nullptr)
continue;
1474 if(numSplit > 0 && numNoSplit > 0)
1475 Msg::Warning(
"Cannot generate simplicial and non-simplicial boundary "
1476 "layers together. Keeping them non-simplicial...");