44 #include <boost/algorithm/string.hpp> 49 namespace NekMeshUtils
54 "Generates a 2D mesh");
59 ConfigOption(
false,
"",
"Generate parallelograms on these curves");
61 ConfigOption(
false,
"0.0",
"Parallelogram layer thickness");
63 ConfigOption(
false,
"",
"Set of pairs of periodic curves");
65 ConfigOption(
false,
"2.0",
"Boundary layer thickness adjustment");
69 ConfigOption(
true,
"0",
"Smooth the BL normal directions to avoid " 70 "(nearly) intersecting normals");
72 false,
"0.5",
"Threshold to space out BL according to Delta");
74 ConfigOption(
false,
"",
"Surfaces where spacing out shouldn't be used");
85 ASSERTL0(fabs(bndBox[5] - bndBox[4]) < 1.0e-7,
"CAD isn't 2D");
89 cout << endl <<
"2D meshing" << endl;
90 cout << endl <<
"\tCurve meshing:" << endl << endl;
105 for (
int i = 1; i <=
m_mesh->m_cad->GetNumCurve(); i++)
112 vector<unsigned int>::iterator f =
124 vector<CADVertSharedPtr> vertices =
125 m_mesh->m_cad->GetCurve(i)->GetVertex();
132 loc = vertices[0]->GetLoc();
140 loc = vertices[1]->GetLoc();
170 for (
int i = 1; i <=
m_mesh->m_cad->GetNumSurf(); i++)
179 vector<NodeSharedPtr> nodes =
182 if (ic.second == 0 || ic.second == 2)
184 nodes.erase(nodes.begin());
186 if (ic.second == 1 || ic.second == 2)
188 nodes.erase(nodes.end() - 1);
201 cout << endl <<
"\tFace meshing:" << endl << endl;
204 for (
int i = 1; i <=
m_mesh->m_cad->GetNumSurf(); i++)
214 m_facemeshes[i]->Mesh();
219 EdgeSet::iterator it;
220 for (
auto &it :
m_mesh->m_edgeSet)
222 vector<NodeSharedPtr> ns;
223 ns.push_back(it->m_n1);
224 ns.push_back(it->m_n2);
230 tags.push_back(it->m_parentCAD->GetId());
233 m_mesh->m_element[1].push_back(E2);
251 set<CADVertSharedPtr> cadverts;
255 vector<CADVertSharedPtr> vertices =
256 m_mesh->m_cad->GetCurve(it)->GetVertex();
258 for (
auto &iv : vertices)
260 set<CADVertSharedPtr>::iterator is = cadverts.find(iv);
262 if (is != cadverts.end())
276 for (
int i = 1; i <=
m_mesh->m_cad->GetNumCurve(); ++i)
278 if (
find(m_blCurves.begin(), m_blCurves.end(), i) != m_blCurves.end())
283 vector<CADVertSharedPtr> vertices =
284 m_mesh->m_cad->GetCurve(i)->GetVertex();
286 for (
int j = 0; j < 2; ++j)
288 if (!cadverts.count(vertices[j]))
309 cout << endl <<
"\tBoundary layer meshing:" << endl << endl;
316 vector<EdgeSharedPtr> localedges =
m_curvemeshes[it]->GetMeshEdges();
317 for (
auto &ie : localedges)
328 map<int, Array<OneD, NekDouble>> edgeNormals;
333 m_mesh->m_cad->GetCurve(it)->GetOrienationWRT(faceid);
334 vector<EdgeSharedPtr> es =
m_curvemeshes[it]->GetMeshEdges();
343 p1 = ie->m_n1->GetCADSurfInfo(faceid);
344 p2 = ie->m_n2->GetCADSurfInfo(faceid);
346 n[0] = p1[1] - p2[1];
347 n[1] = p2[0] - p1[0];
353 NekDouble mag = sqrt(n[0] * n[0] + n[1] * n[1]);
357 np[0] = p1[0] + n[0];
358 np[1] = p1[1] + n[1];
361 n[0] = locp[0] - loc[0];
362 n[1] = locp[1] - loc[1];
363 mag = sqrt(n[0] * n[0] + n[1] * n[1]);
366 edgeNormals[ie->m_id] = n;
370 bool adjust =
m_config[
"bltadjust"].beenSet;
372 bool adjustEverywhere =
m_config[
"adjustblteverywhere"].beenSet;
373 bool smoothbl =
m_config[
"smoothbl"].beenSet;
374 bool spaceoutbl =
m_config[
"spaceoutbl"].beenSet;
379 WARNINGL0(
false,
"BndLayerAdjustment too low, corrected to 2.0");
383 map<NodeSharedPtr, NodeSharedPtr> nodeNormals;
386 ASSERTL0(it.second.size() == 1 || it.second.size() == 2,
387 "weirdness, most likely bl_surfs are incorrect");
391 if (it.second.size() == 1)
393 vector<CADCurveSharedPtr> curves = it.first->GetCADCurves();
395 vector<EdgeSharedPtr> edges =
397 vector<EdgeSharedPtr>::iterator ie =
398 find(edges.begin(), edges.end(), it.second[0]);
400 (ie == edges.end()) ? curves[0]->GetId() : curves[1]->GetId();
402 vector<NodeSharedPtr> nodes =
404 nodeNormals[it.first] =
405 (nodes[0] == it.first) ? nodes[1] : nodes[nodes.size() - 2];
413 n[0] = (n1[0] + n2[0]) / 2.0;
414 n[1] = (n1[1] + n2[1]) / 2.0;
415 NekDouble mag = sqrt(n[0] * n[0] + n[1] * n[1]);
419 it.first->m_y, 0.0, 0.0);
423 if (adjustEverywhere || it.first->GetNumCadCurve() > 1)
425 NekDouble angle = acos(n1[0] * n2[0] + n1[1] * n2[1]);
426 angle = (angle > M_PI) ? 2 * M_PI - angle : angle;
427 t /= cos(angle / divider);
431 n[0] = n[0] * t + it.first->m_x;
432 n[1] = n[1] * t + it.first->m_y;
434 new Node(
m_mesh->m_numNodes++, n[0], n[1], 0.0));
437 nn->SetCADSurf(s, uv);
438 nodeNormals[it.first] = nn;
446 map<NodeSharedPtr, vector<NodeSharedPtr>> unitNormals;
448 map<NodeSharedPtr, NekDouble> dist;
464 Node r = *nodeNormals[
p] - *
p;
465 Node s = *nodeNormals[q] - *q;
482 if ((-0.5 < t && t <= 1.5) || (-0.5 < u && u <= 1.5))
484 dist[
p] = sqrt(r.
abs2());
485 dist[q] = sqrt(s.
abs2());
488 make_shared<Node>(r / dist[
p] + s / dist[q]);
490 unitNormals[
p].push_back(sum);
491 unitNormals[q].push_back(sum);
496 for (
const auto &it : unitNormals)
498 Node avg(0, 0.0, 0.0, 0.0);
500 for (
const auto &i : it.second)
505 avg /= sqrt(avg.
abs2());
509 new Node(nodeNormals[it.first]->GetID(),
510 it.first->m_x + avg.
m_x * dist[it.first],
511 it.first->m_y + avg.
m_y * dist[it.first], 0.0));
513 *nodeNormals[it.first]->GetCADSurfs().begin();
515 nn->SetCADSurf(s, uv);
517 nodeNormals[it.first] = nn;
519 }
while (unitNormals.size() && count++ < 50);
525 cout <<
"\t\tNormals smoothed in " << count <<
" iterations." 530 cout <<
"\t\tNormals smoothed. Algorithm didn't converge after " 531 << count <<
" iterations." << endl;
539 if (spaceoutthr < 0.0 || spaceoutthr > 1.0)
541 WARNINGL0(
false,
"The boundary layer space out threshold should be " 542 "between 0 and 1. It will now be adjusted to " 547 vector<unsigned int> nospaceoutsurf;
552 vector<deque<NodeSharedPtr>> nodesToMove;
565 auto it =
find(nospaceoutsurf.begin(), nospaceoutsurf.end(),
566 ie->m_parentCAD->GetId());
567 if (it != nospaceoutsurf.end())
576 m_mesh->m_octree->Query(((*n1 + *n2) / 2.0).GetLoc());
577 NekDouble realD = sqrt((*n1 - *n2).abs2());
580 if (realD < spaceoutthr * targetD)
582 bool connected =
false;
584 for (
auto &il : nodesToMove)
586 if (il.front() == n1)
592 if (il.front() == n2)
615 deque<NodeSharedPtr> newList;
616 newList.push_back(n1);
617 newList.push_back(n2);
619 nodesToMove.push_back(newList);
624 for (
int i = 0;; ++i)
629 for (
int i1 = 0; i1 < nodesToMove.size(); ++i1)
634 for (
int i2 = i1 + 1; i2 < nodesToMove.size(); ++i2)
639 if (n11 == n21 || n11 == n22 || n12 == n21 ||
642 if (n11 == n21 || n12 == n22)
644 reverse(nodesToMove[i2].begin(),
645 nodesToMove[i2].end());
646 n21 = nodesToMove[i2].front();
647 n22 = nodesToMove[i2].back();
652 nodesToMove[i1].insert(nodesToMove[i1].begin(),
653 nodesToMove[i2].begin(),
654 nodesToMove[i2].end() -
659 nodesToMove[i1].insert(nodesToMove[i1].end(),
660 nodesToMove[i2].begin() +
662 nodesToMove[i2].end());
665 nodesToMove.erase(nodesToMove.begin() + i2);
676 set<EdgeSharedPtr> addedEdges;
680 for (
auto &il : nodesToMove)
688 for (
const auto &ie : m_blEdges)
691 find(nospaceoutsurf.begin(), nospaceoutsurf.end(),
692 ie->m_parentCAD->GetId());
693 if (addedEdges.count(ie) || it != nospaceoutsurf.end())
705 if (n11 == n21 && n12 != n22)
709 else if (n11 == n22 && n12 != n21)
716 il.push_front(frontPush);
718 addedEdges.insert(ie);
721 if (n14 && !frontPush)
723 if (n14 == n21 && n13 != n22)
727 if (n14 == n22 && n13 != n21)
734 il.push_back(backPush);
736 addedEdges.insert(ie);
751 for (
const auto &il : nodesToMove)
756 vector<NekDouble> deltas;
759 for (
int i = 0; i < il.size() - 1; ++i)
765 m_mesh->m_octree->Query(((*n1 + *n2) / 2.0).GetLoc()));
766 total += deltas.back();
769 for (
auto &
id : deltas)
776 for (
int i = 1; i < il.size() - 1; ++i)
778 runningTotal += deltas[i - 1];
780 (*ni * (1.0 - runningTotal) + *nf * runningTotal)
784 m_mesh->m_cad->GetSurf(faceid)->locuv(loc);
786 il[i]->Move(loc, faceid, uv);
789 }
while (nodesToMove.size() && count++ < 50);
795 cout <<
"\t\tBL spaced out in " << count <<
" iterations." 800 cout <<
"\t\tBL spaced out. Algorithm didn't converge after " 801 << count <<
" iterations." << endl;
806 for (
auto &it : m_blCurves)
809 m_mesh->m_cad->GetCurve(it)->GetOrienationWRT(faceid);
810 vector<NodeSharedPtr> ns =
m_curvemeshes[it]->GetMeshPoints();
811 vector<NodeSharedPtr> newNs;
814 newNs.push_back(nodeNormals[in]);
820 reverse(ns.begin(), ns.end());
822 for (
int i = 0; i < ns.size() - 1; ++i)
824 vector<NodeSharedPtr> qns;
825 qns.push_back(ns[i]);
826 qns.push_back(ns[i + 1]);
827 qns.push_back(nodeNormals[ns[i + 1]]);
828 qns.push_back(nodeNormals[ns[i]]);
834 E->m_parentCAD =
m_mesh->m_cad->GetSurf(faceid);
835 for (
int j = 0; j < E->GetEdgeCount(); ++j)
837 pair<EdgeSet::iterator, bool> testIns;
840 EdgeSet::iterator s =
m_mesh->m_edgeSet.find(ed);
841 if (!(s ==
m_mesh->m_edgeSet.end()))
847 m_mesh->m_element[2].push_back(E);
855 set<unsigned> periodic;
858 string s =
m_config[
"periodic"].as<
string>();
859 vector<string> lines;
861 boost::split(lines, s, boost::is_any_of(
":"));
863 for (
auto &il : lines)
866 boost::split(tmp, il, boost::is_any_of(
","));
868 ASSERTL0(tmp.size() == 2,
"periodic pairs ill-defined");
870 vector<unsigned> data(2);
871 data[0] = boost::lexical_cast<
unsigned>(tmp[0]);
872 data[1] = boost::lexical_cast<
unsigned>(tmp[1]);
874 ASSERTL0(!periodic.count(data[0]),
"curve already periodic");
875 ASSERTL0(!periodic.count(data[1]),
"curve already periodic");
878 periodic.insert(data[0]);
879 periodic.insert(data[1]);
894 cout <<
"\t\tPeriodic boundary conditions" << endl;
895 for (
auto &it : m_periodicPairs)
897 cout <<
"\t\t\tCurves " << it.first <<
" => " << it.second << endl;
907 int ns =
m_mesh->m_vertexSet.size();
908 int es =
m_mesh->m_edgeSet.size();
909 int ts =
m_mesh->m_element[2].size();
910 int ep = ns - es + ts;
911 cout << endl <<
"\tSurface mesh statistics" << endl;
912 cout <<
"\t\tNodes: " << ns << endl;
913 cout <<
"\t\tEdges: " << es << endl;
914 cout <<
"\t\tTriangles " << ts << endl;
915 cout <<
"\t\tEuler-Poincaré characteristic: " << ep << endl;
std::shared_ptr< CADSurf > CADSurfSharedPtr
#define ASSERTL0(condition, msg)
Basic information about an element.
int PrintProgressbar(const int position, const int goal, const std::string message, int lastprogress=-1)
Prints a progressbar.
int DefineFunction(const std::string &vlist, const std::string &expr)
Defines a function for the purposes of evaluation.
NEKMESHUTILS_EXPORT NekDouble abs2() const
std::vector< unsigned int > m_blCurves
list of curves needing a BL
NekDouble Evaluate(const int id)
Evaluate a function which depends only on constants and/or parameters.
std::map< int, FaceMeshSharedPtr > m_facemeshes
map of individual surface meshes from parametric surfaces
NekDouble m_y
Y-coordinate.
MeshSharedPtr m_mesh
Mesh object.
std::shared_ptr< Edge > EdgeSharedPtr
Shared pointer to an edge.
std::shared_ptr< Mesh > MeshSharedPtr
Shared pointer to a mesh.
ElementFactory & GetElementFactory()
std::map< unsigned, unsigned > m_blends
map of curves and Bl ends: 0, 1 or 2 (for both)
Represents a point in the domain.
std::shared_ptr< Node > NodeSharedPtr
int m_thickness_ID
BL thickness expression ID.
std::map< unsigned, unsigned > m_periodicPairs
map of periodic curve pairs
LibUtilities::Interpreter m_thickness
BL thickness expression.
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
std::pair< ModuleType, std::string > ModuleKey
virtual NEKMESHUTILS_EXPORT void ProcessFaces(bool ReprocessFaces=true)
Extract element faces.
std::shared_ptr< Element > ElementSharedPtr
virtual NEKMESHUTILS_EXPORT void ProcessElements()
Generate element IDs.
Represents a command-line configuration option.
#define WARNINGL0(condition, msg)
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
std::vector< EdgeSharedPtr > m_blEdges
list of BL edges
std::map< std::string, ConfigOption > m_config
List of configuration values.
NEKMESHUTILS_EXPORT Node curl(const Node &pSrc) const
NekDouble m_x
X-coordinate.
Abstract base class for processing modules.
virtual NEKMESHUTILS_EXPORT void ProcessVertices()
Extract element vertices.
virtual NEKMESHUTILS_EXPORT void ProcessEdges(bool ReprocessEdges=true)
Extract element edges.
InputIterator find(InputIterator first, InputIterator last, InputIterator startingpoint, const EqualityComparable &value)
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
std::map< NodeSharedPtr, std::vector< EdgeSharedPtr > > m_nodesToEdge
map of BL curve nodes to adjacent edges
NekDouble m_z
Z-coordinate.
std::pair< ModuleType, std::string > ModuleKey
std::map< int, CurveMeshSharedPtr > m_curvemeshes
map of individual curve meshes of the curves in the domain
virtual NEKMESHUTILS_EXPORT void ProcessComposites()
Generate composites.
ModuleFactory & GetModuleFactory()
static bool GenerateSeqVector(const std::string &str, std::vector< unsigned int > &out)
Takes a comma-separated compressed string and converts it to entries in a vector. ...