Nektar++
GeomFactors.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: GeomFactors.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: Geometric factors base class.
32 //
33 ////////////////////////////////////////////////////////////////////////////////
34 
37 
38 namespace Nektar
39 {
40  namespace SpatialDomains
41  {
42  /**
43  * @class GeomFactors
44  *
45  * This class stores the various geometric factors associated with a
46  * specific element, necessary for fundamental integration and
47  * differentiation operations as well as edge and surface normals.
48  *
49  * Initially, these algorithms are provided with a mapping from the
50  * reference region element to the physical element. Practically, this
51  * is represented using a corresponding reference region element for
52  * each coordinate component. Note that for straight-sided elements,
53  * these elements will be of linear order. Curved elements are
54  * represented using higher-order coordinate mappings. This geometric
55  * order is in contrast to the order of the spectral/hp expansion order
56  * on the element.
57  *
58  * For application of the chain rule during differentiation we require
59  * the partial derivatives \f[\frac{\partial \xi_i}{\partial \chi_j}\f]
60  * evaluated at the physical points of the expansion basis. We also
61  * construct the inverse metric tensor \f$g^{ij}\f$ which, in the case
62  * of a domain embedded in a higher-dimensional space, supports the
63  * conversion of covariant quantities to contravariant quantities.
64  * When the expansion dimension is equal to the coordinate dimension the
65  * Jacobian of the mapping \f$\chi_j\f$ is a square matrix and
66  * consequently the required terms are the entries of the inverse of the
67  * Jacobian. However, in general this is not the case, so we therefore
68  * implement the construction of these terms following the derivation
69  * in Cantwell, et. al. \cite CaYaKiPeSh13. Given the coordinate maps
70  * \f$\chi_i\f$, this comprises of five steps
71  * -# Compute the terms of the Jacobian
72  * \f$\frac{\partial \chi_i}{\partial \xi_j}\f$.
73  * -# Compute the metric tensor
74  * \f$g_{ij}=\mathbf{t}_{(i)}\cdot\mathbf{t}_{(j)}\f$.
75  * -# Compute the square of the Jacobian determinant
76  * \f$g=|\mathbf{g}|\f$.
77  * -# Compute the inverse metric tensor \f$g^{ij}\f$.
78  * -# Compute the terms \f$\frac{\partial \xi_i}{\partial \chi_j}\f$.
79  */
80 
81  /**
82  * @param gtype Specified whether the geometry is regular or
83  * deformed.
84  * @param coordim Specifies the dimension of the coordinate
85  * system.
86  * @param Coords Coordinate maps of the element.
87  */
89  const GeomType gtype,
90  const int coordim,
92  const Array<OneD, Array<OneD, NekDouble> > &coords) :
93  m_type(gtype),
94  m_expDim(xmap->GetShapeDimension()),
95  m_coordDim(coordim),
96  m_valid(true),
97  m_xmap(xmap),
98  m_coords(coords)
99  {
100  CheckIfValid();
101  }
102 
103 
104  /**
105  * @param S An instance of a GeomFactors class from which
106  * to construct a new instance.
107  */
109  m_type(S.m_type),
110  m_expDim(S.m_expDim),
112  m_valid(S.m_valid),
113  m_xmap(S.m_xmap),
114  m_coords(S.m_coords)
115  {
116  }
117 
118 
119  /**
120  *
121  */
123  {
124  }
125 
126 
127  /**
128  * Member data equivalence is tested in the following order: shape type,
129  * expansion dimension, coordinate dimension and coordinates.
130  */
131  bool operator==(const GeomFactors &lhs, const GeomFactors &rhs)
132  {
133  if(!(lhs.m_type == rhs.m_type))
134  {
135  return false;
136  }
137 
138  if(!(lhs.m_expDim == rhs.m_expDim))
139  {
140  return false;
141  }
142 
143  if(!(lhs.m_coordDim == rhs.m_coordDim))
144  {
145  return false;
146  }
147 
148  const Array<OneD, const NekDouble> jac_lhs =
149  lhs.ComputeJac(lhs.m_xmap->GetPointsKeys());
150  const Array<OneD, const NekDouble> jac_rhs =
151  rhs.ComputeJac(rhs.m_xmap->GetPointsKeys());
152  if(!(jac_lhs == jac_rhs))
153  {
154  return false;
155  }
156 
157  return true;
158  }
159 
160 
161  /**
162  * Derivatives are computed at the geometry point distributions and
163  * interpolated to the target point distributions.
164  *
165  * @param tpoints Target point distributions.
166  * @returns Derivative of coordinate map evaluated at
167  * target point distributions.
168  */
170  const LibUtilities::PointsKeyVector &keyTgt) const
171  {
172  ASSERTL1(keyTgt.size() == m_expDim,
173  "Dimension of target point distribution does not match "
174  "expansion dimension.");
175 
176  int i = 0, j = 0;
177  int nqtot_map = 1;
178  int nqtot_tbasis = 1;
182 
183  // Allocate storage and compute number of points
184  for (i = 0; i < m_expDim; ++i)
185  {
186  map_points[i] = m_xmap->GetBasis(i)->GetPointsKey();
187  nqtot_map *= map_points[i].GetNumPoints();
188  nqtot_tbasis *= keyTgt[i].GetNumPoints();
191  }
192 
193  // Calculate local derivatives
194  for(i = 0; i < m_coordDim; ++i)
195  {
196  Array<OneD, NekDouble> tmp(nqtot_map);
197  // Transform from coefficient space to physical space
198  m_xmap->BwdTrans(m_coords[i], tmp);
199 
200  // Allocate storage and take the derivative (calculated at the
201  // points as specified in 'Coords')
202  for (j = 0; j < m_expDim; ++j)
203  {
204  d_map[j][i] = Array<OneD,NekDouble>(nqtot_map);
205  deriv[j][i] = Array<OneD,NekDouble>(nqtot_tbasis);
206  m_xmap->StdPhysDeriv(j, tmp, d_map[j][i]);
207  }
208  }
209 
210  for (i = 0; i < m_coordDim; ++i)
211  {
212  // Interpolate the derivatives:
213  // - from the points as defined in the mapping ('Coords')
214  // - to the points we at which we want to know the metrics
215  // ('tbasis')
216  bool same = true;
217  for (j = 0; j < m_expDim; ++j)
218  {
219  same = same && (map_points[j] == keyTgt[j]);
220  }
221  if( same )
222  {
223  for (j = 0; j < m_expDim; ++j)
224  {
225  deriv[j][i] = d_map[j][i];
226  }
227  }
228  else
229  {
230  for (j = 0; j < m_expDim; ++j)
231  {
232  Interp(map_points, d_map[j][i], keyTgt, deriv[j][i]);
233  }
234  }
235  }
236 
237  return deriv;
238  }
239 
240 
241  /**
242  * This routine returns an array of values specifying the Jacobian
243  * of the mapping at quadrature points in the element. The array
244  * is either of size 1 in the case of elements having #GeomType
245  * #eRegular, or of size equal to the number of quadrature points for
246  * #eDeformed elements.
247  *
248  * @returns Array containing the Jacobian of the coordinate
249  * mapping at the quadrature points of the element.
250  * @see GeomType
251  */
253  const LibUtilities::PointsKeyVector &keyTgt) const
254  {
255  ASSERTL1(keyTgt.size() == m_expDim,
256  "Dimension of target point distribution does not match "
257  "expansion dimension.");
258 
259  int i = 0, j = 0, k = 0, l = 0;
260  int ptsTgt = 1;
261 
262  if (m_type == eDeformed)
263  {
264  // Allocate storage and compute number of points
265  for (i = 0; i < m_expDim; ++i)
266  {
267  ptsTgt *= keyTgt[i].GetNumPoints();
268  }
269  }
270 
271  // Get derivative at geometry points
272  DerivStorage deriv = ComputeDeriv(keyTgt);
273 
274  Array<TwoD, NekDouble> tmp (m_expDim*m_expDim, ptsTgt, 0.0);
275  Array<TwoD, NekDouble> gmat(m_expDim*m_expDim, ptsTgt, 0.0);
276  Array<OneD, NekDouble> jac (ptsTgt, 0.0);
277 
278  // Compute g_{ij} as t_i \cdot t_j and store in tmp
279  for (i = 0, l = 0; i < m_expDim; ++i)
280  {
281  for (j = 0; j < m_expDim; ++j, ++l)
282  {
283  for (k = 0; k < m_coordDim; ++k)
284  {
285  Vmath::Vvtvp(ptsTgt, &deriv[i][k][0], 1,
286  &deriv[j][k][0], 1,
287  &tmp[l][0], 1,
288  &tmp[l][0], 1);
289  }
290  }
291  }
292 
293  Adjoint(tmp, gmat);
294 
295  // Compute g = det(g_{ij}) (= Jacobian squared) and store
296  // temporarily in m_jac.
297  for (i = 0; i < m_expDim; ++i)
298  {
299  Vmath::Vvtvp(ptsTgt, &tmp[i][0], 1, &gmat[i*m_expDim][0], 1,
300  &jac[0], 1, &jac[0], 1);
301  }
302 
303  // Compute the Jacobian = sqrt(g)
304  Vmath::Vsqrt(ptsTgt, &jac[0], 1, &jac[0], 1);
305 
306  return jac;
307  }
308 
309 
310  /**
311  * This routine returns a two-dimensional array of values specifying
312  * the inverse metric terms associated with the coordinate mapping of
313  * the corresponding reference region to the physical element. These
314  * terms correspond to the \f$g^{ij}\f$ terms in \cite CaYaKiPeSh13 and,
315  * in the case of an embedded manifold, map covariant quantities to
316  * contravariant quantities. The leading index of the array is the index
317  * of the term in the tensor numbered as
318  * \f[\left(\begin{array}{ccc}
319  * 0 & 1 & 2 \\
320  * 1 & 3 & 4 \\
321  * 2 & 4 & 5
322  * \end{array}\right)\f].
323  * The second dimension is either of size 1 in the case of elements
324  * having #GeomType #eRegular, or of size equal to the number of
325  * quadrature points for #eDeformed elements.
326  *
327  * @see [Wikipedia "Covariance and Contravariance of Vectors"]
328  * (http://en.wikipedia.org/wiki/Covariance_and_contravariance_of_vectors)
329  * @returns Two-dimensional array containing the inverse
330  * metric tensor of the coordinate mapping.
331  */
333  const LibUtilities::PointsKeyVector &keyTgt) const
334  {
335  ASSERTL1(keyTgt.size() == m_expDim,
336  "Dimension of target point distribution does not match "
337  "expansion dimension.");
338 
339  int i = 0, j = 0, k = 0, l = 0;
340  int ptsTgt = 1;
341 
342  if (m_type == eDeformed)
343  {
344  // Allocate storage and compute number of points
345  for (i = 0; i < m_expDim; ++i)
346  {
347  ptsTgt *= keyTgt[i].GetNumPoints();
348  }
349  }
350 
351  // Get derivative at geometry points
352  DerivStorage deriv = ComputeDeriv(keyTgt);
353 
354  Array<TwoD, NekDouble> tmp (m_expDim*m_expDim, ptsTgt, 0.0);
355  Array<TwoD, NekDouble> gmat(m_expDim*m_expDim, ptsTgt, 0.0);
356  Array<OneD, NekDouble> jac (ptsTgt, 0.0);
357 
358  // Compute g_{ij} as t_i \cdot t_j and store in tmp
359  for (i = 0, l = 0; i < m_expDim; ++i)
360  {
361  for (j = 0; j < m_expDim; ++j, ++l)
362  {
363  for (k = 0; k < m_coordDim; ++k)
364  {
365  Vmath::Vvtvp(ptsTgt, &deriv[i][k][0], 1,
366  &deriv[j][k][0], 1,
367  &tmp[l][0], 1,
368  &tmp[l][0], 1);
369  }
370  }
371  }
372 
373  Adjoint(tmp, gmat);
374 
375  // Compute g = det(g_{ij}) (= Jacobian squared) and store
376  // temporarily in m_jac.
377  for (i = 0; i < m_expDim; ++i)
378  {
379  Vmath::Vvtvp(ptsTgt, &tmp[i][0], 1, &gmat[i*m_expDim][0], 1,
380  &jac[0], 1, &jac[0], 1);
381  }
382 
383  for (i = 0; i < m_expDim*m_expDim; ++i)
384  {
385  Vmath::Vdiv(ptsTgt, &gmat[i][0], 1, &jac[0], 1, &gmat[i][0], 1);
386  }
387 
388  return gmat;
389  }
390 
391 
392  /**
393  * @param keyTgt Target point distributions.
394  * @returns Derivative factors evaluated at the target
395  * point distributions.
396  */
398  const LibUtilities::PointsKeyVector& keyTgt) const
399  {
400  ASSERTL1(keyTgt.size() == m_expDim,
401  "Dimension of target point distribution does not match "
402  "expansion dimension.");
403 
404  int i = 0, j = 0, k = 0, l = 0;
405  int ptsTgt = 1;
406 
407  if (m_type == eDeformed)
408  {
409  // Allocate storage and compute number of points
410  for (i = 0; i < m_expDim; ++i)
411  {
412  ptsTgt *= keyTgt[i].GetNumPoints();
413  }
414  }
415 
416  // Get derivative at geometry points
417  DerivStorage deriv = ComputeDeriv(keyTgt);
418 
419  Array<TwoD, NekDouble> tmp (m_expDim*m_expDim, ptsTgt, 0.0);
420  Array<TwoD, NekDouble> gmat(m_expDim*m_expDim, ptsTgt, 0.0);
421  Array<OneD, NekDouble> jac (ptsTgt, 0.0);
422  Array<TwoD, NekDouble> factors(m_expDim*m_coordDim, ptsTgt, 0.0);
423 
424  // Compute g_{ij} as t_i \cdot t_j and store in tmp
425  for (i = 0, l = 0; i < m_expDim; ++i)
426  {
427  for (j = 0; j < m_expDim; ++j, ++l)
428  {
429  for (k = 0; k < m_coordDim; ++k)
430  {
431  Vmath::Vvtvp(ptsTgt, &deriv[i][k][0], 1,
432  &deriv[j][k][0], 1,
433  &tmp[l][0], 1,
434  &tmp[l][0], 1);
435  }
436  }
437  }
438 
439  Adjoint(tmp, gmat);
440 
441  // Compute g = det(g_{ij}) (= Jacobian squared) and store
442  // temporarily in m_jac.
443  for (i = 0; i < m_expDim; ++i)
444  {
445  Vmath::Vvtvp(ptsTgt, &tmp[i][0], 1, &gmat[i*m_expDim][0], 1,
446  &jac[0], 1, &jac[0], 1);
447  }
448 
449  for (i = 0; i < m_expDim*m_expDim; ++i)
450  {
451  Vmath::Vdiv(ptsTgt, &gmat[i][0], 1, &jac[0], 1, &gmat[i][0], 1);
452  }
453 
454  // Compute the Jacobian = sqrt(g)
455  Vmath::Vsqrt(ptsTgt, &jac[0], 1, &jac[0], 1);
456 
457  // Compute the derivative factors
458  for (k = 0, l = 0; k < m_coordDim; ++k)
459  {
460  for (j = 0; j < m_expDim; ++j, ++l)
461  {
462  for (i = 0; i < m_expDim; ++i)
463  {
464  Vmath::Vvtvp(ptsTgt, &deriv[i][k][0], 1,
465  &gmat[m_expDim*i+j][0], 1,
466  &factors[l][0], 1,
467  &factors[l][0], 1);
468  }
469  }
470  }
471 
472  return factors;
473  }
474 
476  const LibUtilities::PointsKeyVector& keyTgt,
477  const SpatialDomains::GeomMMF MMFdir,
478  const Array<OneD, const NekDouble> &factors,
479  Array<OneD, Array<OneD, NekDouble> > &movingframes)
480  {
481  ASSERTL1(keyTgt.size() == m_expDim,
482  "Dimension of target point distribution does not match "
483  "expansion dimension.");
484 
485  int i = 0, k = 0;
486  int ptsTgt = 1;
487  int nq = 1;
488 
489  for (i = 0; i < m_expDim; ++i)
490  {
491  nq *= keyTgt[i].GetNumPoints();
492  }
493 
494  if (m_type == eDeformed)
495  {
496  // Allocate storage and compute number of points
497  for (i = 0; i < m_expDim; ++i)
498  {
499  ptsTgt *= keyTgt[i].GetNumPoints();
500  }
501  }
502 
503  // Get derivative at geometry points
504  DerivStorage deriv = ComputeDeriv(keyTgt);
505 
506  // number of moving frames is requited to be 3, even for surfaces
507  int MFdim = 3;
508 
510 
511  // Compute g_{ij} as t_i \cdot t_j and store in tmp
512  for (i = 0; i < MFdim; ++i)
513  {
515  for (k = 0; k < m_coordDim; ++k)
516  {
517  MFtmp[i][k] = Array<OneD, NekDouble>(nq);
518  }
519  }
520 
521  // Compute g_{ij} as t_i \cdot t_j and store in tmp
522  for (i = 0; i < MFdim-1; ++i)
523  {
524  for (k = 0; k < m_coordDim; ++k)
525  {
526  if (m_type == eDeformed)
527  {
528  Vmath::Vcopy(ptsTgt, &deriv[i][k][0], 1,
529  &MFtmp[i][k][0], 1);
530  }
531  else
532  {
533  Vmath::Fill(nq, deriv[i][k][0], MFtmp[i][k], 1);
534  }
535  }
536  }
537 
538  // Direction of MF1 is preserved: MF2 is considered in the same
539  // tangent plane as MF1. MF3 is computed by cross product of MF1
540  // and MF2. MF2 is consequently computed as the cross product of
541  // MF3 and MF1.
543  for (int k=0; k<m_coordDim; k++)
544  {
545  PrincipleDir[k] = Array<OneD, NekDouble>(nq);
546  }
547 
548  if( !(MMFdir == eLOCAL) )
549  {
550  ComputePrincipleDirection(keyTgt, MMFdir,
551  factors, PrincipleDir);
552  }
553 
554  // MF3 = MF1 \times MF2
555  VectorCrossProd(MFtmp[0], MFtmp[1], MFtmp[2]);
556 
557  // Normalizing MF3
558  VectorNormalise(MFtmp[2]);
559 
560  if ( !(MMFdir == eLOCAL) )
561  {
562  Array<OneD, NekDouble> temp(nq, 0.0);
563 
564  // Reorient MF1 along the PrincipleDir
565  for (i = 0; i < m_coordDim; ++i)
566  {
567  Vmath::Vvtvp(nq, MFtmp[2][i], 1,
568  PrincipleDir[i], 1,
569  temp, 1,
570  temp, 1);
571  }
572  Vmath::Neg(nq, temp, 1);
573 
574  // u2 = v2 - < u1 , v2 > ( u1 / < u1, u1 > )
575  for (i = 0; i < m_coordDim; ++i)
576  {
577  Vmath::Vvtvp(nq, temp, 1,
578  MFtmp[2][i], 1,
579  PrincipleDir[i], 1,
580  MFtmp[0][i], 1);
581  }
582  }
583 
584  // Normalizing MF1
585  VectorNormalise(MFtmp[0]);
586 
587  // MF2 = MF3 \times MF1
588  VectorCrossProd(MFtmp[2], MFtmp[0], MFtmp[1]);
589 
590  // Normalizing MF2
591  VectorNormalise(MFtmp[1]);
592 
593  for (i = 0; i < MFdim; ++i)
594  {
595  for (k = 0; k < m_coordDim; ++k)
596  {
597  Vmath::Vcopy(nq, &MFtmp[i][k][0], 1,
598  &movingframes[i*m_coordDim+k][0], 1);
599  }
600  }
601  }
602 
603 
604  /**
605  * Constructs the Jacobian as per Spencer's book p158 and tests if
606  * negative.
607  */
609  {
610  // Jacobian test only makes sense when expdim = coorddim
611  // If one-dimensional then element is valid.
612  if (m_coordDim != m_expDim || m_expDim == 1)
613  {
614  m_valid = true;
615  return;
616  }
617 
619  int nqtot = 1;
620  for (int i = 0; i < m_expDim; ++i)
621  {
622  p[i] = m_xmap->GetBasis(i)->GetPointsKey();
623  nqtot *= p[i].GetNumPoints();
624  }
625  int pts = (m_type == eRegular || m_type == eMovingRegular)
626  ? 1 : nqtot;
627  Array<OneD, NekDouble> jac(pts, 0.0);
628 
629  DerivStorage deriv = GetDeriv(p);
630 
631  switch (m_expDim)
632  {
633  case 2:
634  {
635  Vmath::Vvtvvtm(pts, &deriv[0][0][0], 1, &deriv[1][1][0], 1,
636  &deriv[1][0][0], 1, &deriv[0][1][0], 1,
637  &jac[0], 1);
638  break;
639  }
640  case 3:
641  {
642  Array<OneD, NekDouble> tmp(pts, 0.0);
643 
644  Vmath::Vvtvvtm(pts, &deriv[1][1][0], 1, &deriv[2][2][0], 1,
645  &deriv[2][1][0], 1, &deriv[1][2][0], 1,
646  &tmp[0], 1);
647  Vmath::Vvtvp (pts, &deriv[0][0][0], 1, &tmp[0], 1,
648  &jac[0], 1, &jac[0], 1);
649 
650  Vmath::Vvtvvtm(pts, &deriv[2][1][0], 1, &deriv[0][2][0], 1,
651  &deriv[0][1][0], 1, &deriv[2][2][0], 1,
652  &tmp[0], 1);
653  Vmath::Vvtvp (pts, &deriv[1][0][0], 1, &tmp[0], 1,
654  &jac[0], 1, &jac[0], 1);
655 
656  Vmath::Vvtvvtm(pts, &deriv[0][1][0], 1, &deriv[1][2][0], 1,
657  &deriv[1][1][0], 1, &deriv[0][2][0], 1,
658  &tmp[0], 1);
659  Vmath::Vvtvp (pts, &deriv[2][0][0], 1, &tmp[0], 1,
660  &jac[0], 1, &jac[0], 1);
661 
662  break;
663  }
664  }
665 
666  if (Vmath::Vmin(pts, &jac[0], 1) < 0)
667  {
668  m_valid = false;
669  }
670  }
671 
672 
673  /**
674  * @param map_points Source data point distribution.
675  * @param src Source data to be interpolated.
676  * @param tpoints Target data point distribution.
677  * @param tgt Target data storage.
678  */
680  const LibUtilities::PointsKeyVector &src_points,
681  const Array<OneD, const NekDouble> &src,
682  const LibUtilities::PointsKeyVector &tgt_points,
683  Array<OneD, NekDouble> &tgt) const
684  {
685  ASSERTL1(src_points.size() == tgt_points.size(),
686  "Dimension of target point distribution does not match "
687  "expansion dimension.");
688 
689  switch (m_expDim)
690  {
691  case 1:
692  LibUtilities::Interp1D(src_points[0], src,
693  tgt_points[0], tgt);
694  break;
695  case 2:
696  LibUtilities::Interp2D(src_points[0], src_points[1], src,
697  tgt_points[0], tgt_points[1], tgt);
698  break;
699  case 3:
700  LibUtilities::Interp3D(src_points[0], src_points[1],
701  src_points[2], src,
702  tgt_points[0], tgt_points[1],
703  tgt_points[2], tgt);
704  break;
705  }
706  }
707 
708 
709  /**
710  * Input and output arrays are of dimension
711  * (m_expDim*m_expDim) x num_points. The first index of the input and
712  * output arrays are ordered row-by-row.
713  * @param src Input data array.
714  * @param tgt Storage for adjoint matrix data.
715  */
717  const Array<TwoD, const NekDouble>& src,
718  Array<TwoD, NekDouble>& tgt) const
719  {
720  ASSERTL1(src.num_elements() == tgt.num_elements(),
721  "Source matrix is of different size to destination"
722  "matrix for computing adjoint.");
723 
724  int n = src[0].num_elements();
725  switch (m_expDim)
726  {
727  case 1:
728  Vmath::Fill (n, 1.0, &tgt[0][0], 1);
729  break;
730  case 2:
731  Vmath::Vcopy(n, &src[3][0], 1, &tgt[0][0], 1);
732  Vmath::Smul (n, -1.0, &src[1][0], 1, &tgt[1][0], 1);
733  Vmath::Smul (n, -1.0, &src[2][0], 1, &tgt[2][0], 1);
734  Vmath::Vcopy(n, &src[0][0], 1, &tgt[3][0], 1);
735  break;
736  case 3:
737  {
738  int a, b, c, d, e, i, j;
739 
740  // Compute g^{ij} by computing Cofactors(g_ij)^T
741  for (i = 0; i < m_expDim; ++i)
742  {
743  for (j = 0; j < m_expDim; ++j)
744  {
745  a = ((i+1)%m_expDim) * m_expDim + ((j+1)%m_expDim);
746  b = ((i+1)%m_expDim) * m_expDim + ((j+2)%m_expDim);
747  c = ((i+2)%m_expDim) * m_expDim + ((j+1)%m_expDim);
748  d = ((i+2)%m_expDim) * m_expDim + ((j+2)%m_expDim);
749  e = j*m_expDim + i;
750  Vmath::Vvtvvtm(n, &src[a][0], 1, &src[d][0], 1,
751  &src[b][0], 1, &src[c][0], 1,
752  &tgt[e][0], 1);
753  }
754  }
755  break;
756  }
757  }
758  }
759 
760 
761  /**
762  *
763  */
765  const LibUtilities::PointsKeyVector& keyTgt,
766  const SpatialDomains::GeomMMF MMFdir,
767  const Array<OneD, const NekDouble> &factors,
768  Array<OneD, Array<OneD,NekDouble> > &output)
769  {
770  int nq = output[0].num_elements();
771 
773  for (int i = 0; i < m_coordDim; ++i)
774  {
775  output[i] = Array<OneD, NekDouble> (nq, 0.0);
776  }
777 
778  // Construction of Connection
779  switch(MMFdir)
780  {
781  // projection to x-axis
782  case eTangentX:
783  {
784  Vmath::Fill(nq, 1.0, output[0], 1);
785  break;
786  }
787  case eTangentY:
788  {
789  Vmath::Fill(nq, 1.0, output[1], 1);
790  break;
791  }
792  case eTangentXY:
793  {
794  Vmath::Fill(nq, sqrt(2.0), output[0], 1);
795  Vmath::Fill(nq, sqrt(2.0), output[1], 1);
796  break;
797  }
798  case eTangentZ:
799  {
800  Vmath::Fill(nq, 1.0, output[2], 1);
801  break;
802  }
803  case eTangentCircular:
804  {
805  // Tangent direction depends on spatial location.
806  Array<OneD, Array<OneD, NekDouble> > x(m_coordDim);
807  for (int k = 0; k < m_coordDim; k++)
808  {
809  x[k] = Array<OneD, NekDouble>(nq);
810  }
811 
812  // m_coords are StdExpansions which store the mapping
813  // between the std element and the local element. Bwd
814  // transforming the std element minimum basis gives a
815  // minimum physical basis for geometry. Need to then
816  // interpolate this up to the quadrature basis.
817  int nqtot_map = 1;
819  for (int i = 0; i < m_expDim; ++i)
820  {
821  map_points[i] = m_xmap->GetBasis(i)->GetPointsKey();
822  nqtot_map *= map_points[i].GetNumPoints();
823  }
824  Array<OneD, NekDouble> tmp(nqtot_map);
825  for (int k = 0; k < m_coordDim; k++)
826  {
827  m_xmap->BwdTrans(m_coords[k], tmp);
828  Interp(map_points, tmp, keyTgt, x[k]);
829  }
830 
831  // circular around the center of the domain
832  NekDouble radius, xc=0.0, yc=0.0, xdis, ydis;
833  NekDouble la, lb;
834 
835  ASSERTL1(factors.num_elements() >= 4,
836  "factors is too short.");
837 
838  la = factors[0];
839  lb = factors[1];
840  xc = factors[2];
841  yc = factors[3];
842 
843  for (int i = 0; i < nq; i++)
844  {
845  xdis = x[0][i]-xc;
846  ydis = x[1][i]-yc;
847  radius = sqrt(xdis*xdis/la/la+ydis*ydis/lb/lb);
848  output[0][i] = ydis/radius;
849  output[1][i] = -1.0*xdis/radius;
850  }
851  break;
852  }
853  case eTangentIrregular:
854  {
855  // Tangent direction depends on spatial location.
856  Array<OneD, Array<OneD, NekDouble> > x(m_coordDim);
857  for (int k = 0; k < m_coordDim; k++)
858  {
859  x[k] = Array<OneD, NekDouble>(nq);
860  }
861 
862  int nqtot_map = 1;
864  for (int i = 0; i < m_expDim; ++i)
865  {
866  map_points[i] = m_xmap->GetBasis(i)->GetPointsKey();
867  nqtot_map *= map_points[i].GetNumPoints();
868  }
869  Array<OneD, NekDouble> tmp(nqtot_map);
870  for (int k = 0; k < m_coordDim; k++)
871  {
872  m_xmap->BwdTrans(m_coords[k], tmp);
873  Interp(map_points, tmp, keyTgt, x[k]);
874  }
875 
876  // circular around the center of the domain
877  NekDouble xtan, ytan, mag;
878  for (int i = 0; i < nq; i++)
879  {
880  xtan = -1.0*(x[1][i]*x[1][i]*x[1][i] + x[1][i]);
881  ytan = 2.0*x[0][i];
882  mag = sqrt(xtan*xtan + ytan*ytan);
883  output[0][i] = xtan/mag;
884  output[1][i] = ytan/mag;
885  }
886  break;
887  }
888  case eTangentNonconvex:
889  {
890  // Tangent direction depends on spatial location.
891  Array<OneD, Array<OneD, NekDouble> > x(m_coordDim);
892  for (int k = 0; k < m_coordDim; k++)
893  {
894  x[k] = Array<OneD, NekDouble>(nq);
895  }
896 
897  int nqtot_map = 1;
899  for (int i = 0; i < m_expDim; ++i)
900  {
901  map_points[i] = m_xmap->GetBasis(i)->GetPointsKey();
902  nqtot_map *= map_points[i].GetNumPoints();
903  }
904  Array<OneD, NekDouble> tmp(nqtot_map);
905  for (int k = 0; k < m_coordDim; k++)
906  {
907  m_xmap->BwdTrans(m_coords[k], tmp);
908  Interp(map_points, tmp, keyTgt, x[k]);
909  }
910 
911  // circular around the center of the domain
912  NekDouble xtan, ytan, mag;
913  for (int i = 0; i < nq; i++)
914  {
915  xtan = -2.0*x[1][i]*x[1][i]*x[1][i] + x[1][i];
916  ytan = sqrt(3.0)*x[0][i];
917  mag = sqrt(xtan*xtan + ytan*ytan);
918  output[0][i] = xtan/mag;
919  output[1][i] = ytan/mag;
920  }
921  break;
922  }
923  default:
924  {
925  break;
926  }
927  }
928  }
929 
930 
931  /**
932  *
933  */
936  {
937  int ndim = array.num_elements();
938  ASSERTL0(ndim > 0, "Number of components must be > 0.");
939  for (int i = 1; i < ndim; ++i)
940  {
941  ASSERTL0(array[i].num_elements() == array[0].num_elements(),
942  "Array size mismatch in coordinates.");
943  }
944 
945  int nq = array[0].num_elements();
946  Array<OneD, NekDouble> norm (nq, 0.0);
947 
948  // Compute the norm of each vector.
949  for (int i = 0; i < ndim; ++i)
950  {
951  Vmath::Vvtvp(nq, array[i], 1,
952  array[i], 1,
953  norm, 1,
954  norm, 1);
955  }
956 
957  Vmath::Vsqrt(nq, norm, 1, norm, 1);
958 
959  // Normalise the vectors by the norm
960  for (int i = 0; i < ndim; ++i)
961  {
962  Vmath::Vdiv(nq, array[i], 1, norm, 1, array[i], 1);
963  }
964  }
965 
966 
967  /**
968  * @brief Computes the vector cross-product in 3D of \a v1 and \a v2,
969  * storing the result in \a v3.
970  *
971  * @param v1 First input vector.
972  * @param v2 Second input vector.
973  * @param v3 Output vector computed to be orthogonal to
974  * both \a v1 and \a v2.
975  */
977  const Array<OneD, const Array<OneD, NekDouble> > &v1,
978  const Array<OneD, const Array<OneD, NekDouble> > &v2,
980  {
981  ASSERTL0(v1.num_elements() == 3,
982  "Input 1 has dimension not equal to 3.");
983  ASSERTL0(v2.num_elements() == 3,
984  "Input 2 has dimension not equal to 3.");
985  ASSERTL0(v3.num_elements() == 3,
986  "Output vector has dimension not equal to 3.");
987 
988  int nq = v1[0].num_elements();
989  Array<OneD, NekDouble> temp(nq);
990 
991  Vmath::Vmul (nq, v1[2], 1, v2[1], 1, temp, 1);
992  Vmath::Vvtvm(nq, v1[1], 1, v2[2], 1, temp, 1, v3[0], 1);
993 
994  Vmath::Vmul (nq, v1[0], 1, v2[2], 1, temp, 1);
995  Vmath::Vvtvm(nq, v1[2], 1, v2[0], 1, temp, 1, v3[1], 1);
996 
997  Vmath::Vmul (nq, v1[1], 1, v2[0], 1, temp, 1);
998  Vmath::Vvtvm(nq, v1[0], 1, v2[1], 1, temp, 1, v3[2], 1);
999  }
1000 
1001  } //end of namespace
1002 } //end of namespace
Y coordinate direction.
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
std::vector< PointsKey > PointsKeyVector
Definition: Points.h:246
GeomType m_type
Type of geometry (e.g. eRegular, eDeformed, eMovingRegular).
Definition: GeomFactors.h:135
void ComputePrincipleDirection(const LibUtilities::PointsKeyVector &keyTgt, const SpatialDomains::GeomMMF MMFdir, const Array< OneD, const NekDouble > &CircCentre, Array< OneD, Array< OneD, NekDouble > > &output)
Circular around the centre of domain.
void Vsqrt(int n, const T *x, const int incx, T *y, const int incy)
sqrt y = sqrt(x)
Definition: Vmath.cpp:411
friend bool operator==(const GeomFactors &lhs, const GeomFactors &rhs)
Tests if two GeomFactors classes are equal.
T Vmin(int n, const T *x, const int incx)
Return the minimum element in x - called vmin to avoid conflict with min.
Definition: Vmath.cpp:874
void Fill(int n, const T alpha, T *x, const int incx)
Fill a vector with a constant value.
Definition: Vmath.cpp:45
Array< TwoD, NekDouble > ComputeDerivFactors(const LibUtilities::PointsKeyVector &keyTgt) const
Return the derivative of the reference coordinates with respect to the mapping, . ...
DerivStorage GetDeriv(const LibUtilities::PointsKeyVector &keyTgt)
Return the derivative of the mapping with respect to the reference coordinates, . ...
Definition: GeomFactors.h:232
void Vvtvp(int n, const T *w, const int incw, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
vvtvp (vector times vector plus vector): z = w*x + y
Definition: Vmath.cpp:445
void VectorCrossProd(const Array< OneD, const Array< OneD, NekDouble > > &v1, const Array< OneD, const Array< OneD, NekDouble > > &v2, Array< OneD, Array< OneD, NekDouble > > &v3)
Computes the vector cross-product in 3D of v1 and v2, storing the result in v3.
void CheckIfValid()
Tests if the element is valid and not self-intersecting.
void Vdiv(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Multiply vector z = x/y.
Definition: Vmath.cpp:244
GeomMMF
Principle direction for MMF.
void VectorNormalise(Array< OneD, Array< OneD, NekDouble > > &array)
StandardMatrixTag & lhs
int m_coordDim
Dimension of coordinate system.
Definition: GeomFactors.h:139
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
std::shared_ptr< StdExpansion > StdExpansionSharedPtr
void Smul(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Scalar multiply y = alpha*y.
Definition: Vmath.cpp:216
Circular around the centre of domain.
X coordinate direction.
No Principal direction.
Array< OneD, Array< OneD, Array< OneD, NekDouble > > > DerivStorage
Storage type for derivative of mapping.
Definition: GeomFactors.h:70
bool m_valid
Validity of element (Jacobian positive)
Definition: GeomFactors.h:141
Z coordinate direction.
void Interp(const LibUtilities::PointsKeyVector &src_points, const Array< OneD, const NekDouble > &src, const LibUtilities::PointsKeyVector &tgt_points, Array< OneD, NekDouble > &tgt) const
Perform interpolation of data between two point distributions.
void Neg(int n, T *x, const int incx)
Negate x = -x.
Definition: Vmath.cpp:399
double NekDouble
void Vvtvvtm(int n, const T *v, int incv, const T *w, int incw, const T *x, int incx, const T *y, int incy, T *z, int incz)
vvtvvtm (vector times vector minus vector times vector):
Definition: Vmath.cpp:567
Array< OneD, NekDouble > ComputeJac(const LibUtilities::PointsKeyVector &keyTgt) const
Return the Jacobian of the mapping and cache the result.
DerivStorage ComputeDeriv(const LibUtilities::PointsKeyVector &keyTgt) const
int m_expDim
Dimension of expansion.
Definition: GeomFactors.h:137
void Interp3D(const BasisKey &fbasis0, const BasisKey &fbasis1, const BasisKey &fbasis2, const Array< OneD, const NekDouble > &from, const BasisKey &tbasis0, const BasisKey &tbasis1, const BasisKey &tbasis2, Array< OneD, NekDouble > &to)
this function interpolates a 3D function evaluated at the quadrature points of the 3D basis...
Definition: Interp.cpp:185
Calculation and storage of geometric factors associated with the mapping from StdRegions reference el...
Definition: GeomFactors.h:75
GeomFactors(const GeomType gtype, const int coordim, const StdRegions::StdExpansionSharedPtr &xmap, const Array< OneD, Array< OneD, NekDouble > > &coords)
Constructor for GeomFactors class.
Definition: GeomFactors.cpp:88
Geometry is straight-sided with constant geometric factors.
void Vvtvm(int n, const T *w, const int incw, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
vvtvm (vector times vector plus vector): z = w*x - y
Definition: Vmath.cpp:468
void Interp1D(const BasisKey &fbasis0, const Array< OneD, const NekDouble > &from, const BasisKey &tbasis0, Array< OneD, NekDouble > &to)
this function interpolates a 1D function evaluated at the quadrature points of the basis fbasis0 to ...
Definition: Interp.cpp:53
Array< TwoD, NekDouble > ComputeGmat(const LibUtilities::PointsKeyVector &keyTgt) const
Computes the Laplacian coefficients .
Array< OneD, Array< OneD, NekDouble > > m_coords
Stores coordinates of the geometry.
Definition: GeomFactors.h:149
void Adjoint(const Array< TwoD, const NekDouble > &src, Array< TwoD, NekDouble > &tgt) const
Compute the transpose of the cofactors matrix.
Circular around the centre of domain.
StandardMatrixTag boost::call_traits< LhsDataType >::const_reference rhs
StdRegions::StdExpansionSharedPtr m_xmap
Stores information about the expansion.
Definition: GeomFactors.h:147
GeomType
Indicates the type of element geometry.
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode...
Definition: ErrorUtil.hpp:250
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.cpp:1064
Geometry is curved or has non-constant factors.
void ComputeMovingFrames(const LibUtilities::PointsKeyVector &keyTgt, const SpatialDomains::GeomMMF MMFdir, const Array< OneD, const NekDouble > &CircCentre, Array< OneD, Array< OneD, NekDouble > > &movingframes)
void Vmul(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Multiply vector z = x*y.
Definition: Vmath.cpp:186