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