Nektar++
Loading...
Searching...
No Matches
PhysDeriv.cpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File: PhysDeriv.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: PhysDeriv operator implementations
32//
33///////////////////////////////////////////////////////////////////////////////
34
38#include <MatrixFreeOps/Operator.hpp>
39
40using namespace std;
41
42namespace Nektar::Collections
43{
44
55
56/**
57 * @brief Physical Derivative help class to calculate the size of the collection
58 * that is given as an input and as an output to the PhysDeriv Operator. The
59 * Operator evaluation is happenning in the physical space and the output is
60 * expected to be part of the physical space too.
61 */
62class PhysDeriv_Helper : virtual public Operator
63{
64protected:
66 {
67 // expect input to be number of elements by the number of quadrature
68 // points
69 m_inputSize = m_numElmt * m_stdExp->GetTotPoints();
70 // the derivate is using data from the physical space to evaluate the
71 // derivative in the physical space
73 }
74};
75
76/**
77 * @brief Phys deriv operator using standard matrix approach
78 */
79class PhysDeriv_StdMat final : virtual public Operator,
80 virtual public PhysDeriv_Helper
81{
82public:
84
85 ~PhysDeriv_StdMat() final = default;
86
87 void operator()(const Array<OneD, const NekDouble> &input,
88 Array<OneD, NekDouble> &output0,
89 Array<OneD, NekDouble> &output1,
90 Array<OneD, NekDouble> &output2,
91 Array<OneD, NekDouble> &wsp) final
92 {
93 int nPhys = m_stdExp->GetTotPoints();
94 int ntot = m_numElmt * nPhys;
95 Array<OneD, NekDouble> tmp0, tmp1, tmp2;
98 out[0] = output0;
99 out[1] = output1;
100 out[2] = output2;
101
102 for (int i = 0; i < m_dim; ++i)
103 {
104 Diff[i] = wsp + i * ntot;
105 }
106
107 // calculate local derivatives
108 for (int i = 0; i < m_dim; ++i)
109 {
110 Blas::Dgemm('N', 'N', m_derivMat[i]->GetRows(), m_numElmt,
111 m_derivMat[i]->GetColumns(), 1.0,
112 m_derivMat[i]->GetRawPtr(), m_derivMat[i]->GetRows(),
113 input.data(), nPhys, 0.0, &Diff[i][0], nPhys);
114 }
115
116 // calculate full derivative
117 if (m_isDeformed)
118 {
119 for (int i = 0; i < m_coordim; ++i)
120 {
121 Vmath::Zero(ntot, out[i], 1);
122 for (int j = 0; j < m_dim; ++j)
123 {
124 Vmath::Vvtvp(ntot, m_derivFac[i * m_dim + j], 1, Diff[j], 1,
125 out[i], 1, out[i], 1);
126 }
127 }
128 }
129 else
130 {
132 for (int i = 0; i < m_coordim; ++i)
133 {
134 Vmath::Zero(ntot, out[i], 1);
135 for (int e = 0; e < m_numElmt; ++e)
136 {
137 for (int j = 0; j < m_dim; ++j)
138 {
139 Vmath::Svtvp(m_nqe, m_derivFac[i * m_dim + j][e],
140 Diff[j] + e * m_nqe, 1, out[i] + e * m_nqe,
141 1, t = out[i] + e * m_nqe, 1);
142 }
143 }
144 }
145 }
146 }
147
148 void operator()(int dir, const Array<OneD, const NekDouble> &input,
150 Array<OneD, NekDouble> &wsp) final
151 {
152 int nPhys = m_stdExp->GetTotPoints();
153 int ntot = m_numElmt * nPhys;
154 Array<OneD, NekDouble> tmp0, tmp1, tmp2;
156
157 for (int i = 0; i < m_dim; ++i)
158 {
159 Diff[i] = wsp + i * ntot;
160 }
161
162 // calculate local derivatives
163 for (int i = 0; i < m_dim; ++i)
164 {
165 Blas::Dgemm('N', 'N', m_derivMat[i]->GetRows(), m_numElmt,
166 m_derivMat[i]->GetColumns(), 1.0,
167 m_derivMat[i]->GetRawPtr(), m_derivMat[i]->GetRows(),
168 input.data(), nPhys, 0.0, &Diff[i][0], nPhys);
169 }
170
171 // calculate full derivative
172 Vmath::Zero(ntot, output, 1);
173 if (m_isDeformed)
174 {
175 for (int j = 0; j < m_dim; ++j)
176 {
177 Vmath::Vvtvp(ntot, m_derivFac[dir * m_dim + j], 1, Diff[j], 1,
178 output, 1, output, 1);
179 }
180 }
181 else
182 {
184 for (int e = 0; e < m_numElmt; ++e)
185 {
186 for (int j = 0; j < m_dim; ++j)
187 {
188 Vmath::Svtvp(m_nqe, m_derivFac[dir * m_dim + j][e],
189 Diff[j] + e * m_nqe, 1, output + e * m_nqe, 1,
190 t = output + e * m_nqe, 1);
191 }
192 }
193 }
194 }
195
196protected:
199 int m_dim;
201
202private:
203 PhysDeriv_StdMat(vector<LocalRegions::ExpansionSharedPtr> pCollExp,
205 StdRegions::FactorMap factors)
206 : Operator(pCollExp, pGeomData, factors), PhysDeriv_Helper()
207 {
208 int nqtot = pCollExp[0]->GetTotPoints();
209 m_dim = pCollExp[0]->GetShapeDimension();
210 m_coordim = pCollExp[0]->GetCoordim();
211
212 // set up a PhysDeriv StdMat.
214 for (int i = 0; i < m_dim; ++i)
215 {
216 Array<OneD, NekDouble> tmp(nqtot), tmp1(nqtot);
217 m_derivMat[i] =
219 for (int j = 0; j < nqtot; ++j)
220 {
221 Vmath::Zero(nqtot, tmp, 1);
222 tmp[j] = 1.0;
223 m_stdExp->PhysDeriv(i, tmp, tmp1);
224 Vmath::Vcopy(nqtot, &tmp1[0], 1,
225 &(m_derivMat[i]->GetPtr())[0] + j * nqtot, 1);
226 }
227 }
228 m_derivFac = pGeomData->GetDerivFactors(pCollExp);
229 m_wspSize = 3 * nqtot * m_numElmt;
230 }
231};
232
233/// Factory initialisation for the PhysDeriv_StdMat operators
234OperatorKey PhysDeriv_StdMat::m_typeArr[] = {
236 OperatorKey(eSegment, ePhysDeriv, eStdMat, false),
237 PhysDeriv_StdMat::create, "PhysDeriv_StdMat_Seg"),
239 OperatorKey(eTriangle, ePhysDeriv, eStdMat, false),
240 PhysDeriv_StdMat::create, "PhysDeriv_StdMat_Tri"),
242 OperatorKey(eNodalTri, ePhysDeriv, eStdMat, true),
243 PhysDeriv_StdMat::create, "PhysDeriv_StdMat_NodalTri"),
245 OperatorKey(eQuadrilateral, ePhysDeriv, eStdMat, false),
246 PhysDeriv_StdMat::create, "PhysDeriv_StdMat_Quad"),
248 OperatorKey(eTetrahedron, ePhysDeriv, eStdMat, false),
249 PhysDeriv_StdMat::create, "PhysDeriv_StdMat_Tet"),
251 OperatorKey(eNodalTet, ePhysDeriv, eStdMat, true),
252 PhysDeriv_StdMat::create, "PhysDeriv_StdMat_NodalTet"),
254 OperatorKey(ePyramid, ePhysDeriv, eStdMat, false),
255 PhysDeriv_StdMat::create, "PhysDeriv_StdMat_Pyr"),
257 OperatorKey(ePrism, ePhysDeriv, eStdMat, false),
258 PhysDeriv_StdMat::create, "PhysDeriv_StdMat_Prism"),
260 OperatorKey(eNodalPrism, ePhysDeriv, eStdMat, true),
261 PhysDeriv_StdMat::create, "PhysDeriv_StdMat_NodalPrism"),
263 OperatorKey(eHexahedron, ePhysDeriv, eStdMat, false),
264 PhysDeriv_StdMat::create, "PhysDeriv_StdMat_Hex"),
266 OperatorKey(ePyramid, ePhysDeriv, eSumFac, false),
267 PhysDeriv_StdMat::create, "PhysDeriv_SumFac_Pyr")};
268
269/**
270 * @brief Phys deriv operator using matrix free operators.
271 */
272class PhysDeriv_MatrixFree final : virtual public Operator,
274 virtual public PhysDeriv_Helper
275{
276public:
278
279 ~PhysDeriv_MatrixFree() final = default;
280
281 void operator()(const Array<OneD, const NekDouble> &input,
282 Array<OneD, NekDouble> &output0,
283 Array<OneD, NekDouble> &output1,
284 Array<OneD, NekDouble> &output2,
285 [[maybe_unused]] Array<OneD, NekDouble> &wsp) final
286 {
288 // currently using temporary local temporary space for output
289 // to allow for other operator call below which is
290 // directionally dependent
291 switch (m_coordim)
292 {
293 case 1:
294 output[0] = output0;
295 break;
296 case 2:
297 output[0] = output0;
298 output[1] = output1;
299 break;
300 case 3:
301 output[0] = output0;
302 output[1] = output1;
303 output[2] = output2;
304 break;
305 default:
306 NEKERROR(ErrorUtil::efatal, "Unknown coordinate dimension");
307 break;
308 }
309 (*m_oper)(input, output);
310 }
311
312 void operator()(int dir, const Array<OneD, const NekDouble> &input,
314 [[maybe_unused]] Array<OneD, NekDouble> &wsp) final
315 {
316 (*m_oper)(input, m_output);
317 Vmath::Vcopy(m_nOut, m_output[dir], 1, output, 1);
318 }
319
320private:
321 std::shared_ptr<MatrixFree::PhysDeriv> m_oper;
324
325 PhysDeriv_MatrixFree(vector<LocalRegions::ExpansionSharedPtr> pCollExp,
327 StdRegions::FactorMap factors)
328 : Operator(pCollExp, pGeomData, factors), PhysDeriv_Helper(),
329 MatrixFreeBase(pCollExp[0]->GetTotPoints(),
330 pCollExp[0]->GetTotPoints(), pCollExp.size())
331 {
332 // Check if deformed
333 bool deformed{pGeomData->IsDeformed(pCollExp)};
334 const auto dim = pCollExp[0]->GetShapeDimension();
335
336 // only used operator(dir, in, out)
337 m_coordim = pCollExp[0]->GetCoordim();
338 int nOut = pCollExp[0]->GetTotPoints();
341 if (m_coordim == 2)
342 {
344 }
345 else if (m_coordim == 3)
346 {
349 }
350
351 // Basis vector.
352 std::vector<LibUtilities::BasisSharedPtr> basis(dim);
353 for (unsigned int i = 0; i < dim; ++i)
354 {
355 basis[i] = pCollExp[0]->GetBasis(i);
356 }
357
358 // Get shape type
359 auto shapeType = pCollExp[0]->DetShapeType();
360
361 // Generate operator string and create operator.
362 std::string op_string = "PhysDeriv";
363 op_string += MatrixFree::GetOpstring(shapeType, deformed);
364 auto oper = MatrixFree::GetOperatorFactory().CreateInstance(
365 op_string, basis, pCollExp.size());
366
367 oper->SetUpZW(basis);
368 oper->SetUpD(basis);
369
370 // Set derivative factors
371 oper->SetDF(pGeomData->GetDerivFactorsInterLeave(pCollExp, m_nElmtPad));
372
373 m_oper = std::dynamic_pointer_cast<MatrixFree::PhysDeriv>(oper);
374 ASSERTL0(m_oper, "Failed to cast pointer.");
375 }
376};
377
378/// Factory initialisation for the PhysDeriv_MatrixFree operators
379OperatorKey PhysDeriv_MatrixFree::m_typeArr[] = {
381 OperatorKey(eSegment, ePhysDeriv, eMatrixFree, false),
382 PhysDeriv_MatrixFree::create, "PhysDeriv_MatrixFree_Seg"),
384 OperatorKey(eTriangle, ePhysDeriv, eMatrixFree, false),
385 PhysDeriv_MatrixFree::create, "PhysDeriv_MatrixFree_Tri"),
387 OperatorKey(eQuadrilateral, ePhysDeriv, eMatrixFree, false),
388 PhysDeriv_MatrixFree::create, "PhysDeriv_MatrixFree_Quad"),
390 OperatorKey(eHexahedron, ePhysDeriv, eMatrixFree, false),
391 PhysDeriv_MatrixFree::create, "PhysDeriv_MatrixFree_Hex"),
393 OperatorKey(ePrism, ePhysDeriv, eMatrixFree, false),
394 PhysDeriv_MatrixFree::create, "PhysDeriv_MatrixFree_Prism"),
396 OperatorKey(ePyramid, ePhysDeriv, eMatrixFree, false),
397 PhysDeriv_MatrixFree::create, "PhysDeriv_MatrixFree_Pyr"),
399 OperatorKey(eTetrahedron, ePhysDeriv, eMatrixFree, false),
400 PhysDeriv_MatrixFree::create, "PhysDeriv_MatrixFree_Tet")
401
402};
403
404/**
405 * @brief Phys deriv operator using element-wise operation
406 */
407class PhysDeriv_IterPerExp final : virtual public Operator,
408 virtual public PhysDeriv_Helper
409{
410public:
412
413 ~PhysDeriv_IterPerExp() final = default;
414
415 void operator()(const Array<OneD, const NekDouble> &input,
416 Array<OneD, NekDouble> &output0,
417 Array<OneD, NekDouble> &output1,
418 Array<OneD, NekDouble> &output2,
419 Array<OneD, NekDouble> &wsp) final
420 {
421 int nPhys = m_stdExp->GetTotPoints();
422 int ntot = m_numElmt * nPhys;
423 Array<OneD, NekDouble> tmp0, tmp1, tmp2;
426 out[0] = output0;
427 out[1] = output1;
428 out[2] = output2;
429
430 for (int i = 0; i < m_dim; ++i)
431 {
432 Diff[i] = wsp + i * ntot;
433 }
434
435 // calculate local derivatives
436 for (int i = 0; i < m_numElmt; ++i)
437 {
438 m_stdExp->PhysDeriv(input + i * nPhys, tmp0 = Diff[0] + i * nPhys,
439 tmp1 = Diff[1] + i * nPhys,
440 tmp2 = Diff[2] + i * nPhys);
441 }
442
443 // calculate full derivative
444 if (m_isDeformed)
445 {
446 for (int i = 0; i < m_coordim; ++i)
447 {
448 Vmath::Vmul(ntot, m_derivFac[i * m_dim], 1, Diff[0], 1, out[i],
449 1);
450 for (int j = 1; j < m_dim; ++j)
451 {
452 Vmath::Vvtvp(ntot, m_derivFac[i * m_dim + j], 1, Diff[j], 1,
453 out[i], 1, out[i], 1);
454 }
455 }
456 }
457 else
458 {
460 for (int e = 0; e < m_numElmt; ++e)
461 {
462 for (int i = 0; i < m_coordim; ++i)
463 {
465 Diff[0] + e * m_nqe, 1, t = out[i] + e * m_nqe,
466 1);
467 for (int j = 1; j < m_dim; ++j)
468 {
469 Vmath::Svtvp(m_nqe, m_derivFac[i * m_dim + j][e],
470 Diff[j] + e * m_nqe, 1, out[i] + e * m_nqe,
471 1, t = out[i] + e * m_nqe, 1);
472 }
473 }
474 }
475 }
476 }
477
478 void operator()(int dir, const Array<OneD, const NekDouble> &input,
480 Array<OneD, NekDouble> &wsp) final
481 {
482 int nPhys = m_stdExp->GetTotPoints();
483 int ntot = m_numElmt * nPhys;
484 Array<OneD, NekDouble> tmp0, tmp1, tmp2;
486
487 for (int i = 0; i < m_dim; ++i)
488 {
489 Diff[i] = wsp + i * ntot;
490 }
491
492 // calculate local derivatives
493 for (int i = 0; i < m_numElmt; ++i)
494 {
495 m_stdExp->PhysDeriv(input + i * nPhys, tmp0 = Diff[0] + i * nPhys,
496 tmp1 = Diff[1] + i * nPhys,
497 tmp2 = Diff[2] + i * nPhys);
498 }
499
500 Vmath::Zero(ntot, output, 1);
501 if (m_isDeformed)
502 {
503 for (int j = 0; j < m_dim; ++j)
504 {
505 Vmath::Vvtvp(ntot, m_derivFac[dir * m_dim + j], 1, Diff[j], 1,
506 output, 1, output, 1);
507 }
508 }
509 else
510 {
512 for (int e = 0; e < m_numElmt; ++e)
513 {
514 for (int j = 0; j < m_dim; ++j)
515 {
516 Vmath::Svtvp(m_nqe, m_derivFac[dir * m_dim + j][e],
517 Diff[j] + e * m_nqe, 1, output + e * m_nqe, 1,
518 t = output + e * m_nqe, 1);
519 }
520 }
521 }
522 }
523
524protected:
526 int m_dim;
528
529private:
530 PhysDeriv_IterPerExp(vector<LocalRegions::ExpansionSharedPtr> pCollExp,
532 StdRegions::FactorMap factors)
533 : Operator(pCollExp, pGeomData, factors), PhysDeriv_Helper()
534 {
535 int nqtot = pCollExp[0]->GetTotPoints();
536 m_dim = pCollExp[0]->GetShapeDimension();
537 m_coordim = pCollExp[0]->GetCoordim();
538
539 m_derivFac = pGeomData->GetDerivFactors(pCollExp);
540 m_wspSize = 3 * nqtot * m_numElmt;
541 }
542};
543
544/// Factory initialisation for the PhysDeriv_IterPerExp operators
545OperatorKey PhysDeriv_IterPerExp::m_typeArr[] = {
547 OperatorKey(eSegment, ePhysDeriv, eIterPerExp, false),
548 PhysDeriv_IterPerExp::create, "PhysDeriv_IterPerExp_Seg"),
550 OperatorKey(eTriangle, ePhysDeriv, eIterPerExp, false),
551 PhysDeriv_IterPerExp::create, "PhysDeriv_IterPerExp_Tri"),
553 OperatorKey(eNodalTri, ePhysDeriv, eIterPerExp, true),
554 PhysDeriv_IterPerExp::create, "PhysDeriv_IterPerExp_NodalTri"),
556 OperatorKey(eQuadrilateral, ePhysDeriv, eIterPerExp, false),
557 PhysDeriv_IterPerExp::create, "PhysDeriv_IterPerExp_Quad"),
559 OperatorKey(eTetrahedron, ePhysDeriv, eIterPerExp, false),
560 PhysDeriv_IterPerExp::create, "PhysDeriv_IterPerExp_Tet"),
562 OperatorKey(eNodalTet, ePhysDeriv, eIterPerExp, true),
563 PhysDeriv_IterPerExp::create, "PhysDeriv_IterPerExp_NodalTet"),
565 OperatorKey(ePyramid, ePhysDeriv, eIterPerExp, false),
566 PhysDeriv_IterPerExp::create, "PhysDeriv_IterPerExp_Pyr"),
568 OperatorKey(ePrism, ePhysDeriv, eIterPerExp, false),
569 PhysDeriv_IterPerExp::create, "PhysDeriv_IterPerExp_Prism"),
571 OperatorKey(eNodalPrism, ePhysDeriv, eIterPerExp, true),
572 PhysDeriv_IterPerExp::create, "PhysDeriv_IterPerExp_NodalPrism"),
574 OperatorKey(eHexahedron, ePhysDeriv, eIterPerExp, false),
575 PhysDeriv_IterPerExp::create, "PhysDeriv_IterPerExp_Hex")};
576
577/**
578 * @brief Phys deriv operator using original LocalRegions implementation.
579 */
580class PhysDeriv_NoCollection final : virtual public Operator,
581 virtual public PhysDeriv_Helper
582{
583public:
585
586 ~PhysDeriv_NoCollection() final = default;
587
588 void operator()(const Array<OneD, const NekDouble> &input,
589 Array<OneD, NekDouble> &output0,
590 Array<OneD, NekDouble> &output1,
591 Array<OneD, NekDouble> &output2,
592 [[maybe_unused]] Array<OneD, NekDouble> &wsp) final
593 {
594 const int nPhys = m_expList[0]->GetTotPoints();
595 Array<OneD, NekDouble> tmp0, tmp1, tmp2;
596
597 // calculate local derivatives
598 switch (m_expList[0]->GetCoordim())
599 {
600 case 1:
601 {
602 for (int i = 0; i < m_numElmt; ++i)
603 {
604 m_expList[i]->PhysDeriv(input + i * nPhys,
605 tmp0 = output0 + i * nPhys);
606 }
607 break;
608 }
609 case 2:
610 {
611 for (int i = 0; i < m_numElmt; ++i)
612 {
613 m_expList[i]->PhysDeriv(input + i * nPhys,
614 tmp0 = output0 + i * nPhys,
615 tmp1 = output1 + i * nPhys);
616 }
617 break;
618 }
619 case 3:
620 {
621 for (int i = 0; i < m_numElmt; ++i)
622 {
623 m_expList[i]->PhysDeriv(
624 input + i * nPhys, tmp0 = output0 + i * nPhys,
625 tmp1 = output1 + i * nPhys, tmp2 = output2 + i * nPhys);
626 }
627 break;
628 }
629 default:
630 ASSERTL0(false, "Unknown dimension.");
631 }
632 }
633
634 void operator()(int dir, const Array<OneD, const NekDouble> &input,
636 [[maybe_unused]] Array<OneD, NekDouble> &wsp) final
637 {
638 const int nPhys = m_expList[0]->GetTotPoints();
640
641 // calculate local derivatives
642 for (int i = 0; i < m_numElmt; ++i)
643 {
644 m_expList[i]->PhysDeriv(dir, input + i * nPhys,
645 tmp = output + i * nPhys);
646 }
647 }
648
649protected:
650 vector<LocalRegions::ExpansionSharedPtr> m_expList;
651
652private:
653 PhysDeriv_NoCollection(vector<LocalRegions::ExpansionSharedPtr> pCollExp,
655 StdRegions::FactorMap factors)
656 : Operator(pCollExp, pGeomData, factors), PhysDeriv_Helper()
657 {
658 m_expList = pCollExp;
659 }
660};
661
662/// Factory initialisation for the PhysDeriv_NoCollection operators
663OperatorKey PhysDeriv_NoCollection::m_typeArr[] = {
665 OperatorKey(eSegment, ePhysDeriv, eNoCollection, false),
666 PhysDeriv_NoCollection::create, "PhysDeriv_NoCollection_Seg"),
668 OperatorKey(eTriangle, ePhysDeriv, eNoCollection, false),
669 PhysDeriv_NoCollection::create, "PhysDeriv_NoCollection_Tri"),
671 OperatorKey(eNodalTri, ePhysDeriv, eNoCollection, true),
672 PhysDeriv_NoCollection::create, "PhysDeriv_NoCollection_NodalTri"),
674 OperatorKey(eQuadrilateral, ePhysDeriv, eNoCollection, false),
675 PhysDeriv_NoCollection::create, "PhysDeriv_NoCollection_Quad"),
677 OperatorKey(eTetrahedron, ePhysDeriv, eNoCollection, false),
678 PhysDeriv_NoCollection::create, "PhysDeriv_NoCollection_Tet"),
680 OperatorKey(eNodalTet, ePhysDeriv, eNoCollection, true),
681 PhysDeriv_NoCollection::create, "PhysDeriv_NoCollection_NodalTet"),
683 OperatorKey(ePyramid, ePhysDeriv, eNoCollection, false),
684 PhysDeriv_NoCollection::create, "PhysDeriv_NoCollection_Pyr"),
686 OperatorKey(ePrism, ePhysDeriv, eNoCollection, false),
687 PhysDeriv_NoCollection::create, "PhysDeriv_NoCollection_Prism"),
689 OperatorKey(eNodalPrism, ePhysDeriv, eNoCollection, true),
690 PhysDeriv_NoCollection::create, "PhysDeriv_NoCollection_NodalPrism"),
692 OperatorKey(eHexahedron, ePhysDeriv, eNoCollection, false),
693 PhysDeriv_NoCollection::create, "PhysDeriv_NoCollection_Hex")};
694
695/**
696 * @brief Phys deriv operator using sum-factorisation (Segment)
697 */
698class PhysDeriv_SumFac_Seg final : virtual public Operator,
699 virtual public PhysDeriv_Helper
700{
701public:
703
704 ~PhysDeriv_SumFac_Seg() final = default;
705
706 void operator()(const Array<OneD, const NekDouble> &input,
707 Array<OneD, NekDouble> &output0,
708 Array<OneD, NekDouble> &output1,
709 Array<OneD, NekDouble> &output2,
710 Array<OneD, NekDouble> &wsp) final
711 {
712 const int nqcol = m_nquad0 * m_numElmt;
713
714 ASSERTL1(wsp.size() == m_wspSize, "Incorrect workspace size");
715 ASSERTL1(input.size() >= nqcol, "Incorrect input size");
716
717 Array<OneD, NekDouble> diff0(nqcol, wsp);
718
720 m_nquad0, input.data(), m_nquad0, 0.0, diff0.data(),
721 m_nquad0);
722
723 if (m_isDeformed)
724 {
725 Vmath::Vmul(nqcol, m_derivFac[0], 1, diff0, 1, output0, 1);
726
727 if (m_coordim == 2)
728 {
729 Vmath::Vmul(nqcol, m_derivFac[1], 1, diff0, 1, output1, 1);
730 }
731 else if (m_coordim == 3)
732 {
733 Vmath::Vmul(nqcol, m_derivFac[1], 1, diff0, 1, output1, 1);
734 Vmath::Vmul(nqcol, m_derivFac[2], 1, diff0, 1, output2, 1);
735 }
736 }
737 else
738 {
740 for (int e = 0; e < m_numElmt; ++e)
741 {
742 Vmath::Smul(m_nqe, m_derivFac[0][e], diff0 + e * m_nqe, 1,
743 t = output0 + e * m_nqe, 1);
744 }
745
746 if (m_coordim == 2)
747 {
748 for (int e = 0; e < m_numElmt; ++e)
749 {
750 Vmath::Smul(m_nqe, m_derivFac[1][e], diff0 + e * m_nqe, 1,
751 t = output1 + e * m_nqe, 1);
752 }
753 }
754 else if (m_coordim == 3)
755 {
756 for (int e = 0; e < m_numElmt; ++e)
757 {
758 Vmath::Smul(m_nqe, m_derivFac[1][e], diff0 + e * m_nqe, 1,
759 t = output1 + e * m_nqe, 1);
760 Vmath::Smul(m_nqe, m_derivFac[2][e], diff0 + e * m_nqe, 1,
761 t = output2 + e * m_nqe, 1);
762 }
763 }
764 }
765 }
766
767 void operator()(int dir, const Array<OneD, const NekDouble> &input,
769 Array<OneD, NekDouble> &wsp) final
770 {
771 const int nqcol = m_nquad0 * m_numElmt;
772
773 ASSERTL1(wsp.size() == m_wspSize, "Incorrect workspace size");
774 ASSERTL1(input.size() >= nqcol, "Incorrect input size");
775
776 Array<OneD, NekDouble> diff0(nqcol, wsp);
777
779 m_nquad0, input.data(), m_nquad0, 0.0, diff0.data(),
780 m_nquad0);
781
782 if (m_isDeformed)
783 {
784 Vmath::Vmul(nqcol, m_derivFac[dir], 1, diff0, 1, output, 1);
785 }
786 else
787 {
789 for (int e = 0; e < m_numElmt; ++e)
790 {
791 Vmath::Smul(m_nqe, m_derivFac[0][e], diff0 + e * m_nqe, 1,
792 t = output + e * m_nqe, 1);
793 }
794 }
795 }
796
797protected:
799 const int m_nquad0;
802
803private:
804 PhysDeriv_SumFac_Seg(vector<LocalRegions::ExpansionSharedPtr> pCollExp,
806 StdRegions::FactorMap factors)
807 : Operator(pCollExp, pGeomData, factors), PhysDeriv_Helper(),
808 m_nquad0(m_stdExp->GetNumPoints(0))
809 {
810 m_coordim = pCollExp[0]->GetCoordim();
811
812 m_derivFac = pGeomData->GetDerivFactors(pCollExp);
813
814 m_Deriv0 = &((m_stdExp->GetBasis(0)->GetD())->GetPtr())[0];
816 }
817};
818
819/// Factory initialisation for the PhysDeriv_SumFac_Seg operators
820OperatorKey PhysDeriv_SumFac_Seg::m_type =
822 OperatorKey(eSegment, ePhysDeriv, eSumFac, false),
823 PhysDeriv_SumFac_Seg::create, "PhysDeriv_SumFac_Seg");
824
825/**
826 * @brief Phys deriv operator using sum-factorisation (Quad)
827 */
828class PhysDeriv_SumFac_Quad final : virtual public Operator,
829 virtual public PhysDeriv_Helper
830{
831public:
833
834 ~PhysDeriv_SumFac_Quad() final = default;
835
836 void operator()(const Array<OneD, const NekDouble> &input,
837 Array<OneD, NekDouble> &output0,
838 Array<OneD, NekDouble> &output1,
839 Array<OneD, NekDouble> &output2,
840 Array<OneD, NekDouble> &wsp) final
841 {
842 const int nqtot = m_nquad0 * m_nquad1;
843 const int nqcol = nqtot * m_numElmt;
844
845 ASSERTL1(wsp.size() == m_wspSize, "Incorrect workspace size");
846 ASSERTL1(input.size() >= nqcol, "Incorrect input size");
847
848 Array<OneD, NekDouble> diff0(nqcol, wsp);
849 Array<OneD, NekDouble> diff1(nqcol, wsp + nqcol);
850
852 m_Deriv0, m_nquad0, input.data(), m_nquad0, 0.0,
853 diff0.data(), m_nquad0);
854
855 int cnt = 0;
856 for (int i = 0; i < m_numElmt; ++i, cnt += nqtot)
857 {
858 Blas::Dgemm('N', 'T', m_nquad0, m_nquad1, m_nquad1, 1.0,
859 input.data() + cnt, m_nquad0, m_Deriv1, m_nquad1, 0.0,
860 diff1.data() + cnt, m_nquad0);
861 }
862
863 if (m_isDeformed)
864 {
865 Vmath::Vmul(nqcol, m_derivFac[0], 1, diff0, 1, output0, 1);
866 Vmath::Vvtvp(nqcol, m_derivFac[1], 1, diff1, 1, output0, 1, output0,
867 1);
868 Vmath::Vmul(nqcol, m_derivFac[2], 1, diff0, 1, output1, 1);
869 Vmath::Vvtvp(nqcol, m_derivFac[3], 1, diff1, 1, output1, 1, output1,
870 1);
871
872 if (m_coordim == 3)
873 {
874 Vmath::Vmul(nqcol, m_derivFac[4], 1, diff0, 1, output2, 1);
875 Vmath::Vvtvp(nqcol, m_derivFac[5], 1, diff1, 1, output2, 1,
876 output2, 1);
877 }
878 }
879 else
880 {
882 for (int e = 0; e < m_numElmt; ++e)
883 {
884 Vmath::Smul(m_nqe, m_derivFac[0][e], diff0 + e * m_nqe, 1,
885 t = output0 + e * m_nqe, 1);
886 Vmath::Svtvp(m_nqe, m_derivFac[1][e], diff1 + e * m_nqe, 1,
887 output0 + e * m_nqe, 1, t = output0 + e * m_nqe,
888 1);
889
890 Vmath::Smul(m_nqe, m_derivFac[2][e], diff0 + e * m_nqe, 1,
891 t = output1 + e * m_nqe, 1);
892 Vmath::Svtvp(m_nqe, m_derivFac[3][e], diff1 + e * m_nqe, 1,
893 output1 + e * m_nqe, 1, t = output1 + e * m_nqe,
894 1);
895 }
896
897 if (m_coordim == 3)
898 {
899 for (int e = 0; e < m_numElmt; ++e)
900 {
901 Vmath::Smul(m_nqe, m_derivFac[4][e], diff0 + e * m_nqe, 1,
902 t = output2 + e * m_nqe, 1);
903 Vmath::Svtvp(m_nqe, m_derivFac[5][e], diff1 + e * m_nqe, 1,
904 output2 + e * m_nqe, 1,
905 t = output2 + e * m_nqe, 1);
906 }
907 }
908 }
909 }
910
911 void operator()(int dir, const Array<OneD, const NekDouble> &input,
913 Array<OneD, NekDouble> &wsp) final
914 {
915 const int nqtot = m_nquad0 * m_nquad1;
916 const int nqcol = nqtot * m_numElmt;
917
918 ASSERTL1(wsp.size() == m_wspSize, "Incorrect workspace size");
919 ASSERTL1(input.size() >= nqcol, "Incorrect input size");
920
921 Array<OneD, NekDouble> diff0(nqcol, wsp);
922 Array<OneD, NekDouble> diff1(nqcol, wsp + nqcol);
923
925 m_Deriv0, m_nquad0, input.data(), m_nquad0, 0.0,
926 diff0.data(), m_nquad0);
927
928 int cnt = 0;
929 for (int i = 0; i < m_numElmt; ++i, cnt += nqtot)
930 {
931 Blas::Dgemm('N', 'T', m_nquad0, m_nquad1, m_nquad1, 1.0,
932 input.data() + cnt, m_nquad0, m_Deriv1, m_nquad1, 0.0,
933 diff1.data() + cnt, m_nquad0);
934 }
935
936 if (m_isDeformed)
937 {
938 Vmath::Vmul(nqcol, m_derivFac[2 * dir], 1, diff0, 1, output, 1);
939 Vmath::Vvtvp(nqcol, m_derivFac[2 * dir + 1], 1, diff1, 1, output, 1,
940 output, 1);
941 }
942 else
943 {
945 for (int e = 0; e < m_numElmt; ++e)
946 {
947 Vmath::Smul(m_nqe, m_derivFac[2 * dir][e], diff0 + e * m_nqe, 1,
948 t = output + e * m_nqe, 1);
949 Vmath::Svtvp(m_nqe, m_derivFac[2 * dir + 1][e],
950 diff1 + e * m_nqe, 1, output + e * m_nqe, 1,
951 t = output + e * m_nqe, 1);
952 }
953 }
954 }
955
956protected:
958 const int m_nquad0;
959 const int m_nquad1;
963
964private:
965 PhysDeriv_SumFac_Quad(vector<LocalRegions::ExpansionSharedPtr> pCollExp,
967 StdRegions::FactorMap factors)
968 : Operator(pCollExp, pGeomData, factors), PhysDeriv_Helper(),
969 m_nquad0(m_stdExp->GetNumPoints(0)),
970 m_nquad1(m_stdExp->GetNumPoints(1))
971 {
972 m_coordim = pCollExp[0]->GetCoordim();
973
974 m_derivFac = pGeomData->GetDerivFactors(pCollExp);
975
976 m_Deriv0 = &((m_stdExp->GetBasis(0)->GetD())->GetPtr())[0];
977 m_Deriv1 = &((m_stdExp->GetBasis(1)->GetD())->GetPtr())[0];
979 }
980};
981
982/// Factory initialisation for the PhysDeriv_SumFac_Quad operators
983OperatorKey PhysDeriv_SumFac_Quad::m_type =
985 OperatorKey(eQuadrilateral, ePhysDeriv, eSumFac, false),
986 PhysDeriv_SumFac_Quad::create, "PhysDeriv_SumFac_Quad");
987
988/**
989 * @brief Phys deriv operator using sum-factorisation (Tri)
990 */
991class PhysDeriv_SumFac_Tri final : virtual public Operator,
992 virtual public PhysDeriv_Helper
993{
994public:
996
997 ~PhysDeriv_SumFac_Tri() final = default;
998
999 void operator()(const Array<OneD, const NekDouble> &input,
1000 Array<OneD, NekDouble> &output0,
1001 Array<OneD, NekDouble> &output1,
1002 Array<OneD, NekDouble> &output2,
1003 Array<OneD, NekDouble> &wsp) final
1004 {
1005 const int nqtot = m_nquad0 * m_nquad1;
1006 const int nqcol = nqtot * m_numElmt;
1007
1008 ASSERTL1(wsp.size() == m_wspSize, "Incorrect workspace size");
1009 ASSERTL1(input.size() >= nqcol, "Incorrect input size");
1010
1011 Array<OneD, NekDouble> diff0(nqcol, wsp);
1012 Array<OneD, NekDouble> diff1(nqcol, wsp + nqcol);
1013
1014 // Tensor Product Derivative
1015 Blas::Dgemm('N', 'N', m_nquad0, m_nquad1 * m_numElmt, m_nquad0, 1.0,
1016 m_Deriv0, m_nquad0, input.data(), m_nquad0, 0.0,
1017 diff0.data(), m_nquad0);
1018
1019 int cnt = 0;
1020 for (int i = 0; i < m_numElmt; ++i, cnt += nqtot)
1021 {
1022 // scale diff0 by geometric factor: 2/(1-z1)
1023 Vmath::Vmul(nqtot, &m_fac1[0], 1, diff0.data() + cnt, 1,
1024 diff0.data() + cnt, 1);
1025
1026 Blas::Dgemm('N', 'T', m_nquad0, m_nquad1, m_nquad1, 1.0,
1027 input.data() + cnt, m_nquad0, m_Deriv1, m_nquad1, 0.0,
1028 diff1.data() + cnt, m_nquad0);
1029
1030 // add to diff1 by diff0 scaled by: (1_z0)/(1-z1)
1031 Vmath::Vvtvp(nqtot, m_fac0.data(), 1, diff0.data() + cnt, 1,
1032 diff1.data() + cnt, 1, diff1.data() + cnt, 1);
1033 }
1034
1035 if (m_isDeformed)
1036 {
1037 Vmath::Vmul(nqcol, m_derivFac[0], 1, diff0, 1, output0, 1);
1038 Vmath::Vvtvp(nqcol, m_derivFac[1], 1, diff1, 1, output0, 1, output0,
1039 1);
1040 Vmath::Vmul(nqcol, m_derivFac[2], 1, diff0, 1, output1, 1);
1041 Vmath::Vvtvp(nqcol, m_derivFac[3], 1, diff1, 1, output1, 1, output1,
1042 1);
1043
1044 if (m_coordim == 3)
1045 {
1046 Vmath::Vmul(nqcol, m_derivFac[4], 1, diff0, 1, output2, 1);
1047 Vmath::Vvtvp(nqcol, m_derivFac[5], 1, diff1, 1, output2, 1,
1048 output2, 1);
1049 }
1050 }
1051 else
1052 {
1054 for (int e = 0; e < m_numElmt; ++e)
1055 {
1056 Vmath::Smul(m_nqe, m_derivFac[0][e], diff0 + e * m_nqe, 1,
1057 t = output0 + e * m_nqe, 1);
1058 Vmath::Svtvp(m_nqe, m_derivFac[1][e], diff1 + e * m_nqe, 1,
1059 output0 + e * m_nqe, 1, t = output0 + e * m_nqe,
1060 1);
1061
1062 Vmath::Smul(m_nqe, m_derivFac[2][e], diff0 + e * m_nqe, 1,
1063 t = output1 + e * m_nqe, 1);
1064 Vmath::Svtvp(m_nqe, m_derivFac[3][e], diff1 + e * m_nqe, 1,
1065 output1 + e * m_nqe, 1, t = output1 + e * m_nqe,
1066 1);
1067 }
1068
1069 if (m_coordim == 3)
1070 {
1071 for (int e = 0; e < m_numElmt; ++e)
1072 {
1073 Vmath::Smul(m_nqe, m_derivFac[4][e], diff0 + e * m_nqe, 1,
1074 t = output2 + e * m_nqe, 1);
1075 Vmath::Svtvp(m_nqe, m_derivFac[5][e], diff1 + e * m_nqe, 1,
1076 output2 + e * m_nqe, 1,
1077 t = output2 + e * m_nqe, 1);
1078 }
1079 }
1080 }
1081 }
1082
1083 void operator()(int dir, const Array<OneD, const NekDouble> &input,
1084 Array<OneD, NekDouble> &output,
1085 Array<OneD, NekDouble> &wsp) final
1086 {
1087 const int nqtot = m_nquad0 * m_nquad1;
1088 const int nqcol = nqtot * m_numElmt;
1089
1090 ASSERTL1(wsp.size() == m_wspSize, "Incorrect workspace size");
1091 ASSERTL1(input.size() >= nqcol, "Incorrect input size");
1092
1093 Array<OneD, NekDouble> diff0(nqcol, wsp);
1094 Array<OneD, NekDouble> diff1(nqcol, wsp + nqcol);
1095
1096 // Tensor Product Derivative
1097 Blas::Dgemm('N', 'N', m_nquad0, m_nquad1 * m_numElmt, m_nquad0, 1.0,
1098 m_Deriv0, m_nquad0, input.data(), m_nquad0, 0.0,
1099 diff0.data(), m_nquad0);
1100
1101 int cnt = 0;
1102 for (int i = 0; i < m_numElmt; ++i, cnt += nqtot)
1103 {
1104 // scale diff0 by geometric factor: 2/(1-z1)
1105 Vmath::Vmul(nqtot, &m_fac1[0], 1, diff0.data() + cnt, 1,
1106 diff0.data() + cnt, 1);
1107
1108 Blas::Dgemm('N', 'T', m_nquad0, m_nquad1, m_nquad1, 1.0,
1109 input.data() + cnt, m_nquad0, m_Deriv1, m_nquad1, 0.0,
1110 diff1.data() + cnt, m_nquad0);
1111
1112 // add to diff1 by diff0 scaled by: (1_z0)/(1-z1)
1113 Vmath::Vvtvp(nqtot, m_fac0.data(), 1, diff0.data() + cnt, 1,
1114 diff1.data() + cnt, 1, diff1.data() + cnt, 1);
1115 }
1116
1117 if (m_isDeformed)
1118 {
1119 Vmath::Vmul(nqcol, m_derivFac[2 * dir], 1, diff0, 1, output, 1);
1120 Vmath::Vvtvp(nqcol, m_derivFac[2 * dir + 1], 1, diff1, 1, output, 1,
1121 output, 1);
1122 }
1123 else
1124 {
1126 for (int e = 0; e < m_numElmt; ++e)
1127 {
1128 Vmath::Smul(m_nqe, m_derivFac[2 * dir][e], diff0 + e * m_nqe, 1,
1129 t = output + e * m_nqe, 1);
1130 Vmath::Svtvp(m_nqe, m_derivFac[2 * dir + 1][e],
1131 diff1 + e * m_nqe, 1, output + e * m_nqe, 1,
1132 t = output + e * m_nqe, 1);
1133 }
1134 }
1135 }
1136
1137protected:
1139 const int m_nquad0;
1140 const int m_nquad1;
1146
1147private:
1148 PhysDeriv_SumFac_Tri(vector<LocalRegions::ExpansionSharedPtr> pCollExp,
1150 StdRegions::FactorMap factors)
1151 : Operator(pCollExp, pGeomData, factors), PhysDeriv_Helper(),
1152 m_nquad0(m_stdExp->GetNumPoints(0)),
1153 m_nquad1(m_stdExp->GetNumPoints(1))
1154 {
1155 m_coordim = pCollExp[0]->GetCoordim();
1156
1157 m_derivFac = pGeomData->GetDerivFactors(pCollExp);
1158
1159 const Array<OneD, const NekDouble> &z0 = m_stdExp->GetBasis(0)->GetZ();
1160 const Array<OneD, const NekDouble> &z1 = m_stdExp->GetBasis(1)->GetZ();
1162 // set up geometric factor: 0.5*(1+z0)
1163 for (int i = 0; i < m_nquad0; ++i)
1164 {
1165 for (int j = 0; j < m_nquad1; ++j)
1166 {
1167 m_fac0[i + j * m_nquad0] = 0.5 * (1 + z0[i]);
1168 }
1169 }
1170
1172 // set up geometric factor: 2/(1-z1)
1173 for (int i = 0; i < m_nquad0; ++i)
1174 {
1175 for (int j = 0; j < m_nquad1; ++j)
1176 {
1177 m_fac1[i + j * m_nquad0] = 2.0 / (1 - z1[j]);
1178 }
1179 }
1180
1181 m_Deriv0 = &((m_stdExp->GetBasis(0)->GetD())->GetPtr())[0];
1182 m_Deriv1 = &((m_stdExp->GetBasis(1)->GetD())->GetPtr())[0];
1184 }
1185};
1186
1187/// Factory initialisation for the PhysDeriv_SumFac_Tri operators
1188OperatorKey PhysDeriv_SumFac_Tri::m_typeArr[] = {
1190 OperatorKey(eTriangle, ePhysDeriv, eSumFac, false),
1191 PhysDeriv_SumFac_Tri::create, "PhysDeriv_SumFac_Tri"),
1193 OperatorKey(eNodalTri, ePhysDeriv, eSumFac, true),
1194 PhysDeriv_SumFac_Tri::create, "PhysDeriv_SumFac_NodalTri")};
1195
1196/**
1197 * @brief Phys deriv operator using sum-factorisation (Hex)
1198 */
1199class PhysDeriv_SumFac_Hex final : virtual public Operator,
1200 virtual public PhysDeriv_Helper
1201{
1202public:
1204
1205 ~PhysDeriv_SumFac_Hex() final = default;
1206
1207 void operator()(const Array<OneD, const NekDouble> &input,
1208 Array<OneD, NekDouble> &output0,
1209 Array<OneD, NekDouble> &output1,
1210 Array<OneD, NekDouble> &output2,
1211 Array<OneD, NekDouble> &wsp) final
1212 {
1213 int nPhys = m_stdExp->GetTotPoints();
1214 int ntot = m_numElmt * nPhys;
1215 Array<OneD, NekDouble> tmp0, tmp1, tmp2;
1218 out[0] = output0;
1219 out[1] = output1;
1220 out[2] = output2;
1221
1222 for (int i = 0; i < 3; ++i)
1223 {
1224 Diff[i] = wsp + i * ntot;
1225 }
1226
1228 m_nquad0, 1.0, m_Deriv0, m_nquad0, &input[0], m_nquad0, 0.0,
1229 &Diff[0][0], m_nquad0);
1230
1231 for (int i = 0; i < m_numElmt; ++i)
1232 {
1233 for (int j = 0; j < m_nquad2; ++j)
1234 {
1235 Blas::Dgemm('N', 'T', m_nquad0, m_nquad1, m_nquad1, 1.0,
1236 &input[i * nPhys + j * m_nquad0 * m_nquad1],
1237 m_nquad0, m_Deriv1, m_nquad1, 0.0,
1238 &Diff[1][i * nPhys + j * m_nquad0 * m_nquad1],
1239 m_nquad0);
1240 }
1241
1242 Blas::Dgemm('N', 'T', m_nquad0 * m_nquad1, m_nquad2, m_nquad2, 1.0,
1243 &input[i * nPhys], m_nquad0 * m_nquad1, m_Deriv2,
1244 m_nquad2, 0.0, &Diff[2][i * nPhys],
1245 m_nquad0 * m_nquad1);
1246 }
1247
1248 // calculate full derivative
1249 if (m_isDeformed)
1250 {
1251 for (int i = 0; i < m_coordim; ++i)
1252 {
1253 Vmath::Vmul(ntot, m_derivFac[i * 3], 1, Diff[0], 1, out[i], 1);
1254 for (int j = 1; j < 3; ++j)
1255 {
1256 Vmath::Vvtvp(ntot, m_derivFac[i * 3 + j], 1, Diff[j], 1,
1257 out[i], 1, out[i], 1);
1258 }
1259 }
1260 }
1261 else
1262 {
1264 for (int e = 0; e < m_numElmt; ++e)
1265 {
1266 for (int i = 0; i < m_coordim; ++i)
1267 {
1268 Vmath::Smul(m_nqe, m_derivFac[i * 3][e],
1269 Diff[0] + e * m_nqe, 1, t = out[i] + e * m_nqe,
1270 1);
1271
1272 for (int j = 1; j < 3; ++j)
1273 {
1274 Vmath::Svtvp(m_nqe, m_derivFac[i * 3 + j][e],
1275 Diff[j] + e * m_nqe, 1, out[i] + e * m_nqe,
1276 1, t = out[i] + e * m_nqe, 1);
1277 }
1278 }
1279 }
1280 }
1281 }
1282
1283 void operator()(int dir, const Array<OneD, const NekDouble> &input,
1284 Array<OneD, NekDouble> &output,
1285 Array<OneD, NekDouble> &wsp) final
1286 {
1287 int nPhys = m_stdExp->GetTotPoints();
1288 int ntot = m_numElmt * nPhys;
1289 Array<OneD, NekDouble> tmp0, tmp1, tmp2;
1291
1292 for (int i = 0; i < 3; ++i)
1293 {
1294 Diff[i] = wsp + i * ntot;
1295 }
1296
1298 m_nquad0, 1.0, m_Deriv0, m_nquad0, &input[0], m_nquad0, 0.0,
1299 &Diff[0][0], m_nquad0);
1300
1301 for (int i = 0; i < m_numElmt; ++i)
1302 {
1303 for (int j = 0; j < m_nquad2; ++j)
1304 {
1305 Blas::Dgemm('N', 'T', m_nquad0, m_nquad1, m_nquad1, 1.0,
1306 &input[i * nPhys + j * m_nquad0 * m_nquad1],
1307 m_nquad0, m_Deriv1, m_nquad1, 0.0,
1308 &Diff[1][i * nPhys + j * m_nquad0 * m_nquad1],
1309 m_nquad0);
1310 }
1311
1312 Blas::Dgemm('N', 'T', m_nquad0 * m_nquad1, m_nquad2, m_nquad2, 1.0,
1313 &input[i * nPhys], m_nquad0 * m_nquad1, m_Deriv2,
1314 m_nquad2, 0.0, &Diff[2][i * nPhys],
1315 m_nquad0 * m_nquad1);
1316 }
1317
1318 // calculate full derivative
1319 if (m_isDeformed)
1320 {
1321 // calculate full derivative
1322 Vmath::Vmul(ntot, m_derivFac[dir * 3], 1, Diff[0], 1, output, 1);
1323 for (int j = 1; j < 3; ++j)
1324 {
1325 Vmath::Vvtvp(ntot, m_derivFac[dir * 3 + j], 1, Diff[j], 1,
1326 output, 1, output, 1);
1327 }
1328 }
1329 else
1330 {
1332 for (int e = 0; e < m_numElmt; ++e)
1333 {
1334 Vmath::Smul(m_nqe, m_derivFac[dir * 3][e], Diff[0] + e * m_nqe,
1335 1, t = output + e * m_nqe, 1);
1336
1337 for (int j = 1; j < 3; ++j)
1338 {
1339 Vmath::Svtvp(m_nqe, m_derivFac[dir * 3 + j][e],
1340 Diff[j] + e * m_nqe, 1, output + e * m_nqe, 1,
1341 t = output + e * m_nqe, 1);
1342 }
1343 }
1344 }
1345 }
1346
1347protected:
1350 const int m_nquad0;
1351 const int m_nquad1;
1352 const int m_nquad2;
1356
1357private:
1358 PhysDeriv_SumFac_Hex(vector<LocalRegions::ExpansionSharedPtr> pCollExp,
1360 StdRegions::FactorMap factors)
1361 : Operator(pCollExp, pGeomData, factors), PhysDeriv_Helper(),
1362 m_nquad0(m_stdExp->GetNumPoints(0)),
1363 m_nquad1(m_stdExp->GetNumPoints(1)),
1364 m_nquad2(m_stdExp->GetNumPoints(2))
1365 {
1366 m_coordim = pCollExp[0]->GetCoordim();
1367
1368 m_derivFac = pGeomData->GetDerivFactors(pCollExp);
1369
1370 m_Deriv0 = &((m_stdExp->GetBasis(0)->GetD())->GetPtr())[0];
1371 m_Deriv1 = &((m_stdExp->GetBasis(1)->GetD())->GetPtr())[0];
1372 m_Deriv2 = &((m_stdExp->GetBasis(2)->GetD())->GetPtr())[0];
1373
1375 }
1376};
1377
1378/// Factory initialisation for the PhysDeriv_SumFac_Hex operators
1379OperatorKey PhysDeriv_SumFac_Hex::m_typeArr[] = {
1381 OperatorKey(eHexahedron, ePhysDeriv, eSumFac, false),
1382 PhysDeriv_SumFac_Hex::create, "PhysDeriv_SumFac_Hex")};
1383
1384/**
1385 * @brief Phys deriv operator using sum-factorisation (Tet)
1386 */
1387class PhysDeriv_SumFac_Tet final : virtual public Operator,
1388 virtual public PhysDeriv_Helper
1389{
1390public:
1392
1393 ~PhysDeriv_SumFac_Tet() final = default;
1394
1395 void operator()(const Array<OneD, const NekDouble> &input,
1396 Array<OneD, NekDouble> &output0,
1397 Array<OneD, NekDouble> &output1,
1398 Array<OneD, NekDouble> &output2,
1399 Array<OneD, NekDouble> &wsp) final
1400 {
1401 int nPhys = m_stdExp->GetTotPoints();
1402 int ntot = m_numElmt * nPhys;
1403 Array<OneD, NekDouble> tmp0, tmp1, tmp2;
1406 out[0] = output0;
1407 out[1] = output1;
1408 out[2] = output2;
1409
1410 for (int i = 0; i < 3; ++i)
1411 {
1412 Diff[i] = wsp + i * ntot;
1413 }
1414
1415 // dEta0
1417 m_nquad0, 1.0, m_Deriv0, m_nquad0, &input[0], m_nquad0, 0.0,
1418 &Diff[0][0], m_nquad0);
1419
1420 // dEta2
1421 for (int i = 0; i < m_numElmt; ++i)
1422 {
1423 Blas::Dgemm('N', 'T', m_nquad0 * m_nquad1, m_nquad2, m_nquad2, 1.0,
1424 &input[i * nPhys], m_nquad0 * m_nquad1, m_Deriv2,
1425 m_nquad2, 0.0, &Diff[2][i * nPhys],
1426 m_nquad0 * m_nquad1);
1427 }
1428
1429 for (int i = 0; i < m_numElmt; ++i)
1430 {
1431 // dEta1
1432 for (int j = 0; j < m_nquad2; ++j)
1433 {
1434 Blas::Dgemm('N', 'T', m_nquad0, m_nquad1, m_nquad1, 1.0,
1435 &input[i * nPhys + j * m_nquad0 * m_nquad1],
1436 m_nquad0, m_Deriv1, m_nquad1, 0.0,
1437 &Diff[1][i * nPhys + j * m_nquad0 * m_nquad1],
1438 m_nquad0);
1439 }
1440
1441 // dxi2 = (1 + eta_1)/(1 -eta_2)*dEta1 + dEta2
1442 Vmath::Vvtvp(nPhys, m_fac3.data(), 1, Diff[1].data() + i * nPhys, 1,
1443 Diff[2].data() + i * nPhys, 1,
1444 Diff[2].data() + i * nPhys, 1);
1445
1446 // dxi1 = 2/(1 - eta_2) dEta1
1447 Vmath::Vmul(nPhys, m_fac2.data(), 1, Diff[1].data() + i * nPhys, 1,
1448 Diff[1].data() + i * nPhys, 1);
1449
1450 // dxi1 = 2.0(1+eta_0)/((1-eta_1)(1-eta_2)) dEta0 + dxi1
1451 Vmath::Vvtvp(nPhys, m_fac1.data(), 1, Diff[0].data() + i * nPhys, 1,
1452 Diff[1].data() + i * nPhys, 1,
1453 Diff[1].data() + i * nPhys, 1);
1454
1455 // dxi2 = 2.0(1+eta_0)/((1-eta_1)(1-eta_2)) dEta0 + dxi2
1456 Vmath::Vvtvp(nPhys, m_fac1.data(), 1, Diff[0].data() + i * nPhys, 1,
1457 Diff[2].data() + i * nPhys, 1,
1458 Diff[2].data() + i * nPhys, 1);
1459
1460 // dxi0 = 4.0/((1-eta_1)(1-eta_2)) dEta0
1461 Vmath::Vmul(nPhys, m_fac0.data(), 1, Diff[0].data() + i * nPhys, 1,
1462 Diff[0].data() + i * nPhys, 1);
1463 }
1464
1465 // calculate full derivative
1466 if (m_isDeformed)
1467 {
1468 for (int i = 0; i < m_coordim; ++i)
1469 {
1470 Vmath::Vmul(ntot, m_derivFac[i * 3], 1, Diff[0], 1, out[i], 1);
1471 for (int j = 1; j < 3; ++j)
1472 {
1473 Vmath::Vvtvp(ntot, m_derivFac[i * 3 + j], 1, Diff[j], 1,
1474 out[i], 1, out[i], 1);
1475 }
1476 }
1477 }
1478 else
1479 {
1481 for (int e = 0; e < m_numElmt; ++e)
1482 {
1483 for (int i = 0; i < m_coordim; ++i)
1484 {
1485 Vmath::Smul(m_nqe, m_derivFac[i * 3][e],
1486 Diff[0] + e * m_nqe, 1, t = out[i] + e * m_nqe,
1487 1);
1488 for (int j = 1; j < 3; ++j)
1489 {
1490 Vmath::Svtvp(m_nqe, m_derivFac[i * 3 + j][e],
1491 Diff[j] + e * m_nqe, 1, out[i] + e * m_nqe,
1492 1, t = out[i] + e * m_nqe, 1);
1493 }
1494 }
1495 }
1496 }
1497 }
1498
1499 void operator()(int dir, const Array<OneD, const NekDouble> &input,
1500 Array<OneD, NekDouble> &output,
1501 Array<OneD, NekDouble> &wsp) final
1502 {
1503 int nPhys = m_stdExp->GetTotPoints();
1504 int ntot = m_numElmt * nPhys;
1505 Array<OneD, NekDouble> tmp0, tmp1, tmp2;
1507
1508 for (int i = 0; i < 3; ++i)
1509 {
1510 Diff[i] = wsp + i * ntot;
1511 }
1512
1513 // dEta0
1515 m_nquad0, 1.0, m_Deriv0, m_nquad0, &input[0], m_nquad0, 0.0,
1516 &Diff[0][0], m_nquad0);
1517
1518 // dEta2
1519 for (int i = 0; i < m_numElmt; ++i)
1520 {
1521 Blas::Dgemm('N', 'T', m_nquad0 * m_nquad1, m_nquad2, m_nquad2, 1.0,
1522 &input[i * nPhys], m_nquad0 * m_nquad1, m_Deriv2,
1523 m_nquad2, 0.0, &Diff[2][i * nPhys],
1524 m_nquad0 * m_nquad1);
1525 }
1526
1527 for (int i = 0; i < m_numElmt; ++i)
1528 {
1529 // dEta1
1530 for (int j = 0; j < m_nquad2; ++j)
1531 {
1532 Blas::Dgemm('N', 'T', m_nquad0, m_nquad1, m_nquad1, 1.0,
1533 &input[i * nPhys + j * m_nquad0 * m_nquad1],
1534 m_nquad0, m_Deriv1, m_nquad1, 0.0,
1535 &Diff[1][i * nPhys + j * m_nquad0 * m_nquad1],
1536 m_nquad0);
1537 }
1538
1539 // dxi2 = (1 + eta_1)/(1 -eta_2)*dEta1 + dEta2
1540 Vmath::Vvtvp(nPhys, m_fac3.data(), 1, Diff[1].data() + i * nPhys, 1,
1541 Diff[2].data() + i * nPhys, 1,
1542 Diff[2].data() + i * nPhys, 1);
1543
1544 // dxi1 = 2/(1 - eta_2) dEta1
1545 Vmath::Vmul(nPhys, m_fac2.data(), 1, Diff[1].data() + i * nPhys, 1,
1546 Diff[1].data() + i * nPhys, 1);
1547
1548 // dxi1 = 2.0(1+eta_0)/((1-eta_1)(1-eta_2)) dEta0 + dxi1
1549 Vmath::Vvtvp(nPhys, m_fac1.data(), 1, Diff[0].data() + i * nPhys, 1,
1550 Diff[1].data() + i * nPhys, 1,
1551 Diff[1].data() + i * nPhys, 1);
1552
1553 // dxi2 = 2.0(1+eta_0)/((1-eta_1)(1-eta_2)) dEta0 + dxi2
1554 Vmath::Vvtvp(nPhys, m_fac1.data(), 1, Diff[0].data() + i * nPhys, 1,
1555 Diff[2].data() + i * nPhys, 1,
1556 Diff[2].data() + i * nPhys, 1);
1557
1558 // dxi0 = 4.0/((1-eta_1)(1-eta_2)) dEta0
1559 Vmath::Vmul(nPhys, m_fac0.data(), 1, Diff[0].data() + i * nPhys, 1,
1560 Diff[0].data() + i * nPhys, 1);
1561 }
1562
1563 // calculate full derivative
1564 if (m_isDeformed)
1565 {
1566 // calculate full derivative
1567 Vmath::Vmul(ntot, m_derivFac[dir * 3], 1, Diff[0], 1, output, 1);
1568 for (int j = 1; j < 3; ++j)
1569 {
1570 Vmath::Vvtvp(ntot, m_derivFac[dir * 3 + j], 1, Diff[j], 1,
1571 output, 1, output, 1);
1572 }
1573 }
1574 else
1575 {
1577 for (int e = 0; e < m_numElmt; ++e)
1578 {
1579 Vmath::Smul(m_nqe, m_derivFac[dir * 3][e], Diff[0] + e * m_nqe,
1580 1, t = output + e * m_nqe, 1);
1581 for (int j = 1; j < 3; ++j)
1582 {
1583 Vmath::Svtvp(m_nqe, m_derivFac[dir * 3 + j][e],
1584 Diff[j] + e * m_nqe, 1, output + e * m_nqe, 1,
1585 t = output + e * m_nqe, 1);
1586 }
1587 }
1588 }
1589 }
1590
1591protected:
1594 const int m_nquad0;
1595 const int m_nquad1;
1596 const int m_nquad2;
1604
1605private:
1606 PhysDeriv_SumFac_Tet(vector<LocalRegions::ExpansionSharedPtr> pCollExp,
1608 StdRegions::FactorMap factors)
1609 : Operator(pCollExp, pGeomData, factors), PhysDeriv_Helper(),
1610 m_nquad0(m_stdExp->GetNumPoints(0)),
1611 m_nquad1(m_stdExp->GetNumPoints(1)),
1612 m_nquad2(m_stdExp->GetNumPoints(2))
1613 {
1614 m_coordim = pCollExp[0]->GetCoordim();
1615
1616 m_derivFac = pGeomData->GetDerivFactors(pCollExp);
1617
1618 m_Deriv0 = &((m_stdExp->GetBasis(0)->GetD())->GetPtr())[0];
1619 m_Deriv1 = &((m_stdExp->GetBasis(1)->GetD())->GetPtr())[0];
1620 m_Deriv2 = &((m_stdExp->GetBasis(2)->GetD())->GetPtr())[0];
1621
1623
1624 const Array<OneD, const NekDouble> &z0 = m_stdExp->GetBasis(0)->GetZ();
1625 const Array<OneD, const NekDouble> &z1 = m_stdExp->GetBasis(1)->GetZ();
1626 const Array<OneD, const NekDouble> &z2 = m_stdExp->GetBasis(2)->GetZ();
1627
1632
1633 // calculate 2.0/((1-eta_1)(1-eta_2))
1634 for (int i = 0; i < m_nquad0; ++i)
1635 {
1636 for (int j = 0; j < m_nquad1; ++j)
1637 {
1638 for (int k = 0; k < m_nquad2; ++k)
1639 {
1640 m_fac0[i + j * m_nquad0 + k * m_nquad0 * m_nquad1] =
1641 4.0 / ((1 - z1[j]) * (1 - z2[k]));
1642 m_fac1[i + j * m_nquad0 + k * m_nquad0 * m_nquad1] =
1643 2.0 * (1 + z0[i]) / ((1 - z1[j]) * (1 - z2[k]));
1644 m_fac2[i + j * m_nquad0 + k * m_nquad0 * m_nquad1] =
1645 2.0 / (1 - z2[k]);
1646 m_fac3[i + j * m_nquad0 + k * m_nquad0 * m_nquad1] =
1647 (1 + z1[j]) / (1 - z2[k]);
1648 }
1649 }
1650 }
1651 }
1652};
1653
1654/// Factory initialisation for the PhysDeriv_SumFac_Tet operators
1655OperatorKey PhysDeriv_SumFac_Tet::m_typeArr[] = {
1657 OperatorKey(eTetrahedron, ePhysDeriv, eSumFac, false),
1658 PhysDeriv_SumFac_Tet::create, "PhysDeriv_SumFac_Tet")};
1659
1660/**
1661 * @brief Phys deriv operator using sum-factorisation (Prism)
1662 */
1663class PhysDeriv_SumFac_Prism final : virtual public Operator,
1664 virtual public PhysDeriv_Helper
1665{
1666public:
1668
1669 ~PhysDeriv_SumFac_Prism() final = default;
1670
1671 void operator()(const Array<OneD, const NekDouble> &input,
1672 Array<OneD, NekDouble> &output0,
1673 Array<OneD, NekDouble> &output1,
1674 Array<OneD, NekDouble> &output2,
1675 Array<OneD, NekDouble> &wsp) final
1676 {
1677 int nPhys = m_stdExp->GetTotPoints();
1678 int ntot = m_numElmt * nPhys;
1679 Array<OneD, NekDouble> tmp0, tmp1, tmp2;
1682 out[0] = output0;
1683 out[1] = output1;
1684 out[2] = output2;
1685
1686 for (int i = 0; i < 3; ++i)
1687 {
1688 Diff[i] = wsp + i * ntot;
1689 }
1690
1691 // dEta0
1693 m_nquad0, 1.0, m_Deriv0, m_nquad0, &input[0], m_nquad0, 0.0,
1694 &Diff[0][0], m_nquad0);
1695
1696 int cnt = 0;
1697 for (int i = 0; i < m_numElmt; ++i)
1698 {
1699 // dEta 1
1700 for (int j = 0; j < m_nquad2; ++j)
1701 {
1702 Blas::Dgemm('N', 'T', m_nquad0, m_nquad1, m_nquad1, 1.0,
1703 &input[i * nPhys + j * m_nquad0 * m_nquad1],
1704 m_nquad0, m_Deriv1, m_nquad1, 0.0,
1705 &Diff[1][i * nPhys + j * m_nquad0 * m_nquad1],
1706 m_nquad0);
1707 }
1708
1709 // dEta 2
1710 Blas::Dgemm('N', 'T', m_nquad0 * m_nquad1, m_nquad2, m_nquad2, 1.0,
1711 &input[i * nPhys], m_nquad0 * m_nquad1, m_Deriv2,
1712 m_nquad2, 0.0, &Diff[2][i * nPhys],
1713 m_nquad0 * m_nquad1);
1714
1715 // dxi0 = 2/(1-eta_2) d Eta_0
1716 Vmath::Vmul(nPhys, &m_fac0[0], 1, Diff[0].data() + cnt, 1,
1717 Diff[0].data() + cnt, 1);
1718
1719 // dxi2 = (1+eta0)/(1-eta_2) d Eta_0 + d/dEta2;
1720 Vmath::Vvtvp(nPhys, &m_fac1[0], 1, Diff[0].data() + cnt, 1,
1721 Diff[2].data() + cnt, 1, Diff[2].data() + cnt, 1);
1722 cnt += nPhys;
1723 }
1724
1725 // calculate full derivative
1726 if (m_isDeformed)
1727 {
1728 for (int i = 0; i < m_coordim; ++i)
1729 {
1730 Vmath::Vmul(ntot, m_derivFac[i * 3], 1, Diff[0], 1, out[i], 1);
1731 for (int j = 1; j < 3; ++j)
1732 {
1733 Vmath::Vvtvp(ntot, m_derivFac[i * 3 + j], 1, Diff[j], 1,
1734 out[i], 1, out[i], 1);
1735 }
1736 }
1737 }
1738 else
1739 {
1741 for (int e = 0; e < m_numElmt; ++e)
1742 {
1743 for (int i = 0; i < m_coordim; ++i)
1744 {
1745 Vmath::Smul(m_nqe, m_derivFac[i * 3][e],
1746 Diff[0] + e * m_nqe, 1, t = out[i] + e * m_nqe,
1747 1);
1748
1749 for (int j = 1; j < 3; ++j)
1750 {
1751 Vmath::Svtvp(m_nqe, m_derivFac[i * 3 + j][e],
1752 Diff[j] + e * m_nqe, 1, out[i] + e * m_nqe,
1753 1, t = out[i] + e * m_nqe, 1);
1754 }
1755 }
1756 }
1757 }
1758 }
1759
1760 void operator()(int dir, const Array<OneD, const NekDouble> &input,
1761 Array<OneD, NekDouble> &output,
1762 Array<OneD, NekDouble> &wsp) final
1763 {
1764 int nPhys = m_stdExp->GetTotPoints();
1765 int ntot = m_numElmt * nPhys;
1766 Array<OneD, NekDouble> tmp0, tmp1, tmp2;
1768
1769 for (int i = 0; i < 3; ++i)
1770 {
1771 Diff[i] = wsp + i * ntot;
1772 }
1773
1774 // dEta0
1776 m_nquad0, 1.0, m_Deriv0, m_nquad0, &input[0], m_nquad0, 0.0,
1777 &Diff[0][0], m_nquad0);
1778
1779 int cnt = 0;
1780 for (int i = 0; i < m_numElmt; ++i)
1781 {
1782 // dEta 1
1783 for (int j = 0; j < m_nquad2; ++j)
1784 {
1785 Blas::Dgemm('N', 'T', m_nquad0, m_nquad1, m_nquad1, 1.0,
1786 &input[i * nPhys + j * m_nquad0 * m_nquad1],
1787 m_nquad0, m_Deriv1, m_nquad1, 0.0,
1788 &Diff[1][i * nPhys + j * m_nquad0 * m_nquad1],
1789 m_nquad0);
1790 }
1791
1792 // dEta 2
1793 Blas::Dgemm('N', 'T', m_nquad0 * m_nquad1, m_nquad2, m_nquad2, 1.0,
1794 &input[i * nPhys], m_nquad0 * m_nquad1, m_Deriv2,
1795 m_nquad2, 0.0, &Diff[2][i * nPhys],
1796 m_nquad0 * m_nquad1);
1797
1798 // dxi0 = 2/(1-eta_2) d Eta_0
1799 Vmath::Vmul(nPhys, &m_fac0[0], 1, Diff[0].data() + cnt, 1,
1800 Diff[0].data() + cnt, 1);
1801
1802 // dxi2 = (1+eta0)/(1-eta_2) d Eta_0 + d/dEta2;
1803 Vmath::Vvtvp(nPhys, &m_fac1[0], 1, Diff[0].data() + cnt, 1,
1804 Diff[2].data() + cnt, 1, Diff[2].data() + cnt, 1);
1805 cnt += nPhys;
1806 }
1807
1808 // calculate full derivative
1809 if (m_isDeformed)
1810 {
1811 // calculate full derivative
1812 Vmath::Vmul(ntot, m_derivFac[dir * 3], 1, Diff[0], 1, output, 1);
1813 for (int j = 1; j < 3; ++j)
1814 {
1815 Vmath::Vvtvp(ntot, m_derivFac[dir * 3 + j], 1, Diff[j], 1,
1816 output, 1, output, 1);
1817 }
1818 }
1819 else
1820 {
1822 for (int e = 0; e < m_numElmt; ++e)
1823 {
1824 Vmath::Smul(m_nqe, m_derivFac[dir * 3][e], Diff[0] + e * m_nqe,
1825 1, t = output + e * m_nqe, 1);
1826
1827 for (int j = 1; j < 3; ++j)
1828 {
1829 Vmath::Svtvp(m_nqe, m_derivFac[dir * 3 + j][e],
1830 Diff[j] + e * m_nqe, 1, output + e * m_nqe, 1,
1831 t = output + e * m_nqe, 1);
1832 }
1833 }
1834 }
1835 }
1836
1837protected:
1840 const int m_nquad0;
1841 const int m_nquad1;
1842 const int m_nquad2;
1848
1849private:
1850 PhysDeriv_SumFac_Prism(vector<LocalRegions::ExpansionSharedPtr> pCollExp,
1852 StdRegions::FactorMap factors)
1853 : Operator(pCollExp, pGeomData, factors), PhysDeriv_Helper(),
1854 m_nquad0(m_stdExp->GetNumPoints(0)),
1855 m_nquad1(m_stdExp->GetNumPoints(1)),
1856 m_nquad2(m_stdExp->GetNumPoints(2))
1857 {
1858 m_coordim = pCollExp[0]->GetCoordim();
1859
1860 m_derivFac = pGeomData->GetDerivFactors(pCollExp);
1861
1862 const Array<OneD, const NekDouble> &z0 = m_stdExp->GetBasis(0)->GetZ();
1863 const Array<OneD, const NekDouble> &z2 = m_stdExp->GetBasis(2)->GetZ();
1866 for (int i = 0; i < m_nquad0; ++i)
1867 {
1868 for (int j = 0; j < m_nquad1; ++j)
1869 {
1870 for (int k = 0; k < m_nquad2; ++k)
1871 {
1872 m_fac0[i + j * m_nquad0 + k * m_nquad0 * m_nquad1] =
1873 2.0 / (1 - z2[k]);
1874 m_fac1[i + j * m_nquad0 + k * m_nquad0 * m_nquad1] =
1875 0.5 * (1 + z0[i]);
1876 }
1877 }
1878 }
1879
1880 m_Deriv0 = &((m_stdExp->GetBasis(0)->GetD())->GetPtr())[0];
1881 m_Deriv1 = &((m_stdExp->GetBasis(1)->GetD())->GetPtr())[0];
1882 m_Deriv2 = &((m_stdExp->GetBasis(2)->GetD())->GetPtr())[0];
1883
1885 }
1886};
1887
1888/// Factory initialisation for the PhysDeriv_SumFac_Prism operators
1889OperatorKey PhysDeriv_SumFac_Prism::m_typeArr[] = {
1891 OperatorKey(ePrism, ePhysDeriv, eSumFac, false),
1892 PhysDeriv_SumFac_Prism::create, "PhysDeriv_SumFac_Prism")};
1893
1894/**
1895 * @brief Phys deriv operator using sum-factorisation (Pyramid)
1896 */
1897class PhysDeriv_SumFac_Pyr final : virtual public Operator,
1898 virtual public PhysDeriv_Helper
1899{
1900public:
1902
1903 ~PhysDeriv_SumFac_Pyr() final = default;
1904
1905 void operator()(const Array<OneD, const NekDouble> &input,
1906 Array<OneD, NekDouble> &output0,
1907 Array<OneD, NekDouble> &output1,
1908 Array<OneD, NekDouble> &output2,
1909 Array<OneD, NekDouble> &wsp) final
1910 {
1911 int nPhys = m_stdExp->GetTotPoints();
1912 int ntot = m_numElmt * nPhys;
1913 Array<OneD, NekDouble> tmp0, tmp1, tmp2;
1916 out[0] = output0;
1917 out[1] = output1;
1918 out[2] = output2;
1919
1920 for (int i = 0; i < 3; ++i)
1921 {
1922 Diff[i] = wsp + i * ntot;
1923 }
1924
1925 // dEta0
1927 m_nquad0, 1.0, m_Deriv0, m_nquad0, &input[0], m_nquad0, 0.0,
1928 &Diff[0][0], m_nquad0);
1929
1930 int cnt = 0;
1931 for (int i = 0; i < m_numElmt; ++i)
1932 {
1933 // dEta 1
1934 for (int j = 0; j < m_nquad2; ++j)
1935 {
1936 Blas::Dgemm('N', 'T', m_nquad0, m_nquad1, m_nquad1, 1.0,
1937 &input[i * nPhys + j * m_nquad0 * m_nquad1],
1938 m_nquad0, m_Deriv1, m_nquad1, 0.0,
1939 &Diff[1][i * nPhys + j * m_nquad0 * m_nquad1],
1940 m_nquad0);
1941 }
1942
1943 // dEta 2
1944 Blas::Dgemm('N', 'T', m_nquad0 * m_nquad1, m_nquad2, m_nquad2, 1.0,
1945 &input[i * nPhys], m_nquad0 * m_nquad1, m_Deriv2,
1946 m_nquad2, 0.0, &Diff[2][i * nPhys],
1947 m_nquad0 * m_nquad1);
1948
1949 // dxi0 = 2/(1-eta_2) d Eta_0
1950 Vmath::Vmul(nPhys, &m_fac0[0], 1, Diff[0].data() + cnt, 1,
1951 Diff[0].data() + cnt, 1);
1952
1953 // dxi1 = 2/(1-eta_2) d Eta_1
1954 Vmath::Vmul(nPhys, &m_fac0[0], 1, Diff[1].data() + cnt, 1,
1955 Diff[1].data() + cnt, 1);
1956
1957 // dxi2 = (1+eta0)/(1-eta_2) d Eta_0 + d/dEta2;
1958 Vmath::Vvtvp(nPhys, &m_fac1[0], 1, Diff[0].data() + cnt, 1,
1959 Diff[2].data() + cnt, 1, Diff[2].data() + cnt, 1);
1960
1961 // dxi2 += (1+eta1)/(1-eta_2) d Eta_1
1962 Vmath::Vvtvp(nPhys, &m_fac2[0], 1, Diff[1].data() + cnt, 1,
1963 Diff[2].data() + cnt, 1, Diff[2].data() + cnt, 1);
1964 cnt += nPhys;
1965 }
1966
1967 // calculate full derivative
1968 if (m_isDeformed)
1969 {
1970 for (int i = 0; i < m_coordim; ++i)
1971 {
1972 Vmath::Vmul(ntot, m_derivFac[i * 3], 1, Diff[0], 1, out[i], 1);
1973 for (int j = 1; j < 3; ++j)
1974 {
1975 Vmath::Vvtvp(ntot, m_derivFac[i * 3 + j], 1, Diff[j], 1,
1976 out[i], 1, out[i], 1);
1977 }
1978 }
1979 }
1980 else
1981 {
1983 for (int e = 0; e < m_numElmt; ++e)
1984 {
1985 for (int i = 0; i < m_coordim; ++i)
1986 {
1987 Vmath::Smul(m_nqe, m_derivFac[i * 3][e],
1988 Diff[0] + e * m_nqe, 1, t = out[i] + e * m_nqe,
1989 1);
1990
1991 for (int j = 1; j < 3; ++j)
1992 {
1993 Vmath::Svtvp(m_nqe, m_derivFac[i * 3 + j][e],
1994 Diff[j] + e * m_nqe, 1, out[i] + e * m_nqe,
1995 1, t = out[i] + e * m_nqe, 1);
1996 }
1997 }
1998 }
1999 }
2000 }
2001
2002 void operator()(int dir, const Array<OneD, const NekDouble> &input,
2003 Array<OneD, NekDouble> &output,
2004 Array<OneD, NekDouble> &wsp) final
2005 {
2006 int nPhys = m_stdExp->GetTotPoints();
2007 int ntot = m_numElmt * nPhys;
2008 Array<OneD, NekDouble> tmp0, tmp1, tmp2;
2010
2011 for (int i = 0; i < 3; ++i)
2012 {
2013 Diff[i] = wsp + i * ntot;
2014 }
2015
2016 // dEta0
2018 m_nquad0, 1.0, m_Deriv0, m_nquad0, &input[0], m_nquad0, 0.0,
2019 &Diff[0][0], m_nquad0);
2020
2021 int cnt = 0;
2022 for (int i = 0; i < m_numElmt; ++i)
2023 {
2024 // dEta 1
2025 for (int j = 0; j < m_nquad2; ++j)
2026 {
2027 Blas::Dgemm('N', 'T', m_nquad0, m_nquad1, m_nquad1, 1.0,
2028 &input[i * nPhys + j * m_nquad0 * m_nquad1],
2029 m_nquad0, m_Deriv1, m_nquad1, 0.0,
2030 &Diff[1][i * nPhys + j * m_nquad0 * m_nquad1],
2031 m_nquad0);
2032 }
2033
2034 // dEta 2
2035 Blas::Dgemm('N', 'T', m_nquad0 * m_nquad1, m_nquad2, m_nquad2, 1.0,
2036 &input[i * nPhys], m_nquad0 * m_nquad1, m_Deriv2,
2037 m_nquad2, 0.0, &Diff[2][i * nPhys],
2038 m_nquad0 * m_nquad1);
2039
2040 // dxi0 = 2/(1-eta_2) d Eta_0
2041 Vmath::Vmul(nPhys, &m_fac0[0], 1, Diff[0].data() + cnt, 1,
2042 Diff[0].data() + cnt, 1);
2043
2044 // dxi1 = 2/(1-eta_2) d Eta_1
2045 Vmath::Vmul(nPhys, &m_fac0[0], 1, Diff[1].data() + cnt, 1,
2046 Diff[1].data() + cnt, 1);
2047
2048 // dxi2 = (1+eta0)/(1-eta_2) d Eta_0 + d/dEta2;
2049 Vmath::Vvtvp(nPhys, &m_fac1[0], 1, Diff[0].data() + cnt, 1,
2050 Diff[2].data() + cnt, 1, Diff[2].data() + cnt, 1);
2051
2052 // dxi2 = (1+eta1)/(1-eta_2) d Eta_1 + d/dEta2;
2053 Vmath::Vvtvp(nPhys, &m_fac2[0], 1, Diff[1].data() + cnt, 1,
2054 Diff[2].data() + cnt, 1, Diff[2].data() + cnt, 1);
2055 cnt += nPhys;
2056 }
2057
2058 // calculate full derivative
2059 if (m_isDeformed)
2060 {
2061 // calculate full derivative
2062 Vmath::Vmul(ntot, m_derivFac[dir * 3], 1, Diff[0], 1, output, 1);
2063 for (int j = 1; j < 3; ++j)
2064 {
2065 Vmath::Vvtvp(ntot, m_derivFac[dir * 3 + j], 1, Diff[j], 1,
2066 output, 1, output, 1);
2067 }
2068 }
2069 else
2070 {
2072 for (int e = 0; e < m_numElmt; ++e)
2073 {
2074 Vmath::Smul(m_nqe, m_derivFac[dir * 3][e], Diff[0] + e * m_nqe,
2075 1, t = output + e * m_nqe, 1);
2076
2077 for (int j = 1; j < 3; ++j)
2078 {
2079 Vmath::Svtvp(m_nqe, m_derivFac[dir * 3 + j][e],
2080 Diff[j] + e * m_nqe, 1, output + e * m_nqe, 1,
2081 t = output + e * m_nqe, 1);
2082 }
2083 }
2084 }
2085 }
2086
2087protected:
2090 const int m_nquad0;
2091 const int m_nquad1;
2092 const int m_nquad2;
2099
2100private:
2101 PhysDeriv_SumFac_Pyr(vector<LocalRegions::ExpansionSharedPtr> pCollExp,
2103 StdRegions::FactorMap factors)
2104 : Operator(pCollExp, pGeomData, factors), PhysDeriv_Helper(),
2105 m_nquad0(m_stdExp->GetNumPoints(0)),
2106 m_nquad1(m_stdExp->GetNumPoints(1)),
2107 m_nquad2(m_stdExp->GetNumPoints(2))
2108 {
2109 m_coordim = pCollExp[0]->GetCoordim();
2110
2111 m_derivFac = pGeomData->GetDerivFactors(pCollExp);
2112
2113 const Array<OneD, const NekDouble> &z0 = m_stdExp->GetBasis(0)->GetZ();
2114 const Array<OneD, const NekDouble> &z1 = m_stdExp->GetBasis(1)->GetZ();
2115 const Array<OneD, const NekDouble> &z2 = m_stdExp->GetBasis(2)->GetZ();
2119
2120 int nq0_nq1 = m_nquad0 * m_nquad1;
2121 for (int i = 0; i < m_nquad0; ++i)
2122 {
2123 for (int j = 0; j < m_nquad1; ++j)
2124 {
2125 int ifac = i + j * m_nquad0;
2126 for (int k = 0; k < m_nquad2; ++k)
2127 {
2128 m_fac0[ifac + k * nq0_nq1] = 2.0 / (1 - z2[k]);
2129 m_fac1[ifac + k * nq0_nq1] = 0.5 * (1 + z0[i]);
2130 m_fac2[ifac + k * nq0_nq1] = 0.5 * (1 + z1[j]);
2131 }
2132 }
2133 }
2134
2135 m_Deriv0 = &((m_stdExp->GetBasis(0)->GetD())->GetPtr())[0];
2136 m_Deriv1 = &((m_stdExp->GetBasis(1)->GetD())->GetPtr())[0];
2137 m_Deriv2 = &((m_stdExp->GetBasis(2)->GetD())->GetPtr())[0];
2138
2140 }
2141};
2142
2143/// Factory initialisation for the PhysDeriv_SumFac_Pyr operators
2144OperatorKey PhysDeriv_SumFac_Pyr::m_typeArr[] = {
2146 OperatorKey(ePyramid, ePhysDeriv, eSumFac, false),
2147 PhysDeriv_SumFac_Pyr::create, "PhysDeriv_SumFac_Pyr")};
2148
2149} // namespace Nektar::Collections
#define ASSERTL0(condition, msg)
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mode...
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
#define OPERATOR_CREATE(cname)
Definition Operator.h:43
unsigned int m_nElmtPad
size after padding
unsigned int m_nOut
actural size of output array
Base class for operators on a collection of elements.
Definition Operator.h:138
StdRegions::StdExpansionSharedPtr m_stdExp
Definition Operator.h:230
unsigned int m_numElmt
number of elements that the operator is applied on
Definition Operator.h:232
unsigned int m_outputSize
number of modes or quadrature points that are taken as output from an operator
Definition Operator.h:240
unsigned int m_inputSize
number of modes or quadrature points that are passed as input to an operator
Definition Operator.h:237
Physical Derivative help class to calculate the size of the collection that is given as an input and ...
Definition PhysDeriv.cpp:63
Phys deriv operator using element-wise operation.
void operator()(int dir, const Array< OneD, const NekDouble > &input, Array< OneD, NekDouble > &output, Array< OneD, NekDouble > &wsp) final
PhysDeriv_IterPerExp(vector< LocalRegions::ExpansionSharedPtr > pCollExp, CoalescedGeomDataSharedPtr pGeomData, StdRegions::FactorMap factors)
Array< TwoD, const NekDouble > m_derivFac
Phys deriv operator using matrix free operators.
Array< OneD, Array< OneD, NekDouble > > m_output
std::shared_ptr< MatrixFree::PhysDeriv > m_oper
PhysDeriv_MatrixFree(vector< LocalRegions::ExpansionSharedPtr > pCollExp, CoalescedGeomDataSharedPtr pGeomData, StdRegions::FactorMap factors)
void operator()(int dir, const Array< OneD, const NekDouble > &input, Array< OneD, NekDouble > &output, Array< OneD, NekDouble > &wsp) final
Phys deriv operator using original LocalRegions implementation.
void operator()(int dir, const Array< OneD, const NekDouble > &input, Array< OneD, NekDouble > &output, Array< OneD, NekDouble > &wsp) final
vector< LocalRegions::ExpansionSharedPtr > m_expList
PhysDeriv_NoCollection(vector< LocalRegions::ExpansionSharedPtr > pCollExp, CoalescedGeomDataSharedPtr pGeomData, StdRegions::FactorMap factors)
Phys deriv operator using standard matrix approach.
Definition PhysDeriv.cpp:81
Array< TwoD, const NekDouble > m_derivFac
PhysDeriv_StdMat(vector< LocalRegions::ExpansionSharedPtr > pCollExp, CoalescedGeomDataSharedPtr pGeomData, StdRegions::FactorMap factors)
Array< OneD, DNekMatSharedPtr > m_derivMat
void operator()(int dir, const Array< OneD, const NekDouble > &input, Array< OneD, NekDouble > &output, Array< OneD, NekDouble > &wsp) final
Phys deriv operator using sum-factorisation (Hex)
Array< TwoD, const NekDouble > m_derivFac
PhysDeriv_SumFac_Hex(vector< LocalRegions::ExpansionSharedPtr > pCollExp, CoalescedGeomDataSharedPtr pGeomData, StdRegions::FactorMap factors)
void operator()(int dir, const Array< OneD, const NekDouble > &input, Array< OneD, NekDouble > &output, Array< OneD, NekDouble > &wsp) final
Phys deriv operator using sum-factorisation (Prism)
void operator()(int dir, const Array< OneD, const NekDouble > &input, Array< OneD, NekDouble > &output, Array< OneD, NekDouble > &wsp) final
Array< TwoD, const NekDouble > m_derivFac
PhysDeriv_SumFac_Prism(vector< LocalRegions::ExpansionSharedPtr > pCollExp, CoalescedGeomDataSharedPtr pGeomData, StdRegions::FactorMap factors)
Phys deriv operator using sum-factorisation (Pyramid)
PhysDeriv_SumFac_Pyr(vector< LocalRegions::ExpansionSharedPtr > pCollExp, CoalescedGeomDataSharedPtr pGeomData, StdRegions::FactorMap factors)
Array< TwoD, const NekDouble > m_derivFac
void operator()(int dir, const Array< OneD, const NekDouble > &input, Array< OneD, NekDouble > &output, Array< OneD, NekDouble > &wsp) final
Phys deriv operator using sum-factorisation (Quad)
PhysDeriv_SumFac_Quad(vector< LocalRegions::ExpansionSharedPtr > pCollExp, CoalescedGeomDataSharedPtr pGeomData, StdRegions::FactorMap factors)
void operator()(int dir, const Array< OneD, const NekDouble > &input, Array< OneD, NekDouble > &output, Array< OneD, NekDouble > &wsp) final
Array< TwoD, const NekDouble > m_derivFac
Phys deriv operator using sum-factorisation (Segment)
Array< TwoD, const NekDouble > m_derivFac
PhysDeriv_SumFac_Seg(vector< LocalRegions::ExpansionSharedPtr > pCollExp, CoalescedGeomDataSharedPtr pGeomData, StdRegions::FactorMap factors)
void operator()(int dir, const Array< OneD, const NekDouble > &input, Array< OneD, NekDouble > &output, Array< OneD, NekDouble > &wsp) final
Phys deriv operator using sum-factorisation (Tet)
void operator()(int dir, const Array< OneD, const NekDouble > &input, Array< OneD, NekDouble > &output, Array< OneD, NekDouble > &wsp) final
Array< TwoD, const NekDouble > m_derivFac
PhysDeriv_SumFac_Tet(vector< LocalRegions::ExpansionSharedPtr > pCollExp, CoalescedGeomDataSharedPtr pGeomData, StdRegions::FactorMap factors)
Phys deriv operator using sum-factorisation (Tri)
void operator()(int dir, const Array< OneD, const NekDouble > &input, Array< OneD, NekDouble > &output, Array< OneD, NekDouble > &wsp) final
Array< TwoD, const NekDouble > m_derivFac
PhysDeriv_SumFac_Tri(vector< LocalRegions::ExpansionSharedPtr > pCollExp, CoalescedGeomDataSharedPtr pGeomData, StdRegions::FactorMap factors)
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
static void Dgemm(const char &transa, const char &transb, const int &m, const int &n, const int &k, const double &alpha, const double *a, const int &lda, const double *b, const int &ldb, const double &beta, double *c, const int &ldc)
BLAS level 3: Matrix-matrix multiply C = A x B where op(A)[m x k], op(B)[k x n], C[m x n] DGEMM perfo...
Definition Blas.hpp:324
std::tuple< LibUtilities::ShapeType, OperatorType, ImplementationType, ExpansionIsNodal > OperatorKey
Key for describing an Operator.
Definition Operator.h:120
std::shared_ptr< CoalescedGeomData > CoalescedGeomDataSharedPtr
OperatorFactory & GetOperatorFactory()
Returns the singleton Operator factory object.
Definition Operator.cpp:44
ConstFactorMap FactorMap
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 Svtvp(int n, const T alpha, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Svtvp (scalar times vector plus vector): z = alpha*x + y.
Definition Vmath.hpp:396
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 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 Zero(int n, T *x, const int incx)
Zero vector.
Definition Vmath.hpp:273
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition Vmath.hpp:825
STL namespace.