Nektar++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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 // License for the specific language governing rights and limitations under
14 // Permission is hereby granted, free of charge, to any person obtaining a
15 // copy of this software and associated documentation files (the "Software"),
16 // to deal in the Software without restriction, including without limitation
17 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 // and/or sell copies of the Software, and to permit persons to whom the
19 // Software is furnished to do so, subject to the following conditions:
20 //
21 // The above copyright notice and this permission notice shall be included
22 // in all copies or substantial portions of the Software.
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 // DEALINGS IN THE SOFTWARE.
31 //
32 // Description: 3D geometry information.
33 //
34 ////////////////////////////////////////////////////////////////////////////////
35 
37 
41 #include <SpatialDomains/SegGeom.h>
42 
43 #include <iomanip>
44 namespace Nektar
45 {
46 namespace SpatialDomains
47 {
49  {
50  }
51 
52  Geometry3D::Geometry3D(const int coordim):
53  Geometry(coordim)
54  {
55  ASSERTL0(m_coordim > 2,
56  "Coordinate dimension should be at least 3 for a 3D geometry.");
57  }
58 
60  {
61  }
62 
63 
64  //---------------------------------------
65  // Helper functions
66  //---------------------------------------
67 
68  /**
69  * @brief Return the ID of edge i in this element.
70  */
71  int Geometry3D::GetEid(int i) const
72  {
73  return v_GetEid(i);
74  }
75 
76  /**
77  * @brief Return face i in this element.
78  */
80  {
81  return v_GetFace(i);
82  }
83 
84  /**
85  * @brief Return the orientation of face i in this element.
86  */
88  {
89  return v_GetFaceOrient(i);
90  }
91 
92 
93  /**
94  * @brief Returns the element coordinate direction corresponding to a
95  * given face coordinate direction
96  */
97  int Geometry3D::GetDir(const int faceidx, const int facedir) const
98  {
99  return v_GetDir(faceidx, facedir);
100  }
101 
102  //---------------------------------------
103  // 3D Geometry Methods
104  //---------------------------------------
106  const Array<OneD, const NekDouble> &coords,
107  const Array<OneD, const NekDouble> &ptsx,
108  const Array<OneD, const NekDouble> &ptsy,
109  const Array<OneD, const NekDouble> &ptsz,
110  Array<OneD, NekDouble> &Lcoords,
111  NekDouble &resid)
112  {
113  // maximum iterations for convergence
114  const int MaxIterations = 51;
115  // |x-xp|^2 < EPSILON error tolerance
116  const NekDouble Tol = 1.e-8;
117  // |r,s| > LcoordDIV stop the search
118  const NekDouble LcoordDiv = 15.0;
119 
120  Array<OneD, const NekDouble > Jac =
121  m_geomFactors->GetJac(m_xmap->GetPointsKeys());
122 
123  NekDouble ScaledTol = Vmath::Vsum(Jac.num_elements(), Jac, 1) /
124  ((NekDouble)Jac.num_elements());
125  ScaledTol *= Tol;
126 
127  NekDouble xmap,ymap,zmap, F1,F2, F3;
128 
129  NekDouble derx_1, derx_2, derx_3, dery_1, dery_2, dery_3,
130  derz_1, derz_2, derz_3, jac;
131 
132  // save intiial guess for later reference if required.
133  NekDouble init0 = Lcoords[0], init1 = Lcoords[1], init2 = Lcoords[2];
134 
135  Array<OneD, NekDouble> DxD1(ptsx.num_elements());
136  Array<OneD, NekDouble> DxD2(ptsx.num_elements());
137  Array<OneD, NekDouble> DxD3(ptsx.num_elements());
138  Array<OneD, NekDouble> DyD1(ptsx.num_elements());
139  Array<OneD, NekDouble> DyD2(ptsx.num_elements());
140  Array<OneD, NekDouble> DyD3(ptsx.num_elements());
141  Array<OneD, NekDouble> DzD1(ptsx.num_elements());
142  Array<OneD, NekDouble> DzD2(ptsx.num_elements());
143  Array<OneD, NekDouble> DzD3(ptsx.num_elements());
144 
145  // Ideally this will be stored in m_geomfactors
146  m_xmap->PhysDeriv(ptsx,DxD1,DxD2,DxD3);
147  m_xmap->PhysDeriv(ptsy,DyD1,DyD2,DyD3);
148  m_xmap->PhysDeriv(ptsz,DzD1,DzD2,DzD3);
149 
150  int cnt=0;
151  Array<OneD, DNekMatSharedPtr > I(3);
152  Array<OneD, NekDouble> eta(3);
153 
154  F1 = F2 = F3 = 2000; // Starting value of Function
155 
156  while(cnt++ < MaxIterations)
157  {
158  // evaluate lagrange interpolant at Lcoords
159  m_xmap->LocCoordToLocCollapsed(Lcoords,eta);
160  I[0] = m_xmap->GetBasis(0)->GetI(eta );
161  I[1] = m_xmap->GetBasis(1)->GetI(eta+1);
162  I[2] = m_xmap->GetBasis(2)->GetI(eta+2);
163 
164  //calculate the global point `corresponding to Lcoords
165  xmap = m_xmap->PhysEvaluate(I, ptsx);
166  ymap = m_xmap->PhysEvaluate(I, ptsy);
167  zmap = m_xmap->PhysEvaluate(I, ptsz);
168 
169  F1 = coords[0] - xmap;
170  F2 = coords[1] - ymap;
171  F3 = coords[2] - zmap;
172 
173  if(F1*F1 + F2*F2 + F3*F3 < ScaledTol)
174  {
175  resid = sqrt(F1*F1 + F2*F2 + F3*F3);
176  break;
177  }
178 
179  //Interpolate derivative metric at Lcoords
180  derx_1 = m_xmap->PhysEvaluate(I, DxD1);
181  derx_2 = m_xmap->PhysEvaluate(I, DxD2);
182  derx_3 = m_xmap->PhysEvaluate(I, DxD3);
183  dery_1 = m_xmap->PhysEvaluate(I, DyD1);
184  dery_2 = m_xmap->PhysEvaluate(I, DyD2);
185  dery_3 = m_xmap->PhysEvaluate(I, DyD3);
186  derz_1 = m_xmap->PhysEvaluate(I, DzD1);
187  derz_2 = m_xmap->PhysEvaluate(I, DzD2);
188  derz_3 = m_xmap->PhysEvaluate(I, DzD3);
189 
190  jac = derx_1*(dery_2*derz_3 - dery_3*derz_2)
191  - derx_2*(dery_1*derz_3 - dery_3*derz_1)
192  + derx_3*(dery_1*derz_2 - dery_2*derz_1);
193 
194  // use analytical inverse of derivitives which are also similar to
195  // those of metric factors.
196  Lcoords[0] = Lcoords[0]
197  +((dery_2*derz_3 - dery_3*derz_2)*(coords[0]-xmap)
198  - (derx_2*derz_3 - derx_3*derz_2)*(coords[1]-ymap)
199  + (derx_2*dery_3 - derx_3*dery_2)*(coords[2]-zmap)
200  )/jac;
201 
202  Lcoords[1] = Lcoords[1]
203  -((dery_1*derz_3 - dery_3*derz_1)*(coords[0]-xmap)
204  - (derx_1*derz_3 - derx_3*derz_1)*(coords[1]-ymap)
205  + (derx_1*dery_3 - derx_3*dery_1)*(coords[2]-zmap)
206  )/jac;
207 
208  Lcoords[2] = Lcoords[2]
209  +((dery_1*derz_2 - dery_2*derz_1)*(coords[0]-xmap)
210  - (derx_1*derz_2 - derx_2*derz_1)*(coords[1]-ymap)
211  + (derx_1*dery_2 - derx_2*dery_1)*(coords[2]-zmap)
212  )/jac;
213 
214  if (fabs(Lcoords[0]) > LcoordDiv || fabs(Lcoords[1]) > LcoordDiv ||
215  fabs(Lcoords[0]) > LcoordDiv)
216  {
217  break; // lcoords have diverged so stop iteration
218  }
219  }
220 
221  resid = sqrt(F1*F1 + F2*F2 + F3*F3);
222 
223  if(cnt >= MaxIterations)
224  {
225  Array<OneD, NekDouble> collCoords(3);
226  m_xmap->LocCoordToLocCollapsed(Lcoords,collCoords);
227 
228  // if coordinate is inside element dump error!
229  if((collCoords[0] >= -1.0 && collCoords[0] <= 1.0)&&
230  (collCoords[1] >= -1.0 && collCoords[1] <= 1.0)&&
231  (collCoords[2] >= -1.0 && collCoords[2] <= 1.0))
232  {
233  std::ostringstream ss;
234 
235  ss << "Reached MaxIterations (" << MaxIterations << ") in Newton iteration ";
236  ss << "Init value ("<< setprecision(4) << init0 << "," << init1<< "," << init2 <<") ";
237  ss << "Fin value ("<<Lcoords[0] << "," << Lcoords[1]<< "," << Lcoords[2] << ") ";
238  ss << "Resid = " << resid << " Tolerance = " << sqrt(ScaledTol) ;
239 
240  WARNINGL1(cnt < MaxIterations,ss.str());
241  }
242  }
243  }
244 
245  /**
246  * @brief Put all quadrature information into face/edge structure and
247  * backward transform.
248  *
249  * Note verts, edges, and faces are listed according to anticlockwise
250  * convention but points in _coeffs have to be in array format from left
251  * to right.
252  */
254  {
255  if (m_state == ePtsFilled)
256  return;
257 
258  int i,j,k;
259 
260  for(i = 0; i < m_forient.size(); i++)
261  {
262  m_faces[i]->FillGeom();
263 
264  int nFaceCoeffs = m_faces[i]->GetXmap()->GetNcoeffs();
265 
266  Array<OneD, unsigned int> mapArray (nFaceCoeffs);
267  Array<OneD, int> signArray(nFaceCoeffs);
268 
269  if (m_forient[i] < 9)
270  {
271  m_xmap->GetFaceToElementMap(
272  i, m_forient[i], mapArray, signArray,
273  m_faces[i]->GetXmap()->GetEdgeNcoeffs(0),
274  m_faces[i]->GetXmap()->GetEdgeNcoeffs(1));
275  }
276  else
277  {
278  m_xmap->GetFaceToElementMap(
279  i, m_forient[i], mapArray, signArray,
280  m_faces[i]->GetXmap()->GetEdgeNcoeffs(1),
281  m_faces[i]->GetXmap()->GetEdgeNcoeffs(0));
282  }
283 
284  for (j = 0; j < m_coordim; j++)
285  {
286  const Array<OneD, const NekDouble> &coeffs =
287  m_faces[i]->GetCoeffs(j);
288 
289  for (k = 0; k < nFaceCoeffs; k++)
290  {
291  NekDouble v = signArray[k] * coeffs[k];
292  m_coeffs[j][mapArray[k]] = v;
293  }
294  }
295  }
296 
298  }
299 
300  /**
301  * Generate the geometry factors for this element.
302  */
304  {
306  {
307  GeomType Gtype = eRegular;
308 
309  v_FillGeom();
310 
311  // check to see if expansions are linear
312  for(int i = 0; i < m_coordim; ++i)
313  {
314  if (m_xmap->GetBasisNumModes(0) != 2 ||
315  m_xmap->GetBasisNumModes(1) != 2 ||
316  m_xmap->GetBasisNumModes(2) != 2)
317  {
318  Gtype = eDeformed;
319  }
320  }
321 
323  Gtype, m_coordim, m_xmap, m_coeffs);
325  }
326  }
327 
328  /**
329  * @brief Given local collapsed coordinate Lcoord return the value of
330  * physical coordinate in direction i.
331  */
333  const int i, const Array<OneD, const NekDouble> &Lcoord)
334  {
336  "Geometry is not in physical space");
337 
338  Array<OneD, NekDouble> tmp(m_xmap->GetTotPoints());
339  m_xmap->BwdTrans(m_coeffs[i], tmp);
340 
341  return m_xmap->PhysEvaluate(Lcoord, tmp);
342  }
343 
344 
345  //---------------------------------------
346  // Helper functions
347  //---------------------------------------
348 
349  /**
350  * @brief Return the dimension of this element.
351  */
353  {
354  return 3;
355  }
356 
357  /**
358  * @brief Return the vertex ID of vertex i.
359  */
360  int Geometry3D::v_GetVid(const int i) const
361  {
362  ASSERTL2(i >= 0 && i <= m_verts.size() - 1,
363  "Vertex ID must be between 0 and "+
364  boost::lexical_cast<string>(m_verts.size() - 1));
365  return m_verts[i]->GetVid();
366  }
367 
368  /**
369  * @brief Return vertex i in this element.
370  */
372  {
373  return m_verts[i];
374  }
375 
376  /**
377  * @brief Return edge i of this element.
378  */
380  {
381  ASSERTL2(i >= 0 && i <= m_edges.size() - 1,
382  "Edge ID must be between 0 and "+
383  boost::lexical_cast<string>(m_edges.size() - 1));
384  return m_edges[i];
385  }
386 
387  /**
388  * @brief Return the orientation of edge i in this element.
389  */
391  const int i) const
392  {
393  ASSERTL2(i >= 0 && i <= m_edges.size() - 1,
394  "Edge ID must be between 0 and "+
395  boost::lexical_cast<string>(m_edges.size() - 1));
396  return m_eorient[i];
397  }
398 
399  /**
400  * @brief Return the ID of edge i in this element.
401  */
402  int Geometry3D::v_GetEid(int i) const
403  {
404  ASSERTL2(i >= 0 && i <= m_edges.size() - 1,
405  "Edge ID must be between 0 and "+
406  boost::lexical_cast<string>(m_edges.size() - 1));
407  return m_edges[i]->GetEid();
408  }
409 
410  /**
411  * @brief Return face i in this element.
412  */
414  {
415  ASSERTL2((i >=0) && (i <= 5),"Edge id must be between 0 and 4");
416  return m_faces[i];
417  }
418 
419  /**
420  * @brief Return the orientation of face i in this element.
421  */
423  {
424  ASSERTL2(i >= 0 && i <= m_faces.size() - 1,
425  "Face ID must be between 0 and "+
426  boost::lexical_cast<string>(m_faces.size() - 1));
427  return m_forient[i];
428  }
429 
430  /**
431  * @brief Return the ID of face i in this element.
432  */
433  int Geometry3D::v_GetFid(int i) const
434  {
435  ASSERTL2(i >= 0 && i <= m_faces.size() - 1,
436  "Face ID must be between 0 and "+
437  boost::lexical_cast<string>(m_faces.size() - 1));
438  return m_faces[i]->GetFid();
439  }
440 
441  /**
442  * @brief Return the ID of this element.
443  */
445  {
446  return m_eid;
447  }
448 
449  /**
450  * @brief Return the j-th basis of the i-th co-ordinate dimension.
451  */
453  const int i)
454  {
455  return m_xmap->GetBasis(i);
456  }
457 
458  /**
459  * @brief Return the local ID of a given edge.
460  *
461  * The local ID of an edge is a number between 0 and the number of edges
462  * in this element. If the edge is not found, this function returns -1.
463  */
465  {
466  int returnval = -1;
467 
468  SegGeomVector::iterator edgeIter;
469  int i;
470 
471  for (i=0,edgeIter = m_edges.begin(); edgeIter != m_edges.end(); ++edgeIter,++i)
472  {
473  if (*edgeIter == edge)
474  {
475  returnval = i;
476  break;
477  }
478  }
479 
480  return returnval;
481  }
482 
483  /**
484  * @brief Return the local ID of a given face.
485  *
486  * The local ID of a face is a number between 0 and the number of faces
487  * in this element. If the face is not found, this function returns -1.
488  */
490  {
491  int i = 0;
492 
494  for (i = 0, f = m_faces.begin(); f != m_faces.end(); ++f,++i)
495  {
496  if (*f == face)
497  {
498  break;
499  }
500  }
501  return i;
502  }
503 
504  //---------------------------------------
505  // Element connection functions
506  //---------------------------------------
507 
508  void Geometry3D::v_AddElmtConnected(int gvo_id, int locid)
509  {
510  CompToElmt ee(gvo_id,locid);
511  m_elmtmap.push_back(ee);
512  }
513 
515  {
516  return int(m_elmtmap.size());
517  }
518 
519  bool Geometry3D::v_IsElmtConnected(int gvo_id, int locid) const
520  {
521  std::list<CompToElmt>::const_iterator def;
522  CompToElmt ee(gvo_id,locid);
523 
524  def = find(m_elmtmap.begin(),m_elmtmap.end(),ee);
525 
526  // Found the element connectivity object in the list
527  return (def != m_elmtmap.end());
528  }
529 
531  {
532  m_owndata = true;
533  }
534 
535 }; //end of namespace
536 }; //end of namespace