Nektar++
ExpListHomogeneous1D.cpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File: ExpListHomogeneous1D.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: An ExpList which is homogeneous in 1-direction
32//
33///////////////////////////////////////////////////////////////////////////////
34
35#include <LibUtilities/Foundations/ManagerAccess.h> // for PointsManager, etc
41
42using namespace std;
43
45{
46// Forward declaration for typedefs
48 : ExpList(type), m_homogeneousBasis(LibUtilities::NullBasisSharedPtr),
49 m_lhom(1), m_homogeneous1DBlockMat(
50 MemoryManager<Homo1DBlockMatrixMap>::AllocateSharedPtr())
51{
52}
53
55 const ExpansionType type,
57 const LibUtilities::BasisKey &HomoBasis, const NekDouble lhom,
58 const bool useFFT, const bool dealiasing)
59 : ExpList(type), m_useFFT(useFFT), m_lhom(lhom),
60 m_homogeneous1DBlockMat(
61 MemoryManager<Homo1DBlockMatrixMap>::AllocateSharedPtr()),
62 m_dealiasing(dealiasing)
63{
64 m_session = pSession;
65 m_comm = pSession->GetComm();
66
68 "Homogeneous Basis is a null basis");
69
71
72 m_StripZcomm = m_session->DefinesSolverInfo("HomoStrip")
73 ? m_comm->GetColumnComm()->GetColumnComm()
74 : m_comm->GetColumnComm();
75
76 ASSERTL0(m_homogeneousBasis->GetNumPoints() % m_StripZcomm->GetSize() == 0,
77 "HomModesZ should be a multiple of npz.");
78
79 if ((m_homogeneousBasis->GetBasisType() !=
81 (m_homogeneousBasis->GetBasisType() !=
83 {
85 (m_homogeneousBasis->GetNumPoints() / m_StripZcomm->GetSize()) %
86 2 ==
87 0,
88 "HomModesZ/npz should be an even integer.");
89 }
90
93 HomoBasis, m_comm, m_StripZcomm);
94
96 m_homogeneousBasis->GetNumPoints() / m_StripZcomm->GetSize());
97
98 if (m_useFFT)
99 {
101 "NekFFTW", m_homogeneousBasis->GetNumPoints());
102 }
103
104 if (m_dealiasing)
105 {
106 if (m_useFFT)
107 {
108 int size = m_homogeneousBasis->GetNumPoints() +
109 m_homogeneousBasis->GetNumPoints() / 2;
110 m_padsize = size + (size % 2);
112 "NekFFTW", m_padsize);
113 }
114 else
115 {
116 ASSERTL0(false, "Dealiasing available just in combination "
117 "with FFTW");
118 }
119 }
120}
121
122/**
123 * @param In ExpListHomogeneous1D object to copy.
124 */
126 : ExpList(In, false), m_transposition(In.m_transposition),
127 m_StripZcomm(In.m_StripZcomm), m_useFFT(In.m_useFFT), m_FFT(In.m_FFT),
128 m_tmpIN(In.m_tmpIN), m_tmpOUT(In.m_tmpOUT),
129 m_homogeneousBasis(In.m_homogeneousBasis), m_lhom(In.m_lhom),
130 m_homogeneous1DBlockMat(In.m_homogeneous1DBlockMat),
131 m_dealiasing(In.m_dealiasing), m_padsize(In.m_padsize)
132{
134}
135
137 const ExpListHomogeneous1D &In, const std::vector<unsigned int> &eIDs,
139 : ExpList(In, eIDs, false, ImpType), m_transposition(In.m_transposition),
140 m_useFFT(In.m_useFFT), m_FFT(In.m_FFT), m_tmpIN(In.m_tmpIN),
141 m_tmpOUT(In.m_tmpOUT), m_homogeneousBasis(In.m_homogeneousBasis),
142 m_lhom(In.m_lhom),
143 m_homogeneous1DBlockMat(
144 MemoryManager<Homo1DBlockMatrixMap>::AllocateSharedPtr()),
145 m_dealiasing(In.m_dealiasing), m_padsize(In.m_padsize)
146{
148}
149
150/**
151 * Destructor
152 */
154{
155}
156
158 const int npts, const Array<OneD, const NekDouble> &inarray,
159 Array<OneD, NekDouble> &outarray, bool Shuff, bool UnShuff)
160{
161 // Forwards trans
162 Homogeneous1DTrans(npts, inarray, outarray, true, Shuff, UnShuff);
163}
164
166 const int npts, const Array<OneD, const NekDouble> &inarray,
167 Array<OneD, NekDouble> &outarray, bool Shuff, bool UnShuff)
168{
169 // Backwards trans
170 Homogeneous1DTrans(npts, inarray, outarray, false, Shuff, UnShuff);
171}
172
173/**
174 * Dealiasing routine
175 *
176 * @param inarray1 First term of the product
177 * @param inarray2 Second term of the product
178 * @param outarray Dealiased product
179 */
181 const int num_dofs, const Array<OneD, NekDouble> &inarray1,
182 const Array<OneD, NekDouble> &inarray2, Array<OneD, NekDouble> &outarray)
183{
184 // int num_dofs = inarray1.size();
185 int N = m_homogeneousBasis->GetNumPoints();
186
187 Array<OneD, NekDouble> V1(num_dofs);
188 Array<OneD, NekDouble> V2(num_dofs);
189 Array<OneD, NekDouble> V1V2(num_dofs);
190
191 if (m_WaveSpace)
192 {
193 V1 = inarray1;
194 V2 = inarray2;
195 }
196 else
197 {
198 HomogeneousFwdTrans(num_dofs, inarray1, V1);
199 HomogeneousFwdTrans(num_dofs, inarray2, V2);
200 }
201
202 int num_points_per_plane = num_dofs / m_planes.size();
203 int num_proc;
204 if (!m_session->DefinesSolverInfo("HomoStrip"))
205 {
206 num_proc = m_comm->GetColumnComm()->GetSize();
207 }
208 else
209 {
210 num_proc = m_StripZcomm->GetSize();
211 }
212 int num_dfts_per_proc =
213 num_points_per_plane / num_proc + (num_points_per_plane % num_proc > 0);
214
215 Array<OneD, NekDouble> ShufV1(num_dfts_per_proc * N, 0.0);
216 Array<OneD, NekDouble> ShufV2(num_dfts_per_proc * N, 0.0);
217 Array<OneD, NekDouble> ShufV1V2(num_dfts_per_proc * N, 0.0);
218
219 Array<OneD, NekDouble> ShufV1_PAD_coef(m_padsize, 0.0);
220 Array<OneD, NekDouble> ShufV2_PAD_coef(m_padsize, 0.0);
221 Array<OneD, NekDouble> ShufV1_PAD_phys(m_padsize, 0.0);
222 Array<OneD, NekDouble> ShufV2_PAD_phys(m_padsize, 0.0);
223
224 Array<OneD, NekDouble> ShufV1V2_PAD_coef(m_padsize, 0.0);
225 Array<OneD, NekDouble> ShufV1V2_PAD_phys(m_padsize, 0.0);
226
227 m_transposition->Transpose(num_dofs, V1, ShufV1, false,
229 m_transposition->Transpose(num_dofs, V2, ShufV2, false,
231
232 // Looping on the pencils
233 for (int i = 0; i < num_dfts_per_proc; i++)
234 {
235 // Copying the i-th pencil pf lenght N into a bigger
236 // pencil of lenght 3/2N We are in Fourier space
237 Vmath::Vcopy(N, &(ShufV1[i * N]), 1, &(ShufV1_PAD_coef[0]), 1);
238 Vmath::Vcopy(N, &(ShufV2[i * N]), 1, &(ShufV2_PAD_coef[0]), 1);
239
240 // Moving to physical space using the padded system
241 m_FFT_deal->FFTBwdTrans(ShufV1_PAD_coef, ShufV1_PAD_phys);
242 m_FFT_deal->FFTBwdTrans(ShufV2_PAD_coef, ShufV2_PAD_phys);
243
244 // Perfroming the vectors multiplication in physical space on
245 // the padded system
246 Vmath::Vmul(m_padsize, ShufV1_PAD_phys, 1, ShufV2_PAD_phys, 1,
247 ShufV1V2_PAD_phys, 1);
248
249 // Moving back the result (V1*V2)_phys in Fourier space, padded
250 // system
251 m_FFT_deal->FFTFwdTrans(ShufV1V2_PAD_phys, ShufV1V2_PAD_coef);
252
253 // Copying the first half of the padded pencil in the full
254 // vector (Fourier space)
255 Vmath::Vcopy(N, &(ShufV1V2_PAD_coef[0]), 1, &(ShufV1V2[i * N]), 1);
256 }
257
258 // Moving the results to the output
259 if (m_WaveSpace)
260 {
261 m_transposition->Transpose(num_dofs, ShufV1V2, outarray, false,
263 }
264 else
265 {
266 m_transposition->Transpose(num_dofs, ShufV1V2, V1V2, false,
268 HomogeneousBwdTrans(num_dofs, V1V2, outarray);
269 }
270}
271
272/**
273 * Dealiasing routine for dot product
274 *
275 * @param inarray1 First term of the product with dimension ndim
276 * (e.g. U)
277 * @param inarray2 Second term of the product with dimension ndim*nvec
278 * (e.g. grad U)
279 * @param outarray Dealiased product with dimension nvec
280 */
282 const int num_dofs, const Array<OneD, Array<OneD, NekDouble>> &inarray1,
283 const Array<OneD, Array<OneD, NekDouble>> &inarray2,
285{
286 int ndim = inarray1.size();
287 ASSERTL1(inarray2.size() % ndim == 0,
288 "Wrong dimensions for DealiasedDotProd.");
289 int nvec = inarray2.size() / ndim;
290
291 // int num_dofs = inarray1[0].size();
292 int N = m_homogeneousBasis->GetNumPoints();
293
294 int num_points_per_plane = num_dofs / m_planes.size();
295 int num_proc;
296 if (!m_session->DefinesSolverInfo("HomoStrip"))
297 {
298 num_proc = m_comm->GetColumnComm()->GetSize();
299 }
300 else
301 {
302 num_proc = m_StripZcomm->GetSize();
303 }
304 int num_dfts_per_proc =
305 num_points_per_plane / num_proc + (num_points_per_plane % num_proc > 0);
306
307 // Get inputs in Fourier space
309 Array<OneD, Array<OneD, NekDouble>> V2(ndim * nvec);
310 if (m_WaveSpace)
311 {
312 for (int i = 0; i < ndim; i++)
313 {
314 V1[i] = inarray1[i];
315 }
316 for (int i = 0; i < ndim * nvec; i++)
317 {
318 V2[i] = inarray2[i];
319 }
320 }
321 else
322 {
323 for (int i = 0; i < ndim; i++)
324 {
325 V1[i] = Array<OneD, NekDouble>(num_dofs);
326 HomogeneousFwdTrans(num_dofs, inarray1[i], V1[i]);
327 }
328 for (int i = 0; i < ndim * nvec; i++)
329 {
330 V2[i] = Array<OneD, NekDouble>(num_dofs);
331 HomogeneousFwdTrans(num_dofs, inarray2[i], V2[i]);
332 }
333 }
334
335 // Allocate variables for ffts
337 Array<OneD, NekDouble> ShufV1_PAD_coef(m_padsize, 0.0);
338 Array<OneD, Array<OneD, NekDouble>> ShufV1_PAD_phys(ndim);
339 for (int i = 0; i < ndim; i++)
340 {
341 ShufV1[i] = Array<OneD, NekDouble>(num_dfts_per_proc * N, 0.0);
342 ShufV1_PAD_phys[i] = Array<OneD, NekDouble>(m_padsize, 0.0);
343 }
344
345 Array<OneD, Array<OneD, NekDouble>> ShufV2(ndim * nvec);
346 Array<OneD, NekDouble> ShufV2_PAD_coef(m_padsize, 0.0);
347 Array<OneD, Array<OneD, NekDouble>> ShufV2_PAD_phys(ndim * nvec);
348 for (int i = 0; i < ndim * nvec; i++)
349 {
350 ShufV2[i] = Array<OneD, NekDouble>(num_dfts_per_proc * N, 0.0);
351 ShufV2_PAD_phys[i] = Array<OneD, NekDouble>(m_padsize, 0.0);
352 }
353
355 Array<OneD, NekDouble> ShufV1V2_PAD_coef(m_padsize, 0.0);
356 Array<OneD, NekDouble> ShufV1V2_PAD_phys(m_padsize, 0.0);
357 for (int i = 0; i < nvec; i++)
358 {
359 ShufV1V2[i] = Array<OneD, NekDouble>(num_dfts_per_proc * N, 0.0);
360 }
361
362 for (int i = 0; i < ndim; i++)
363 {
364 m_transposition->Transpose(num_dofs, V1[i], ShufV1[i], false,
366 }
367 for (int i = 0; i < ndim * nvec; i++)
368 {
369 m_transposition->Transpose(num_dofs, V2[i], ShufV2[i], false,
371 }
372
373 // Looping on the pencils
374 for (int i = 0; i < num_dfts_per_proc; i++)
375 {
376 for (int j = 0; j < ndim; j++)
377 {
378 // Copying the i-th pencil pf lenght N into a bigger
379 // pencil of lenght 1.5N We are in Fourier space
380 Vmath::Vcopy(N, &(ShufV1[j][i * N]), 1, &(ShufV1_PAD_coef[0]), 1);
381 // Moving to physical space using the padded system
382 m_FFT_deal->FFTBwdTrans(ShufV1_PAD_coef, ShufV1_PAD_phys[j]);
383 }
384 for (int j = 0; j < ndim * nvec; j++)
385 {
386 Vmath::Vcopy(N, &(ShufV2[j][i * N]), 1, &(ShufV2_PAD_coef[0]), 1);
387 m_FFT_deal->FFTBwdTrans(ShufV2_PAD_coef, ShufV2_PAD_phys[j]);
388 }
389
390 // Performing the vectors multiplication in physical space on
391 // the padded system
392 for (int j = 0; j < nvec; j++)
393 {
394 Vmath::Zero(m_padsize, ShufV1V2_PAD_phys, 1);
395 for (int k = 0; k < ndim; k++)
396 {
397 Vmath::Vvtvp(m_padsize, ShufV1_PAD_phys[k], 1,
398 ShufV2_PAD_phys[j * ndim + k], 1,
399 ShufV1V2_PAD_phys, 1, ShufV1V2_PAD_phys, 1);
400 }
401 // Moving back the result (V1*V2)_phys in Fourier space,
402 // padded system
403 m_FFT_deal->FFTFwdTrans(ShufV1V2_PAD_phys, ShufV1V2_PAD_coef);
404 // Copying the first half of the padded pencil in the full
405 // vector (Fourier space)
406 Vmath::Vcopy(N, &(ShufV1V2_PAD_coef[0]), 1, &(ShufV1V2[j][i * N]),
407 1);
408 }
409 }
410
411 // Moving the results to the output
412 if (m_WaveSpace)
413 {
414 for (int j = 0; j < nvec; j++)
415 {
416 m_transposition->Transpose(num_dofs, ShufV1V2[j], outarray[j],
417 false, LibUtilities::eZtoXY);
418 }
419 }
420 else
421 {
422 Array<OneD, NekDouble> V1V2(num_dofs);
423 for (int j = 0; j < nvec; j++)
424 {
425 m_transposition->Transpose(num_dofs, ShufV1V2[j], V1V2, false,
427 HomogeneousBwdTrans(num_dofs, V1V2, outarray[j]);
428 }
429 }
430}
431
432/**
433 * Forward transform
434 */
436 const Array<OneD, const NekDouble> &inarray,
437 Array<OneD, NekDouble> &outarray)
438{
439 int cnt = 0, cnt1 = 0;
440 Array<OneD, NekDouble> tmparray;
441
442 for (int n = 0; n < m_planes.size(); ++n)
443 {
444 m_planes[n]->FwdTrans(inarray + cnt, tmparray = outarray + cnt1);
445 cnt += m_planes[n]->GetTotPoints();
446
447 cnt1 += m_planes[n]->GetNcoeffs(); // need to skip ncoeffs
448 }
449 if (!m_WaveSpace)
450 {
451 HomogeneousFwdTrans(cnt1, outarray, outarray);
452 }
453}
454
455/**
456 * Forward transform element by element
457 */
459 const Array<OneD, const NekDouble> &inarray,
460 Array<OneD, NekDouble> &outarray)
461{
462 int cnt = 0, cnt1 = 0;
463 Array<OneD, NekDouble> tmparray;
464
465 // spectral element FwdTrans plane by plane
466 for (int n = 0; n < m_planes.size(); ++n)
467 {
468 m_planes[n]->FwdTransLocalElmt(inarray + cnt,
469 tmparray = outarray + cnt1);
470 cnt += m_planes[n]->GetTotPoints();
471 cnt1 += m_planes[n]->GetNcoeffs();
472 }
473 if (!m_WaveSpace)
474 {
475 HomogeneousFwdTrans(cnt1, outarray, outarray);
476 }
477}
478
479/**
480 * Forward transform element by element with boundaries constrained
481 */
483 const Array<OneD, const NekDouble> &inarray,
484 Array<OneD, NekDouble> &outarray)
485{
486 int cnt = 0, cnt1 = 0;
487 Array<OneD, NekDouble> tmparray;
488
489 // spectral element FwdTrans plane by plane
490 for (int n = 0; n < m_planes.size(); ++n)
491 {
492 m_planes[n]->FwdTransBndConstrained(inarray + cnt,
493 tmparray = outarray + cnt1);
494 cnt += m_planes[n]->GetTotPoints();
495 cnt1 += m_planes[n]->GetNcoeffs();
496 }
497 if (!m_WaveSpace)
498 {
499 HomogeneousFwdTrans(cnt1, outarray, outarray);
500 }
501}
502
503/**
504 * Backward transform
505 */
507 const Array<OneD, const NekDouble> &inarray,
508 Array<OneD, NekDouble> &outarray)
509{
510 int cnt = 0, cnt1 = 0;
511 Array<OneD, NekDouble> tmparray;
512
513 for (int n = 0; n < m_planes.size(); ++n)
514 {
515 m_planes[n]->BwdTrans(inarray + cnt, tmparray = outarray + cnt1);
516 cnt += m_planes[n]->GetNcoeffs();
517 cnt1 += m_planes[n]->GetTotPoints();
518 }
519 if (!m_WaveSpace)
520 {
521 HomogeneousBwdTrans(cnt1, outarray, outarray);
522 }
523}
524
525/**
526 * Inner product
527 */
529 const Array<OneD, const NekDouble> &inarray,
530 Array<OneD, NekDouble> &outarray)
531{
532 ASSERTL1(inarray.size() >= m_npoints,
533 "Inarray is not of sufficient length");
534 int cnt = 0, cnt1 = 0;
535 Array<OneD, NekDouble> tmparray, tmpIn;
536
537 if (m_WaveSpace)
538 {
539 tmpIn = inarray;
540 }
541 else
542 {
543 tmpIn = Array<OneD, NekDouble>(m_npoints, 0.0);
544 HomogeneousFwdTrans(m_npoints, inarray, tmpIn);
545 }
546
547 for (int n = 0; n < m_planes.size(); ++n)
548 {
549 m_planes[n]->IProductWRTBase(tmpIn + cnt, tmparray = outarray + cnt1);
550
551 cnt1 += m_planes[n]->GetNcoeffs();
552 cnt += m_planes[n]->GetTotPoints();
553 }
554}
555
556/**
557 * Inner product with respect to the derivative of the Basis
558 * including one homogeneous direction.
559 *
560 * This function evaluates \f[\int_\Omega \partial_d \phi \mathbf{a}_d\f],
561 * where \f$\partial_d \phi\f$ is the derivative of the basis function
562 * (including a homogeneous basis) in direction \f$d\f$ and \f$\mathbf{a}_d\f$
563 * is the \f$d\f$-th component of a generic vector \f$\mathbf{a}\f$, which is
564 * fourier decomposed into modes of wavenumber \f$k\f$.
565 *
566 * Assuming a 3DH1D basis, the generic vector \f$\mathbf{a}\f$ is defined as
567 * \f[\mathbf{a}=\sum_k\begin{bmatrix}a_x^k(x,y)\\a_y^k(x,y)\\a_z^k(x,y)\end{bmatrix}e^{i
568 * \beta k z}\f].
569 *
570 */
572 const int dir, const Array<OneD, const NekDouble> &inarray,
573 Array<OneD, NekDouble> &outarray)
574{
575 int nT_pts = m_npoints; // number of total points = n. of Fourier
576 // points * n. of points per plane (nT_pts)
577 int nP_pts =
578 nT_pts / m_planes.size(); // number of points per plane = n of
579 // Fourier transform required (nP_pts)
580 int nT_coeffs = m_planes[0]->GetNcoeffs() * m_planes.size();
581 int nP_coeffs = nT_coeffs / m_planes.size();
582
583 Array<OneD, NekDouble> tmpIn(nT_pts);
584 Array<OneD, NekDouble> tmp1, tmp2;
585
586 // Check: input in Fourier space
587 if (m_WaveSpace)
588 {
589 tmpIn = inarray;
590 }
591 else
592 {
593 HomogeneousFwdTrans(m_npoints, inarray, tmpIn);
594 }
595
596 // Do 2D-IProductWRTDerivBase on each plane
597 if (dir == 0 || dir == 1)
598 {
599 for (int i = 0; i < m_planes.size(); i++)
600 {
601 // Call 2D routine on each plane
602 m_planes[i]->IProductWRTDerivBase(dir, tmpIn + i * nP_pts,
603 tmp1 = outarray + i * nP_coeffs);
604 }
605 }
606 // Do homogeneous derivative
607 else if (dir == 2)
608 {
609 if (m_homogeneousBasis->GetBasisType() == LibUtilities::eFourier ||
610 m_homogeneousBasis->GetBasisType() ==
612 m_homogeneousBasis->GetBasisType() ==
614 m_homogeneousBasis->GetBasisType() ==
616 {
617 // TODO Check that nT_coeffs is correct for HalfMode
618 Array<OneD, NekDouble> tmpHom(nT_coeffs, 0.0);
619
620 NekDouble sign = -1.0;
622
623 // Half Modes
624 if (m_homogeneousBasis->GetBasisType() ==
626 {
627 // Do IProduct with 2D basis
628 m_planes[0]->IProductWRTBase(tmpIn, tmpHom);
629
630 // Add fourier coefficient
631 beta = sign * 2 * M_PI * (m_transposition->GetK(0)) / m_lhom;
632 Vmath::Smul(nT_coeffs, beta, tmpHom, 1, tmpHom, 1);
633 }
634 else if (m_homogeneousBasis->GetBasisType() ==
636 {
637 // Do IProduct with 2D basis
638 m_planes[0]->IProductWRTBase(tmpIn, tmpHom);
639
640 // Add fourier coefficient
641 beta = -sign * 2 * M_PI * (m_transposition->GetK(0)) / m_lhom;
642 Vmath::Smul(nT_coeffs, beta, tmpHom, 1, tmpHom, 1);
643 }
644 // Fully complex (Fourier or FourierSingleMode)
645 else
646 {
647 Array<OneD, NekDouble> tmpHomTwo(nT_coeffs, 0.0);
648 for (int i = 0; i < m_planes.size(); i++)
649 {
650 if (i != 1 || m_transposition->GetK(i) !=
651 0) // Mean + Null mode unchanged
652 {
653
654 // Do IProduct with 2D basis ie \int_\Omega \phi_{pq}
655 // inarray[ndim]
656 m_planes[i]->IProductWRTBase(tmpIn + i * nP_pts,
657 tmp1 = tmpHomTwo +
658 i * nP_coeffs);
659
660 // Add fourier coefficient (switch Real and Imaginary
661 // parts ie planes) Multiply by i changes real and
662 // imaginary parts
663 beta = sign * 2 * M_PI * (m_transposition->GetK(i)) /
664 m_lhom;
666 nP_coeffs, beta, tmp1 = tmpHomTwo + i * nP_coeffs,
667 1, tmp2 = tmpHom + (i - int(sign)) * nP_coeffs, 1);
668 }
669 sign = -1.0 * sign;
670 }
671 }
672
673 // Add last term to innerproduct
674 Vmath::Vcopy(nT_coeffs, tmpHom, 1, outarray, 1);
675 }
676 else
677 {
679 "The IProductWRTDerivBase routine with one homogeneous "
680 "direction is not implemented for the homogeneous basis "
681 "if it is is not of type Fourier "
682 "or FourierSingleMode/HalfModeRe/HalfModeIm");
683 }
684 }
685 else
686 {
687 NEKERROR(
689 "cannot handle direction give to IProductWRTDerivBase operator."
690 "dir != 0, 1 or 2.");
691 }
692}
693
694/**
695 * Inner product with respect to the derivative of the Basis
696 * including one homogeneous direction.
697 *
698 * This function evaluates \f[\int_\Omega \nabla \phi \cdot \mathbf{a}\f],
699 * where \f$\phi\f$ are the basis functions (including a homogeneous basis)
700 * and \f$\mathbf{a}\f$ is a generic vector \f$\mathbf{a}\f$, which is fourier
701 * decomposed into modes of wavenumber \f$k\f$.
702 *
703 * Assuming a 3DH1D basis the generic vector \f$\mathbf{a}\f$ is defined as
704 * \f[\mathbf{a}=\sum_k\begin{bmatrix}a_x^k(x,y)\\a_y^k(x,y)\\a_z^k(x,y)\end{bmatrix}e^{i
705 * \beta k z}\f].
706 *
707 */
709 const Array<OneD, const Array<OneD, NekDouble>> &inarray,
710 Array<OneD, NekDouble> &outarray)
711{
712 int ndim = inarray.size(); // Dimension including homogeneous direction
713 // (e.g. 3DH1D, ndim=3D)
714 int nT_coeffs = m_planes[0]->GetNcoeffs() * m_planes.size();
715
716 // Write x-direction into outarray
717 v_IProductWRTDerivBase(0, inarray[0], outarray);
718
719 // Add other directions on top
720 // requires temporary array
721 Array<OneD, NekDouble> tmp(nT_coeffs, 0.0);
722 for (int dir = 1; dir < ndim; dir++)
723 {
724 v_IProductWRTDerivBase(dir, inarray[dir], tmp);
725 Vmath::Vadd(nT_coeffs, tmp, 1, outarray, 1, outarray, 1);
726 }
727}
728
729/**
730 * Homogeneous transform Bwd/Fwd (MVM and FFT)
731 */
733 const int num_dofs, const Array<OneD, const NekDouble> &inarray,
734 Array<OneD, NekDouble> &outarray, bool IsForwards, bool Shuff, bool UnShuff)
735{
736
737 if (m_useFFT)
738 {
739 int num_points_per_plane = num_dofs / m_planes.size();
740 int num_dfts_per_proc;
741 if (!m_session->DefinesSolverInfo("HomoStrip"))
742 {
743 int nP = m_comm->GetColumnComm()->GetSize();
744 num_dfts_per_proc =
745 num_points_per_plane / nP + (num_points_per_plane % nP > 0);
746 }
747 else
748 {
749 int nP = m_StripZcomm->GetSize();
750 num_dfts_per_proc =
751 num_points_per_plane / nP + (num_points_per_plane % nP > 0);
752 }
753
755 num_dfts_per_proc * m_homogeneousBasis->GetNumPoints(), 0.0);
757 num_dfts_per_proc * m_homogeneousBasis->GetNumPoints(), 0.0);
758
759 if (Shuff)
760 {
761 m_transposition->Transpose(num_dofs, inarray, fft_in, false,
763 }
764 else
765 {
766 Vmath::Vcopy(num_dfts_per_proc * m_homogeneousBasis->GetNumPoints(),
767 inarray, 1, fft_in, 1);
768 }
769
770 if (IsForwards)
771 {
772 for (int i = 0; i < num_dfts_per_proc; i++)
773 {
774 m_FFT->FFTFwdTrans(
775 m_tmpIN = fft_in + i * m_homogeneousBasis->GetNumPoints(),
776 m_tmpOUT =
777 fft_out + i * m_homogeneousBasis->GetNumPoints());
778 }
779 }
780 else
781 {
782 for (int i = 0; i < num_dfts_per_proc; i++)
783 {
784 m_FFT->FFTBwdTrans(
785 m_tmpIN = fft_in + i * m_homogeneousBasis->GetNumPoints(),
786 m_tmpOUT =
787 fft_out + i * m_homogeneousBasis->GetNumPoints());
788 }
789 }
790
791 if (UnShuff)
792 {
793 m_transposition->Transpose(num_dofs, fft_out, outarray, false,
795 }
796 else
797 {
798 Vmath::Vcopy(num_dfts_per_proc * m_homogeneousBasis->GetNumPoints(),
799 fft_out, 1, outarray, 1);
800 }
801 }
802 else
803 {
804 DNekBlkMatSharedPtr blkmat;
805
806 if (num_dofs == m_npoints) // transform phys space
807 {
808 if (IsForwards)
809 {
811 }
812 else
813 {
815 }
816 }
817 else
818 {
819 if (IsForwards)
820 {
822 }
823 else
824 {
826 }
827 }
828
829 int nrows = blkmat->GetRows();
830 int ncols = blkmat->GetColumns();
831
832 Array<OneD, NekDouble> sortedinarray(ncols, 0.0);
833 Array<OneD, NekDouble> sortedoutarray(nrows, 0.0);
834
835 if (Shuff)
836 {
837 m_transposition->Transpose(num_dofs, inarray, sortedinarray,
838 !IsForwards, LibUtilities::eXYtoZ);
839 }
840 else
841 {
842 Vmath::Vcopy(ncols, inarray, 1, sortedinarray, 1);
843 }
844
845 // Create NekVectors from the given data arrays
846 NekVector<NekDouble> in(ncols, sortedinarray, eWrapper);
847 NekVector<NekDouble> out(nrows, sortedoutarray, eWrapper);
848
849 // Perform matrix-vector multiply.
850 out = (*blkmat) * in;
851
852 if (UnShuff)
853 {
854 m_transposition->Transpose(num_dofs, sortedoutarray, outarray,
855 IsForwards, LibUtilities::eZtoXY);
856 }
857 else
858 {
859 Vmath::Vcopy(nrows, sortedoutarray, 1, outarray, 1);
860 }
861 }
862}
863
865 Homogeneous1DMatType mattype) const
866{
867 auto matrixIter = m_homogeneous1DBlockMat->find(mattype);
868
869 if (matrixIter == m_homogeneous1DBlockMat->end())
870 {
871 return ((*m_homogeneous1DBlockMat)[mattype] =
873 }
874 else
875 {
876 return matrixIter->second;
877 }
878}
879
881 Homogeneous1DMatType mattype) const
882{
883 DNekMatSharedPtr loc_mat;
884 DNekBlkMatSharedPtr BlkMatrix;
885 int n_exp = 0;
886 int num_trans_per_proc = 0;
887
888 if ((mattype == eForwardsCoeffSpace1D) ||
889 (mattype == eBackwardsCoeffSpace1D)) // will operate on coeffs
890 {
891 n_exp = m_planes[0]->GetNcoeffs();
892 }
893 else
894 {
895 n_exp = m_planes[0]->GetTotPoints(); // will operatore on phys
896 }
897
898 num_trans_per_proc = n_exp / m_comm->GetColumnComm()->GetSize() +
899 (n_exp % m_comm->GetColumnComm()->GetSize() > 0);
900
901 Array<OneD, unsigned int> nrows(num_trans_per_proc);
902 Array<OneD, unsigned int> ncols(num_trans_per_proc);
903
904 if ((mattype == eForwardsCoeffSpace1D) || (mattype == eForwardsPhysSpace1D))
905 {
906 nrows = Array<OneD, unsigned int>(num_trans_per_proc,
907 m_homogeneousBasis->GetNumModes());
908 ncols = Array<OneD, unsigned int>(num_trans_per_proc,
909 m_homogeneousBasis->GetNumPoints());
910 }
911 else
912 {
913 nrows = Array<OneD, unsigned int>(num_trans_per_proc,
914 m_homogeneousBasis->GetNumPoints());
915 ncols = Array<OneD, unsigned int>(num_trans_per_proc,
916 m_homogeneousBasis->GetNumModes());
917 }
918
919 MatrixStorage blkmatStorage = eDIAGONAL;
920 BlkMatrix = MemoryManager<DNekBlkMat>::AllocateSharedPtr(nrows, ncols,
921 blkmatStorage);
922
923 // Half Mode
924 if (m_homogeneousBasis->GetBasisType() ==
927 {
928 StdRegions::StdPointExp StdPoint(m_homogeneousBasis->GetBasisKey());
929
930 if ((mattype == eForwardsCoeffSpace1D) ||
931 (mattype == eForwardsPhysSpace1D))
932 {
934 StdPoint.DetShapeType(), StdPoint);
935
936 loc_mat = StdPoint.GetStdMatrix(matkey);
937 }
938 else
939 {
941 StdPoint.DetShapeType(), StdPoint);
942
943 loc_mat = StdPoint.GetStdMatrix(matkey);
944 }
945 }
946 // other cases
947 else
948 {
949 StdRegions::StdSegExp StdSeg(m_homogeneousBasis->GetBasisKey());
950
951 if ((mattype == eForwardsCoeffSpace1D) ||
952 (mattype == eForwardsPhysSpace1D))
953 {
955 StdSeg.DetShapeType(), StdSeg);
956
957 loc_mat = StdSeg.GetStdMatrix(matkey);
958 }
959 else
960 {
962 StdSeg.DetShapeType(), StdSeg);
963
964 loc_mat = StdSeg.GetStdMatrix(matkey);
965 }
966 }
967
968 // set up array of block matrices.
969 for (int i = 0; i < num_trans_per_proc; ++i)
970 {
971 BlkMatrix->SetBlock(i, i, loc_mat);
972 }
973
974 return BlkMatrix;
975}
976
977std::vector<LibUtilities::FieldDefinitionsSharedPtr> ExpListHomogeneous1D::
979{
980 std::vector<LibUtilities::FieldDefinitionsSharedPtr> returnval;
981
982 // Set up Homogeneous length details.
984
985 std::vector<NekDouble> HomoLen;
986 HomoLen.push_back(m_lhom);
987
988 std::vector<unsigned int> StripsIDs;
989
990 bool strips;
991 m_session->MatchSolverInfo("HomoStrip", "True", strips, false);
992 if (strips)
993 {
994 StripsIDs.push_back(m_transposition->GetStripID());
995 }
996
997 std::vector<unsigned int> PlanesIDs;
998 int IDoffset = 0;
999
1000 // introduce a 2 plane offset for single mode case so can
1001 // be post-processed or used in MultiMode expansion.
1003 {
1004 IDoffset = 2;
1005 }
1006
1007 for (int i = 0; i < m_planes.size(); i++)
1008 {
1009 PlanesIDs.push_back(m_transposition->GetPlaneID(i) + IDoffset);
1010 }
1011
1012 m_planes[0]->GeneralGetFieldDefinitions(returnval, 1, HomoBasis, HomoLen,
1013 strips, StripsIDs, PlanesIDs);
1014 return returnval;
1015}
1016
1018 std::vector<LibUtilities::FieldDefinitionsSharedPtr> &fielddef)
1019{
1020 // Set up Homogeneous length details.
1022
1023 std::vector<NekDouble> HomoLen;
1024 HomoLen.push_back(m_lhom);
1025
1026 std::vector<unsigned int> StripsIDs;
1027
1028 bool strips;
1029 m_session->MatchSolverInfo("HomoStrip", "True", strips, false);
1030 if (strips)
1031 {
1032 StripsIDs.push_back(m_transposition->GetStripID());
1033 }
1034
1035 std::vector<unsigned int> PlanesIDs;
1036 int IDoffset = 0;
1037
1039 {
1040 IDoffset = 2;
1041 }
1042
1043 for (int i = 0; i < m_planes.size(); i++)
1044 {
1045 PlanesIDs.push_back(m_transposition->GetPlaneID(i) + IDoffset);
1046 }
1047
1048 // enforce NumHomoDir == 1 by direct call
1049 m_planes[0]->GeneralGetFieldDefinitions(fielddef, 1, HomoBasis, HomoLen,
1050 strips, StripsIDs, PlanesIDs);
1051}
1052
1053/** This routine appends the data from the expansion list into
1054 the output format where each element is given by looping
1055 over its Fourier modes where as data in the expandion is
1056 stored with all consecutive elements and then the Fourier
1057 modes
1058 */
1061 std::vector<NekDouble> &fielddata, Array<OneD, NekDouble> &coeffs)
1062{
1063 int i, n;
1064 int ncoeffs_per_plane = m_planes[0]->GetNcoeffs();
1065
1066 // Determine mapping from element ids to location in
1067 // expansion list
1068 if (m_elmtToExpId.size() == 0)
1069 {
1070 for (i = 0; i < m_planes[0]->GetExpSize(); ++i)
1071 {
1072 m_elmtToExpId[(*m_exp)[i]->GetGeom()->GetGlobalID()] = i;
1073 }
1074 }
1075
1076 for (i = 0; i < fielddef->m_elementIDs.size(); ++i)
1077 {
1078 int eid = m_elmtToExpId[fielddef->m_elementIDs[i]];
1079 int datalen = (*m_exp)[eid]->GetNcoeffs();
1080
1081 for (n = 0; n < m_planes.size(); ++n)
1082 {
1083 fielddata.insert(
1084 fielddata.end(),
1085 &coeffs[m_coeff_offset[eid] + n * ncoeffs_per_plane],
1086 &coeffs[m_coeff_offset[eid] + n * ncoeffs_per_plane] + datalen);
1087 }
1088 }
1089}
1090
1093 std::vector<NekDouble> &fielddata)
1094{
1095 v_AppendFieldData(fielddef, fielddata, m_coeffs);
1096}
1097
1098// Extract the data in fielddata into the m_coeff list
1101 std::vector<NekDouble> &fielddata, std::string &field,
1102 Array<OneD, NekDouble> &coeffs, std::unordered_map<int, int> zIdToPlane)
1103{
1104 int i, n;
1105 int offset = 0;
1106 int nzmodes = 1;
1107 int datalen = fielddata.size() / fielddef->m_fields.size();
1108 std::vector<unsigned int> fieldDefHomoZids;
1109
1110 // Find data location according to field definition
1111 for (i = 0; i < fielddef->m_fields.size(); ++i)
1112 {
1113 if (fielddef->m_fields[i] == field)
1114 {
1115 break;
1116 }
1117 offset += datalen;
1118 }
1119
1120 if (i == fielddef->m_fields.size())
1121 {
1122 cout << "Field " << field << "not found in data file. " << endl;
1123 }
1124 else
1125 {
1126
1127 int modes_offset = 0;
1128 int planes_offset = 0;
1129 Array<OneD, NekDouble> coeff_tmp;
1130
1131 // Build map of plane IDs lying on this processor and determine
1132 // mapping from element ids to location in expansion list.
1133 if (zIdToPlane.size() == 0)
1134 {
1135 int IDoffset = m_homogeneousBasis->GetBasisType() ==
1137 ? 2
1138 : 0;
1139 for (i = 0; i < m_planes.size(); ++i)
1140 {
1141 zIdToPlane[m_transposition->GetPlaneID(i) + IDoffset] = i;
1142 }
1143 }
1144
1145 if (m_elmtToExpId.size() == 0)
1146 {
1147 for (i = 0; i < m_planes[0]->GetExpSize(); ++i)
1148 {
1149 m_elmtToExpId[(*m_exp)[i]->GetGeom()->GetGlobalID()] = i;
1150 }
1151 }
1152
1153 if (fielddef->m_numHomogeneousDir)
1154 {
1155 nzmodes = fielddef->m_homogeneousZIDs.size();
1156 fieldDefHomoZids = fielddef->m_homogeneousZIDs;
1157 }
1158 else // input file is 2D and so set nzmodes to 1
1159 {
1160 nzmodes = 1;
1161 fieldDefHomoZids.push_back(0);
1162 }
1163
1164 // calculate number of modes in the current partition
1165 int ncoeffs_per_plane = m_planes[0]->GetNcoeffs();
1166
1167 for (i = 0; i < fielddef->m_elementIDs.size(); ++i)
1168 {
1169 if (fielddef->m_uniOrder == true) // reset modes_offset to zero
1170 {
1171 modes_offset = 0;
1172 }
1173
1175 fielddef->m_shapeType, fielddef->m_numModes, modes_offset);
1176
1177 auto it = m_elmtToExpId.find(fielddef->m_elementIDs[i]);
1178
1179 // ensure element is on this partition for parallel case.
1180 if (it == m_elmtToExpId.end())
1181 {
1182 // increase offset for correct FieldData access
1183 offset += datalen * nzmodes;
1184 modes_offset +=
1185 (*m_exp)[0]->GetNumBases() + fielddef->m_numHomogeneousDir;
1186 continue;
1187 }
1188
1189 int eid = it->second;
1190 bool sameBasis = true;
1191 for (int j = 0; j < fielddef->m_basis.size() - 1; ++j)
1192 {
1193 if (fielddef->m_basis[j] != (*m_exp)[eid]->GetBasisType(j))
1194 {
1195 sameBasis = false;
1196 break;
1197 }
1198 }
1199
1200 for (n = 0; n < nzmodes; ++n, offset += datalen)
1201 {
1202
1203 it = zIdToPlane.find(fieldDefHomoZids[n]);
1204
1205 // Check to make sure this mode number lies in this field.
1206 if (it == zIdToPlane.end())
1207 {
1208 continue;
1209 }
1210
1211 planes_offset = it->second;
1212 if (datalen == (*m_exp)[eid]->GetNcoeffs() && sameBasis)
1213 {
1214 Vmath::Vcopy(datalen, &fielddata[offset], 1,
1215 &coeffs[m_coeff_offset[eid] +
1216 planes_offset * ncoeffs_per_plane],
1217 1);
1218 }
1219 else // unpack data to new order
1220 {
1221 (*m_exp)[eid]->ExtractDataToCoeffs(
1222 &fielddata[offset], fielddef->m_numModes, modes_offset,
1223 &coeffs[m_coeff_offset[eid] +
1224 planes_offset * ncoeffs_per_plane],
1225 fielddef->m_basis);
1226 }
1227 }
1228 modes_offset +=
1229 (*m_exp)[0]->GetNumBases() + fielddef->m_numHomogeneousDir;
1230 }
1231 }
1232}
1233
1234// Extract the data in fielddata into the m_coeff list
1236 const std::shared_ptr<ExpList> &fromExpList,
1237 const Array<OneD, const NekDouble> &fromCoeffs,
1238 Array<OneD, NekDouble> &toCoeffs)
1239{
1240 int i;
1241 int fromNcoeffs_per_plane = fromExpList->GetPlane(0)->GetNcoeffs();
1242 int toNcoeffs_per_plane = m_planes[0]->GetNcoeffs();
1243 Array<OneD, NekDouble> tocoeffs_tmp, fromcoeffs_tmp;
1244
1245 for (i = 0; i < m_planes.size(); ++i)
1246 {
1247 m_planes[i]->ExtractCoeffsToCoeffs(
1248 fromExpList->GetPlane(i),
1249 fromcoeffs_tmp = fromCoeffs + fromNcoeffs_per_plane * i,
1250 tocoeffs_tmp = toCoeffs + toNcoeffs_per_plane * i);
1251 }
1252}
1253
1255 int expansion, std::string var)
1256{
1257 // If there is only one plane (e.g. HalfMode), we write a 2D plane.
1258 if (m_planes.size() == 1)
1259 {
1260 m_planes[0]->WriteVtkPieceData(outfile, expansion, var);
1261 return;
1262 }
1263
1264 int i;
1265 int nq = (*m_exp)[expansion]->GetTotPoints();
1266 int npoints_per_plane = m_planes[0]->GetTotPoints();
1267
1268 // If we are using Fourier points, output extra plane to fill domain
1269 int outputExtraPlane = 0;
1270 Array<OneD, NekDouble> extraPlane;
1271 if (m_homogeneousBasis->GetBasisType() == LibUtilities::eFourier &&
1272 m_homogeneousBasis->GetPointsType() ==
1274 {
1275 outputExtraPlane = 1;
1276 // Get extra plane data
1277 if (m_StripZcomm->GetSize() == 1)
1278 {
1279 extraPlane = m_phys + m_phys_offset[expansion];
1280 }
1281 else
1282 {
1283 // Determine to and from rank for communication
1284 int size = m_StripZcomm->GetSize();
1285 int rank = m_StripZcomm->GetRank();
1286 int fromRank = (rank + 1) % size;
1287 int toRank = (rank == 0) ? size - 1 : rank - 1;
1288 // Communicate using SendRecv
1289 extraPlane = Array<OneD, NekDouble>(nq);
1290 Array<OneD, NekDouble> send(nq, m_phys + m_phys_offset[expansion]);
1291
1292 m_StripZcomm->SendRecv(toRank, send, fromRank, extraPlane);
1293 }
1294 }
1295
1296 // printing the fields of that zone
1297 outfile << R"( <DataArray type="Float64" Name=")" << var << "\">"
1298 << endl;
1299 outfile << " ";
1300 for (int n = 0; n < m_planes.size(); ++n)
1301 {
1302 const Array<OneD, NekDouble> phys =
1303 m_phys + m_phys_offset[expansion] + n * npoints_per_plane;
1304
1305 for (i = 0; i < nq; ++i)
1306 {
1307 outfile << (fabs(phys[i]) < NekConstants::kNekZeroTol ? 0 : phys[i])
1308 << " ";
1309 }
1310 }
1311 if (outputExtraPlane)
1312 {
1313 for (i = 0; i < nq; ++i)
1314 {
1315 outfile << (fabs(extraPlane[i]) < NekConstants::kNekZeroTol
1316 ? 0
1317 : extraPlane[i])
1318 << " ";
1319 }
1320 }
1321 outfile << endl;
1322 outfile << " </DataArray>" << endl;
1323}
1324
1326 const NekDouble scale, const Array<OneD, NekDouble> &inarray,
1327 Array<OneD, NekDouble> &outarray)
1328{
1329 int cnt, cnt1;
1330 Array<OneD, NekDouble> tmparray;
1331 cnt = m_planes[0]->GetTotPoints();
1332 cnt1 = m_planes[0]->Get1DScaledTotPoints(scale);
1333
1334 ASSERTL1(m_planes.size() * cnt1 <= outarray.size(),
1335 "size of outarray does not match internal estimage");
1336
1337 for (int i = 0; i < m_planes.size(); i++)
1338 {
1339
1340 m_planes[i]->PhysInterp1DScaled(scale, inarray + i * cnt,
1341 tmparray = outarray + i * cnt1);
1342 }
1343}
1344
1346 const NekDouble scale, const Array<OneD, NekDouble> &inarray,
1347 Array<OneD, NekDouble> &outarray)
1348{
1349 int cnt, cnt1;
1350 Array<OneD, NekDouble> tmparray;
1351 cnt = m_planes[0]->Get1DScaledTotPoints(scale);
1352 cnt1 = m_planes[0]->GetTotPoints();
1353 ASSERTL1(m_planes.size() * cnt <= inarray.size(),
1354 "size of outarray does not match internal estimage");
1355
1356 for (int i = 0; i < m_planes.size(); i++)
1357 {
1358 m_planes[i]->PhysGalerkinProjection1DScaled(
1359 scale, inarray + i * cnt, tmparray = outarray + i * cnt1);
1360 }
1361}
1365{
1366 int nT_pts = m_npoints; // number of total points = n. of
1367 // Fourier points * n. of points per plane (nT_pts)
1368 int nP_pts =
1369 nT_pts / m_planes.size(); // number of points per plane = n of
1370 // Fourier transform required (nP_pts)
1371
1372 Array<OneD, NekDouble> temparray(nT_pts);
1373 Array<OneD, NekDouble> outarray(nT_pts);
1377
1378 for (int i = 0; i < m_planes.size(); i++)
1379 {
1380 m_planes[i]->PhysDeriv(inarray + i * nP_pts, tmp2 = out_d0 + i * nP_pts,
1381 tmp3 = out_d1 + i * nP_pts);
1382 }
1383
1384 if (out_d2 != NullNekDouble1DArray)
1385 {
1386 if (m_homogeneousBasis->GetBasisType() == LibUtilities::eFourier ||
1387 m_homogeneousBasis->GetBasisType() ==
1389 m_homogeneousBasis->GetBasisType() ==
1391 m_homogeneousBasis->GetBasisType() ==
1393 {
1394 if (m_WaveSpace)
1395 {
1396 temparray = inarray;
1397 }
1398 else
1399 {
1400 HomogeneousFwdTrans(nT_pts, inarray, temparray);
1401 }
1402
1403 NekDouble sign = -1.0;
1405
1406 // Half Mode
1407 if (m_homogeneousBasis->GetBasisType() ==
1409 {
1410 beta = sign * 2 * M_PI * (m_transposition->GetK(0)) / m_lhom;
1411
1412 Vmath::Smul(nP_pts, beta, temparray, 1, outarray, 1);
1413 }
1414 else if (m_homogeneousBasis->GetBasisType() ==
1416 {
1417 beta = -sign * 2 * M_PI * (m_transposition->GetK(0)) / m_lhom;
1418
1419 Vmath::Smul(nP_pts, beta, temparray, 1, outarray, 1);
1420 }
1421
1422 // Fully complex
1423 else
1424 {
1425 for (int i = 0; i < m_planes.size(); i++)
1426 {
1427 beta =
1428 -sign * 2 * M_PI * (m_transposition->GetK(i)) / m_lhom;
1429
1430 Vmath::Smul(nP_pts, beta, tmp1 = temparray + i * nP_pts, 1,
1431 tmp2 = outarray + (i - int(sign)) * nP_pts, 1);
1432
1433 sign = -1.0 * sign;
1434 }
1435 }
1436
1437 if (m_WaveSpace)
1438 {
1439 out_d2 = outarray;
1440 }
1441 else
1442 {
1443 HomogeneousBwdTrans(nT_pts, outarray, out_d2);
1444 }
1445 }
1446 else
1447 {
1448 if (!m_session->DefinesSolverInfo("HomoStrip"))
1449 {
1450 ASSERTL0(m_comm->GetColumnComm()->GetSize() == 1,
1451 "Parallelisation in the homogeneous direction "
1452 "implemented just for Fourier basis");
1453 }
1454 else
1455 {
1456 ASSERTL0(m_StripZcomm->GetSize() == 1,
1457 "Parallelisation in the homogeneous direction "
1458 "implemented just for Fourier basis");
1459 }
1460
1461 if (m_WaveSpace)
1462 {
1463 ASSERTL0(false, "Semi-phyisical time-stepping not "
1464 "implemented yet for non-Fourier "
1465 "basis");
1466 }
1467 else
1468 {
1469 StdRegions::StdSegExp StdSeg(m_homogeneousBasis->GetBasisKey());
1470
1471 m_transposition->Transpose(nT_pts, inarray, temparray, false,
1473
1474 for (int i = 0; i < nP_pts; i++)
1475 {
1476 StdSeg.PhysDeriv(temparray + i * m_planes.size(),
1477 tmp2 = outarray + i * m_planes.size());
1478 }
1479
1480 m_transposition->Transpose(nT_pts, outarray, out_d2, false,
1482
1483 Vmath::Smul(nT_pts, 2.0 / m_lhom, out_d2, 1, out_d2, 1);
1484 }
1485 }
1486 }
1487}
1488
1490 Direction edir, const Array<OneD, const NekDouble> &inarray,
1492
1493{
1494 int nT_pts = m_npoints; // number of total points = n. of Fourier
1495 // points * n. of points per plane (nT_pts)
1496 int nP_pts =
1497 nT_pts / m_planes.size(); // number of points per plane = n of
1498 // Fourier transform required (nP_pts)
1499
1500 int dir = (int)edir;
1501
1502 Array<OneD, NekDouble> temparray(nT_pts);
1503 Array<OneD, NekDouble> outarray(nT_pts);
1506
1507 if (dir < 2)
1508 {
1509 for (int i = 0; i < m_planes.size(); i++)
1510 {
1511 m_planes[i]->PhysDeriv(edir, inarray + i * nP_pts,
1512 tmp2 = out_d + i * nP_pts);
1513 }
1514 }
1515 else
1516 {
1517 if (m_homogeneousBasis->GetBasisType() == LibUtilities::eFourier ||
1518 m_homogeneousBasis->GetBasisType() ==
1520 m_homogeneousBasis->GetBasisType() ==
1522 m_homogeneousBasis->GetBasisType() ==
1524 {
1525 if (m_WaveSpace)
1526 {
1527 temparray = inarray;
1528 }
1529 else
1530 {
1531 HomogeneousFwdTrans(nT_pts, inarray, temparray);
1532 }
1533
1534 NekDouble sign = -1.0;
1536
1537 // HalfMode
1538 if (m_homogeneousBasis->GetBasisType() ==
1540 {
1541 beta = 2 * sign * M_PI * (m_transposition->GetK(0)) / m_lhom;
1542
1543 Vmath::Smul(nP_pts, beta, temparray, 1, outarray, 1);
1544 }
1545 else if (m_homogeneousBasis->GetBasisType() ==
1547 {
1548 beta = -2 * sign * M_PI * (m_transposition->GetK(0)) / m_lhom;
1549
1550 Vmath::Smul(nP_pts, beta, temparray, 1, outarray, 1);
1551 }
1552 // Fully complex
1553 else
1554 {
1555 for (int i = 0; i < m_planes.size(); i++)
1556 {
1557 beta =
1558 -sign * 2 * M_PI * (m_transposition->GetK(i)) / m_lhom;
1559
1560 Vmath::Smul(nP_pts, beta, tmp1 = temparray + i * nP_pts, 1,
1561 tmp2 = outarray + (i - int(sign)) * nP_pts, 1);
1562
1563 sign = -1.0 * sign;
1564 }
1565 }
1566 if (m_WaveSpace)
1567 {
1568 out_d = outarray;
1569 }
1570 else
1571 {
1572 HomogeneousBwdTrans(nT_pts, outarray, out_d);
1573 }
1574 }
1575 else
1576 {
1577 if (!m_session->DefinesSolverInfo("HomoStrip"))
1578 {
1579 ASSERTL0(m_comm->GetColumnComm()->GetSize() == 1,
1580 "Parallelisation in the homogeneous direction "
1581 "implemented just for Fourier basis");
1582 }
1583 else
1584 {
1585 ASSERTL0(m_StripZcomm->GetSize() == 1,
1586 "Parallelisation in the homogeneous direction "
1587 "implemented just for Fourier basis");
1588 }
1589
1590 if (m_WaveSpace)
1591 {
1592 ASSERTL0(false, "Semi-phyisical time-stepping not implemented "
1593 "yet for non-Fourier basis");
1594 }
1595 else
1596 {
1597 StdRegions::StdSegExp StdSeg(m_homogeneousBasis->GetBasisKey());
1598
1599 m_transposition->Transpose(nT_pts, inarray, temparray, false,
1601
1602 for (int i = 0; i < nP_pts; i++)
1603 {
1604 StdSeg.PhysDeriv(temparray + i * m_planes.size(),
1605 tmp2 = outarray + i * m_planes.size());
1606 }
1607
1608 m_transposition->Transpose(nT_pts, outarray, out_d, false,
1610
1611 Vmath::Smul(nT_pts, 2.0 / m_lhom, out_d, 1, out_d, 1);
1612 }
1613 }
1614 }
1615}
1616
1620
1621{
1622 v_PhysDeriv(inarray, out_d0, out_d1, out_d2);
1623}
1624
1626 Direction edir, const Array<OneD, const NekDouble> &inarray,
1628{
1629 v_PhysDeriv(edir, inarray, out_d);
1630}
1631
1633 void)
1634{
1635 return m_transposition;
1636}
1637
1639{
1640 return m_lhom;
1641}
1642
1644{
1645 m_lhom = lhom;
1646}
1647
1649{
1650 return m_transposition->GetPlanesIDs();
1651}
1652
1654 const Array<OneD, const NekDouble> &inarray)
1655{
1656 NekDouble val = 0.0;
1657 int i = 0;
1658
1659 for (i = 0; i < (*m_exp).size(); ++i)
1660 {
1661 val += (*m_exp)[i]->Integral(inarray + m_phys_offset[i]);
1662 }
1663 val *= m_lhom / m_homogeneousBasis->GetNumModes();
1664
1665 m_comm->GetSpaceComm()->AllReduce(val, LibUtilities::ReduceSum);
1666
1667 return val;
1668}
1669} // namespace Nektar::MultiRegions
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:208
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mode...
Definition: ErrorUtil.hpp:202
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
Definition: ErrorUtil.hpp:242
#define ASSERTL2(condition, msg)
Assert Level 2 – Debugging which is used FULLDEBUG compilation mode. This level assert is designed to...
Definition: ErrorUtil.hpp:265
#define sign(a, b)
return the sign(b)*a
Definition: Polylib.cpp:47
Describes the specification for a Basis.
Definition: Basis.h:45
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
General purpose memory allocation routines with the ability to allocate from thread specific memory p...
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
Abstraction of a two-dimensional multi-elemental expansion which is merely a collection of local expa...
void PhysDeriv(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &out_d0, Array< OneD, NekDouble > &out_d1, Array< OneD, NekDouble > &out_d2)
std::vector< LibUtilities::FieldDefinitionsSharedPtr > v_GetFieldDefinitions(void) override
void v_BwdTrans(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
LibUtilities::TranspositionSharedPtr v_GetTransposition(void) override
NekDouble m_lhom
Width of homogeneous direction.
LibUtilities::TranspositionSharedPtr m_transposition
void v_ExtractDataToCoeffs(LibUtilities::FieldDefinitionsSharedPtr &fielddef, std::vector< NekDouble > &fielddata, std::string &field, Array< OneD, NekDouble > &coeffs, std::unordered_map< int, int > zIdToPlane) override
Extract data from raw field data into expansion list.
void v_WriteVtkPieceData(std::ostream &outfile, int expansion, std::string var) override
void v_DealiasedDotProd(const int num_dofs, const Array< OneD, Array< OneD, NekDouble > > &inarray1, const Array< OneD, Array< OneD, NekDouble > > &inarray2, Array< OneD, Array< OneD, NekDouble > > &outarray) override
void v_FwdTransLocalElmt(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
Array< OneD, ExpListSharedPtr > m_planes
void v_FwdTrans(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
void v_AppendFieldData(LibUtilities::FieldDefinitionsSharedPtr &fielddef, std::vector< NekDouble > &fielddata) override
void v_FwdTransBndConstrained(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
LibUtilities::BasisSharedPtr m_homogeneousBasis
Definition of the total number of degrees of freedom and quadrature points. Sets up the storage for m...
void v_PhysGalerkinProjection1DScaled(const NekDouble scale, const Array< OneD, NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
LibUtilities::NektarFFTSharedPtr m_FFT_deal
void v_HomogeneousFwdTrans(const int npts, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, bool Shuff=true, bool UnShuff=true) override
void v_ExtractCoeffsToCoeffs(const std::shared_ptr< ExpList > &fromExpList, const Array< OneD, const NekDouble > &fromCoeffs, Array< OneD, NekDouble > &toCoeffs) override
NekDouble v_Integral(const Array< OneD, const NekDouble > &inarray) override
void v_PhysDeriv(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &out_d0, Array< OneD, NekDouble > &out_d1, Array< OneD, NekDouble > &out_d2) override
void v_IProductWRTBase(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
LibUtilities::NektarFFTSharedPtr m_FFT
void Homogeneous1DTrans(const int npts, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, bool IsForwards, bool Shuff=true, bool UnShuff=true)
void v_HomogeneousBwdTrans(const int npts, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, bool Shuff=true, bool UnShuff=true) override
void v_SetHomoLen(const NekDouble lhom) override
DNekBlkMatSharedPtr GenHomogeneous1DBlockMatrix(Homogeneous1DMatType mattype) const
DNekBlkMatSharedPtr GetHomogeneous1DBlockMatrix(Homogeneous1DMatType mattype) const
Array< OneD, const unsigned int > v_GetZIDs(void) override
void v_DealiasedProd(const int num_dofs, const Array< OneD, NekDouble > &inarray1, const Array< OneD, NekDouble > &inarray2, Array< OneD, NekDouble > &outarray) override
void v_IProductWRTDerivBase(const int dir, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
void v_PhysInterp1DScaled(const NekDouble scale, const Array< OneD, NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
ExpListHomogeneous1D(const ExpansionType type)
Default constructor.
Base class for all multi-elemental spectral/hp expansions.
Definition: ExpList.h:99
Array< OneD, NekDouble > m_coeffs
Concatenation of all local expansion coefficients.
Definition: ExpList.h:1083
int GetNcoeffs(void) const
Returns the total number of local degrees of freedom .
Definition: ExpList.h:1512
Array< OneD, int > m_coeff_offset
Offset of elemental data into the array m_coeffs.
Definition: ExpList.h:1123
LibUtilities::CommSharedPtr m_comm
Communicator.
Definition: ExpList.h:1056
std::shared_ptr< LocalRegions::ExpansionVector > m_exp
The list of local expansions.
Definition: ExpList.h:1118
void HomogeneousBwdTrans(const int npts, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, bool Shuff=true, bool UnShuff=true)
Definition: ExpList.h:1849
std::unordered_map< int, int > m_elmtToExpId
Mapping from geometry ID of element to index inside m_exp.
Definition: ExpList.h:1135
LibUtilities::SessionReaderSharedPtr m_session
Session.
Definition: ExpList.h:1058
Array< OneD, int > m_phys_offset
Offset of elemental data into the array m_phys.
Definition: ExpList.h:1125
Array< OneD, NekDouble > m_phys
The global expansion evaluated at the quadrature points.
Definition: ExpList.h:1099
void HomogeneousFwdTrans(const int npts, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, bool Shuff=true, bool UnShuff=true)
Definition: ExpList.h:1840
DNekMatSharedPtr GetStdMatrix(const StdMatrixKey &mkey)
Definition: StdExpansion.h:603
LibUtilities::ShapeType DetShapeType() const
This function returns the shape of the expansion domain.
Definition: StdExpansion.h:367
void PhysDeriv(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &out_d0, Array< OneD, NekDouble > &out_d1=NullNekDouble1DArray, Array< OneD, NekDouble > &out_d2=NullNekDouble1DArray)
Definition: StdExpansion.h:849
Class representing a segment element in reference space All interface of this class sits in StdExpans...
Definition: StdSegExp.h:45
static BasisSharedPtr NullBasisSharedPtr
Definition: Basis.h:350
BasisManagerT & BasisManager(void)
NektarFFTFactory & GetNektarFFTFactory()
Definition: NektarFFT.cpp:65
static const BasisKey NullBasisKey(eNoBasisType, 0, NullPointsKey)
Defines a null basis with no type or points.
std::shared_ptr< SessionReader > SessionReaderSharedPtr
std::shared_ptr< FieldDefinitions > FieldDefinitionsSharedPtr
Definition: FieldIO.h:184
int GetNumberOfCoefficients(ShapeType shape, std::vector< unsigned int > &modes, int offset=0)
Definition: ShapeType.hpp:305
std::shared_ptr< Transposition > TranspositionSharedPtr
@ beta
Gauss Radau pinned at x=-1,.
Definition: PointsType.h:59
@ eFourierEvenlySpaced
1D Evenly-spaced points using Fourier Fit
Definition: PointsType.h:74
@ eFourierSingleMode
Fourier ModifiedExpansion with just the first mode .
Definition: BasisType.h:64
@ eFourierHalfModeIm
Fourier Modified expansions with just the imaginary part of the first mode .
Definition: BasisType.h:68
@ eFourierHalfModeRe
Fourier Modified expansions with just the real part of the first mode .
Definition: BasisType.h:66
@ eFourier
Fourier Expansion .
Definition: BasisType.h:55
std::map< Homogeneous1DMatType, DNekBlkMatSharedPtr > Homo1DBlockMatrixMap
A map between homo matrix keys and their associated block matrices.
static const NekDouble kNekZeroTol
std::shared_ptr< DNekBlkMat > DNekBlkMatSharedPtr
Definition: NekTypeDefs.hpp:77
static Array< OneD, NekDouble > NullNekDouble1DArray
std::shared_ptr< DNekMat > DNekMatSharedPtr
Definition: NekTypeDefs.hpp:75
double NekDouble
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 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 Vadd(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Add vector z = x+y.
Definition: Vmath.hpp:180
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.