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