35 #include <boost/geometry.hpp> 36 #include <boost/geometry/geometries/point.hpp> 37 #include <boost/geometry/geometries/box.hpp> 38 #include <boost/geometry/index/rtree.hpp> 53 namespace bg = boost::geometry;
54 namespace bgi = boost::geometry::index;
59 #define TOL_BLEND 1.0e-8 101 ConfigOption(
false,
"5",
"Number of points to add to face edges.");
103 ConfigOption(
false,
"-1",
"Tag identifying surface to process.");
105 true,
"-1",
"Curve both triangular faces of prism on boundary.");
107 false,
"NoFile",
"Use alternative file for Spherigon definition");
109 false,
"1.0",
"Apply scaling factor to coordinates in file ");
113 "Add randowm noise to normals of amplitude AMP " 114 "in specified region. input string is " 115 "Amp,xmin,xmax,ymin,ymax,zmin,zmax");
153 return sqrt(tmp1 * tmp1 + tmp2 * tmp2 + tmp3 * tmp3);
183 vector<double> &blend)
185 vector<double> tmp(r.size());
186 double totBlend = 0.0;
190 for (i = 0; i < nV; ++i)
193 tmp[i] = (Q[i] -
P).abs2();
196 for (i = 0; i < nV; ++i)
198 int ip = (i + 1) % nV, im = (i - 1 + nV) % nV;
203 r[i] * r[i] * (r[im] * r[im] * tmp[im] / (tmp[im] + tmp[i]) +
204 r[ip] * r[ip] * tmp[ip] / (tmp[ip] + tmp[i]));
205 totBlend += blend[i];
209 for (i = 0; i < nV; ++i)
211 blend[i] /= totBlend;
224 map<int,NodeSharedPtr> &surfverts)
230 typedef bg::model::point<NekDouble, 3, bg::cs::cartesian>
Point;
231 typedef pair<Point, unsigned int> PointI;
235 map<int,int> TreeidtoPlyid;
238 vector<PointI> dataPts;
239 for (
auto &it : plymesh->m_vertexSet)
241 dataPts.push_back(make_pair(Point(it->m_x, it->m_y, it->m_z), j));
242 TreeidtoPlyid[j++] = it->m_id;
246 bgi::rtree<PointI, bgi::rstar<16> > rtree;
247 rtree.insert(dataPts.begin(), dataPts.end());
250 for (
auto &vIt : surfverts)
255 "Nearest ply verts",prog);
258 Point queryPt(vIt.second->m_x, vIt.second->m_y, vIt.second->m_z);
259 vector<PointI> result;
260 rtree.query(bgi::nearest(queryPt, n_neighbs),
261 std::back_inserter(result));
263 cntmin = TreeidtoPlyid[result[0].second];
265 ASSERTL1(cntmin < plymesh->m_vertexNormals.size(),
266 "cntmin is out of range");
268 m_mesh->m_vertexNormals[vIt.first] =
269 plymesh->m_vertexNormals[cntmin];
290 for (
int i = 0; i < el.size(); ++i)
298 "Spherigon expansions must be lines, triangles or " 302 int nV = e->GetVertexCount();
303 vector<NodeSharedPtr> node(nV);
305 for (
int j = 0; j < nV; ++j)
307 node[j] = e->GetVertex(j);
312 if (mesh->m_spaceDim == 3)
315 Node v1 = *(node[1]) - *(node[0]);
316 Node v2 = *(node[2]) - *(node[0]);
322 Node dx = *(node[1]) - *(node[0]);
332 for (
int j = 0; j < nV; ++j)
334 auto nIt = mesh->m_vertexNormals.find(e->GetVertex(j)->m_id);
335 if (nIt == mesh->m_vertexNormals.end())
337 mesh->m_vertexNormals[e->GetVertex(j)->m_id] = n;
347 for (
auto &nIt : mesh->m_vertexNormals)
349 Node &n = nIt.second;
361 "Spherigon implementation only valid in 2D/3D.");
363 std::unordered_set<int> visitedEdges;
366 vector<ElementSharedPtr> el;
370 cout <<
"ProcessSpherigon: Smoothing mesh..." << endl;
382 set<pair<int, int> >::iterator it;
387 string surfTag =
m_config[
"surf"].as<
string>();
388 bool prismTag =
m_config[
"BothTriFacesOnPrism"].beenSet;
392 vector<unsigned int> surfs;
394 sort(surfs.begin(), surfs.end());
396 m_mesh->m_spherigonSurfs.clear();
397 for (
int i = 0; i <
m_mesh->m_element[
m_mesh->m_expDim].size(); ++i)
400 int nSurf =
m_mesh->m_expDim == 3 ? el->GetFaceCount()
401 : el->GetEdgeCount();
403 for (
int j = 0; j < nSurf; ++j)
405 int bl = el->GetBoundaryLink(j);
413 vector<int> tags = bEl->GetTagList();
416 sort(tags.begin(), tags.end());
417 set_intersection(surfs.begin(),
421 back_inserter(inter));
423 if (inter.size() == 1)
425 m_mesh->m_spherigonSurfs.insert(make_pair(i, j));
429 if (nSurf == 5 && prismTag)
433 int triFace = j == 1 ? 3 : 1;
434 m_mesh->m_spherigonSurfs.insert(
435 make_pair(i, triFace));
442 if (
m_mesh->m_spherigonSurfs.size() == 0)
444 cerr <<
"WARNING: Spherigon surfaces have not been defined " 445 <<
"-- ignoring smoothing." << endl;
449 if (
m_mesh->m_expDim == 3)
451 for (it =
m_mesh->m_spherigonSurfs.begin();
452 it !=
m_mesh->m_spherigonSurfs.end();
456 m_mesh->m_element[
m_mesh->m_expDim][it->first]->GetFace(
458 vector<NodeSharedPtr> nodes = f->m_vertexList;
468 for (
int i = 0; i < f->m_vertexList.size(); ++i)
470 elmt->SetVertex(i, f->m_vertexList[i]);
472 for (
int i = 0; i < f->m_edgeList.size(); ++i)
474 elmt->SetEdge(i, f->m_edgeList[i]);
482 for (it =
m_mesh->m_spherigonSurfs.begin();
483 it !=
m_mesh->m_spherigonSurfs.end();
487 m_mesh->m_element[
m_mesh->m_expDim][it->first]->GetEdge(
489 vector<NodeSharedPtr> nodes;
493 nodes.push_back(edge->m_n1);
494 nodes.push_back(edge->m_n2);
501 elmt->SetVertex(0, nodes[0]);
502 elmt->SetVertex(1, nodes[1]);
505 m_mesh->m_element[
m_mesh->m_expDim][it->first]->GetEdge(
513 ASSERTL0(
false,
"Spherigon expansions must be 2/3 dimensional");
518 bool normalsGenerated =
false;
521 std::string normalfile =
m_config[
"usenormalfile"].as<
string>();
522 if (normalfile.compare(
"NoFile") != 0)
528 cout <<
"Inputing normal file: " << normalfile
529 <<
" with scaling of " << scale << endl;
533 io::filtering_istream inply;
536 inplyTmp.open(normalfile.c_str());
538 string(
"Could not open input ply file: ") + normalfile);
540 inply.push(inplyTmp);
543 plyfile = std::shared_ptr<InputPly>(
new InputPly(m));
544 plyfile->ReadPly(inply, scale);
545 plyfile->ProcessVertices();
550 cout <<
"\t Generating ply normals" << endl;
556 Node minx(0, 0.0, 0.0, 0.0), tmp, tmpsav;
557 NodeSet::iterator it;
558 map<int, NodeSharedPtr>::iterator vIt;
559 map<int, NodeSharedPtr> surfverts;
562 for (
int i = 0; i < el.size(); ++i)
565 int nV = e->GetVertexCount();
566 for (
int j = 0; j < nV; ++j)
568 int id = e->GetVertex(j)->m_id;
569 surfverts[id] = e->GetVertex(j);
576 cout <<
"\t Processing surface normals " << endl;
583 normalsGenerated =
true;
585 else if (
m_mesh->m_vertexNormals.size() == 0)
588 normalsGenerated =
true;
592 std::string normalnoise =
m_config[
"normalnoise"].as<
string>();
593 if (normalnoise.compare(
"NotSpecified") != 0)
595 vector<NekDouble> values;
597 "Failed to interpret normal noise string");
599 int nvalues = values.size() / 2;
604 cout <<
"\t adding noise to normals of amplitude " << amp
606 for (
int i = 0; i < nvalues; ++i)
608 cout << values[2 * i + 1] <<
"," << values[2 * i + 2] <<
" ";
613 map<int, NodeSharedPtr>::iterator vIt;
614 map<int, NodeSharedPtr> surfverts;
617 for (
int i = 0; i < el.size(); ++i)
620 int nV = e->GetVertexCount();
621 for (
int j = 0; j < nV; ++j)
623 int id = e->GetVertex(j)->m_id;
624 surfverts[id] = e->GetVertex(j);
628 for (vIt = surfverts.begin(); vIt != surfverts.end(); ++vIt)
630 bool AddNoise =
false;
632 for (
int i = 0; i < nvalues; ++i)
639 if (((vIt->second)->m_x > values[2 * i + 1]) &&
640 ((vIt->second)->m_x < values[2 * i + 2]))
648 if (((vIt->second)->m_x > values[2 * i + 1]) &&
649 ((vIt->second)->m_x < values[2 * i + 2]) &&
650 ((vIt->second)->m_y > values[2 * i + 3]) &&
651 ((vIt->second)->m_y < values[2 * i + 4]))
659 if (((vIt->second)->m_x > values[2 * i + 1]) &&
660 ((vIt->second)->m_x < values[2 * i + 2]) &&
661 ((vIt->second)->m_y > values[2 * i + 3]) &&
662 ((vIt->second)->m_y < values[2 * i + 4]) &&
663 ((vIt->second)->m_z > values[2 * i + 5]) &&
664 ((vIt->second)->m_z < values[2 * i + 6]))
676 Node rvec(0, rand(), rand(), rand());
677 rvec *= values[0] / sqrt(rvec.
abs2());
679 Node normal =
m_mesh->m_vertexNormals[vIt->first];
682 normal /= sqrt(normal.abs2());
684 m_mesh->m_vertexNormals[vIt->first] = normal;
692 int nquad =
m_mesh->m_spaceDim == 3 ? nq * nq : nq;
701 ASSERTL0(nq > 2,
"Number of points must be greater than 2.");
716 stdtri->GetNodalPoints(xnodal, ynodal);
718 int edgeMap[3][4][2] = {
719 {{0, 1}, {-1, -1}, {-1, -1}, {-1, -1}},
720 {{0, 1}, {nq - 1, nq}, {nq * (nq - 1), -nq}, {-1, -1}},
721 {{0, 1}, {nq - 1, nq}, {nq * nq - 1, -1}, {nq * (nq - 1), -nq}}
724 int vertMap[3][4][2] = {
725 {{0, 1}, {0, 0}, {0, 0}, {0, 0}},
726 {{0, 1}, {1, 2}, {2, 3}, {0, 0}},
727 {{0, 1}, {1, 2}, {2, 3}, {3, 0}},
730 for (
int i = 0; i < el.size(); ++i)
746 e->GetGeom(
m_mesh->m_spaceDim));
750 seg->GetCoords(x, y, z);
763 tri->GetCoords(xc, yc, zc);
764 nquad = nq * (nq + 1) / 2;
766 for (
int j = 0; j < nquad; ++j)
768 coord[0] = xnodal[j];
769 coord[1] = ynodal[j];
770 x[j] = stdtri->PhysEvaluate(coord, xc);
773 for (
int j = 0; j < nquad; ++j)
775 coord[0] = xnodal[j];
776 coord[1] = ynodal[j];
777 y[j] = stdtri->PhysEvaluate(coord, yc);
780 for (
int j = 0; j < nquad; ++j)
782 coord[0] = xnodal[j];
783 coord[1] = ynodal[j];
784 z[j] = stdtri->PhysEvaluate(coord, zc);
795 quad->GetCoords(x, y, z);
800 ASSERTL0(
false,
"Unknown expansion type.");
804 if (
m_mesh->m_spaceDim == 2)
810 int nV = e->GetVertexCount();
812 for (
int j = 0; j < nV; ++j)
814 v.push_back(*(e->GetVertex(j)));
816 "Normal has not been defined");
817 vN.push_back(
m_mesh->m_vertexNormals[v[j].m_id]);
820 vector<Node> tmp(nV);
821 vector<NekDouble> r(nV);
825 vector<NekDouble> blend(nV);
826 vector<Node> out(nquad);
829 NekDouble segLength = sqrt((v[0] - v[1]).abs2());
832 for (
int j = 0; j < nquad; ++j)
834 Node P(0, x[j], y[j], z[j]);
839 if (
m_mesh->m_spaceDim == 2)
844 r[0] = sqrt((P - v[0]).abs2()) / segLength;
845 r[0] = max(min(1.0, r[0]), 0.0);
849 N = vN[0] * r[0] + vN[1] * r[1];
851 else if (
m_mesh->m_spaceDim == 3)
853 for (
int k = 0; k < nV; ++k)
861 for (
int k = 0; k < nV; ++k)
864 for (
int l = 0; l < nV - 2; ++l)
867 tmp[(k + l + 2) % nV]);
873 for (
int k = 0; k < nV; ++k)
883 for (
int k = 0; k < nV; ++k)
888 K[k] = P + N * ((v[k] -
P).dot(N));
889 tmp1 = (v[k] - K[k]).dot(vN[k]) / (1.0 + N.
dot(vN[k]));
890 Q[k] = K[k] + N * tmp1;
891 Qp[k] = v[k] - N * ((v[k] -
P).dot(N));
900 for (
int k = 0; k < nV; ++k)
902 P += Q[k] * blend[k];
905 if ((boost::math::isnan)(P.
m_x) || (boost::math::isnan)(P.
m_y) ||
906 (boost::math::isnan)(P.
m_z))
909 "spherigon point is a nan. Check to see if " 910 "ply file is correct if using input normal file");
920 int offset = (int)e->GetConf().m_e - 2;
922 for (
int edge = 0; edge < e->GetEdgeCount(); ++edge)
924 auto eIt = visitedEdges.find(e->GetEdge(edge)->m_id);
925 if (eIt == visitedEdges.end())
928 !(v[vertMap[offset][edge][0]] == *(e->GetEdge(edge)->m_n1));
931 e->GetEdge(edge)->m_edgeNodes.clear();
935 for (
int j = 1; j < nq - 1; ++j)
937 int v = edgeMap[offset][edge][0] +
938 j * edgeMap[offset][edge][1];
939 e->GetEdge(edge)->m_edgeNodes.push_back(
945 for (
int j = 0; j < nq - 2; ++j)
947 int v = 3 + edge * (nq - 2) + j;
948 e->GetEdge(edge)->m_edgeNodes.push_back(
955 reverse(e->GetEdge(edge)->m_edgeNodes.begin(),
956 e->GetEdge(edge)->m_edgeNodes.end());
959 e->GetEdge(edge)->m_curveType =
962 visitedEdges.insert(e->GetEdge(edge)->m_id);
967 if (
m_mesh->m_spaceDim == 3)
969 vector<NodeSharedPtr> volNodes;
973 volNodes.resize((nq - 2) * (nq - 2));
974 for (
int j = 1; j < nq - 1; ++j)
976 for (
int k = 1; k < nq - 1; ++k)
979 volNodes[(j - 1) * (nq - 2) + (k - 1)] =
986 for (
int j = 3 + 3 * (nq - 2); j < nquad; ++j)
992 e->SetVolumeNodes(volNodes);
997 if (
m_mesh->m_expDim == 3)
1000 for (
auto &it :
m_mesh->m_spherigonSurfs)
1003 m_mesh->m_element[
m_mesh->m_expDim][it.first]->GetFace(
1006 f->m_faceNodes = el[elmt++]->GetVolumeNodes();
1007 f->m_curveType = f->m_vertexList.size() == 3
1013 if (normalsGenerated)
1015 m_mesh->m_vertexNormals.clear();
void UnitCrossProd(NekMeshUtils::Node &a, NekMeshUtils::Node &b, NekMeshUtils::Node &c)
NekDouble CrossProdMag(NekMeshUtils::Node &a, NekMeshUtils::Node &b)
Calculate the magnitude of the cross product .
#define ASSERTL0(condition, msg)
Basic information about an element.
std::shared_ptr< StdNodalTriExp > StdNodalTriExpSharedPtr
void FindNormalFromPlyFile(NekMeshUtils::MeshSharedPtr &plymesh, std::map< int, NekMeshUtils::NodeSharedPtr > &surfverts)
int PrintProgressbar(const int position, const int goal, const std::string message, int lastprogress=-1)
Prints a progressbar.
NEKMESHUTILS_EXPORT NekDouble abs2() const
virtual ~ProcessSpherigon()
Destructor.
std::shared_ptr< InputPly > InputPlySharedPtr
void SuperBlend(std::vector< NekDouble > &r, std::vector< NekMeshUtils::Node > &Q, NekMeshUtils::Node &P, std::vector< NekDouble > &blend)
Calculate the blending function for spherigon implementation.
std::shared_ptr< QuadGeom > QuadGeomSharedPtr
void GenerateNormals(std::vector< NekMeshUtils::ElementSharedPtr > &el, NekMeshUtils::MeshSharedPtr &mesh)
Generate a set of approximate vertex normals to a surface represented by line segments in 2D and a hy...
Principle Modified Functions .
NekDouble m_y
Y-coordinate.
NEKMESHUTILS_EXPORT NekDouble dot(const Node &pSrc) const
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()
Represents a point in the domain.
std::shared_ptr< Node > NodeSharedPtr
virtual void Process()
Write mesh to output file.
std::shared_ptr< NodalTriExp > NodalTriExpSharedPtr
Gauss Radau pinned at x=-1, .
std::shared_ptr< Face > FaceSharedPtr
Principle Orthogonal Functions .
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
std::shared_ptr< TriGeom > TriGeomSharedPtr
std::pair< ModuleType, std::string > ModuleKey
std::shared_ptr< Element > ElementSharedPtr
Represents a command-line configuration option.
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
Principle Orthogonal Functions .
Defines a specification for a set of points.
std::map< std::string, ConfigOption > m_config
List of configuration values.
static bool GenerateVector(const std::string &str, std::vector< T > &out)
Takes a comma-separated string and converts it to entries in a vector.
NekDouble m_x
X-coordinate.
Abstract base class for processing modules.
NekDouble Blend(NekDouble r)
Calculate the blending function for spherigon implementation.
std::shared_ptr< SegExp > SegExpSharedPtr
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
NekDouble m_z
Z-coordinate.
std::pair< ModuleType, std::string > ModuleKey
std::shared_ptr< QuadExp > QuadExpSharedPtr
void Zero(int n, T *x, const int incx)
Zero vector.
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode...
std::shared_ptr< SegGeom > SegGeomSharedPtr
Describes the specification for a Basis.
1D Gauss-Lobatto-Legendre quadrature points
2D Nodal Electrostatic Points on a Triangle
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. ...