Nektar++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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 // 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:
33 //
34 //
35 ////////////////////////////////////////////////////////////////////////////////
36 
37 #include <SpatialDomains/TriGeom.h>
41 
42 #include <SpatialDomains/SegGeom.h>
44 
45 
46 namespace Nektar
47 {
48  namespace SpatialDomains
49  {
50  /**
51  *
52  */
54  {
56  }
57 
58  /**
59  *
60  */
61  TriGeom::TriGeom(int id, const int coordim):
62  Geometry2D(coordim), m_fid(id)
63  {
68 
69  m_globalID = m_fid;
70 
72  SetUpCoeffs(m_xmap->GetNcoeffs());
73  }
74 
75 
76  /**
77  *
78  */
79  TriGeom::TriGeom(const int id,
80  const PointGeomSharedPtr verts[],
81  const SegGeomSharedPtr edges[],
82  const StdRegions::Orientation eorient[]):
83  Geometry2D(verts[0]->GetCoordim()),
84  m_fid(id)
85  {
86  m_globalID = m_fid;
88 
89  /// Copy the vert shared pointers.
90  m_verts.insert(m_verts.begin(), verts, verts+TriGeom::kNverts);
91 
92  /// Copy the edge shared pointers.
93  m_edges.insert(m_edges.begin(), edges, edges+TriGeom::kNedges);
94 
95  for (int j=0; j<kNedges; ++j)
96  {
97  m_eorient[j] = eorient[j];
98  }
99 
100  m_coordim = verts[0]->GetCoordim();
101  ASSERTL0(m_coordim > 1,
102  "Cannot call function with dim == 1");
103 
104  int order0 = edges[0]->GetBasis(0)->GetNumModes();
105  int points0 = edges[0]->GetBasis(0)->GetNumPoints();
106  int order1 = max(order0,
107  max(edges[1]->GetBasis(0)->GetNumModes(),
108  edges[2]->GetBasis(0)->GetNumModes()));
109  int points1 = max(points0,
110  max(edges[1]->GetBasis(0)->GetNumPoints(),
111  edges[2]->GetBasis(0)->GetNumPoints()));
112 
113 
118 
120  SetUpCoeffs(m_xmap->GetNcoeffs());
121  }
122 
123 
124  /**
125  *
126  */
127  TriGeom::TriGeom(const int id, const SegGeomSharedPtr edges[],
128  const StdRegions::Orientation eorient[]):
129  Geometry2D(edges[0]->GetVertex(0)->GetCoordim()),
130  m_fid(id)
131  {
132  m_globalID = m_fid;
134 
135  /// Copy the edge shared pointers.
136  m_edges.insert(m_edges.begin(), edges, edges+TriGeom::kNedges);
137 
138  for(int j=0; j <kNedges; ++j)
139  {
140  if(eorient[j] == StdRegions::eForwards)
141  {
142  m_verts.push_back(edges[j]->GetVertex(0));
143  }
144  else
145  {
146  m_verts.push_back(edges[j]->GetVertex(1));
147  }
148  }
149 
150  for (int j=0; j<kNedges; ++j)
151  {
152  m_eorient[j] = eorient[j];
153  }
154 
155  m_coordim = edges[0]->GetVertex(0)->GetCoordim();
156  ASSERTL0(m_coordim > 1,"Cannot call function with dim == 1");
157 
158  int order0 = edges[0]->GetBasis(0)->GetNumModes();
159  int points0 = edges[0]->GetBasis(0)->GetNumPoints();
160  int order1 = max(order0,
161  max(edges[1]->GetBasis(0)->GetNumModes(),
162  edges[2]->GetBasis(0)->GetNumModes()));
163  int points1 = max(points0,
164  max(edges[1]->GetBasis(0)->GetNumPoints(),
165  edges[2]->GetBasis(0)->GetNumPoints()));
166 
171 
173  SetUpCoeffs(m_xmap->GetNcoeffs());
174  }
175 
176 
177  /**
178  *
179  */
180  TriGeom::TriGeom(const int id,
181  const SegGeomSharedPtr edges[],
182  const StdRegions::Orientation eorient[],
183  const CurveSharedPtr &curve) :
184  Geometry2D(edges[0]->GetVertex(0)->GetCoordim()),
185  m_fid(id)
186  {
187  m_globalID = m_fid;
189 
190  /// Copy the edge shared pointers.
191  m_edges.insert(m_edges.begin(), edges, edges+TriGeom::kNedges);
192 
193  for(int j=0; j <kNedges; ++j)
194  {
195  if(eorient[j] == StdRegions::eForwards)
196  {
197  m_verts.push_back(edges[j]->GetVertex(0));
198  }
199  else
200  {
201  m_verts.push_back(edges[j]->GetVertex(1));
202  }
203  }
204 
205  for (int j=0; j<kNedges; ++j)
206  {
207  m_eorient[j] = eorient[j];
208  }
209 
210  m_coordim = edges[0]->GetVertex(0)->GetCoordim();
211  ASSERTL0(m_coordim > 1,"Cannot call function with dim == 1");
212 
213  int order0 = edges[0]->GetBasis(0)->GetNumModes();
214  int points0 = edges[0]->GetBasis(0)->GetNumPoints();
215  int order1 = max(order0,
216  max(edges[1]->GetBasis(0)->GetNumModes(),
217  edges[2]->GetBasis(0)->GetNumModes()));
218  int points1 = max(points0,
219  max(edges[1]->GetBasis(0)->GetNumPoints(),
220  edges[2]->GetBasis(0)->GetNumPoints()));
221 
226 
228  SetUpCoeffs(m_xmap->GetNcoeffs());
229 
230  for(int i = 0; i < m_coordim; ++i)
231  {
232  int pdim = LibUtilities::PointsManager()[
233  LibUtilities::PointsKey(2, curve->m_ptype)]->GetPointsDim();
234 
235  // Deal with 2D points type separately (e.g. electrostatic or
236  // Fekete points).
237  if (pdim == 2)
238  {
239  int N = curve->m_points.size();
240  int nEdgePts = (-1+(int)sqrt(static_cast<NekDouble>(8*N+1)))/2;
241 
242  ASSERTL0(nEdgePts*(nEdgePts+1)/2 == N,
243  "NUMPOINTS must be a triangle number for 2D basis.");
244 
245  for (int j = 0; j < kNedges; ++j)
246  {
247  ASSERTL0(edges[j]->GetXmap()->GetNcoeffs() == nEdgePts,
248  "Number of edge points does not correspond "
249  "to number of face points.");
250  }
251 
252  // Create a StdNodalTriExp.
253  const LibUtilities::PointsKey P0(
255  const LibUtilities::PointsKey P1(
257  const LibUtilities::BasisKey T0(
258  LibUtilities::eOrtho_A, nEdgePts, P0);
259  const LibUtilities::BasisKey T1(
260  LibUtilities::eOrtho_B, nEdgePts, P1);
261 
264  T0, T1, curve->m_ptype);
265 
266  Array<OneD, NekDouble> phys(max(t->GetTotPoints(),
267  m_xmap->GetTotPoints()));
268  for (int j = 0; j < N; ++j)
269  {
270  phys[j] = (curve->m_points[j]->GetPtr())[i];
271  }
272 
273  Array<OneD, NekDouble> tmp(nEdgePts*nEdgePts);
274  t->BwdTrans(phys, tmp);
275 
276  // Interpolate points to standard region.
277  LibUtilities::Interp2D(P0, P1, tmp,
278  B0.GetPointsKey(),B1.GetPointsKey(),
279  phys);
280 
281  // Forwards transform to get coefficient space.
282  m_xmap->FwdTrans(phys, m_coeffs[i]);
283  }
284  else if (pdim == 1)
285  {
286  int npts = curve->m_points.size();
287  int nEdgePts = (int)sqrt(static_cast<NekDouble>(npts));
288  Array<OneD,NekDouble> tmp(npts);
289  LibUtilities::PointsKey curveKey(nEdgePts, curve->m_ptype);
290 
291  // Sanity checks:
292  // - Curved faces should have square number of points;
293  // - Each edge should have sqrt(npts) points.
294  ASSERTL0(nEdgePts*nEdgePts == npts,
295  "NUMPOINTS should be a square number");
296 
297  for (int j = 0; j < kNedges; ++j)
298  {
299  ASSERTL0(edges[j]->GetXmap()->GetNcoeffs() == nEdgePts,
300  "Number of edge points does not correspond "
301  "to number of face points.");
302  }
303 
304  for (int j = 0; j < npts; ++j)
305  {
306  tmp[j] = (curve->m_points[j]->GetPtr())[i];
307  }
308 
309  // Interpolate curve points to standard triangle points.
310  Array<OneD, NekDouble> phys(m_xmap->GetTotPoints());
311  LibUtilities::Interp2D(curveKey,curveKey,tmp,
312  B0.GetPointsKey(),B1.GetPointsKey(),
313  phys);
314 
315  // Forwards transform to get coefficient space.
316  m_xmap->FwdTrans(phys, m_coeffs[i]);
317  }
318  else
319  {
320  ASSERTL0(false, "Only 1D/2D points distributions supported.");
321  }
322  }
323  }
324 
325 
326  /**
327  *
328  */
330  {
331  // From Geomtry
333 
334  // From TriFaceComponent
335  m_fid = in.m_fid;
336  m_globalID = m_fid;
337  m_ownVerts = in.m_ownVerts;
338  std::list<CompToElmt>::const_iterator def;
339  for(def = in.m_elmtMap.begin(); def != in.m_elmtMap.end(); def++)
340  {
341  m_elmtMap.push_back(*def);
342  }
343 
344  // From TriGeom
345  m_verts = in.m_verts;
346  m_edges = in.m_edges;
347  for (int i = 0; i < kNedges; i++)
348  {
349  m_eorient[i] = in.m_eorient[i];
350  }
351  m_ownData = in.m_ownData;
352  }
353 
354 
355  /**
356  *
357  */
359  {
360  }
361 
362 
363  /**
364  * Given local collapsed coordinate Lcoord return the value of physical
365  * coordinate in direction i
366  */
368  const Array<OneD, const NekDouble> &Lcoord)
369  {
371  "Geometry is not in physical space");
372 
373  Array<OneD, NekDouble> tmp(m_xmap->GetTotPoints());
374  m_xmap->BwdTrans(m_coeffs[i], tmp);
375 
376  return m_xmap->PhysEvaluate(Lcoord, tmp);
377  }
378 
380  const TriGeom &face1,
381  const TriGeom &face2)
382  {
383  return GetFaceOrientation(face1.m_verts, face2.m_verts);
384  }
385 
387  const PointGeomVector &face1,
388  const PointGeomVector &face2)
389  {
390  int i, j, vmap[3] = {-1,-1,-1};
391  NekDouble x, y, z, x1, y1, z1, cx = 0.0, cy = 0.0, cz = 0.0;
392 
393  // For periodic faces, we calculate the vector between the centre
394  // points of the two faces. (For connected faces this will be
395  // zero). We can then use this to determine alignment later in the
396  // algorithm.
397  for (i = 0; i < 3; ++i)
398  {
399  cx += (*face2[i])(0) - (*face1[i])(0);
400  cy += (*face2[i])(1) - (*face1[i])(1);
401  cz += (*face2[i])(2) - (*face1[i])(2);
402  }
403  cx /= 3;
404  cy /= 3;
405  cz /= 3;
406 
407  // Now construct a mapping which takes us from the vertices of one
408  // face to the other. That is, vertex j of face2 corresponds to
409  // vertex vmap[j] of face1.
410  for (i = 0; i < 3; ++i)
411  {
412  x = (*face1[i])(0);
413  y = (*face1[i])(1);
414  z = (*face1[i])(2);
415  for (j = 0; j < 3; ++j)
416  {
417  x1 = (*face2[j])(0)-cx;
418  y1 = (*face2[j])(1)-cy;
419  z1 = (*face2[j])(2)-cz;
420  if (sqrt((x1-x)*(x1-x)+(y1-y)*(y1-y)+(z1-z)*(z1-z)) < 1e-8)
421  {
422  vmap[j] = i;
423  break;
424  }
425  }
426  }
427 
428  if (vmap[1] == (vmap[0]+1) % 3)
429  {
430  switch (vmap[0])
431  {
432  case 0:
434  break;
435  case 1:
437  break;
438  case 2:
440  break;
441  }
442  }
443  else
444  {
445  switch (vmap[0])
446  {
447  case 0:
449  break;
450  case 1:
452  break;
453  case 2:
455  break;
456  }
457  }
458 
459  ASSERTL0(false, "Unable to determine triangle orientation");
461  }
462 
463 
464  /**
465  *
466  */
467  void TriGeom::v_AddElmtConnected(int gvo_id, int locid)
468  {
469  CompToElmt ee(gvo_id,locid);
470  m_elmtMap.push_back(ee);
471  }
472 
473 
474  /**
475  *
476  */
478  {
479  return int(m_elmtMap.size());
480  }
481 
482 
483  /**
484  *
485  */
486  bool TriGeom::v_IsElmtConnected(int gvo_id, int locid) const
487  {
488  std::list<CompToElmt>::const_iterator def;
489  CompToElmt ee(gvo_id,locid);
490 
491  def = find(m_elmtMap.begin(),m_elmtMap.end(),ee);
492 
493  // Found the element connectivity object in the list
494  return (def != m_elmtMap.end());
495  }
496 
497 
498  /**
499  *
500  */
501  int TriGeom::v_GetFid() const
502  {
503  return m_fid;
504  }
505 
506 
507  /**
508  *
509  */
511  {
512  return m_coordim;
513  }
514 
515 
516  /**
517  *
518  */
520  {
521  return m_xmap->GetBasis(i);
522  }
523 
524 
525  /**
526  *
527  */
529  {
530  ASSERTL1(i <= 2, "edge is out of range");
531 
532  if(i == 0)
533  {
534  return m_xmap->GetBasis(0);
535  }
536  else
537  {
538  return m_xmap->GetBasis(1);
539  }
540  }
541 
542 
543  /**
544  *
545  */
546  NekDouble TriGeom::v_GetCoord(const int i, const Array<OneD,const NekDouble> &Lcoord)
547  {
548  return GetCoord(i,Lcoord);
549  }
550 
551 
552  /**
553  * Set up GeoFac for this geometry using Coord quadrature distribution
554  */
556  {
558  {
559  GeomType Gtype = eRegular;
560 
562 
563  // check to see if expansions are linear
564  for(int i = 0; i < m_coordim; ++i)
565  {
566  if(m_xmap->GetBasisNumModes(0) != 2 ||
567  m_xmap->GetBasisNumModes(1) != 2)
568  {
569  Gtype = eDeformed;
570  }
571  }
572 
574  Gtype, m_coordim, m_xmap, m_coeffs);
575 
577  }
578  }
579 
580  /**
581  *
582  */
584  {
585  m_ownData = true;
586  }
587 
588 
589  /**
590  * Note verts and edges are listed according to anticlockwise
591  * convention but points in _coeffs have to be in array format from
592  * left to right.
593  */
595  {
596  // check to see if geometry structure is already filled
597  if(m_state != ePtsFilled)
598  {
599  int i,j,k;
600  int nEdgeCoeffs = m_xmap->GetEdgeNcoeffs(0);
601 
602  Array<OneD, unsigned int> mapArray (nEdgeCoeffs);
603  Array<OneD, int> signArray(nEdgeCoeffs);
604 
605  for(i = 0; i < kNedges; i++)
606  {
607  m_edges[i]->FillGeom();
608  m_xmap->GetEdgeToElementMap(i,m_eorient[i],mapArray,signArray);
609 
610  nEdgeCoeffs = m_edges[i]->GetXmap()->GetNcoeffs();
611 
612  for(j = 0 ; j < m_coordim; j++)
613  {
614  for(k = 0; k < nEdgeCoeffs; k++)
615  {
616  m_coeffs[j][mapArray[k]] =
617  signArray[k] * m_edges[i]->GetCoeffs(j)[k];
618  }
619  }
620  }
621 
623  }
624  }
625 
626 
627  /**
628  *
629  */
630  NekDouble TriGeom::v_GetLocCoords(const Array<OneD,const NekDouble> &coords,
631  Array<OneD,NekDouble> &Lcoords)
632  {
633  NekDouble resid = 0.0;
635 
636  // calculate local coordinate for coord
637  if(GetMetricInfo()->GetGtype() == eRegular)
638  {
639  NekDouble coords2 = (m_coordim == 3)? coords[2]: 0.0;
640  PointGeom dv1, dv2, norm, orth1, orth2;
641  PointGeom xin(m_coordim,0,coords[0],coords[1],coords2);
642 
643  // Calculate edge vectors from 0-1 and 0-2 edges.
644  dv1.Sub(*m_verts[1],*m_verts[0]);
645  dv2.Sub(*m_verts[2],*m_verts[0]);
646 
647  // Obtain normal to plane in which dv1 and dv2 lie
648  norm.Mult(dv1,dv2);
649 
650  // Obtain vector which are proportional to normal of dv1 and dv2.
651  orth1.Mult(norm,dv1);
652  orth2.Mult(norm,dv2);
653 
654  // Start with vector of desired points minus vertex_0
655  xin -= *m_verts[0];
656 
657  // Calculate length using L/|dv1| = (x-v0).n1/(dv1.n1) for coordiante 1
658  // Then rescale to [-1,1].
659  Lcoords[0] = xin.dot(orth2)/dv1.dot(orth2);
660  Lcoords[0] = 2*Lcoords[0]-1;
661  Lcoords[1] = xin.dot(orth1)/dv2.dot(orth1);
662  Lcoords[1] = 2*Lcoords[1]-1;
663  }
664  else
665  {
666  // Determine nearest point of coords to values in m_xmap
667  int npts = m_xmap->GetTotPoints();
668  Array<OneD, NekDouble> ptsx(npts), ptsy(npts);
669  Array<OneD, NekDouble> tmpx(npts), tmpy(npts);
670 
671  m_xmap->BwdTrans(m_coeffs[0], ptsx);
672  m_xmap->BwdTrans(m_coeffs[1], ptsy);
673 
674  const Array<OneD, const NekDouble> za = m_xmap->GetPoints(0);
675  const Array<OneD, const NekDouble> zb = m_xmap->GetPoints(1);
676 
677  //guess the first local coords based on nearest point
678  Vmath::Sadd(npts, -coords[0], ptsx,1,tmpx,1);
679  Vmath::Sadd(npts, -coords[1], ptsy,1,tmpy,1);
680  Vmath::Vmul (npts, tmpx,1,tmpx,1,tmpx,1);
681  Vmath::Vvtvp(npts, tmpy,1,tmpy,1,tmpx,1,tmpx,1);
682 
683  int min_i = Vmath::Imin(npts,tmpx,1);
684 
685  Lcoords[0] = za[min_i%za.num_elements()];
686  Lcoords[1] = zb[min_i/za.num_elements()];
687 
688  // recover cartesian coordinate from collapsed coordinate.
689  Lcoords[0] = (1.0+Lcoords[0])*(1.0-Lcoords[1])/2 -1.0;
690 
691  // Perform newton iteration to find local coordinates
692  NewtonIterationForLocCoord(coords, ptsx, ptsy, Lcoords,resid);
693  }
694  return resid;
695  }
696 
697 
698  /**
699  *
700  */
701  int TriGeom::v_GetEid(int i) const
702  {
703  ASSERTL2((i >=0) && (i <= 2),"Edge id must be between 0 and 2");
704  return m_edges[i]->GetEid();
705  }
706 
707 
708  /**
709  *
710  */
711  int TriGeom::v_GetVid(int i) const
712  {
713  ASSERTL2((i >=0) && (i <= 2),"Vertex id must be between 0 and 2");
714  return m_verts[i]->GetVid();
715  }
716 
717 
718  /**
719  *
720  */
722  {
723  ASSERTL2((i >=0) && (i <= 2),"Vertex id must be between 0 and 2");
724  return m_verts[i];
725  }
726 
727 
728  /**
729  *
730  */
732  {
733  ASSERTL2((i >=0) && (i <= 2),"Edge id must be between 0 and 3");
734  return m_edges[i];
735  }
736 
737 
738  /**
739  *
740  */
742  {
743  ASSERTL2((i >=0) && (i <= 2),"Edge id must be between 0 and 2");
744  return m_eorient[i];
745  }
746 
747 
748  /**
749  *
750  */
752  {
753  ASSERTL2((i >=0) && (i <= 3),"Edge id must be between 0 and 3");
754  if(i < 2)
755  {
756  return m_eorient[i];
757  }
758  else
759  {
761  {
762  return StdRegions::eBackwards;
763  }
764  else
765  {
766  return StdRegions::eForwards;
767  }
768  }
769  }
770 
771 
772  /**
773  *
774  */
776  {
777  int returnval = -1;
778 
779  SegGeomVector::iterator edgeIter;
780  int i;
781 
782  for (i=0,edgeIter = m_edges.begin(); edgeIter != m_edges.end(); ++edgeIter,++i)
783  {
784  if (*edgeIter == edge)
785  {
786  returnval = i;
787  break;
788  }
789  }
790 
791  return returnval;
792  }
793 
794 
795  /**
796  *
797  */
799  {
800  return kNverts;
801  }
802 
803 
804  /**
805  *
806  */
808  {
809  return kNedges;
810  }
811 
812 
813  /**
814  * @brief Determines if a point specified in global coordinates is
815  * located within this tetrahedral geometry.
816  */
818  const Array<OneD, const NekDouble> &gloCoord, NekDouble tol)
819  {
820  Array<OneD,NekDouble> locCoord(GetCoordim(),0.0);
821  return v_ContainsPoint(gloCoord,locCoord,tol);
822 
823  }
824 
825  /**
826  *
827  */
828  bool TriGeom::v_ContainsPoint(const Array<OneD, const NekDouble> &gloCoord,
829  Array<OneD, NekDouble> &stdCoord,
830  NekDouble tol)
831  {
832  NekDouble resid;
833  return v_ContainsPoint(gloCoord,stdCoord,tol,resid);
834  }
835 
836  bool TriGeom::v_ContainsPoint(const Array<OneD, const NekDouble> &gloCoord,
837  Array<OneD, NekDouble> &stdCoord,
838  NekDouble tol,
839  NekDouble &resid)
840  {
841  ASSERTL1(gloCoord.num_elements() >= 2,
842  "Two dimensional geometry expects at least two coordinates.");
843 
844  resid = GetLocCoords(gloCoord, stdCoord);
845  if (stdCoord[0] >= -(1+tol) && stdCoord[1] >= -(1+tol)
846  && stdCoord[0] + stdCoord[1] <= tol)
847  {
848  return true;
849  }
850  return false;
851  }
852  }; //end of namespace
853 }; //end of namespace