Nektar++
HOSurfaceMesh.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: SurfaceMeshing.cpp
4 //
5 // For more information, please see: http://www.nektar.info/
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 //
31 // Description: surfacemeshing object methods.
32 //
33 ////////////////////////////////////////////////////////////////////////////////
34 
35 #include <algorithm>
36 #include <list>
37 
43 
46 #include <LocalRegions/MatrixKey.h>
47 
48 using namespace std;
49 namespace Nektar
50 {
51 namespace NekMeshUtils
52 {
53 
54 ModuleKey HOSurfaceMesh::className = GetModuleFactory().RegisterCreatorFunction(
55  ModuleKey(eProcessModule, "hosurface"), HOSurfaceMesh::create,
56  "Generates a high-order surface mesh based on CAD");
57 
58 HOSurfaceMesh::HOSurfaceMesh(MeshSharedPtr m) : ProcessModule(m)
59 {
60  m_config["opti"] =
61  ConfigOption(true, "0", "Perform edge node optimisation.");
62 }
63 
65 {
66 }
67 
69 {
70  if (m_mesh->m_verbose)
71  cout << endl << "\tHigh-Order Surface meshing" << endl;
72 
73  LibUtilities::PointsKey ekey(m_mesh->m_nummode,
76 
77  LibUtilities::PointsManager()[ekey]->GetPoints(gll);
78 
79  LibUtilities::PointsKey pkey(m_mesh->m_nummode,
81 
83 
84  int nq = m_mesh->m_nummode;
85 
86  int np = nq * (nq + 1) / 2;
87 
88  int ni = (nq - 2) * (nq - 3) / 2;
89 
90  int npq = nq * nq;
91 
92  int niq = npq - 4 - 4 * (nq - 2);
93 
94  LibUtilities::PointsManager()[pkey]->GetPoints(u, v);
95 
96  bool qOpti = m_config["opti"].beenSet;
97 
98  // loop over all the faces in the surface mesh, check all three edges for
99  // high order info, if nothing high-order the edge.
100 
101  EdgeSet surfaceEdges;
102  EdgeSet completedEdges;
103 
104  for (int i = 0; i < m_mesh->m_element[2].size(); i++)
105  {
106  vector<EdgeSharedPtr> es = m_mesh->m_element[2][i]->GetEdgeList();
107  for (int j = 0; j < es.size(); j++)
108  surfaceEdges.insert(es[j]);
109  }
110 
111  for (int i = 0; i < m_mesh->m_element[2].size(); i++)
112  {
113  if (m_mesh->m_verbose)
114  {
115  LibUtilities::PrintProgressbar(i, m_mesh->m_element[2].size(),
116  "\t\tSurface elements");
117  }
118 
119  if (!m_mesh->m_element[2][i]->m_parentCAD)
120  {
121  // no parent cad
122  continue;
123  }
124 
125  CADObjectSharedPtr o = m_mesh->m_element[2][i]->m_parentCAD;
126  CADSurfSharedPtr s = std::dynamic_pointer_cast<CADSurf>(o);
127  int surf = s->GetId();
128 
129  FaceSharedPtr f = m_mesh->m_element[2][i]->GetFaceLink();
130 
131  bool dumFace = false;
132 
133  if (!f)
134  {
135  //This uses a fake face to build the high-order info
136  //in the case of 2D and manifold geometries without having to
137  //rewrite the 3D code
138  //important to note that face nodes need to be inserted into the
139  //volume nodes of the surface element or they will be forgotton
140  f = std::shared_ptr<Face>(new Face(
141  m_mesh->m_element[2][i]->GetVertexList(),
142  vector<NodeSharedPtr>(), m_mesh->m_element[2][i]->GetEdgeList(),
144 
145  dumFace = true;
146  }
147 
148  f->m_parentCAD = s;
149 
150  vector<EdgeSharedPtr> edges = f->m_edgeList;
151  for (int j = 0; j < edges.size(); j++)
152  {
153  EdgeSharedPtr e = edges[j];
154  // test insert the edge into completedEdges
155  // if the edge already exists move on
156  // if not figure out its high-order information
157 
158  EdgeSet::iterator test = completedEdges.find(e);
159 
160  if (test != completedEdges.end())
161  {
162  continue;
163  }
164 
165  // the edges in the element are different to those in the face
166  // the cad information is stored in the element edges which are not
167  // in the m_mesh->m_edgeSet groups
168  // need to link them together and copy the cad information to be
169  // able to identify how to make it high-order
170  EdgeSet::iterator it = surfaceEdges.find(e);
171  ASSERTL0(it != surfaceEdges.end(),
172  "could not find edge in surface");
173 
174  if ((*it)->m_parentCAD)
175  {
176  e->m_parentCAD = (*it)->m_parentCAD;
177  }
178  else
179  {
180  e->m_parentCAD = s;
181  }
182 
183  vector<NodeSharedPtr> honodes(m_mesh->m_nummode - 2);
184 
185  if (e->m_parentCAD->GetType() == CADType::eCurve)
186  {
187  int cid = e->m_parentCAD->GetId();
189  std::dynamic_pointer_cast<CADCurve>(e->m_parentCAD);
190  NekDouble tb = e->m_n1->GetCADCurveInfo(cid);
191  NekDouble te = e->m_n2->GetCADCurveInfo(cid);
192 
193  // distrobute points along curve as inital guess
194  Array<OneD, NekDouble> ti(m_mesh->m_nummode);
195  for (int k = 0; k < m_mesh->m_nummode; k++)
196  {
197  ti[k] =
198  tb * (1.0 - gll[k]) / 2.0 + te * (1.0 + gll[k]) / 2.0;
199  }
200 
201  if (qOpti)
202  {
203  Array<OneD, NekDouble> xi(nq - 2);
204  for (int k = 1; k < nq - 1; k++)
205  {
206  xi[k - 1] = ti[k];
207  }
208 
209  OptiEdgeSharedPtr opti =
211 
212  DNekMat B(nq - 2, nq - 2,
213  0.0); // approximate hessian (I to start)
214  for (int k = 0; k < nq - 2; k++)
215  {
216  B(k, k) = 1.0;
217  }
218  DNekMat H(nq - 2, nq - 2,
219  0.0); // approximate inverse hessian (I to start)
220  for (int k = 0; k < nq - 2; k++)
221  {
222  H(k, k) = 1.0;
223  }
224 
225  DNekMat J = opti->dF(xi);
226 
227  Array<OneD, NekDouble> bnds = c->GetBounds();
228 
229  bool repeat = true;
230  int itct = 0;
231  while (repeat)
232  {
233  NekDouble Norm = 0;
234  for (int k = 0; k < nq - 2; k++)
235  {
236  Norm += J(k, 0) * J(k, 0) / (bnds[1] - bnds[0]) /
237  (bnds[1] - bnds[0]);
238  }
239  Norm = sqrt(Norm);
240 
241  if (Norm < 1E-8)
242  {
243  repeat = false;
244  break;
245  }
246  if (itct > 1000)
247  {
248  cout << "failed to optimise on curve" << endl;
249  for (int k = 0; k < nq; k++)
250  {
251  ti[k] = tb * (1.0 - gll[k]) / 2.0 +
252  te * (1.0 + gll[k]) / 2.0;
253  }
254  break;
255  }
256  itct++;
257 
258  if (!BGFSUpdate(opti, J, B, H))
259  {
260  if (m_mesh->m_verbose)
261  {
262  cout << "BFGS reported no update, curve on "
263  << c->GetId() << endl;
264  }
265  break;
266  }
267  }
268  // need to pull the solution out of opti
269  ti = opti->GetSolution();
270  }
271  vector<pair<CADSurfSharedPtr, CADOrientation::Orientation>> s =
272  c->GetAdjSurf();
273 
274  for (int k = 1; k < m_mesh->m_nummode - 1; k++)
275  {
276  Array<OneD, NekDouble> loc = c->P(ti[k]);
277  NodeSharedPtr nn = std::shared_ptr<Node>(
278  new Node(0, loc[0], loc[1], loc[2]));
279 
280  nn->SetCADCurve(c, ti[k]);
281  for (int m = 0; m < s.size(); m++)
282  {
283  Array<OneD, NekDouble> uv = s[m].first->locuv(loc);
284  nn->SetCADSurf(s[m].first, uv);
285  }
286 
287  honodes[k - 1] = nn;
288  }
289  }
290  else
291  {
292  // edge is on surface and needs 2d optimisation
293  Array<OneD, NekDouble> uvb, uve;
294  uvb = e->m_n1->GetCADSurfInfo(surf);
295  uve = e->m_n2->GetCADSurfInfo(surf);
296 
297  Array<OneD, NekDouble> l1 = e->m_n1->GetLoc();
298  Array<OneD, NekDouble> l2 = e->m_n2->GetLoc();
299 
300  e->m_parentCAD = s;
302 
303  for (int k = 0; k < nq; k++)
304  {
306  uv[0] = uvb[0] * (1.0 - gll[k]) / 2.0 +
307  uve[0] * (1.0 + gll[k]) / 2.0;
308  uv[1] = uvb[1] * (1.0 - gll[k]) / 2.0 +
309  uve[1] * (1.0 + gll[k]) / 2.0;
310  uvi[k] = uv;
311  }
312 
313  if (qOpti)
314  {
315  Array<OneD, NekDouble> bnds = s->GetBounds();
316  Array<OneD, NekDouble> all(2 * nq);
317  for (int k = 0; k < nq; k++)
318  {
319  all[k * 2 + 0] = uvi[k][0];
320  all[k * 2 + 1] = uvi[k][1];
321  }
322 
323  Array<OneD, NekDouble> xi(2 * (nq - 2));
324  for (int k = 1; k < nq - 1; k++)
325  {
326  xi[(k - 1) * 2 + 0] = all[k * 2 + 0];
327  xi[(k - 1) * 2 + 1] = all[k * 2 + 1];
328  }
329 
330  OptiEdgeSharedPtr opti =
332 
333  DNekMat B(2 * (nq - 2), 2 * (nq - 2),
334  0.0); // approximate hessian (I to start)
335  for (int k = 0; k < 2 * (nq - 2); k++)
336  {
337  B(k, k) = 1.0;
338  }
339  DNekMat H(2 * (nq - 2), 2 * (nq - 2),
340  0.0); // approximate inverse hessian (I to start)
341  for (int k = 0; k < 2 * (nq - 2); k++)
342  {
343  H(k, k) = 1.0;
344  }
345 
346  DNekMat J = opti->dF(xi);
347 
348  bool repeat = true;
349  int itct = 0;
350  while (repeat)
351  {
352  NekDouble Norm = 0;
353  for (int k = 0; k < 2 * (nq - 2); k++)
354  {
355  if (k % 2 == 0)
356  {
357  Norm +=
358  J(k, 0) * J(k, 0); // (bnds[1] - bnds[0]) /
359  //(bnds[1] - bnds[0]);
360  }
361  else
362  {
363  Norm +=
364  J(k, 0) * J(k, 0); // (bnds[3] - bnds[2]) /
365  //(bnds[3] - bnds[2]);
366  }
367  }
368  Norm = sqrt(Norm);
369 
370  if (Norm < 2E-2)
371  {
372  repeat = false;
373  break;
374  }
375 
376  if (itct > 1000)
377  {
378  cout << "failed to optimise on edge " << Norm
379  << endl;
380  for (int k = 0; k < nq; k++)
381  {
383  uv[0] = uvb[0] * (1.0 - gll[k]) / 2.0 +
384  uve[0] * (1.0 + gll[k]) / 2.0;
385  uv[1] = uvb[1] * (1.0 - gll[k]) / 2.0 +
386  uve[1] * (1.0 + gll[k]) / 2.0;
387  uvi[k] = uv;
388  }
389  break;
390  }
391  itct++;
392 
393  if (!BGFSUpdate(opti, J, B, H))
394  {
395  if (m_mesh->m_verbose)
396  {
397  cout << "BFGS reported no update, edge on "
398  << surf << endl;
399  }
400  // exit(-1);
401  break;
402  }
403  }
404 
405  all = opti->GetSolution();
406 
407  // need to put all backinto uv
408  for (int k = 0; k < nq; k++)
409  {
410  uvi[k][0] = all[k * 2 + 0];
411  uvi[k][1] = all[k * 2 + 1];
412  }
413  }
414 
415  for (int k = 1; k < nq - 1; k++)
416  {
417  Array<OneD, NekDouble> loc = s->P(uvi[k]);
418  NodeSharedPtr nn = std::shared_ptr<Node>(
419  new Node(0, loc[0], loc[1], loc[2]));
420  nn->SetCADSurf(s, uvi[k]);
421  honodes[k - 1] = nn;
422  }
423  }
424 
425  e->m_edgeNodes = honodes;
426  e->m_curveType = LibUtilities::eGaussLobattoLegendre;
427  completedEdges.insert(e);
428  }
429 
430  // just add the face interior nodes through interp and project
431  vector<NodeSharedPtr> vertices = f->m_vertexList;
432 
433  SpatialDomains::GeometrySharedPtr geom = f->GetGeom(3);
434  geom->FillGeom();
435  StdRegions::StdExpansionSharedPtr xmap = geom->GetXmap();
436  Array<OneD, NekDouble> coeffs0 = geom->GetCoeffs(0);
437  Array<OneD, NekDouble> coeffs1 = geom->GetCoeffs(1);
438  Array<OneD, NekDouble> coeffs2 = geom->GetCoeffs(2);
439 
440  Array<OneD, NekDouble> xc(xmap->GetTotPoints());
441  Array<OneD, NekDouble> yc(xmap->GetTotPoints());
442  Array<OneD, NekDouble> zc(xmap->GetTotPoints());
443 
444  xmap->BwdTrans(coeffs0,xc);
445  xmap->BwdTrans(coeffs1,yc);
446  xmap->BwdTrans(coeffs2,zc);
447 
448  if(vertices.size() == 3)
449  {
450  //build an array of all uvs
451  vector<Array<OneD, NekDouble> > uvi;
452  for(int j = np-ni; j < np; j++)
453  {
455  xp[0] = u[j];
456  xp[1] = v[j];
457 
459  loc[0] = xmap->PhysEvaluate(xp, xc);
460  loc[1] = xmap->PhysEvaluate(xp, yc);
461  loc[2] = xmap->PhysEvaluate(xp, zc);
462 
463  Array<OneD, NekDouble> uv = s->locuv(loc);
464  uvi.push_back(uv);
465  }
466 
467  vector<NodeSharedPtr> honodes;
468  for(int j = 0; j < ni; j++)
469  {
471  loc = s->P(uvi[j]);
472  NodeSharedPtr nn = std::shared_ptr<Node>(new
473  Node(0,loc[0],loc[1],loc[2]));
474  nn->SetCADSurf(s, uvi[j]);
475  honodes.push_back(nn);
476  }
477 
478  f->m_faceNodes = honodes;
479  f->m_curveType = LibUtilities::eNodalTriElec;
480  }
481  else if(vertices.size() == 4)
482  {
483  //build an array of all uvs
484  vector<Array<OneD, NekDouble> > uvi;
485  for(int i = 1; i < nq - 1; i++)
486  {
487  for(int j = 1; j < nq - 1; j++)
488  {
490  xp[0] = gll[j];
491  xp[1] = gll[i];
492 
494  loc[0] = xmap->PhysEvaluate(xp, xc);
495  loc[1] = xmap->PhysEvaluate(xp, yc);
496  loc[2] = xmap->PhysEvaluate(xp, zc);
497 
498  Array<OneD, NekDouble> uv = s->locuv(loc);
499  uvi.push_back(uv);
500  }
501  }
502 
503  vector<NodeSharedPtr> honodes;
504  for(int j = 0; j < niq; j++)
505  {
507  loc = s->P(uvi[j]);
508  NodeSharedPtr nn = std::shared_ptr<Node>(new
509  Node(0,loc[0],loc[1],loc[2]));
510  nn->SetCADSurf(s, uvi[j]);
511  honodes.push_back(nn);
512  }
513 
514  f->m_faceNodes = honodes;
515  f->m_curveType = LibUtilities::eGaussLobattoLegendre;
516  }
517 
518  if(dumFace)
519  {
520  m_mesh->m_element[2][i]->SetVolumeNodes(f->m_faceNodes);
521  m_mesh->m_element[2][i]->SetCurveType(f->m_curveType);
522  }
523  }
524 
525  if (m_mesh->m_verbose)
526  cout << endl;
527 }
528 }
529 }
std::shared_ptr< CADSurf > CADSurfSharedPtr
Definition: CADCurve.h:51
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
base class for CAD curves.
Definition: CADCurve.h:58
int PrintProgressbar(const int position, const int goal, const std::string message, int lastprogress=-1)
Prints a progressbar.
Definition: Progressbar.hpp:67
std::shared_ptr< OptiEdge > OptiEdgeSharedPtr
std::unordered_set< EdgeSharedPtr, EdgeHash > EdgeSet
Definition: Edge.h:159
int GetId()
Return ID of the CAD object.
Definition: CADObject.h:84
Represents a face comprised of three or more edges.
Definition: Face.h:63
STL namespace.
std::shared_ptr< Edge > EdgeSharedPtr
Shared pointer to an edge.
Definition: Edge.h:136
std::shared_ptr< Mesh > MeshSharedPtr
Shared pointer to a mesh.
Definition: Mesh.h:156
std::shared_ptr< Node > NodeSharedPtr
Definition: CADVert.h:49
std::shared_ptr< Face > FaceSharedPtr
Definition: Face.h:155
1D Evenly-spaced points using Lagrange polynomial
Definition: PointsType.h:64
std::shared_ptr< StdExpansion > StdExpansionSharedPtr
std::pair< ModuleType, std::string > ModuleKey
std::shared_ptr< CADCurve > CADCurveSharedPtr
Definition: CADCurve.h:219
Represents a command-line configuration option.
std::shared_ptr< Geometry > GeometrySharedPtr
Definition: Geometry.h:53
base class for a cad surface
Definition: CADSurf.h:71
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
PointsManagerT & PointsManager(void)
Defines a specification for a set of points.
Definition: Points.h:59
double NekDouble
std::map< std::string, ConfigOption > m_config
List of configuration values.
std::shared_ptr< CADObject > CADObjectSharedPtr
Definition: CADObject.h:133
Abstract base class for processing modules.
bool BGFSUpdate(OptiObjSharedPtr opti, DNekMat &J, DNekMat &B, DNekMat &H)
Definition: BGFS-B.cpp:49
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:199
1D Gauss-Lobatto-Legendre quadrature points
Definition: PointsType.h:51
2D Nodal Electrostatic Points on a Triangle
Definition: PointsType.h:69
ModuleFactory & GetModuleFactory()