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