Nektar++
TriGeom.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: TriGeom.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:
32 //
33 //
34 ////////////////////////////////////////////////////////////////////////////////
35 
36 #include <SpatialDomains/TriGeom.h>
40 
41 #include <SpatialDomains/SegGeom.h>
43 
44 using namespace std;
45 
46 namespace Nektar
47 {
48 namespace SpatialDomains
49 {
50 
51 TriGeom::TriGeom()
52 {
53  m_shapeType = LibUtilities::eTriangle;
54 }
55 
56 TriGeom::TriGeom(const int id,
57  const SegGeomSharedPtr edges[],
58  const CurveSharedPtr curve)
59  : Geometry2D(edges[0]->GetVertex(0)->GetCoordim(), curve)
60 {
61  int j;
62 
64  m_globalID = id;
65 
66  // Copy the edge shared pointers.
67  m_edges.insert(m_edges.begin(), edges, edges + TriGeom::kNedges);
68  m_eorient.resize(kNedges);
69 
70  for (j = 0; j < kNedges; ++j)
71  {
72  m_eorient[j] =
73  SegGeom::GetEdgeOrientation(*edges[j], *edges[(j + 1) % kNedges]);
74  m_verts.push_back(
75  edges[j]->GetVertex(m_eorient[j] == StdRegions::eForwards ? 0 : 1));
76  }
77 
80 
81  m_coordim = edges[0]->GetVertex(0)->GetCoordim();
82  ASSERTL0(m_coordim > 1, "Cannot call function with dim == 1");
83 }
84 
86  : Geometry2D(in)
87 {
88  // From Geometry
90 
91  // From TriFaceComponent
93 
94  // From TriGeom
95  m_verts = in.m_verts;
96  m_edges = in.m_edges;
97  for (int i = 0; i < kNedges; i++)
98  {
99  m_eorient[i] = in.m_eorient[i];
100  }
101 }
102 
104 {
105 }
106 
108  const Array<OneD, const NekDouble> &Lcoord)
109 {
110  ASSERTL1(m_state == ePtsFilled, "Geometry is not in physical space");
111 
112  Array<OneD, NekDouble> tmp(m_xmap->GetTotPoints());
113  m_xmap->BwdTrans(m_coeffs[i], tmp);
114 
115  return m_xmap->PhysEvaluate(Lcoord, tmp);
116 }
117 
119  const TriGeom &face2, bool doRot, int dir,
120  NekDouble angle, NekDouble tol)
121 {
122  return GetFaceOrientation(face1.m_verts, face2.m_verts,
123  doRot, dir, angle, tol);
124 }
125 
127  const PointGeomVector &face1, const PointGeomVector &face2,
128  bool doRot, int dir, NekDouble angle, NekDouble tol)
129 {
130  int i, j, vmap[3] = {-1, -1, -1};
131 
132  if(doRot)
133  {
134  PointGeom rotPt;
135 
136  for (i = 0; i < 3; ++i)
137  {
138  rotPt.Rotate((*face1[i]), dir, angle);
139  for (j = 0; j < 3; ++j)
140  {
141  if (rotPt.dist(*face2[j]) < tol)
142  {
143  vmap[j] = i;
144  break;
145  }
146  }
147  }
148  }
149  else
150  {
151 
152  NekDouble x, y, z, x1, y1, z1, cx = 0.0, cy = 0.0, cz = 0.0;
153 
154  // For periodic faces, we calculate the vector between the centre
155  // points of the two faces. (For connected faces this will be
156  // zero). We can then use this to determine alignment later in the
157  // algorithm.
158  for (i = 0; i < 3; ++i)
159  {
160  cx += (*face2[i])(0) - (*face1[i])(0);
161  cy += (*face2[i])(1) - (*face1[i])(1);
162  cz += (*face2[i])(2) - (*face1[i])(2);
163  }
164  cx /= 3;
165  cy /= 3;
166  cz /= 3;
167 
168  // Now construct a mapping which takes us from the vertices of one
169  // face to the other. That is, vertex j of face2 corresponds to
170  // vertex vmap[j] of face1.
171  for (i = 0; i < 3; ++i)
172  {
173  x = (*face1[i])(0);
174  y = (*face1[i])(1);
175  z = (*face1[i])(2);
176  for (j = 0; j < 3; ++j)
177  {
178  x1 = (*face2[j])(0) - cx;
179  y1 = (*face2[j])(1) - cy;
180  z1 = (*face2[j])(2) - cz;
181  if (sqrt((x1 - x) * (x1 - x) + (y1 - y) * (y1 - y) +
182  (z1 - z) * (z1 - z)) < 1e-8)
183  {
184  vmap[j] = i;
185  break;
186  }
187  }
188  }
189  }
190 
191  if (vmap[1] == (vmap[0] + 1) % 3)
192  {
193  switch (vmap[0])
194  {
195  case 0:
197  break;
198  case 1:
200  break;
201  case 2:
203  break;
204  }
205  }
206  else
207  {
208  switch (vmap[0])
209  {
210  case 0:
212  break;
213  case 1:
215  break;
216  case 2:
218  break;
219  }
220  }
221 
222  ASSERTL0(false, "Unable to determine triangle orientation");
224 }
225 
227 {
228  if(!m_setupState)
229  {
231  }
232 
234  {
235  GeomType Gtype = eRegular;
236 
238 
239  // check to see if expansions are linear
240  for (int i = 0; i < m_coordim; ++i)
241  {
242  if (m_xmap->GetBasisNumModes(0) != 2 ||
243  m_xmap->GetBasisNumModes(1) != 2)
244  {
245  Gtype = eDeformed;
246  }
247  }
248 
250  Gtype, m_coordim, m_xmap, m_coeffs);
251 
253  }
254 }
255 
256 /**
257  * Note verts and edges are listed according to anticlockwise
258  * convention but points in _coeffs have to be in array format from
259  * left to right.
260  */
262 {
263  // check to see if geometry structure is already filled
264  if (m_state == ePtsFilled)
265  {
266  return;
267  }
268 
269  int i, j, k;
270  int nEdgeCoeffs = m_xmap->GetTraceNcoeffs(0);
271 
272  if (m_curve)
273  {
275  2, m_curve->m_ptype)]
276  ->GetPointsDim();
277 
278  // Deal with 2D points type separately
279  // (e.g. electrostatic or Fekete points) to 1D tensor
280  // product.
281  if (pdim == 2)
282  {
283  int N = m_curve->m_points.size();
284  int nEdgePts =
285  (-1 + (int)sqrt(static_cast<NekDouble>(8 * N + 1))) / 2;
286 
287  ASSERTL0(nEdgePts * (nEdgePts + 1) / 2 == N,
288  "NUMPOINTS should be a triangle number for"
289  " triangle curved face " +
290  boost::lexical_cast<string>(m_globalID));
291 
292  // Sanity check 1: are curved vertices consistent with
293  // triangle vertices?
294  for (i = 0; i < 3; ++i)
295  {
296  NekDouble dist = m_verts[i]->dist(*(m_curve->m_points[i]));
298  {
299  std::stringstream ss;
300  ss << "Curved vertex " << i << " of triangle " << m_globalID
301  << " is separated from expansion vertex by"
302  << " more than " << NekConstants::kVertexTheSameDouble
303  << " (dist = " << dist << ")";
304  NEKERROR(ErrorUtil::ewarning, ss.str().c_str());
305  }
306  }
307 
308  // Sanity check 2: are curved edges from the face curvature
309  // consistent with curved edges?
310  for (i = 0; i < kNedges; ++i)
311  {
312  CurveSharedPtr edgeCurve = m_edges[i]->GetCurve();
313 
314  ASSERTL0(edgeCurve->m_points.size() == nEdgePts,
315  "Number of edge points does not correspond "
316  "to number of face points in triangle " +
317  boost::lexical_cast<string>(m_globalID));
318 
319  const int offset = 3 + i * (nEdgePts - 2);
320  NekDouble maxDist = 0.0;
321 
322  // Account for different ordering of nodal coordinates
323  // vs. Cartesian ordering of element.
325 
326  if (i == 2)
327  {
328  orient = orient == StdRegions::eForwards ?
330  }
331 
332  if (orient == StdRegions::eForwards)
333  {
334  for (j = 0; j < nEdgePts - 2; ++j)
335  {
336  NekDouble dist = m_curve->m_points[offset + j]->dist(
337  *(edgeCurve->m_points[j + 1]));
338  maxDist = dist > maxDist ? dist : maxDist;
339  }
340  }
341  else
342  {
343  for (j = 0; j < nEdgePts - 2; ++j)
344  {
345  NekDouble dist = m_curve->m_points[offset + j]->dist(
346  *(edgeCurve->m_points[nEdgePts - 2 - j]));
347  maxDist = dist > maxDist ? dist : maxDist;
348  }
349  }
350 
352  {
353  std::stringstream ss;
354  ss << "Curved edge " << i << " of triangle " << m_globalID
355  << " has a point separated from edge interior"
356  << " points by more than "
358  << " (maxdist = " << maxDist << ")";
359  NEKERROR(ErrorUtil::ewarning, ss.str().c_str());
360  }
361  }
362 
363  const LibUtilities::PointsKey P0(
365  const LibUtilities::PointsKey P1(
367  const LibUtilities::BasisKey T0(
368  LibUtilities::eOrtho_A, nEdgePts, P0);
369  const LibUtilities::BasisKey T1(
370  LibUtilities::eOrtho_B, nEdgePts, P1);
372  max(nEdgePts * nEdgePts, m_xmap->GetTotPoints()));
373  Array<OneD, NekDouble> tmp(nEdgePts * nEdgePts);
374 
375  for (i = 0; i < m_coordim; ++i)
376  {
377  // Create a StdNodalTriExp.
380  AllocateSharedPtr(T0, T1, m_curve->m_ptype);
381 
382  for (j = 0; j < N; ++j)
383  {
384  phys[j] = (m_curve->m_points[j]->GetPtr())[i];
385  }
386 
387  t->BwdTrans(phys, tmp);
388 
389  // Interpolate points to standard region.
391  P1,
392  tmp,
393  m_xmap->GetBasis(0)->GetPointsKey(),
394  m_xmap->GetBasis(1)->GetPointsKey(),
395  phys);
396 
397  // Forwards transform to get coefficient space.
398  m_xmap->FwdTrans(phys, m_coeffs[i]);
399  }
400  }
401  else if (pdim == 1)
402  {
403  int npts = m_curve->m_points.size();
404  int nEdgePts = (int)sqrt(static_cast<NekDouble>(npts));
405  Array<OneD, NekDouble> tmp(npts);
406  Array<OneD, NekDouble> phys(m_xmap->GetTotPoints());
407  LibUtilities::PointsKey curveKey(nEdgePts, m_curve->m_ptype);
408 
409  // Sanity checks:
410  // - Curved faces should have square number of points;
411  // - Each edge should have sqrt(npts) points.
412  ASSERTL0(nEdgePts * nEdgePts == npts,
413  "NUMPOINTS should be a square number for"
414  " triangle " +
415  boost::lexical_cast<string>(m_globalID));
416 
417  for (i = 0; i < kNedges; ++i)
418  {
419  ASSERTL0(m_edges[i]->GetXmap()->GetNcoeffs() == nEdgePts,
420  "Number of edge points does not correspond to "
421  "number of face points in triangle " +
422  boost::lexical_cast<string>(m_globalID));
423  }
424 
425  for (i = 0; i < m_coordim; ++i)
426  {
427  for (j = 0; j < npts; ++j)
428  {
429  tmp[j] = (m_curve->m_points[j]->GetPtr())[i];
430  }
431 
432  // Interpolate curve points to standard triangle
433  // points.
434  LibUtilities::Interp2D(curveKey,
435  curveKey,
436  tmp,
437  m_xmap->GetBasis(0)->GetPointsKey(),
438  m_xmap->GetBasis(1)->GetPointsKey(),
439  phys);
440 
441  // Forwards transform to get coefficient space.
442  m_xmap->FwdTrans(phys, m_coeffs[i]);
443  }
444  }
445  else
446  {
447  ASSERTL0(false,
448  "Only 1D/2D points distributions "
449  "supported.");
450  }
451  }
452 
453  Array<OneD, unsigned int> mapArray(nEdgeCoeffs);
454  Array<OneD, int> signArray(nEdgeCoeffs);
455 
456  for (i = 0; i < kNedges; i++)
457  {
458  m_edges[i]->FillGeom();
459  m_xmap->GetTraceToElementMap(i, mapArray, signArray, m_eorient[i]);
460 
461  nEdgeCoeffs = m_edges[i]->GetXmap()->GetNcoeffs();
462 
463  for (j = 0; j < m_coordim; j++)
464  {
465  for (k = 0; k < nEdgeCoeffs; k++)
466  {
467  m_coeffs[j][mapArray[k]] =
468  signArray[k] * m_edges[i]->GetCoeffs(j)[k];
469  }
470  }
471  }
472 
474 }
475 
476 int TriGeom::v_GetDir(const int i, const int j) const
477 {
478  boost::ignore_unused(j); // required in 3D shapes
479 
480  return i == 0 ? 0:1;
481 }
482 
483 void TriGeom::v_Reset(CurveMap &curvedEdges, CurveMap &curvedFaces)
484 {
485  Geometry::v_Reset(curvedEdges, curvedFaces);
486  CurveMap::iterator it = curvedFaces.find(m_globalID);
487 
488  if (it != curvedFaces.end())
489  {
490  m_curve = it->second;
491  }
492 
493  for (int i = 0; i < 3; ++i)
494  {
495  m_edges[i]->Reset(curvedEdges, curvedFaces);
496  }
497 
498  SetUpXmap();
499  SetUpCoeffs(m_xmap->GetNcoeffs());
500 }
501 
503 {
504  if(!m_setupState)
505  {
506  for (int i = 0; i < 3; ++i)
507  {
508  m_edges[i]->Setup();
509  }
510  SetUpXmap();
511  SetUpCoeffs(m_xmap->GetNcoeffs());
512  m_setupState = true;
513  }
514 }
515 
517 {
518  int order0 = m_edges[0]->GetXmap()->GetBasis(0)->GetNumModes();
519  int order1 = max(order0,
520  max(m_edges[1]->GetXmap()->GetBasis(0)->GetNumModes(),
521  m_edges[2]->GetXmap()->GetBasis(0)->GetNumModes()));
522 
523  const LibUtilities::BasisKey B0(
525  order0,
527  const LibUtilities::BasisKey B1(
529  order1,
532 
534 }
535 
536 }
537 }
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mode...
Definition: ErrorUtil.hpp:209
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
Definition: ErrorUtil.hpp:250
Describes the specification for a Basis.
Definition: Basis.h:50
Defines a specification for a set of points.
Definition: Points.h:60
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
2D geometry information
Definition: Geometry2D.h:69
std::vector< StdRegions::Orientation > m_eorient
Definition: Geometry2D.h:80
bool m_setupState
Wether or not the setup routines have been run.
Definition: Geometry.h:195
PointGeomSharedPtr GetVertex(int i) const
Returns vertex i of this object.
Definition: Geometry.h:348
GeomState m_state
Enumeration to dictate whether coefficients are filled.
Definition: Geometry.h:193
void SetUpCoeffs(const int nCoeffs)
Initialise the Geometry::m_coeffs array.
Definition: Geometry.h:658
virtual void v_Reset(CurveMap &curvedEdges, CurveMap &curvedFaces)
Reset this geometry object: unset the current state, zero Geometry::m_coeffs and remove allocated Geo...
Definition: Geometry.cpp:355
LibUtilities::ShapeType m_shapeType
Type of shape.
Definition: Geometry.h:199
Array< OneD, Array< OneD, NekDouble > > m_coeffs
Array containing expansion coefficients of m_xmap.
Definition: Geometry.h:203
GeomState m_geomFactorsState
State of the geometric factors.
Definition: Geometry.h:189
StdRegions::StdExpansionSharedPtr m_xmap
mapping containing isoparametric transformation.
Definition: Geometry.h:191
StdRegions::StdExpansionSharedPtr GetXmap() const
Return the mapping object Geometry::m_xmap that represents the coordinate transformation from standar...
Definition: Geometry.h:426
GeomFactorsSharedPtr m_geomFactors
Geometric factors.
Definition: Geometry.h:187
int m_coordim
Coordinate dimension of this geometry object.
Definition: Geometry.h:185
void Rotate(PointGeom &a, int dir, NekDouble angle)
_this = rotation of a by angle 'angle' around axis dir
Definition: PointGeom.cpp:143
NekDouble dist(PointGeom &a)
return distance between this and input a
Definition: PointGeom.cpp:181
static StdRegions::Orientation GetEdgeOrientation(const SegGeom &edge1, const SegGeom &edge2)
Get the orientation of edge1.
Definition: SegGeom.cpp:200
static const int kNedges
Get the orientation of face1.
Definition: TriGeom.h:73
static StdRegions::Orientation GetFaceOrientation(const TriGeom &face1, const TriGeom &face2, bool doRot, int dir, NekDouble angle, NekDouble tol)
Definition: TriGeom.cpp:118
virtual NekDouble v_GetCoord(const int i, const Array< OneD, const NekDouble > &Lcoord)
Given local collapsed coordinate Lcoord, return the value of physical coordinate in direction i.
Definition: TriGeom.cpp:107
virtual int v_GetDir(const int faceidx, const int facedir) const
Returns the element coordinate direction corresponding to a given face coordinate direction.
Definition: TriGeom.cpp:476
virtual void v_Reset(CurveMap &curvedEdges, CurveMap &curvedFaces)
Reset this geometry object: unset the current state, zero Geometry::m_coeffs and remove allocated Geo...
Definition: TriGeom.cpp:483
virtual void v_GenGeomFactors()
Definition: TriGeom.cpp:226
PointsManagerT & PointsManager(void)
void Interp2D(const BasisKey &fbasis0, const BasisKey &fbasis1, const Array< OneD, const NekDouble > &from, const BasisKey &tbasis0, const BasisKey &tbasis1, Array< OneD, NekDouble > &to)
this function interpolates a 2D function evaluated at the quadrature points of the 2D basis,...
Definition: Interp.cpp:115
@ eGaussLobattoLegendre
1D Gauss-Lobatto-Legendre quadrature points
Definition: PointsType.h:51
@ eGaussRadauMAlpha1Beta0
Gauss Radau pinned at x=-1, .
Definition: PointsType.h:58
@ eModified_B
Principle Modified Functions .
Definition: BasisType.h:49
@ eOrtho_A
Principle Orthogonal Functions .
Definition: BasisType.h:45
@ eOrtho_B
Principle Orthogonal Functions .
Definition: BasisType.h:46
@ eModified_A
Principle Modified Functions .
Definition: BasisType.h:48
static const NekDouble kVertexTheSameDouble
std::vector< PointGeomSharedPtr > PointGeomVector
Definition: Geometry2D.h:64
std::shared_ptr< Curve > CurveSharedPtr
Definition: Curve.hpp:61
std::unordered_map< int, CurveSharedPtr > CurveMap
Definition: Curve.hpp:62
GeomType
Indicates the type of element geometry.
@ eRegular
Geometry is straight-sided with constant geometric factors.
@ eDeformed
Geometry is curved or has non-constant factors.
std::shared_ptr< SegGeom > SegGeomSharedPtr
Definition: Geometry2D.h:62
@ ePtsFilled
Geometric information has been generated.
std::shared_ptr< StdNodalTriExp > StdNodalTriExpSharedPtr
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:1
double NekDouble
scalarT< T > sqrt(scalarT< T > in)
Definition: scalar.hpp:267