Nektar++
Geometry3D.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: Geometry3D.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: 3D geometry information.
32 //
33 ////////////////////////////////////////////////////////////////////////////////
34 
35 #include <iomanip>
36 
41 #include <SpatialDomains/SegGeom.h>
42 #include <iomanip>
43 
44 using namespace std;
45 
46 namespace Nektar
47 {
48 namespace SpatialDomains
49 {
50 
51 Geometry3D::Geometry3D()
52 {
53 }
54 
55 Geometry3D::Geometry3D(const int coordim) : Geometry(coordim)
56 {
57  ASSERTL0(m_coordim > 2,
58  "Coordinate dimension should be at least 3 for a 3D geometry.");
59 }
60 
62 {
63 }
64 
65 //---------------------------------------
66 // Helper functions
67 //---------------------------------------
68 
69 /**
70  * @brief Returns the element coordinate direction corresponding to a given face
71  * coordinate direction
72  */
73 int Geometry3D::GetDir(const int faceidx, const int facedir) const
74 {
75  return v_GetDir(faceidx, facedir);
76 }
77 
78 //---------------------------------------
79 // 3D Geometry Methods
80 //---------------------------------------
82  const Array<OneD, const NekDouble> &coords,
83  const Array<OneD, const NekDouble> &ptsx,
84  const Array<OneD, const NekDouble> &ptsy,
85  const Array<OneD, const NekDouble> &ptsz,
86  Array<OneD, NekDouble> &Lcoords,
87  NekDouble &resid)
88 {
89  // maximum iterations for convergence
90  const int MaxIterations = 51;
91  // |x-xp|^2 < EPSILON error tolerance
92  const NekDouble Tol = 1.e-8;
93  // |r,s| > LcoordDIV stop the search
94  const NekDouble LcoordDiv = 15.0;
95 
97  m_geomFactors->GetJac(m_xmap->GetPointsKeys());
98 
99  NekDouble ScaledTol = Vmath::Vsum(Jac.num_elements(), Jac, 1) /
100  ((NekDouble)Jac.num_elements());
101  ScaledTol *= Tol;
102 
103  NekDouble xmap, ymap, zmap, F1, F2, F3;
104 
105  NekDouble derx_1, derx_2, derx_3, dery_1, dery_2, dery_3, derz_1, derz_2,
106  derz_3, jac;
107 
108  // save intiial guess for later reference if required.
109  NekDouble init0 = Lcoords[0], init1 = Lcoords[1], init2 = Lcoords[2];
110 
111  Array<OneD, NekDouble> DxD1(ptsx.num_elements());
112  Array<OneD, NekDouble> DxD2(ptsx.num_elements());
113  Array<OneD, NekDouble> DxD3(ptsx.num_elements());
114  Array<OneD, NekDouble> DyD1(ptsx.num_elements());
115  Array<OneD, NekDouble> DyD2(ptsx.num_elements());
116  Array<OneD, NekDouble> DyD3(ptsx.num_elements());
117  Array<OneD, NekDouble> DzD1(ptsx.num_elements());
118  Array<OneD, NekDouble> DzD2(ptsx.num_elements());
119  Array<OneD, NekDouble> DzD3(ptsx.num_elements());
120 
121  // Ideally this will be stored in m_geomfactors
122  m_xmap->PhysDeriv(ptsx, DxD1, DxD2, DxD3);
123  m_xmap->PhysDeriv(ptsy, DyD1, DyD2, DyD3);
124  m_xmap->PhysDeriv(ptsz, DzD1, DzD2, DzD3);
125 
126  int cnt = 0;
128  Array<OneD, NekDouble> eta(3);
129 
130  F1 = F2 = F3 = 2000; // Starting value of Function
131 
132  while (cnt++ < MaxIterations)
133  {
134  // evaluate lagrange interpolant at Lcoords
135  m_xmap->LocCoordToLocCollapsed(Lcoords, eta);
136  I[0] = m_xmap->GetBasis(0)->GetI(eta);
137  I[1] = m_xmap->GetBasis(1)->GetI(eta + 1);
138  I[2] = m_xmap->GetBasis(2)->GetI(eta + 2);
139 
140  // calculate the global point `corresponding to Lcoords
141  xmap = m_xmap->PhysEvaluate(I, ptsx);
142  ymap = m_xmap->PhysEvaluate(I, ptsy);
143  zmap = m_xmap->PhysEvaluate(I, ptsz);
144 
145  F1 = coords[0] - xmap;
146  F2 = coords[1] - ymap;
147  F3 = coords[2] - zmap;
148 
149  if (F1 * F1 + F2 * F2 + F3 * F3 < ScaledTol)
150  {
151  resid = sqrt(F1 * F1 + F2 * F2 + F3 * F3);
152  break;
153  }
154 
155  // Interpolate derivative metric at Lcoords
156  derx_1 = m_xmap->PhysEvaluate(I, DxD1);
157  derx_2 = m_xmap->PhysEvaluate(I, DxD2);
158  derx_3 = m_xmap->PhysEvaluate(I, DxD3);
159  dery_1 = m_xmap->PhysEvaluate(I, DyD1);
160  dery_2 = m_xmap->PhysEvaluate(I, DyD2);
161  dery_3 = m_xmap->PhysEvaluate(I, DyD3);
162  derz_1 = m_xmap->PhysEvaluate(I, DzD1);
163  derz_2 = m_xmap->PhysEvaluate(I, DzD2);
164  derz_3 = m_xmap->PhysEvaluate(I, DzD3);
165 
166  jac = derx_1 * (dery_2 * derz_3 - dery_3 * derz_2) -
167  derx_2 * (dery_1 * derz_3 - dery_3 * derz_1) +
168  derx_3 * (dery_1 * derz_2 - dery_2 * derz_1);
169 
170  // use analytical inverse of derivitives which are also similar to
171  // those of metric factors.
172  Lcoords[0] =
173  Lcoords[0] +
174  ((dery_2 * derz_3 - dery_3 * derz_2) * (coords[0] - xmap) -
175  (derx_2 * derz_3 - derx_3 * derz_2) * (coords[1] - ymap) +
176  (derx_2 * dery_3 - derx_3 * dery_2) * (coords[2] - zmap)) /
177  jac;
178 
179  Lcoords[1] =
180  Lcoords[1] -
181  ((dery_1 * derz_3 - dery_3 * derz_1) * (coords[0] - xmap) -
182  (derx_1 * derz_3 - derx_3 * derz_1) * (coords[1] - ymap) +
183  (derx_1 * dery_3 - derx_3 * dery_1) * (coords[2] - zmap)) /
184  jac;
185 
186  Lcoords[2] =
187  Lcoords[2] +
188  ((dery_1 * derz_2 - dery_2 * derz_1) * (coords[0] - xmap) -
189  (derx_1 * derz_2 - derx_2 * derz_1) * (coords[1] - ymap) +
190  (derx_1 * dery_2 - derx_2 * dery_1) * (coords[2] - zmap)) /
191  jac;
192 
193  if (fabs(Lcoords[0]) > LcoordDiv || fabs(Lcoords[1]) > LcoordDiv ||
194  fabs(Lcoords[0]) > LcoordDiv)
195  {
196  break; // lcoords have diverged so stop iteration
197  }
198  }
199 
200  resid = sqrt(F1 * F1 + F2 * F2 + F3 * F3);
201 
202  if (cnt >= MaxIterations)
203  {
204  Array<OneD, NekDouble> collCoords(3);
205  m_xmap->LocCoordToLocCollapsed(Lcoords, collCoords);
206 
207  // if coordinate is inside element dump error!
208  if ((collCoords[0] >= -1.0 && collCoords[0] <= 1.0) &&
209  (collCoords[1] >= -1.0 && collCoords[1] <= 1.0) &&
210  (collCoords[2] >= -1.0 && collCoords[2] <= 1.0))
211  {
212  std::ostringstream ss;
213 
214  ss << "Reached MaxIterations (" << MaxIterations
215  << ") in Newton iteration ";
216  ss << "Init value (" << setprecision(4) << init0 << "," << init1
217  << "," << init2 << ") ";
218  ss << "Fin value (" << Lcoords[0] << "," << Lcoords[1] << ","
219  << Lcoords[2] << ") ";
220  ss << "Resid = " << resid << " Tolerance = " << sqrt(ScaledTol);
221 
222  WARNINGL1(cnt < MaxIterations, ss.str());
223  }
224  }
225 }
226 
227 /**
228  * @brief Put all quadrature information into face/edge structure and
229  * backward transform.
230  *
231  * Note verts, edges, and faces are listed according to anticlockwise
232  * convention but points in _coeffs have to be in array format from left
233  * to right.
234  */
236 {
237  if (m_state == ePtsFilled)
238  {
239  return;
240  }
241 
242  int i, j, k;
243 
244  for (i = 0; i < m_forient.size(); i++)
245  {
246  m_faces[i]->FillGeom();
247 
248  int nFaceCoeffs = m_faces[i]->GetXmap()->GetNcoeffs();
249 
250  Array<OneD, unsigned int> mapArray(nFaceCoeffs);
251  Array<OneD, int> signArray(nFaceCoeffs);
252 
253  if (m_forient[i] < 9)
254  {
255  m_xmap->GetFaceToElementMap(
256  i,
257  m_forient[i],
258  mapArray,
259  signArray,
260  m_faces[i]->GetXmap()->GetEdgeNcoeffs(0),
261  m_faces[i]->GetXmap()->GetEdgeNcoeffs(1));
262  }
263  else
264  {
265  m_xmap->GetFaceToElementMap(
266  i,
267  m_forient[i],
268  mapArray,
269  signArray,
270  m_faces[i]->GetXmap()->GetEdgeNcoeffs(1),
271  m_faces[i]->GetXmap()->GetEdgeNcoeffs(0));
272  }
273 
274  for (j = 0; j < m_coordim; j++)
275  {
276  const Array<OneD, const NekDouble> &coeffs =
277  m_faces[i]->GetCoeffs(j);
278 
279  for (k = 0; k < nFaceCoeffs; k++)
280  {
281  NekDouble v = signArray[k] * coeffs[k];
282  m_coeffs[j][mapArray[k]] = v;
283  }
284  }
285  }
286 
288 }
289 
290 /**
291 * @brief Given local collapsed coordinate Lcoord return the value of
292 * physical coordinate in direction i.
293 */
295  const Array<OneD, const NekDouble> &Lcoord)
296 {
297  ASSERTL1(m_state == ePtsFilled, "Geometry is not in physical space");
298 
299  Array<OneD, NekDouble> tmp(m_xmap->GetTotPoints());
300  m_xmap->BwdTrans(m_coeffs[i], tmp);
301 
302  return m_xmap->PhysEvaluate(Lcoord, tmp);
303 }
304 
305 //---------------------------------------
306 // Helper functions
307 //---------------------------------------
308 
310 {
311  return 3;
312 }
313 
315 {
316  return m_verts.size();
317 }
318 
320 {
321  return m_edges.size();
322 }
323 
325 {
326  return m_faces.size();
327 }
328 
330 {
331  return m_verts[i];
332 }
333 
335 {
336  ASSERTL2(i >= 0 && i <= m_edges.size() - 1,
337  "Edge ID must be between 0 and " +
338  boost::lexical_cast<string>(m_edges.size() - 1));
339  return m_edges[i];
340 }
341 
343 {
344  ASSERTL2((i >= 0) && (i <= 5), "Edge id must be between 0 and 4");
345  return m_faces[i];
346 }
347 
349 {
350  ASSERTL2(i >= 0 && i <= m_edges.size() - 1,
351  "Edge ID must be between 0 and " +
352  boost::lexical_cast<string>(m_edges.size() - 1));
353  return m_eorient[i];
354 }
355 
357 {
358  ASSERTL2(i >= 0 && i <= m_faces.size() - 1,
359  "Face ID must be between 0 and " +
360  boost::lexical_cast<string>(m_faces.size() - 1));
361  return m_forient[i];
362 }
363 
364 }
365 }
StdRegions::StdExpansionSharedPtr m_xmap
mapping containing isoparametric transformation.
Definition: Geometry.h:189
int GetDir(const int faceidx, const int facedir) const
Returns the element coordinate direction corresponding to a given face coordinate direction...
Definition: Geometry3D.cpp:73
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
virtual StdRegions::Orientation v_GetEorient(const int i) const
Returns the orientation of edge i with respect to the ordering of edges in the standard element...
Definition: Geometry3D.cpp:348
std::vector< StdRegions::Orientation > m_eorient
Definition: Geometry3D.h:86
std::shared_ptr< Geometry2D > Geometry2DSharedPtr
Definition: Geometry.h:65
Base class for shape geometry information.
Definition: Geometry.h:83
GeomFactorsSharedPtr m_geomFactors
Geometric factors.
Definition: Geometry.h:185
StdRegions::StdExpansionSharedPtr GetXmap() const
Return the mapping object Geometry::m_xmap that represents the coordinate transformation from standar...
Definition: Geometry.h:421
virtual PointGeomSharedPtr v_GetVertex(int i) const
Definition: Geometry3D.cpp:329
virtual StdRegions::Orientation v_GetForient(const int i) const
Returns the orientation of face i with respect to the ordering of faces in the standard element...
Definition: Geometry3D.cpp:356
STL namespace.
std::vector< StdRegions::Orientation > m_forient
Definition: Geometry3D.h:87
virtual int v_GetNumEdges() const
Get the number of edges of this object.
Definition: Geometry3D.cpp:319
void NewtonIterationForLocCoord(const Array< OneD, const NekDouble > &coords, const Array< OneD, const NekDouble > &ptsx, const Array< OneD, const NekDouble > &ptsy, const Array< OneD, const NekDouble > &ptsz, Array< OneD, NekDouble > &Lcoords, NekDouble &resid)
Definition: Geometry3D.cpp:81
virtual Geometry1DSharedPtr v_GetEdge(int i) const
Returns edge i of this object.
Definition: Geometry3D.cpp:334
virtual int v_GetDir(const int faceidx, const int facedir) const =0
double NekDouble
std::shared_ptr< PointGeom > PointGeomSharedPtr
Definition: Geometry.h:59
virtual int v_GetNumVerts() const
Get the number of vertices of this object.
Definition: Geometry3D.cpp:314
virtual Geometry2DSharedPtr v_GetFace(int i) const
Returns face i of this object.
Definition: Geometry3D.cpp:342
virtual void v_FillGeom()
Put all quadrature information into face/edge structure and backward transform.
Definition: Geometry3D.cpp:235
Array< OneD, Array< OneD, NekDouble > > m_coeffs
Array containing expansion coefficients of m_xmap.
Definition: Geometry.h:201
#define WARNINGL1(condition, msg)
Definition: ErrorUtil.hpp:251
#define ASSERTL2(condition, msg)
Assert Level 2 – Debugging which is used FULLDEBUG compilation mode. This level assert is designed t...
Definition: ErrorUtil.hpp:274
virtual int v_GetNumFaces() const
Get the number of faces of this object.
Definition: Geometry3D.cpp:324
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: Geometry3D.cpp:294
std::shared_ptr< Geometry1D > Geometry1DSharedPtr
Definition: Geometry.h:63
virtual int v_GetShapeDim() const
Get the object&#39;s shape dimension.
Definition: Geometry3D.cpp:309
Geometric information has been generated.
GeomState m_state
Enumeration to dictate whether coefficients are filled.
Definition: Geometry.h:191
T Vsum(int n, const T *x, const int incx)
Subtract return sum(x)
Definition: Vmath.cpp:740
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode...
Definition: ErrorUtil.hpp:250
int m_coordim
Coordinate dimension of this geometry object.
Definition: Geometry.h:183