Nektar++
ExpList.cpp
Go to the documentation of this file.
1//////////////////////////////////////////////////////////////////////////////
2//
3// File: ExpList.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: Expansion list definition
32//
33///////////////////////////////////////////////////////////////////////////////
34
40#include <LibUtilities/Foundations/ManagerAccess.h> // for PointsManager, etc
47#include <LocalRegions/HexExp.h>
48#include <LocalRegions/MatrixKey.h> // for MatrixKey
52#include <LocalRegions/PyrExp.h>
54#include <LocalRegions/SegExp.h>
55#include <LocalRegions/TetExp.h>
56#include <LocalRegions/TriExp.h>
57#include <MultiRegions/AssemblyMap/AssemblyMapCG.h> // for AssemblyMapCG, etc
58#include <MultiRegions/AssemblyMap/AssemblyMapDG.h> // for AssemblyMapCG, etc
61#include <MultiRegions/GlobalLinSysKey.h> // for GlobalLinSysKey
62#include <MultiRegions/GlobalMatrix.h> // for GlobalMatrix, etc
63#include <MultiRegions/GlobalMatrixKey.h> // for GlobalMatrixKey
64#include <iomanip>
65
66using namespace std;
67
69{
70/**
71 * @class ExpList
72 * All multi-elemental expansions \f$u^{\delta}(\boldsymbol{x})\f$ can
73 * be considered as the assembly of the various elemental contributions.
74 * On a discrete level, this yields,
75 * \f[u^{\delta}(\boldsymbol{x}_i)=\sum_{e=1}^{{N_{\mathrm{el}}}}
76 * \sum_{n=0}^{N^{e}_m-1}\hat{u}_n^e\phi_n^e(\boldsymbol{x}_i).\f]
77 * where \f${N_{\mathrm{el}}}\f$ is the number of elements and
78 * \f$N^{e}_m\f$ is the local elemental number of expansion modes.
79 * As it is the lowest level class, it contains the definition of the
80 * common data and common routines to all multi-elemental expansions.
81 *
82 * The class stores a vector of expansions, \a m_exp, (each derived from
83 * StdRegions#StdExpansion) which define the constituent components of
84 * the domain.
85 */
86
87/**
88 * Creates an empty expansion list.
89 */
91 : m_expType(type), m_ncoeffs(0), m_npoints(0), m_physState(false),
92 m_exp(MemoryManager<LocalRegions::ExpansionVector>::AllocateSharedPtr()),
93 m_blockMat(MemoryManager<BlockMatrixMap>::AllocateSharedPtr()),
94 m_WaveSpace(false)
95{
96}
97
98/*----------------------------------------------------------------*/
99/* Copy Construtor */
100/*-----------------------------------------------------------------*/
101
102/**
103 * Copies an existing expansion list.
104 * @param in Source expansion list.
105 */
106ExpList::ExpList(const ExpList &in, const bool DeclareCoeffPhysArrays)
107 : std::enable_shared_from_this<ExpList>(in), m_expType(in.m_expType),
108
109 m_comm(in.m_comm), m_session(in.m_session), m_graph(in.m_graph),
110 m_ncoeffs(in.m_ncoeffs), m_npoints(in.m_npoints), m_physState(false),
111 m_exp(in.m_exp), m_collections(in.m_collections),
112 m_collectionsDoInit(in.m_collectionsDoInit),
113 m_coll_coeff_offset(in.m_coll_coeff_offset),
114 m_coll_phys_offset(in.m_coll_phys_offset),
115 m_coeff_offset(in.m_coeff_offset), m_phys_offset(in.m_phys_offset),
116 m_blockMat(in.m_blockMat), m_WaveSpace(false),
117 m_elmtToExpId(in.m_elmtToExpId)
118{
119 // Set up m_coeffs, m_phys and offset arrays.
120 // use this to keep memory declaration in one place
121 SetupCoeffPhys(DeclareCoeffPhysArrays, false);
122}
123
124/**
125 * Copies the eIds elements from an existing expansion list.
126 * @param in Source expansion list.
127 * @param in elements that will be in the new exp list.
128 */
129ExpList::ExpList(const ExpList &in, const std::vector<unsigned int> &eIDs,
130 const bool DeclareCoeffPhysArrays,
132 : m_expType(in.m_expType), m_comm(in.m_comm), m_session(in.m_session),
133 m_graph(in.m_graph), m_physState(false),
134 m_exp(MemoryManager<LocalRegions::ExpansionVector>::AllocateSharedPtr()),
135 m_blockMat(MemoryManager<BlockMatrixMap>::AllocateSharedPtr()),
136 m_WaveSpace(false)
137{
138 for (int i = 0; i < eIDs.size(); ++i)
139 {
140 (*m_exp).push_back((*(in.m_exp))[eIDs[i]]);
141 }
142
143 // Set up m_coeffs, m_phys and offset arrays.
144 SetupCoeffPhys(DeclareCoeffPhysArrays);
145
146 // set up collections
147 CreateCollections(ImpType);
148}
149
150/**
151 * Given a meshgraph \a graph, containing information about
152 * the domain and the spectral/hp element expansion, this
153 * constructor fills the list of local expansions
154 * \texttt{m_exp} with the proper expansions, calculates the
155 * total number of quadrature points \f$x_i\f$ and local
156 * expansion coefficients \f$\hat{u}^e_n\f$ and
157 *
158 * @param pSession A session within information about expansion
159 *
160 * @param graph A meshgraph, containing information about the
161 * domain and the spectral/hp element expansion.
162 *
163 * @param DeclareCoeffPhysArrays Declare the coefficient and
164 * phys space arrays
165 *
166 * @param ImpType Detail about the implementation type to use
167 * in operators
168 */
171 const bool DeclareCoeffPhysArrays, const std::string &var,
173 : m_comm(pSession->GetComm()), m_session(pSession), m_graph(graph),
174 m_physState(false),
175 m_exp(MemoryManager<LocalRegions::ExpansionVector>::AllocateSharedPtr()),
176 m_blockMat(MemoryManager<BlockMatrixMap>::AllocateSharedPtr()),
177 m_WaveSpace(false)
178{
179 // Retrieve the list of expansions
180 const SpatialDomains::ExpansionInfoMap &expansions =
181 graph->GetExpansionInfo(var);
182
183 // Initialise Expansionn Vector
184 InitialiseExpVector(expansions);
185
186 // Setup phys coeff space
187 SetupCoeffPhys(DeclareCoeffPhysArrays);
188
189 // Initialise collection
190 CreateCollections(ImpType);
191}
192
193/**
194 * Given an expansion vector \a expansions, containing
195 * information about the domain and the spectral/hp element
196 * expansion, this constructor fills the list of local
197 * expansions \texttt{m_exp} with the proper expansions,
198 * calculates the total number of quadrature points
199 * \f$\boldsymbol{x}_i\f$ and local expansion coefficients
200 * \f$\hat{u}^e_n\f$.
201 *
202 * @param pSession A session within information about expansion
203 * @param expansions A vector containing information about the
204 * domain and the spectral/hp element
205 * expansion.
206 * @param DeclareCoeffPhysArrays Declare the coefficient and
207 * phys space arrays
208 * @param ImpType Detail about the implementation type to use
209 * in operators
210 */
212 const SpatialDomains::ExpansionInfoMap &expansions,
213 const bool DeclareCoeffPhysArrays,
215 : m_comm(pSession->GetComm()), m_session(pSession), m_physState(false),
216 m_exp(MemoryManager<LocalRegions::ExpansionVector>::AllocateSharedPtr()),
217 m_blockMat(MemoryManager<BlockMatrixMap>::AllocateSharedPtr()),
218 m_WaveSpace(false)
219{
220 // Initialise expansion vector
221 InitialiseExpVector(expansions);
222
223 // Set up m_coeffs, m_phys and offset arrays.
224 SetupCoeffPhys(DeclareCoeffPhysArrays);
225
226 // Setup Collection
227 CreateCollections(ImpType);
228}
229
230//----------------------------------------------------------------------
231// 0D Expansion Constructors
232//----------------------------------------------------------------------
234 : m_expType(e0D), m_ncoeffs(1), m_npoints(1), m_physState(false),
235 m_exp(MemoryManager<LocalRegions::ExpansionVector>::AllocateSharedPtr()),
236 m_blockMat(MemoryManager<BlockMatrixMap>::AllocateSharedPtr()),
237 m_WaveSpace(false)
238{
241 (*m_exp).push_back(Point);
242
244}
245
246/**
247 * Store expansions for the trace space expansions used in
248 * DisContField
249 *
250 * @param pSession A session within information about expansion
251 * @param bndConstraint Array of ExpList1D objects each containing a
252 * 1D spectral/hp element expansion on a single
253 * boundary region.
254 * @param bndCond Array of BoundaryCondition objects which contain
255 * information about the boundary conditions on the
256 * different boundary regions.
257 * @param locexp Complete domain expansion list.
258 * @param graph mesh corresponding to the expansion list.
259 * @param DeclareCoeffPhysArrays Declare the coefficient and
260 * phys space arrays
261 * @param variable The variable name associated with the expansion
262 * @param ImpType Detail about the implementation type to use
263 * in operators
264 */
267 const Array<OneD, const ExpListSharedPtr> &bndConstraint,
269 const LocalRegions::ExpansionVector &locexp,
271 const LibUtilities::CommSharedPtr &comm, const bool DeclareCoeffPhysArrays,
272 [[maybe_unused]] const std::string variable,
273 [[maybe_unused]] const Collections::ImplementationType ImpType)
274 : m_comm(comm), m_session(pSession), m_graph(graph), m_physState(false),
275 m_exp(MemoryManager<LocalRegions::ExpansionVector>::AllocateSharedPtr()),
276 m_blockMat(MemoryManager<BlockMatrixMap>::AllocateSharedPtr()),
277 m_WaveSpace(false)
278{
279 int i, j, id, elmtid = 0;
280 set<int> tracesDone;
281
288
294
295 // First loop over boundary conditions to reorder
296 // Dirichlet boundaries
297 for (i = 0; i < bndCond.size(); ++i)
298 {
299 if (bndCond[i]->GetBoundaryConditionType() ==
301 {
302 for (j = 0; j < bndConstraint[i]->GetExpSize(); ++j)
303 {
304 if ((exp0D =
305 std::dynamic_pointer_cast<LocalRegions::Expansion0D>(
306 bndConstraint[i]->GetExp(j))))
307 {
308 m_expType = e0D;
309
310 PointGeom = exp0D->GetGeom()->GetVertex(0);
311 exp = MemoryManager<
312 LocalRegions::PointExp>::AllocateSharedPtr(PointGeom);
313 tracesDone.insert(PointGeom->GetVid());
314 }
315 else if ((exp1D = std::dynamic_pointer_cast<
317 bndConstraint[i]->GetExp(j))))
318 {
319 m_expType = e1D;
320
322 exp1D->GetBasis(0)->GetBasisKey();
323 segGeom = exp1D->GetGeom1D();
324 exp =
326 bkey, segGeom);
327 tracesDone.insert(segGeom->GetGlobalID());
328 }
329 else if ((exp2D = std::dynamic_pointer_cast<
330 LocalRegions::Expansion2D>(
331 bndConstraint[i]->GetExp(j))))
332 {
333 m_expType = e2D;
334
335 LibUtilities::BasisKey bkey0 =
336 exp2D->GetBasis(0)->GetBasisKey();
337 LibUtilities::BasisKey bkey1 =
338 exp2D->GetBasis(1)->GetBasisKey();
339 FaceGeom = exp2D->GetGeom2D();
340
341 // if face is a quad
342 if ((QuadGeom = std::dynamic_pointer_cast<
343 SpatialDomains::QuadGeom>(FaceGeom)))
344 {
345 exp = MemoryManager<
346 LocalRegions::QuadExp>::AllocateSharedPtr(bkey0,
347 bkey1,
348 QuadGeom);
349 tracesDone.insert(QuadGeom->GetGlobalID());
350 }
351 // if face is a triangle
352 else if ((TriGeom = std::dynamic_pointer_cast<
353 SpatialDomains::TriGeom>(FaceGeom)))
354 {
355 exp = MemoryManager<
356 LocalRegions::TriExp>::AllocateSharedPtr(bkey0,
357 bkey1,
358 TriGeom);
359 tracesDone.insert(TriGeom->GetGlobalID());
360 }
361 else
362 {
364 "dynamic cast to a "
365 "proper face geometry failed");
366 }
367 }
368 // Assign next id
369 exp->SetElmtId(elmtid++);
370
371 // Add the expansion
372 (*m_exp).push_back(exp);
373 }
374 }
375 }
376
377 map<int, pair<SpatialDomains::Geometry1DSharedPtr, LibUtilities::BasisKey>>
378 edgeOrders;
379
381 pair<LibUtilities::BasisKey, LibUtilities::BasisKey>>>
382 faceOrders;
383
384 for (i = 0; i < locexp.size(); ++i)
385 {
386 if ((exp1D = std::dynamic_pointer_cast<LocalRegions::Expansion1D>(
387 locexp[i])))
388 {
389 m_expType = e0D;
390
391 for (j = 0; j < 2; ++j)
392 {
393 PointGeom = (exp1D->GetGeom1D())->GetVertex(j);
394 id = PointGeom->GetVid();
395
396 // Ignore Dirichlet edges
397 if (tracesDone.count(id) != 0)
398 {
399 continue;
400 }
401
403 PointGeom);
404 tracesDone.insert(id);
405 exp->SetElmtId(elmtid++);
406 (*m_exp).push_back(exp);
407 }
408 }
409 else if ((exp2D = std::dynamic_pointer_cast<LocalRegions::Expansion2D>(
410 locexp[i])))
411 {
412 m_expType = e1D;
413 for (j = 0; j < locexp[i]->GetNtraces(); ++j)
414 {
415 segGeom = exp2D->GetGeom2D()->GetEdge(j);
416 id = segGeom->GetGlobalID();
417 // Ignore Dirichlet edges
418 if (tracesDone.count(id) != 0)
419 {
420 continue;
421 }
422
423 auto it = edgeOrders.find(id);
424
425 if (it == edgeOrders.end()) // not exist, insert new one
426 {
427 edgeOrders.insert(std::make_pair(
428 id, std::make_pair(segGeom,
429 locexp[i]->GetTraceBasisKey(j))));
430 }
431 else // already exist, check if we need to update it
432 {
433 LibUtilities::BasisKey edge =
434 locexp[i]->GetTraceBasisKey(j);
435 LibUtilities::BasisKey existing = it->second.second;
436
437 int np1 = edge.GetNumPoints();
438 int np2 = existing.GetNumPoints();
439 int nm1 = edge.GetNumModes();
440 int nm2 = existing.GetNumModes();
441
442 // if the existing edge has less points/modes than the
443 // present edge, then we update the existing edge with
444 // present one (trace should always have highest order)
445
446 // The pointsType is always GLL for edges
447 // So we can directly compare them.
448 if (np2 >= np1 && nm2 >= nm1)
449 {
450 continue;
451 }
452 else if (np2 <= np1 && nm2 <= nm1)
453 {
454 it->second.second = edge;
455 }
456 else
457 {
459 "inappropriate number of points/modes (max"
460 "num of points is not set with max order)");
461 }
462 }
463 }
464 }
465 else if ((exp3D = dynamic_pointer_cast<LocalRegions::Expansion3D>(
466 locexp[i])))
467 {
468 m_expType = e2D;
469 for (j = 0; j < exp3D->GetNtraces(); ++j)
470 {
471 FaceGeom = exp3D->GetGeom3D()->GetFace(j);
472 id = FaceGeom->GetGlobalID();
473 // Ignore Dirichlet edges
474 if (tracesDone.count(id) != 0)
475 {
476 continue;
477 }
478 auto it = faceOrders.find(id);
479
480 if (it == faceOrders.end()) // not exist, insert new one
481 {
482 // GetTraceBasisKey does not take into account
483 // the orientaion. It is w.r.t local face axes.
484 LibUtilities::BasisKey face_dir0 =
485 locexp[i]->GetTraceBasisKey(j, 0);
486 LibUtilities::BasisKey face_dir1 =
487 locexp[i]->GetTraceBasisKey(j, 1);
488
489 // If the axes 1, 2 of the local face correspond to
490 // the axes 2, 1 of global face, respectively,
491 // then swap face0 and face1
492 if (locexp[i]->GetTraceOrient(j) >= 9)
493 {
494 std::swap(face_dir0, face_dir1);
495 }
496
497 faceOrders.insert(std::make_pair(
498 id,
499 std::make_pair(FaceGeom,
500 std::make_pair(face_dir0, face_dir1))));
501 }
502 else // already exist, check if we need to update it
503 {
504 LibUtilities::BasisKey face0 =
505 locexp[i]->GetTraceBasisKey(j, 0);
506 LibUtilities::BasisKey face1 =
507 locexp[i]->GetTraceBasisKey(j, 1);
508 LibUtilities::BasisKey existing0 = it->second.second.first;
509 LibUtilities::BasisKey existing1 = it->second.second.second;
510
511 // np -- number of points; nm -- number of modes;
512 // np_I_J --- I=1 current; I=2 existing; J=1 dir0; J=2 dir1;
513 int np11 = face0.GetNumPoints();
514 int np12 = face1.GetNumPoints();
515 int np21 = existing0.GetNumPoints();
516 int np22 = existing1.GetNumPoints();
517 int nm11 = face0.GetNumModes();
518 int nm12 = face1.GetNumModes();
519 int nm21 = existing0.GetNumModes();
520 int nm22 = existing1.GetNumModes();
521
522 // If the axes 1, 2 of the current face correspond to
523 // the axes 2, 1 of existing face, respectively,
524 // then swap face0 and face1
525 // eDir1FwdDir2_Dir2FwdDir1 = 9
526 // eDir1FwdDir2_Dir2BwdDir1 = 10
527 // eDir1BwdDir2_Dir2FwdDir1 = 11
528 // eDir1BwdDir2_Dir2BwdDir1 = 12
529 if (locexp[i]->GetTraceOrient(j) >= 9)
530 {
531 std::swap(np11, np12);
532 std::swap(nm11, nm12);
533 std::swap(face0, face1);
534 }
535
536 // The baiskey return by GetTraceBasisKey should always
537 // have GLL for eModified_A and GR for eModified_B.
538 // But we still use GetPointsType to check this.
539 if (existing1.GetPointsType() ==
540 LibUtilities::eGaussRadauMAlpha1Beta0)
541 {
542 if (face1.GetPointsType() ==
544 {
545 np12--; // make np12 comparable to np22
546 }
547 }
548 else
549 {
550 if (face1.GetPointsType() ==
551 LibUtilities::eGaussRadauMAlpha1Beta0)
552 {
553 np12++; // make np12 comparable to np22
554 }
555 }
556
557 if (existing0.GetPointsType() ==
558 LibUtilities::eGaussRadauMAlpha1Beta0)
559 {
560 if (face0.GetPointsType() ==
562 {
563 np11--; // make np11 comparable to np21
564 }
565 }
566 else
567 {
568 if (face0.GetPointsType() ==
569 LibUtilities::eGaussRadauMAlpha1Beta0)
570 {
571 np11++; // make np11 comparable to np21
572 }
573 }
574
575 // if the existing face_i has less points/modes than the
576 // present face_i, then we update the existing face_i with
577 // present one (trace should always have highest order)
578 if (np22 >= np12 && nm22 >= nm12)
579 {
580 // keep existing face_i and do nothing
581 }
582 else if (np22 <= np12 && nm22 <= nm12)
583 {
584 // Instead of using face0 directly, We create new
585 // basiskey with original Type but higher order.
586 LibUtilities::BasisKey newbkey(
587 existing1.GetBasisType(), nm12,
588 LibUtilities::PointsKey(np12,
589 existing1.GetPointsType()));
590 it->second.second.second = newbkey;
591 }
592 else // np22 > np12 but nm22 < nm12
593 {
595 "inappropriate number of points/modes (max"
596 "num of points is not set with max order)");
597 }
598
599 if (np21 >= np11 && nm21 >= nm11)
600 {
601 // keep existing face_i and do nothing
602 }
603 else if (np21 <= np11 && nm21 <= nm11)
604 {
605 // Instead of using face0 directly, We create new
606 // basiskey with original Type but higher order.
607 LibUtilities::PointsKey newpkey(
608 np11, existing0.GetPointsType());
609 LibUtilities::BasisKey newbkey(existing0.GetBasisType(),
610 nm11, newpkey);
611 it->second.second.first = newbkey;
612 }
613 else // np21 > np11 but nm21 < nm11
614 {
616 "inappropriate number of points/modes (max"
617 "num of points is not set with max order)");
618 }
619 }
620 }
621 }
622 }
623
624 int nproc = m_comm->GetRowComm()->GetSize(); // number of processors
625 int tracepr = m_comm->GetRowComm()->GetRank(); // ID processor
626
627 if (nproc > 1)
628 {
629 int tCnt = 0;
630
631 // Count the number of traces on each partition
632 for (i = 0; i < locexp.size(); ++i)
633 {
634 tCnt += locexp[i]->GetNtraces();
635 }
636
637 // Record the number traces on each partition,
638 // then reduce this across processors.
639 Array<OneD, int> tracesCnt(nproc, 0);
640 tracesCnt[tracepr] = tCnt;
641 m_comm->GetRowComm()->AllReduce(tracesCnt, LibUtilities::ReduceSum);
642
643 // Set up offset array.
644 int totTraceCnt = Vmath::Vsum(nproc, tracesCnt, 1);
645 Array<OneD, int> tTotOffsets(nproc, 0);
646
647 for (i = 1; i < nproc; ++i)
648 {
649 tTotOffsets[i] = tTotOffsets[i - 1] + tracesCnt[i - 1];
650 }
651
652 // Set up arrays that are large enough to hold all traces
653 // in the domain, not just those in local partition.
654 Array<OneD, int> TracesTotID(totTraceCnt, 0);
655 Array<OneD, int> TracesTotNm0(totTraceCnt, 0);
656 Array<OneD, int> TracesTotNm1(totTraceCnt, 0);
657 Array<OneD, int> TracesTotPnts0(totTraceCnt, 0);
658 Array<OneD, int> TracesTotPnts1(totTraceCnt, 0);
659 Array<OneD, int> TracesPointsType0(totTraceCnt, 0);
660 Array<OneD, int> TracesPointsType1(totTraceCnt, 0);
661 // convert enum PointsType to integer, so that MPI can handle it
662
663 // TODO: Change this design to save memory and improve performance.
664 //
665 // In the current design, After AllReduce, each processor will
666 // store a full copy these large arrays, which might be too
667 // expensive when nproc and mesh are large. So basically, this
668 // design is just a naive implementation and we need to redesign it
669 // in the future.
670
671 int cntr = tTotOffsets[tracepr];
672
673 for (i = 0; i < locexp.size(); ++i)
674 {
675 if ((exp2D = locexp[i]->as<LocalRegions::Expansion2D>()))
676 {
677 int nedges = locexp[i]->GetNtraces();
678
679 for (j = 0; j < nedges; ++j, ++cntr)
680 {
681 LibUtilities::BasisKey bkeyEdge =
682 locexp[i]->GetTraceBasisKey(j);
683 TracesTotID[cntr] = exp2D->GetGeom2D()->GetEid(j);
684 TracesTotNm0[cntr] = bkeyEdge.GetNumModes();
685 TracesTotPnts0[cntr] = bkeyEdge.GetNumPoints();
686 TracesPointsType0[cntr] =
687 static_cast<int>(bkeyEdge.GetPointsType());
688 // Althought for edges, we only have GLL points, we still
689 // keep this design for backup.
690 }
691 }
692 else if ((exp3D = locexp[i]->as<LocalRegions::Expansion3D>()))
693 {
694 int nfaces = locexp[i]->GetNtraces();
695
696 for (j = 0; j < nfaces; ++j, ++cntr)
697 {
698 LibUtilities::BasisKey face_dir0 =
699 locexp[i]->GetTraceBasisKey(j, 0);
700 LibUtilities::BasisKey face_dir1 =
701 locexp[i]->GetTraceBasisKey(j, 1);
702
703 // If the axes 1, 2 of the local face correspond to
704 // the axes 2, 1 of global face, respectively,
705 // then swap face0 and face1
706 if (locexp[i]->GetTraceOrient(j) >= 9)
707 {
708 std::swap(face_dir0, face_dir1);
709 }
710
711 TracesTotID[cntr] = exp3D->GetGeom3D()->GetFid(j);
712 TracesTotNm0[cntr] = face_dir0.GetNumModes();
713 TracesTotNm1[cntr] = face_dir1.GetNumModes();
714 TracesTotPnts0[cntr] = face_dir0.GetNumPoints();
715 TracesTotPnts1[cntr] = face_dir1.GetNumPoints();
716 TracesPointsType0[cntr] =
717 static_cast<int>(face_dir0.GetPointsType());
718 TracesPointsType1[cntr] =
719 static_cast<int>(face_dir1.GetPointsType());
720 }
721 }
722 }
723
724 m_comm->GetRowComm()->AllReduce(TracesTotID, LibUtilities::ReduceSum);
725 m_comm->GetRowComm()->AllReduce(TracesTotNm0, LibUtilities::ReduceSum);
726 m_comm->GetRowComm()->AllReduce(TracesTotPnts0,
728 m_comm->GetRowComm()->AllReduce(TracesPointsType0,
730 if (m_expType == e2D) // 2D face
731 {
732 m_comm->GetRowComm()->AllReduce(TracesTotNm1,
734 m_comm->GetRowComm()->AllReduce(TracesTotPnts1,
736 m_comm->GetRowComm()->AllReduce(TracesPointsType1,
738 }
739 // TracesTotXXX has collected traces info of entire domain
740 // Now compare them with current traces info - edgeOrders
741 // and update traces basiskey. This step is to ensure the
742 // m_trace has highest order even on parition interfaces.
743
744 if (edgeOrders.size())
745 {
746 for (i = 0; i < totTraceCnt; ++i)
747 {
748 auto it = edgeOrders.find(TracesTotID[i]);
749
750 if (it == edgeOrders.end())
751 {
752 continue;
753 }
754
755 LibUtilities::BasisKey existing = it->second.second;
756
757 int np1 = TracesTotPnts0[i];
758 int np2 = existing.GetNumPoints();
759 int nm1 = TracesTotNm0[i];
760 int nm2 = existing.GetNumModes();
761
762 // The pointsType is always GLL for edges
763 // So we can directly compare them.
764 if (np2 >= np1 && nm2 >= nm1)
765 {
766 continue;
767 }
768 else if (np2 <= np1 && nm2 <= nm1)
769 {
770 // We have to rebuild the basis key locally because
771 // MPI::AllReduce does not support BasisKey directly.
772 LibUtilities::BasisKey newbkey(
773 existing.GetBasisType(), nm1,
774 LibUtilities::PointsKey(np1, existing.GetPointsType()));
775 it->second.second = newbkey;
776 }
777 else
778 {
780 "inappropriate number of points/modes (max "
781 "num of points is not set with max order)");
782 }
783 }
784 }
785 else if (faceOrders.size())
786 {
787 for (i = 0; i < totTraceCnt; ++i)
788 {
789 auto it = faceOrders.find(TracesTotID[i]);
790
791 if (it == faceOrders.end())
792 {
793 continue;
794 }
795
796 LibUtilities::BasisKey existing0 = it->second.second.first;
797 LibUtilities::BasisKey existing1 = it->second.second.second;
798
799 // np -- number of points; nm -- number of modes;
800 // np_I_J --- I=1 current; I=2 existing; J=1 dir0; J=2 dir1;
801 int np11 = TracesTotPnts0[i];
802 int np12 = TracesTotPnts1[i];
803 int np21 = existing0.GetNumPoints();
804 int np22 = existing1.GetNumPoints();
805 int nm11 = TracesTotNm0[i];
806 int nm12 = TracesTotNm1[i];
807 int nm21 = existing0.GetNumModes();
808 int nm22 = existing1.GetNumModes();
809
810 // The orientation is already aligned
811 // Here we only need to compare pointsType
812 // and adjust np
813 if (existing1.GetPointsType() ==
814 LibUtilities::eGaussRadauMAlpha1Beta0)
815 {
816 if (static_cast<LibUtilities::PointsType>(
817 TracesPointsType1[i]) ==
819 {
820 np12--; // make np12 comparable to np22
821 }
822 }
823 else
824 {
825 if (static_cast<LibUtilities::PointsType>(
826 TracesPointsType1[i]) ==
827 LibUtilities::eGaussRadauMAlpha1Beta0)
828 {
829 np12++; // make np12 comparable to np22
830 }
831 }
832
833 if (existing0.GetPointsType() ==
834 LibUtilities::eGaussRadauMAlpha1Beta0)
835 {
836 if (static_cast<LibUtilities::PointsType>(
837 TracesPointsType0[i]) ==
839 {
840 np11--; // make np11 comparable to np21
841 }
842 }
843 else
844 {
845 if (static_cast<LibUtilities::PointsType>(
846 TracesPointsType0[i]) ==
847 LibUtilities::eGaussRadauMAlpha1Beta0)
848 {
849 np11++; // make np11 comparable to np21
850 }
851 }
852
853 // if the existing face_i has less points/modes than the
854 // present face_i, then we update the existing face_i with
855 // present one (trace should always have highest order)
856 if (np22 >= np12 && nm22 >= nm12)
857 {
858 // keep existing face_i and do nothing
859 }
860 else if (np22 <= np12 && nm22 <= nm12)
861 {
862 LibUtilities::BasisKey newbkey(
863 existing1.GetBasisType(), nm12,
864 LibUtilities::PointsKey(np12,
865 existing1.GetPointsType()));
866 it->second.second.second = newbkey;
867 }
868 else // np22 > np12 but nm22 < nm12
869 {
871 "inappropriate number of points/modes (max "
872 "num of points is not set with max order)");
873 }
874
875 if (np21 >= np11 && nm21 >= nm11)
876 {
877 // keep existing face_i and do nothing
878 }
879 else if (np21 <= np11 && nm21 <= nm11)
880 {
881 LibUtilities::BasisKey newbkey(
882 existing0.GetBasisType(), nm11,
883 LibUtilities::PointsKey(np11,
884 existing0.GetPointsType()));
885 it->second.second.first = newbkey;
886 }
887 else // np21 > np11 but nm21 < nm11
888 {
890 "inappropriate number of points/modes (max"
891 "num of points is not set with max order)");
892 }
893 }
894 }
895 }
896
897 if (edgeOrders.size())
898 {
899 for (auto &it : edgeOrders)
900 {
902 it.second.second, it.second.first);
903 exp->SetElmtId(elmtid++);
904 (*m_exp).push_back(exp);
905 }
906 }
907 else
908 {
909 for (auto &it : faceOrders)
910 {
911 FaceGeom = it.second.first;
912
913 if ((QuadGeom = std::dynamic_pointer_cast<SpatialDomains::QuadGeom>(
914 FaceGeom)))
915 {
917 it.second.second.first, it.second.second.second, QuadGeom);
918 }
919 else if ((TriGeom =
920 std::dynamic_pointer_cast<SpatialDomains::TriGeom>(
921 FaceGeom)))
922 {
924 it.second.second.first, it.second.second.second, TriGeom);
925 }
926 exp->SetElmtId(elmtid++);
927 (*m_exp).push_back(exp);
928 }
929 }
930
931 // Set up m_coeffs, m_phys and offset arrays.
932 SetupCoeffPhys(DeclareCoeffPhysArrays);
933
934 // Set up collections
935 if (m_expType != e0D)
936 {
937 CreateCollections(ImpType);
938 }
939
940 // Setup element to expansion ID maps for the trace elements
941 // Loop in reverse order so that in case where using a
942 // Homogeneous expansion it sets geometry ids to first part of
943 // m_exp list. Otherwise will set to second (complex) expansion
944 for (int i = (*m_exp).size() - 1; i >= 0; --i)
945 {
946 m_elmtToExpId[(*m_exp)[i]->GetGeom()->GetGlobalID()] = i;
947 }
948}
949
950/**
951 * Set expansions for localtrace space expansions used in
952 * DisContField as part of Gradient Jump Penalisation
953 *
954 * @param pSession A session within information about expansion
955 * @param locexp Complete domain expansion list.
956 * @param graph mesh corresponding to the expansion list.
957 * @param DeclareCoeffPhysArrays Declare the coefficient and
958 * phys space arrays
959 * @param variable The variable name associated with the expansion
960 * @param ImpType Detail about the implementation type to use
961 * in operators
962 */
964 const LocalRegions::ExpansionVector &locexp,
966 const bool DeclareCoeffPhysArrays,
967 [[maybe_unused]] const std::string variable,
968 [[maybe_unused]] const Collections::ImplementationType ImpType)
969 : m_comm(pSession->GetComm()), m_session(pSession), m_graph(graph),
970 m_physState(false),
971 m_exp(MemoryManager<LocalRegions::ExpansionVector>::AllocateSharedPtr()),
972 m_blockMat(MemoryManager<BlockMatrixMap>::AllocateSharedPtr()),
973 m_WaveSpace(false)
974{
975 int i, j, elmtid = 0;
976
983
989
990 for (i = 0; i < locexp.size(); ++i)
991 {
992 if ((exp1D = std::dynamic_pointer_cast<LocalRegions::Expansion1D>(
993 locexp[i])))
994 {
995 m_expType = e0D;
996
997 for (j = 0; j < 2; ++j)
998 {
999 PointGeom = (exp1D->GetGeom1D())->GetVertex(j);
1000
1002 PointGeom);
1003 exp->SetElmtId(elmtid++);
1004 (*m_exp).push_back(exp);
1005 }
1006 }
1007 else if ((exp2D = std::dynamic_pointer_cast<LocalRegions::Expansion2D>(
1008 locexp[i])))
1009 {
1010 m_expType = e1D;
1011 LibUtilities::BasisKey edgeKey0 =
1012 locexp[i]->GetBasis(0)->GetBasisKey();
1013
1014 for (j = 0; j < locexp[i]->GetNtraces(); ++j)
1015 {
1016 segGeom = exp2D->GetGeom2D()->GetEdge(j);
1017
1018 int dir = exp2D->GetGeom2D()->GetDir(j);
1019
1020 if (locexp[i]->GetNtraces() == 3)
1021 {
1022 LibUtilities::BasisKey edgeKey =
1023 locexp[i]->GetBasis(dir)->GetBasisKey();
1024
1025 LibUtilities::BasisKey nEdgeKey(edgeKey0.GetBasisType(),
1026 edgeKey.GetNumModes(),
1027 edgeKey.GetPointsKey());
1028
1029 exp =
1031 nEdgeKey, segGeom);
1032 }
1033 else
1034 {
1035 exp =
1037 locexp[i]->GetBasis(dir)->GetBasisKey(), segGeom);
1038 }
1039
1040 exp->SetElmtId(elmtid++);
1041 (*m_exp).push_back(exp);
1042 }
1043 }
1044 else if ((exp3D = dynamic_pointer_cast<LocalRegions::Expansion3D>(
1045 locexp[i])))
1046 {
1047 m_expType = e2D;
1048
1049 LibUtilities::BasisKey face0_dir0 =
1050 locexp[i]->GetBasis(0)->GetBasisKey();
1051 LibUtilities::BasisKey face0_dir1 =
1052 locexp[i]->GetBasis(1)->GetBasisKey();
1053
1054 for (j = 0; j < exp3D->GetNtraces(); ++j)
1055 {
1056 FaceGeom = exp3D->GetGeom3D()->GetFace(j);
1057
1058 int dir0 = exp3D->GetGeom3D()->GetDir(j, 0);
1059 int dir1 = exp3D->GetGeom3D()->GetDir(j, 1);
1060
1061 LibUtilities::BasisKey face_dir0 =
1062 locexp[i]->GetBasis(dir0)->GetBasisKey();
1063 LibUtilities::BasisKey face_dir1 =
1064 locexp[i]->GetBasis(dir1)->GetBasisKey();
1065
1066 if ((QuadGeom =
1067 std::dynamic_pointer_cast<SpatialDomains::QuadGeom>(
1068 FaceGeom)))
1069 {
1070 exp =
1072 face_dir0, face_dir1, QuadGeom);
1073 }
1074 else if ((TriGeom = std::dynamic_pointer_cast<
1075 SpatialDomains::TriGeom>(FaceGeom)))
1076 {
1077 LibUtilities::BasisKey nface_dir0(face0_dir0.GetBasisType(),
1078 face_dir0.GetNumModes(),
1079 face_dir0.GetPointsKey());
1080 LibUtilities::BasisKey nface_dir1(face0_dir1.GetBasisType(),
1081 face_dir1.GetNumModes(),
1082 face_dir1.GetPointsKey());
1083 exp =
1085 nface_dir0, nface_dir1, TriGeom);
1086 }
1087 exp->SetElmtId(elmtid++);
1088 (*m_exp).push_back(exp);
1089 }
1090 }
1091 }
1092
1093 // Set up m_coeffs, m_phys and offset arrays.
1094 SetupCoeffPhys(DeclareCoeffPhysArrays);
1095
1096 // Set up collections
1097 if (m_expType != e0D)
1098 {
1099 CreateCollections(ImpType);
1100 }
1101}
1102
1103/**
1104 * Fills the list of local expansions with the trace from the mesh
1105 * specified by \a domain. This CompositeMap contains a list of
1106 * Composites which define the boundary. It is also used to set up
1107 * expansion domains in the 1D Pulse Wave solver.
1108 *
1109 * @param pSession A session within information about expansion
1110 * @param domain A domain, comprising of one or more composite
1111 * regions,
1112 * @param graph A mesh, containing information about the
1113 * domain and the spectral/hp element expansion.
1114 * @param DeclareCoeffPhysArrays Declare the coefficient and
1115 * phys space arrays. Default is true.
1116 * @param variable The variable name associated with the expansion
1117 * @param SetToOneSpaceDimension Reduce to one space dimension expansion
1118 * @param comm An optional communicator that can be used with the
1119 * boundary expansion in case of more global
1120 * parallel operations. Default to a Null Communicator
1121 * @param ImpType Detail about the implementation type to use
1122 * in operators. Default is eNoImpType.
1123 *
1124 */
1126 const SpatialDomains::CompositeMap &domain,
1128 const bool DeclareCoeffPhysArrays, const std::string variable,
1129 bool SetToOneSpaceDimension,
1130 const LibUtilities::CommSharedPtr comm,
1131 const Collections::ImplementationType ImpType)
1132 : m_comm(comm), m_session(pSession), m_graph(graph), m_physState(false),
1133 m_exp(MemoryManager<LocalRegions::ExpansionVector>::AllocateSharedPtr()),
1134 m_blockMat(MemoryManager<BlockMatrixMap>::AllocateSharedPtr()),
1135 m_WaveSpace(false)
1136{
1137 int j, elmtid = 0;
1142
1144
1146
1147 int meshdim = graph->GetMeshDimension();
1148
1149 // Retrieve the list of expansions (element exp)
1150 const SpatialDomains::ExpansionInfoMap &expansions =
1151 graph->GetExpansionInfo(variable);
1152
1153 // Retrieve the list of expansions
1154 // Process each composite region.
1155 for (auto &compIt : domain)
1156 {
1157 // Process each expansion in the region.
1158 for (j = 0; j < compIt.second->m_geomVec.size(); ++j)
1159 {
1160 if ((PtGeom = std::dynamic_pointer_cast<SpatialDomains::PointGeom>(
1161 compIt.second->m_geomVec[j])))
1162 {
1163 m_expType = e0D;
1164
1166 PtGeom);
1167 }
1168 else if ((SegGeom =
1169 std::dynamic_pointer_cast<SpatialDomains::SegGeom>(
1170 compIt.second->m_geomVec[j])))
1171 {
1172 m_expType = e1D;
1173
1174 // Retrieve the basis key from the expansion.
1176
1177 if (meshdim == 1)
1178 {
1179 // map<int, ExpansionInfoShPtr>
1180 auto expIt = expansions.find(SegGeom->GetGlobalID());
1181 ASSERTL0(expIt != expansions.end(),
1182 "Failed to find basis key");
1183 bkey = expIt->second->m_basisKeyVector[0];
1184 }
1185 else // get bkey from Tri or Quad
1186 {
1187 // First, create the element stdExp that the edge belongs to
1189 graph->GetElementsFromEdge(SegGeom);
1190 // elmts -> std::vector<std::pair<GeometrySharedPtr, int> >
1191 // Currently we assume the elements adjacent to the edge
1192 // have the same type. So we directly fetch the first
1193 // element.
1194 SpatialDomains::GeometrySharedPtr geom = elmts->at(0).first;
1195 int edge_id = elmts->at(0).second;
1197 graph->GetExpansionInfo(geom, variable);
1198 LibUtilities::BasisKey Ba = expInfo->m_basisKeyVector[0];
1199 LibUtilities::BasisKey Bb = expInfo->m_basisKeyVector[1];
1201
1202 if (geom->GetShapeType() == LibUtilities::eTriangle)
1203 {
1204 elmtStdExp = MemoryManager<
1205 StdRegions::StdTriExp>::AllocateSharedPtr(Ba, Bb);
1206 }
1207 else if (geom->GetShapeType() ==
1209 {
1210 elmtStdExp = MemoryManager<
1211 StdRegions::StdQuadExp>::AllocateSharedPtr(Ba, Bb);
1212 }
1213 else
1214 {
1216 "Fail to cast geom to a known 2D shape.");
1217 }
1218 // Then, get the trace basis key from the element stdExp,
1219 // which may be different from Ba and Bb.
1220 bkey = elmtStdExp->GetTraceBasisKey(edge_id);
1221 }
1222
1223 if (SetToOneSpaceDimension)
1224 {
1225 SpatialDomains::SegGeomSharedPtr OneDSegmentGeom =
1226 SegGeom->GenerateOneSpaceDimGeom();
1227
1228 exp =
1230 bkey, OneDSegmentGeom);
1231 }
1232 else
1233 {
1234 exp =
1236 bkey, SegGeom);
1237 }
1238 }
1239 else if ((TriGeom =
1240 std::dynamic_pointer_cast<SpatialDomains::TriGeom>(
1241 compIt.second->m_geomVec[j])))
1242 {
1243 m_expType = e2D;
1244
1245 // First, create the element stdExp that the face belongs to
1247 graph->GetElementsFromFace(TriGeom);
1248 // elmts -> std::vector<std::pair<GeometrySharedPtr, int> >
1249 // Currently we assume the elements adjacent to the face have
1250 // the same type. So we directly fetch the first element.
1251 SpatialDomains::GeometrySharedPtr geom = elmts->at(0).first;
1252 int face_id = elmts->at(0).second;
1254 graph->GetExpansionInfo(geom, variable);
1255 LibUtilities::BasisKey Ba = expInfo->m_basisKeyVector[0];
1256 LibUtilities::BasisKey Bb = expInfo->m_basisKeyVector[1];
1257 LibUtilities::BasisKey Bc = expInfo->m_basisKeyVector[2];
1259
1260 if (geom->GetShapeType() == LibUtilities::ePrism)
1261 {
1262 elmtStdExp = MemoryManager<
1263 StdRegions::StdPrismExp>::AllocateSharedPtr(Ba, Bb, Bc);
1264 }
1265 else if (geom->GetShapeType() == LibUtilities::eTetrahedron)
1266 {
1267 elmtStdExp =
1269 Ba, Bb, Bc);
1270 }
1271 else if (geom->GetShapeType() == LibUtilities::ePyramid)
1272 {
1273 elmtStdExp =
1275 Ba, Bb, Bc);
1276 }
1277 else // hex cannot have tri surface
1278 {
1280 "Fail to cast geom to a known 3D shape.");
1281 }
1282 // Then, get the trace basis key from the element stdExp,
1283 // which may be different from Ba, Bb and Bc.
1285 elmtStdExp->GetTraceBasisKey(face_id, 0);
1287 elmtStdExp->GetTraceBasisKey(face_id, 1);
1288 // swap TriBa and TriBb orientation is transposed
1289 if (geom->GetForient(face_id) >= 9)
1290 {
1291 std::swap(TriBa, TriBb);
1292 }
1293
1294 if (graph->GetExpansionInfo()
1295 .begin()
1296 ->second->m_basisKeyVector[0]
1297 .GetBasisType() == LibUtilities::eGLL_Lagrange)
1298 {
1299 NEKERROR(ErrorUtil::efatal, "This method needs sorting");
1301
1302 exp = MemoryManager<
1303 LocalRegions::NodalTriExp>::AllocateSharedPtr(TriBa,
1304 TriBb,
1305 TriNb,
1306 TriGeom);
1307 }
1308 else
1309 {
1310 exp =
1312 TriBa, TriBb, TriGeom);
1313 }
1314 }
1315 else if ((QuadGeom =
1316 std::dynamic_pointer_cast<SpatialDomains::QuadGeom>(
1317 compIt.second->m_geomVec[j])))
1318 {
1319 m_expType = e2D;
1320
1321 // First, create the element stdExp that the face belongs to
1323 graph->GetElementsFromFace(QuadGeom);
1324 // elmts -> std::vector<std::pair<GeometrySharedPtr, int> >
1325 // Currently we assume the elements adjacent to the face have
1326 // the same type. So we directly fetch the first element.
1327 SpatialDomains::GeometrySharedPtr geom = elmts->at(0).first;
1328 int face_id = elmts->at(0).second;
1330 graph->GetExpansionInfo(geom, variable);
1331 LibUtilities::BasisKey Ba = expInfo->m_basisKeyVector[0];
1332 LibUtilities::BasisKey Bb = expInfo->m_basisKeyVector[1];
1333 LibUtilities::BasisKey Bc = expInfo->m_basisKeyVector[2];
1335
1336 if (geom->GetShapeType() == LibUtilities::ePrism)
1337 {
1338 elmtStdExp = MemoryManager<
1339 StdRegions::StdPrismExp>::AllocateSharedPtr(Ba, Bb, Bc);
1340 }
1341 else if (geom->GetShapeType() == LibUtilities::eHexahedron)
1342 {
1343 elmtStdExp =
1345 Ba, Bb, Bc);
1346 }
1347 else if (geom->GetShapeType() == LibUtilities::ePyramid)
1348 {
1349 elmtStdExp =
1351 Ba, Bb, Bc);
1352 }
1353 else // Tet cannot have quad surface
1354 {
1356 "Fail to cast geom to a known 3D shape.");
1357 }
1358 // Then, get the trace basis key from the element stdExp,
1359 // which may be different from Ba, Bb and Bc.
1360 LibUtilities::BasisKey QuadBa =
1361 elmtStdExp->GetTraceBasisKey(face_id, 0);
1362 LibUtilities::BasisKey QuadBb =
1363 elmtStdExp->GetTraceBasisKey(face_id, 1);
1364 // swap Ba and Bb if the orientation is transposed
1365 if (geom->GetForient(face_id) >= 9)
1366 {
1367 std::swap(QuadBa, QuadBb);
1368 }
1369
1371 QuadBa, QuadBb, QuadGeom);
1372 }
1373 else
1374 {
1376 "dynamic cast to a Geom (possibly 3D) failed");
1377 }
1378
1379 exp->SetElmtId(elmtid++);
1380 (*m_exp).push_back(exp);
1381 }
1382 }
1383
1384 // Set up m_coeffs, m_phys and offset arrays.
1385 SetupCoeffPhys(DeclareCoeffPhysArrays);
1386
1387 if (m_expType != e0D)
1388 {
1389 CreateCollections(ImpType);
1390 }
1391}
1392
1393/**
1394 * Each expansion (local element) is processed in turn to
1395 * determine the number of coefficients and physical data
1396 * points it contributes to the domain. Two arrays,
1397 * #m_coeff_offset are #m_phys_offset are also initialised and
1398 * updated to store the data offsets of each element in the
1399 * #m_coeffs and #m_phys arrays, and the element id that each
1400 * consecutive block is associated respectively.
1401 * Finally we initialise #m_coeffs and #m_phys
1402 */
1403void ExpList::SetupCoeffPhys(bool DeclareCoeffPhysArrays, bool SetupOffsets)
1404{
1405 if (SetupOffsets)
1406 {
1407 int i;
1408
1409 // Set up offset information and array sizes
1412
1413 m_ncoeffs = m_npoints = 0;
1414
1415 for (i = 0; i < m_exp->size(); ++i)
1416 {
1419 m_ncoeffs += (*m_exp)[i]->GetNcoeffs();
1420 m_npoints += (*m_exp)[i]->GetTotPoints();
1421 }
1422 }
1423
1424 if (DeclareCoeffPhysArrays)
1425 {
1428 }
1429
1431
1432 for (int i = 0; i < m_exp->size(); ++i)
1433 {
1434 int coeffs_offset = m_coeff_offset[i];
1435
1436 int loccoeffs = (*m_exp)[i]->GetNcoeffs();
1437
1438 for (int j = 0; j < loccoeffs; ++j)
1439 {
1440 m_coeffsToElmt[coeffs_offset + j].first = i;
1441 m_coeffsToElmt[coeffs_offset + j].second = j;
1442 }
1443 }
1444}
1445
1448{
1451 SpatialDomains::QuadGeomSharedPtr QuadrilateralGeom;
1456
1457 int id = 0;
1459
1461 // Process each expansion in the graph
1462 for (auto &expIt : expmap)
1463 {
1464 const SpatialDomains::ExpansionInfoShPtr expInfo = expIt.second;
1465
1466 switch (expInfo->m_basisKeyVector.size())
1467 {
1468 case 1: // Segment Expansions
1469 {
1471 "Cannot mix expansion dimensions in one vector");
1472 m_expType = e1D;
1473
1474 if ((SegmentGeom =
1475 std::dynamic_pointer_cast<SpatialDomains::SegGeom>(
1476 expInfo->m_geomShPtr)))
1477 {
1478 // Retrieve basis key from expansion
1479 LibUtilities::BasisKey bkey = expInfo->m_basisKeyVector[0];
1480
1481 exp =
1483 bkey, SegmentGeom);
1484 }
1485 else
1486 {
1488 "dynamic cast to a 1D Geom failed");
1489 }
1490 }
1491 break;
1492 case 2:
1493 {
1495 "Cannot mix expansion dimensions in one vector");
1496 m_expType = e2D;
1497
1498 LibUtilities::BasisKey Ba = expInfo->m_basisKeyVector[0];
1499 LibUtilities::BasisKey Bb = expInfo->m_basisKeyVector[1];
1500
1501 if ((TriangleGeom =
1502 std::dynamic_pointer_cast<SpatialDomains ::TriGeom>(
1503 expInfo->m_geomShPtr)))
1504 {
1505 // This is not elegantly implemented needs re-thinking.
1507 {
1509 Ba.GetNumModes(),
1510 Ba.GetPointsKey());
1511
1515 AllocateSharedPtr(newBa, Bb, TriNb, TriangleGeom);
1516 }
1517 else
1518 {
1520 AllocateSharedPtr(Ba, Bb, TriangleGeom);
1521 }
1522 }
1523 else if ((QuadrilateralGeom = std::dynamic_pointer_cast<
1524 SpatialDomains::QuadGeom>(expInfo->m_geomShPtr)))
1525 {
1526 exp =
1528 Ba, Bb, QuadrilateralGeom);
1529 }
1530 else
1531 {
1533 "dynamic cast to a 2D Geom failed");
1534 }
1535 }
1536 break;
1537 case 3:
1538 {
1540 "Cannot mix expansion dimensions in one vector");
1541 m_expType = e3D;
1542
1543 LibUtilities::BasisKey Ba = expInfo->m_basisKeyVector[0];
1544 LibUtilities::BasisKey Bb = expInfo->m_basisKeyVector[1];
1545 LibUtilities::BasisKey Bc = expInfo->m_basisKeyVector[2];
1546
1547 if ((TetGeom =
1548 std::dynamic_pointer_cast<SpatialDomains::TetGeom>(
1549 expInfo->m_geomShPtr)))
1550 {
1553 {
1555 "LocalRegions::NodalTetExp is not implemented "
1556 "yet");
1557 }
1558 else
1559 {
1560 exp = MemoryManager<
1561 LocalRegions::TetExp>::AllocateSharedPtr(Ba, Bb, Bc,
1562 TetGeom);
1563 }
1564 }
1565 else if ((PrismGeom = std::dynamic_pointer_cast<
1566 SpatialDomains ::PrismGeom>(
1567 expInfo->m_geomShPtr)))
1568 {
1569 exp = MemoryManager<
1570 LocalRegions::PrismExp>::AllocateSharedPtr(Ba, Bb, Bc,
1571 PrismGeom);
1572 }
1573 else if ((PyrGeom = std::dynamic_pointer_cast<
1574 SpatialDomains::PyrGeom>(expInfo->m_geomShPtr)))
1575 {
1576 exp =
1578 Ba, Bb, Bc, PyrGeom);
1579 }
1580 else if ((HexGeom = std::dynamic_pointer_cast<
1581 SpatialDomains::HexGeom>(expInfo->m_geomShPtr)))
1582 {
1583 exp =
1585 Ba, Bb, Bc, HexGeom);
1586 }
1587 else
1588 {
1590 "dynamic cast to a Geom failed");
1591 }
1592 }
1593 break;
1594 default:
1596 "Dimension of basis key is greater than 3");
1597 }
1598
1599 // Assign next id
1600 exp->SetElmtId(id++);
1601
1602 // Add the expansion
1603 (*m_exp).push_back(exp);
1604 }
1605}
1606
1607/**
1608 *
1609 */
1611{
1612 return m_expType;
1613}
1614
1616{
1617}
1618
1619/**
1620 * Retrieves the block matrix specified by \a bkey, and computes
1621 * \f$ y=Mx \f$.
1622 * @param gkey GlobalMatrixKey specifying the block matrix to
1623 * use in the matrix-vector multiply.
1624 * @param inarray Input vector \f$ x \f$.
1625 * @param outarray Output vector \f$ y \f$.
1626 */
1628 const Array<OneD, const NekDouble> &inarray,
1629 Array<OneD, NekDouble> &outarray)
1630{
1631 // Retrieve the block matrix using the given key.
1632 const DNekScalBlkMatSharedPtr &blockmat = GetBlockMatrix(gkey);
1633 int nrows = blockmat->GetRows();
1634 int ncols = blockmat->GetColumns();
1635
1636 // Create NekVectors from the given data arrays
1637 NekVector<NekDouble> in(ncols, inarray, eWrapper);
1638 NekVector<NekDouble> out(nrows, outarray, eWrapper);
1639
1640 // Perform matrix-vector multiply.
1641 out = (*blockmat) * in;
1642}
1643
1644/**
1645 * multiply the metric jacobi and quadrature weights
1646 */
1648 const Array<OneD, const NekDouble> &inarray,
1649 Array<OneD, NekDouble> &outarray)
1650{
1651 Array<OneD, NekDouble> e_outarray;
1652
1653 for (int i = 0; i < (*m_exp).size(); ++i)
1654 {
1655 (*m_exp)[i]->MultiplyByQuadratureMetric(inarray + m_phys_offset[i],
1656 e_outarray = outarray +
1657 m_phys_offset[i]);
1658 }
1659}
1660
1661/**
1662 * Divided by the metric jacobi and quadrature weights
1663 */
1665 const Array<OneD, const NekDouble> &inarray,
1666 Array<OneD, NekDouble> &outarray)
1667{
1668 Array<OneD, NekDouble> e_outarray;
1669
1670 for (int i = 0; i < (*m_exp).size(); ++i)
1671 {
1672 (*m_exp)[i]->DivideByQuadratureMetric(inarray + m_phys_offset[i],
1673 e_outarray =
1674 outarray + m_phys_offset[i]);
1675 }
1676}
1677
1678/**
1679 * The operation is evaluated locally for every element by the function
1680 * StdRegions#Expansion#IProductWRTDerivBase.
1681 *
1682 * @param dir {0,1} is the direction in which the
1683 * derivative of the basis should be taken
1684 * @param inarray An array of size \f$Q_{\mathrm{tot}}\f$
1685 * containing the values of the function
1686 * \f$f(\boldsymbol{x})\f$ at the quadrature
1687 * points \f$\boldsymbol{x}_i\f$.
1688 * @param outarray An array of size \f$N_{\mathrm{eof}}\f$
1689 * used to store the result.
1690 */
1692 const int dir, const Array<OneD, const NekDouble> &inarray,
1693 Array<OneD, NekDouble> &outarray)
1694{
1695 int i;
1696
1697 Array<OneD, NekDouble> e_outarray;
1698 for (i = 0; i < (*m_exp).size(); ++i)
1699 {
1700 (*m_exp)[i]->IProductWRTDerivBase(dir, inarray + m_phys_offset[i],
1701 e_outarray =
1702 outarray + m_coeff_offset[i]);
1703 }
1704}
1705
1706/**
1707 * @brief Directional derivative along a given direction
1708 *
1709 */
1711 const Array<OneD, const NekDouble> &direction,
1712 const Array<OneD, const NekDouble> &inarray,
1713 Array<OneD, NekDouble> &outarray)
1714{
1715 int npts_e;
1716 int coordim = (*m_exp)[0]->GetGeom()->GetCoordim();
1717 int nq = direction.size() / coordim;
1718
1719 Array<OneD, NekDouble> e_outarray;
1720 Array<OneD, NekDouble> e_MFdiv;
1721
1723
1724 for (int i = 0; i < (*m_exp).size(); ++i)
1725 {
1726 npts_e = (*m_exp)[i]->GetTotPoints();
1727 locdir = Array<OneD, NekDouble>(npts_e * coordim);
1728
1729 for (int k = 0; k < coordim; ++k)
1730 {
1731 Vmath::Vcopy(npts_e, &direction[k * nq + m_phys_offset[i]], 1,
1732 &locdir[k * npts_e], 1);
1733 }
1734
1735 (*m_exp)[i]->IProductWRTDirectionalDerivBase(
1736 locdir, inarray + m_phys_offset[i],
1737 e_outarray = outarray + m_coeff_offset[i]);
1738 }
1739}
1740
1741/**
1742 * The operation is evaluated locally for every element by the function
1743 * StdRegions#StdExpansion#IProductWRTDerivBase.
1744 *
1745 * @param inarray An array of arrays of size \f$Q_{\mathrm{tot}}\f$
1746 * containing the values of the function
1747 * \f$f(\boldsymbol{x})\f$ at the quadrature
1748 * points \f$\boldsymbol{x}_i\f$ in dir directions.
1749 * @param outarray An array of size \f$N_{\mathrm{eof}}\f$
1750 * used to store the result.
1751 */
1753 const Array<OneD, const Array<OneD, NekDouble>> &inarray,
1754 Array<OneD, NekDouble> &outarray)
1755{
1756 Array<OneD, NekDouble> tmp0, tmp1, tmp2;
1757 // assume coord dimension defines the size of Deriv Base
1758 int dim = GetCoordim(0);
1759
1760 ASSERTL1(inarray.size() >= dim, "inarray is not of sufficient dimension");
1761
1762 // initialise if required
1764 {
1765 for (int i = 0; i < m_collections.size(); ++i)
1766 {
1768 }
1770 }
1771
1772 LibUtilities::Timer timer;
1773 int input_offset{0};
1774 int output_offset{0};
1775 LIKWID_MARKER_START("IProductWRTDerivBase_coll");
1776 timer.Start();
1777
1778 switch (dim)
1779 {
1780 case 1:
1781 for (int i = 0; i < m_collections.size(); ++i)
1782 {
1783 m_collections[i].ApplyOperator(
1785 inarray[0] + input_offset, tmp0 = outarray + output_offset);
1786 input_offset += m_collections[i].GetInputSize(
1788 output_offset += m_collections[i].GetOutputSize(
1790 }
1791 break;
1792 case 2:
1793 for (int i = 0; i < m_collections.size(); ++i)
1794 {
1795 m_collections[i].ApplyOperator(
1797 inarray[0] + input_offset, tmp0 = inarray[1] + input_offset,
1798 tmp1 = outarray + output_offset);
1799 input_offset += m_collections[i].GetInputSize(
1801 output_offset += m_collections[i].GetOutputSize(
1803 }
1804 break;
1805 case 3:
1806 for (int i = 0; i < m_collections.size(); ++i)
1807 {
1808 m_collections[i].ApplyOperator(
1810 inarray[0] + input_offset, tmp0 = inarray[1] + input_offset,
1811 tmp1 = inarray[2] + input_offset,
1812 tmp2 = outarray + output_offset);
1813 input_offset += m_collections[i].GetInputSize(
1815 output_offset += m_collections[i].GetOutputSize(
1817 }
1818 break;
1819 default:
1820 NEKERROR(ErrorUtil::efatal, "Dimension of inarray not correct");
1821 break;
1822 }
1823
1824 timer.Stop();
1825 LIKWID_MARKER_STOP("IProductWRTDerivBase_coll");
1826
1827 // Elapsed time
1828 timer.AccumulateRegion("Collections:IProductWRTDerivBase", 10);
1829}
1830/**
1831 * Given a function \f$f(\boldsymbol{x})\f$ evaluated at
1832 * the quadrature points, this function calculates the
1833 * derivatives \f$\frac{d}{dx_1}\f$, \f$\frac{d}{dx_2}\f$
1834 * and \f$\frac{d}{dx_3}\f$ of the function
1835 * \f$f(\boldsymbol{x})\f$ at the same quadrature
1836 * points. The local distribution of the quadrature points
1837 * allows an elemental evaluation of the derivative. This
1838 * is done by a call to the function
1839 * StdRegions#StdExpansion#PhysDeriv.
1840 *
1841 * @param inarray An array of size \f$Q_{\mathrm{tot}}\f$
1842 * containing the values of the function
1843 * \f$f(\boldsymbol{x})\f$ at the quadrature
1844 * points \f$\boldsymbol{x}_i\f$.
1845 * @param out_d0 The discrete evaluation of the
1846 * derivative\f$\frac{d}{dx_1}\f$ will
1847 * be stored in this array of size
1848 * \f$Q_{\mathrm{tot}}\f$.
1849 * @param out_d1 The discrete evaluation of the
1850 * derivative\f$\frac{d}{dx_2}\f$ will be
1851 * stored in this array of size
1852 * \f$Q_{\mathrm{tot}}\f$. Note that if no
1853 * memory is allocated for \a out_d1, the
1854 * derivative \f$\frac{d}{dx_2}\f$ will not be
1855 * calculated.
1856 * @param out_d2 The discrete evaluation of the
1857 * derivative\f$\frac{d}{dx_3}\f$ will be
1858 * stored in this array of size
1859 * \f$Q_{\mathrm{tot}}\f$. Note that if no
1860 * memory is allocated for \a out_d2, the
1861 * derivative \f$\frac{d}{dx_3}\f$ will not be
1862 * calculated.
1863 */
1865 Array<OneD, NekDouble> &out_d0,
1866 Array<OneD, NekDouble> &out_d1,
1867 Array<OneD, NekDouble> &out_d2)
1868{
1869 Array<OneD, NekDouble> e_out_d0;
1870 Array<OneD, NekDouble> e_out_d1;
1871 Array<OneD, NekDouble> e_out_d2;
1872
1873 // initialise if required
1875 {
1876 for (int i = 0; i < m_collections.size(); ++i)
1877 {
1879 }
1881 }
1882
1883 int offset{0};
1884 LibUtilities::Timer timer;
1885 timer.Start();
1886 for (int i = 0; i < m_collections.size(); ++i)
1887 {
1888 e_out_d0 = out_d0 + offset;
1889 e_out_d1 = out_d1 + offset;
1890 e_out_d2 = out_d2 + offset;
1891 m_collections[i].ApplyOperator(Collections::ePhysDeriv,
1892 inarray + offset, e_out_d0, e_out_d1,
1893 e_out_d2);
1894 offset += m_collections[i].GetInputSize(Collections::ePhysDeriv);
1895 }
1896 timer.Stop();
1897 // Elapsed time
1898 timer.AccumulateRegion("Collections:PhysDeriv", 10);
1899}
1900
1901void ExpList::v_PhysDeriv(const int dir,
1902 const Array<OneD, const NekDouble> &inarray,
1904{
1905 Direction edir = DirCartesianMap[dir];
1906 v_PhysDeriv(edir, inarray, out_d);
1907}
1908
1910 const Array<OneD, const NekDouble> &inarray,
1912{
1913 int i;
1914 if (edir == MultiRegions::eS)
1915 {
1916 Array<OneD, NekDouble> e_out_ds;
1917 for (i = 0; i < (*m_exp).size(); ++i)
1918 {
1919 e_out_ds = out_d + m_phys_offset[i];
1920 (*m_exp)[i]->PhysDeriv_s(inarray + m_phys_offset[i], e_out_ds);
1921 }
1922 }
1923 else if (edir == MultiRegions::eN)
1924 {
1925 Array<OneD, NekDouble> e_out_dn;
1926 for (i = 0; i < (*m_exp).size(); i++)
1927 {
1928 e_out_dn = out_d + m_phys_offset[i];
1929 (*m_exp)[i]->PhysDeriv_n(inarray + m_phys_offset[i], e_out_dn);
1930 }
1931 }
1932 else
1933 {
1934 // initialise if required
1936 {
1937 for (int i = 0; i < m_collections.size(); ++i)
1938 {
1940 }
1942 }
1943
1944 // convert enum into int
1945 int intdir = (int)edir;
1946 Array<OneD, NekDouble> e_out_d;
1947 int offset{0};
1948 for (int i = 0; i < m_collections.size(); ++i)
1949 {
1950 e_out_d = out_d + offset;
1951 m_collections[i].ApplyOperator(Collections::ePhysDeriv, intdir,
1952 inarray + offset, e_out_d);
1953 offset += m_collections[i].GetInputSize(Collections::ePhysDeriv);
1954 }
1955 }
1956}
1957
1958/* Computes the curl of velocity = \nabla \times u
1959 * if m_expType == 2D, Q = [omg_z, (nothing done)]
1960 * if m_expType == 3D, Q = [omg_x, omg_y, omg_z]
1961 */
1964{
1965 int nq = GetTotPoints();
1969
1970 switch (m_expType)
1971 {
1972 case e2D:
1973 {
1974 PhysDeriv(xDir, Vel[yDir], Vx);
1975 PhysDeriv(yDir, Vel[xDir], Uy);
1976
1977 Vmath::Vsub(nq, Vx, 1, Uy, 1, Q[0], 1);
1978 }
1979 break;
1980
1981 case e3D:
1982 {
1987
1988 PhysDeriv(Vel[xDir], Dummy, Uy, Uz);
1989 PhysDeriv(Vel[yDir], Vx, Dummy, Vz);
1990 PhysDeriv(Vel[zDir], Wx, Wy, Dummy);
1991
1992 Vmath::Vsub(nq, Wy, 1, Vz, 1, Q[0], 1);
1993 Vmath::Vsub(nq, Uz, 1, Wx, 1, Q[1], 1);
1994 Vmath::Vsub(nq, Vx, 1, Uy, 1, Q[2], 1);
1995 }
1996 break;
1997 default:
1998 ASSERTL0(0, "Dimension not supported by ExpList::Curl");
1999 break;
2000 }
2001}
2002
2003/* Computes the curl of vorticity = \nabla \times \nabla \times u
2004 * if m_expType == 2D, Q = [dy omg_z, -dx omg_z, 0]
2005 *
2006 * if m_expType == 3D, Q = [dy omg_z - dz omg_y,
2007 * dz omg_x - dx omg_z,
2008 * dx omg_y - dy omg_x]
2009 *
2010 */
2013{
2014 int nq = GetTotPoints();
2018
2019 bool halfMode = false;
2020 if (GetExpType() == e3DH1D)
2021 {
2022 m_session->MatchSolverInfo("ModeType", "HalfMode", halfMode, false);
2023 }
2024
2025 switch (m_expType)
2026 {
2027 case e2D:
2028 {
2029 PhysDeriv(xDir, Vel[yDir], Vx);
2030 PhysDeriv(yDir, Vel[xDir], Uy);
2031
2032 Vmath::Vsub(nq, Vx, 1, Uy, 1, Dummy, 1);
2033
2034 PhysDeriv(Dummy, Q[1], Q[0]);
2035
2036 Vmath::Smul(nq, -1.0, Q[1], 1, Q[1], 1);
2037 }
2038 break;
2039
2040 case e3D:
2041 case e3DH1D:
2042 case e3DH2D:
2043 {
2048
2049 PhysDeriv(Vel[xDir], Dummy, Uy, Uz);
2050 PhysDeriv(Vel[yDir], Vx, Dummy, Vz);
2051 PhysDeriv(Vel[zDir], Wx, Wy, Dummy);
2052
2053 Vmath::Vsub(nq, Wy, 1, Vz, 1, Q[0], 1);
2054 Vmath::Vsub(nq, Uz, 1, Wx, 1, Q[1], 1);
2055 Vmath::Vsub(nq, Vx, 1, Uy, 1, Q[2], 1);
2056
2057 PhysDeriv(Q[0], Dummy, Uy, Uz);
2058 PhysDeriv(Q[1], Vx, Dummy, Vz);
2059 PhysDeriv(Q[2], Wx, Wy, Dummy);
2060
2061 // For halfmode, need to change the sign of z derivatives
2062 if (halfMode)
2063 {
2064 Vmath::Neg(nq, Uz, 1);
2065 Vmath::Neg(nq, Vz, 1);
2066 }
2067
2068 Vmath::Vsub(nq, Wy, 1, Vz, 1, Q[0], 1);
2069 Vmath::Vsub(nq, Uz, 1, Wx, 1, Q[1], 1);
2070 Vmath::Vsub(nq, Vx, 1, Uy, 1, Q[2], 1);
2071 }
2072 break;
2073 default:
2074 ASSERTL0(0, "Dimension not supported");
2075 break;
2076 }
2077}
2078
2080 const Array<OneD, const NekDouble> &direction,
2081 const Array<OneD, const NekDouble> &inarray,
2082 Array<OneD, NekDouble> &outarray)
2083{
2084 int npts_e;
2085 int coordim = (*m_exp)[0]->GetGeom()->GetCoordim();
2086 int nq = direction.size() / coordim;
2087
2088 Array<OneD, NekDouble> e_outarray;
2089 Array<OneD, NekDouble> e_MFdiv;
2091
2092 for (int i = 0; i < (*m_exp).size(); ++i)
2093 {
2094 npts_e = (*m_exp)[i]->GetTotPoints();
2095 locdir = Array<OneD, NekDouble>(npts_e * coordim);
2096
2097 for (int k = 0; k < coordim; ++k)
2098 {
2099 Vmath::Vcopy(npts_e, &direction[k * nq + m_phys_offset[i]], 1,
2100 &locdir[k * npts_e], 1);
2101 }
2102
2103 (*m_exp)[i]->PhysDirectionalDeriv(inarray + m_phys_offset[i], locdir,
2104 e_outarray =
2105 outarray + m_phys_offset[i]);
2106 }
2107}
2108
2110 const NekDouble alpha, const NekDouble exponent,
2111 const NekDouble cutoff)
2112{
2113 Array<OneD, NekDouble> e_array;
2114
2115 for (int i = 0; i < (*m_exp).size(); ++i)
2116 {
2117 (*m_exp)[i]->ExponentialFilter(e_array = array + m_phys_offset[i],
2118 alpha, exponent, cutoff);
2119 }
2120}
2121
2122/**
2123 * The coefficients of the function to be acted upon
2124 * should be contained in the \param inarray. The
2125 * resulting coefficients are stored in \param outarray
2126 *
2127 * @param inarray An array of size \f$N_{\mathrm{eof}}\f$
2128 * containing the inner product.
2129 */
2131 Array<OneD, NekDouble> &outarray)
2132{
2134 const DNekScalBlkMatSharedPtr &InvMass = GetBlockMatrix(mkey);
2135
2136 // Inverse mass matrix
2137 NekVector<NekDouble> out(m_ncoeffs, outarray, eWrapper);
2138 if (inarray.get() == outarray.get())
2139 {
2140 NekVector<NekDouble> in(m_ncoeffs, inarray); // copy data
2141 out = (*InvMass) * in;
2142 }
2143 else
2144 {
2146 out = (*InvMass) * in;
2147 }
2148}
2149
2150/**
2151 * Given a function \f$u(\boldsymbol{x})\f$ defined at the
2152 * quadrature points, this function determines the
2153 * transformed elemental coefficients \f$\hat{u}_n^e\f$
2154 * employing a discrete elemental Galerkin projection from
2155 * physical space to coefficient space. For each element,
2156 * the operation is evaluated locally by the function
2157 * StdRegions#StdExpansion#IproductWRTBase followed by a
2158 * call to #MultiRegions#MultiplyByElmtInvMass.
2159 *
2160 * @param inarray An array of size \f$Q_{\mathrm{tot}}\f$
2161 * containing the values of the function
2162 * \f$f(\boldsymbol{x})\f$ at the quadrature
2163 * points \f$\boldsymbol{x}_i\f$.
2164 * @param outarray The resulting coefficients
2165 * \f$\hat{u}_n^e\f$ will be stored in this
2166 * array of size \f$N_{\mathrm{eof}}\f$.
2167 */
2169 Array<OneD, NekDouble> &outarray)
2170{
2172
2173 IProductWRTBase(inarray, f);
2174 MultiplyByElmtInvMass(f, outarray);
2175}
2176
2178 const Array<OneD, const NekDouble> &inarray,
2179 Array<OneD, NekDouble> &outarray)
2180{
2181 int i;
2182
2183 Array<OneD, NekDouble> e_outarray;
2184
2185 for (i = 0; i < (*m_exp).size(); ++i)
2186 {
2187 (*m_exp)[i]->FwdTransBndConstrained(inarray + m_phys_offset[i],
2188 e_outarray =
2189 outarray + m_coeff_offset[i]);
2190 }
2191}
2192
2193/**
2194 * This function smooth a field after some calculaitons which have
2195 * been done elementally.
2196 *
2197 * @param field An array containing the field in physical space
2198 *
2199 */
2201{
2202 // Do nothing unless the method is implemented in the appropriate
2203 // class, i.e. ContField1D,ContField2D, etc.
2204
2205 // So far it has been implemented just for ContField2D and
2206 // ContField3DHomogeneous1D
2207
2208 // Block in case users try the smoothing with a modal expansion.
2209 // Maybe a different techique for the smoothing require
2210 // implementation for modal basis.
2211
2212 ASSERTL0((*m_exp)[0]->GetBasisType(0) == LibUtilities::eGLL_Lagrange ||
2213 (*m_exp)[0]->GetBasisType(0) == LibUtilities::eGauss_Lagrange,
2214 "Smoothing is currently not allowed unless you are using "
2215 "a nodal base for efficiency reasons. The implemented "
2216 "smoothing technique requires the mass matrix inversion "
2217 "which is trivial just for GLL_LAGRANGE_SEM and "
2218 "GAUSS_LAGRANGE_SEMexpansions.");
2219}
2220
2221/**
2222 * This function assembles the block diagonal matrix
2223 * \f$\underline{\boldsymbol{M}}^e\f$, which is the
2224 * concatenation of the local matrices
2225 * \f$\boldsymbol{M}^e\f$ of the type \a mtype, that is
2226 *
2227 * \f[
2228 * \underline{\boldsymbol{M}}^e = \left[
2229 * \begin{array}{cccc}
2230 * \boldsymbol{M}^1 & 0 & \hspace{3mm}0 \hspace{3mm}& 0 \\
2231 * 0 & \boldsymbol{M}^2 & 0 & 0 \\
2232 * 0 & 0 & \ddots & 0 \\
2233 * 0 & 0 & 0 & \boldsymbol{M}^{N_{\mathrm{el}}} \end{array}\right].\f]
2234 *
2235 * @param mtype the type of matrix to be assembled
2236 * @param scalar an optional parameter
2237 * @param constant an optional parameter
2238 */
2240 const GlobalMatrixKey &gkey)
2241{
2242 int i, cnt1;
2243 int n_exp = 0;
2244 DNekScalMatSharedPtr loc_mat;
2245 DNekScalBlkMatSharedPtr BlkMatrix;
2246 map<int, int> elmt_id;
2248
2250 {
2251 for (i = 0; i < (*m_exp).size(); ++i)
2252 {
2253 if ((*m_exp)[i]->DetShapeType() == ShapeType)
2254 {
2255 elmt_id[n_exp++] = i;
2256 }
2257 }
2258 }
2259 else
2260 {
2261 n_exp = (*m_exp).size();
2262 for (i = 0; i < n_exp; ++i)
2263 {
2264 elmt_id[i] = i;
2265 }
2266 }
2267
2268 Array<OneD, unsigned int> nrows(n_exp);
2269 Array<OneD, unsigned int> ncols(n_exp);
2270
2271 switch (gkey.GetMatrixType())
2272 {
2274 {
2275 // set up an array of integers for block matrix construction
2276 for (i = 0; i < n_exp; ++i)
2277 {
2278 nrows[i] = (*m_exp)[elmt_id.find(i)->second]->GetTotPoints();
2279 ncols[i] = (*m_exp)[elmt_id.find(i)->second]->GetNcoeffs();
2280 }
2281 }
2282 break;
2284 {
2285 // set up an array of integers for block matrix construction
2286 for (i = 0; i < n_exp; ++i)
2287 {
2288 nrows[i] = (*m_exp)[elmt_id.find(i)->second]->GetNcoeffs();
2289 ncols[i] = (*m_exp)[elmt_id.find(i)->second]->GetTotPoints();
2290 }
2291 }
2292 break;
2293 case StdRegions::eMass:
2298 {
2299 // set up an array of integers for block matrix construction
2300 for (i = 0; i < n_exp; ++i)
2301 {
2302 nrows[i] = (*m_exp)[elmt_id.find(i)->second]->GetNcoeffs();
2303 ncols[i] = (*m_exp)[elmt_id.find(i)->second]->GetNcoeffs();
2304 }
2305 }
2306 break;
2307
2309 {
2310 // set up an array of integers for block matrix construction
2311 for (i = 0; i < n_exp; ++i)
2312 {
2313 nrows[i] = (*m_exp)[elmt_id.find(i)->second]->GetNcoeffs();
2314 ncols[i] =
2315 (*m_exp)[elmt_id.find(i)->second]->NumDGBndryCoeffs();
2316 }
2317 }
2318 break;
2320 {
2321 // set up an array of integers for block matrix construction
2322 for (i = 0; i < n_exp; ++i)
2323 {
2324 nrows[i] =
2325 (*m_exp)[elmt_id.find(i)->second]->NumDGBndryCoeffs();
2326 ncols[i] =
2327 (*m_exp)[elmt_id.find(i)->second]->NumDGBndryCoeffs();
2328 }
2329 }
2330 break;
2331 default:
2332 {
2334 "Global Matrix creation not defined for this "
2335 "type of matrix");
2336 }
2337 }
2338
2339 MatrixStorage blkmatStorage = eDIAGONAL;
2340 BlkMatrix = MemoryManager<DNekScalBlkMat>::AllocateSharedPtr(nrows, ncols,
2341 blkmatStorage);
2342
2343 int nvarcoeffs = gkey.GetNVarCoeffs();
2344 int eid;
2345 Array<OneD, NekDouble> varcoeffs_wk;
2346
2347 for (i = cnt1 = 0; i < n_exp; ++i)
2348 {
2349 // need to be initialised with zero size for non
2350 // variable coefficient case
2351 StdRegions::VarCoeffMap varcoeffs;
2352
2353 eid = elmt_id[i];
2354 if (nvarcoeffs > 0)
2355 {
2356 varcoeffs = StdRegions::RestrictCoeffMap(
2357 gkey.GetVarCoeffs(), m_phys_offset[i],
2358 (*m_exp)[i]->GetTotPoints());
2359 }
2360
2362 gkey.GetMatrixType(), (*m_exp)[eid]->DetShapeType(), *(*m_exp)[eid],
2363 gkey.GetConstFactors(), varcoeffs);
2364
2365 loc_mat = std::dynamic_pointer_cast<LocalRegions::Expansion>(
2366 (*m_exp)[elmt_id.find(i)->second])
2367 ->GetLocMatrix(matkey);
2368 BlkMatrix->SetBlock(i, i, loc_mat);
2369 }
2370
2371 return BlkMatrix;
2372}
2373
2375 const GlobalMatrixKey &gkey)
2376{
2377 auto matrixIter = m_blockMat->find(gkey);
2378
2379 if (matrixIter == m_blockMat->end())
2380 {
2381 return ((*m_blockMat)[gkey] = GenBlockMatrix(gkey));
2382 }
2383 else
2384 {
2385 return matrixIter->second;
2386 }
2387}
2388
2389// Routines for continous matrix solution
2390/**
2391 * This operation is equivalent to the evaluation of
2392 * \f$\underline{\boldsymbol{M}}^e\boldsymbol{\hat{u}}_l\f$, that is,
2393 * \f[ \left[
2394 * \begin{array}{cccc}
2395 * \boldsymbol{M}^1 & 0 & \hspace{3mm}0 \hspace{3mm}& 0 \\
2396 * 0 & \boldsymbol{M}^2 & 0 & 0 \\
2397 * 0 & 0 & \ddots & 0 \\
2398 * 0 & 0 & 0 & \boldsymbol{M}^{N_{\mathrm{el}}} \end{array} \right]
2399 *\left [ \begin{array}{c}
2400 * \boldsymbol{\hat{u}}^{1} \\
2401 * \boldsymbol{\hat{u}}^{2} \\
2402 * \vdots \\
2403 * \boldsymbol{\hat{u}}^{{{N_{\mathrm{el}}}}} \end{array} \right ]\f]
2404 * where \f$\boldsymbol{M}^e\f$ are the local matrices of type
2405 * specified by the key \a mkey. The decoupling of the local matrices
2406 * allows for a local evaluation of the operation. However, rather than
2407 * a local matrix-vector multiplication, the local operations are
2408 * evaluated as implemented in the function
2409 * StdRegions#StdExpansion#GeneralMatrixOp.
2410 *
2411 * @param mkey This key uniquely defines the type matrix
2412 * required for the operation.
2413 * @param inarray The vector \f$\boldsymbol{\hat{u}}_l\f$ of
2414 * size \f$N_{\mathrm{eof}}\f$.
2415 * @param outarray The resulting vector of size
2416 * \f$N_{\mathrm{eof}}\f$.
2417 */
2419 const Array<OneD, const NekDouble> &inarray,
2420 Array<OneD, NekDouble> &outarray)
2421{
2422 int nvarcoeffs = gkey.GetNVarCoeffs();
2423
2424 if ((nvarcoeffs == 0) && (gkey.GetMatrixType() == StdRegions::eHelmholtz))
2425 {
2426 // initialise if required
2427 if (m_collections.size() &&
2429 {
2430 for (int i = 0; i < m_collections.size(); ++i)
2431 {
2433 gkey.GetConstFactors());
2434 }
2436 }
2437 else
2438 {
2439 for (int i = 0; i < m_collections.size(); ++i)
2440 {
2441 m_collections[i].CheckFactors(Collections::eHelmholtz,
2442 gkey.GetConstFactors(),
2444 }
2445 }
2446
2448 int input_offset{0};
2449 int output_offset{0};
2450 for (int i = 0; i < m_collections.size(); ++i)
2451 {
2452 // the input_offset is equal to the output_offset - this is
2453 // happenning inside the Helmholtz_Helper class
2454 m_collections[i].ApplyOperator(Collections::eHelmholtz,
2455 inarray + input_offset,
2456 tmp = outarray + output_offset);
2457 input_offset +=
2458 m_collections[i].GetInputSize(Collections::eHelmholtz);
2459 output_offset +=
2460 m_collections[i].GetOutputSize(Collections::eHelmholtz);
2461 }
2462 }
2463 else
2464 {
2465 Array<OneD, NekDouble> tmp_outarray;
2466 for (int i = 0; i < (*m_exp).size(); ++i)
2467 {
2468 // need to be initialised with zero size for non
2469 // variable coefficient case
2470 StdRegions::VarCoeffMap varcoeffs;
2471
2472 if (nvarcoeffs > 0)
2473 {
2474 varcoeffs = StdRegions::RestrictCoeffMap(
2475 gkey.GetVarCoeffs(), m_phys_offset[i],
2476 (*m_exp)[i]->GetTotPoints());
2477 }
2478
2480 gkey.GetMatrixType(), (*m_exp)[i]->DetShapeType(),
2481 *((*m_exp)[i]), gkey.GetConstFactors(), varcoeffs);
2482
2483 (*m_exp)[i]->GeneralMatrixOp(
2484 inarray + m_coeff_offset[i],
2485 tmp_outarray = outarray + m_coeff_offset[i], mkey);
2486 }
2487 }
2488}
2489
2490/**
2491 * Retrieves local matrices from each expansion in the expansion list
2492 * and combines them together to generate a global matrix system.
2493 * @param mkey Matrix key for the matrix to be generated.
2494 * @param locToGloMap Local to global mapping.
2495 * @returns Shared pointer to the generated global matrix.
2496 */
2498 const GlobalMatrixKey &mkey, const AssemblyMapCGSharedPtr &locToGloMap)
2499{
2500 int i, j, n, gid1, gid2, cntdim1, cntdim2;
2501 NekDouble sign1, sign2;
2502 DNekScalMatSharedPtr loc_mat;
2503
2504 unsigned int glob_rows = 0;
2505 unsigned int glob_cols = 0;
2506 unsigned int loc_rows = 0;
2507 unsigned int loc_cols = 0;
2508
2509 bool assembleFirstDim = false;
2510 bool assembleSecondDim = false;
2511
2512 switch (mkey.GetMatrixType())
2513 {
2515 {
2516 glob_rows = m_npoints;
2517 glob_cols = locToGloMap->GetNumGlobalCoeffs();
2518
2519 assembleFirstDim = false;
2520 assembleSecondDim = true;
2521 }
2522 break;
2524 {
2525 glob_rows = locToGloMap->GetNumGlobalCoeffs();
2526 glob_cols = m_npoints;
2527
2528 assembleFirstDim = true;
2529 assembleSecondDim = false;
2530 }
2531 break;
2532 case StdRegions::eMass:
2536 {
2537 glob_rows = locToGloMap->GetNumGlobalCoeffs();
2538 glob_cols = locToGloMap->GetNumGlobalCoeffs();
2539
2540 assembleFirstDim = true;
2541 assembleSecondDim = true;
2542 }
2543 break;
2544 default:
2545 {
2547 "Global Matrix creation not defined for this "
2548 "type of matrix");
2549 }
2550 }
2551
2552 COOMatType spcoomat;
2553 CoordType coord;
2554
2555 int nvarcoeffs = mkey.GetNVarCoeffs();
2556 int eid;
2557
2558 // fill global matrix
2559 for (n = cntdim1 = cntdim2 = 0; n < (*m_exp).size(); ++n)
2560 {
2561 // need to be initialised with zero size for non
2562 // variable coefficient case
2563 StdRegions::VarCoeffMap varcoeffs;
2564
2565 eid = n;
2566 if (nvarcoeffs > 0)
2567 {
2568 varcoeffs = StdRegions::RestrictCoeffMap(
2569 mkey.GetVarCoeffs(), m_phys_offset[eid],
2570 (*m_exp)[eid]->GetTotPoints());
2571 }
2572
2574 mkey.GetMatrixType(), (*m_exp)[eid]->DetShapeType(),
2575 *((*m_exp)[eid]), mkey.GetConstFactors(), varcoeffs);
2576
2577 loc_mat =
2578 std::dynamic_pointer_cast<LocalRegions::Expansion>((*m_exp)[n])
2579 ->GetLocMatrix(matkey);
2580
2581 loc_rows = loc_mat->GetRows();
2582 loc_cols = loc_mat->GetColumns();
2583
2584 for (i = 0; i < loc_rows; ++i)
2585 {
2586 if (assembleFirstDim)
2587 {
2588 gid1 = locToGloMap->GetLocalToGlobalMap(cntdim1 + i);
2589 sign1 = locToGloMap->GetLocalToGlobalSign(cntdim1 + i);
2590 }
2591 else
2592 {
2593 gid1 = cntdim1 + i;
2594 sign1 = 1.0;
2595 }
2596
2597 for (j = 0; j < loc_cols; ++j)
2598 {
2599 if (assembleSecondDim)
2600 {
2601 gid2 = locToGloMap->GetLocalToGlobalMap(cntdim2 + j);
2602 sign2 = locToGloMap->GetLocalToGlobalSign(cntdim2 + j);
2603 }
2604 else
2605 {
2606 gid2 = cntdim2 + j;
2607 sign2 = 1.0;
2608 }
2609
2610 // sparse matrix fill
2611 coord = make_pair(gid1, gid2);
2612 if (spcoomat.count(coord) == 0)
2613 {
2614 spcoomat[coord] = sign1 * sign2 * (*loc_mat)(i, j);
2615 }
2616 else
2617 {
2618 spcoomat[coord] += sign1 * sign2 * (*loc_mat)(i, j);
2619 }
2620 }
2621 }
2622 cntdim1 += loc_rows;
2623 cntdim2 += loc_cols;
2624 }
2625
2627 glob_cols, spcoomat);
2628}
2629
2631 const GlobalLinSysKey &mkey, const AssemblyMapCGSharedPtr &locToGloMap)
2632{
2633 int i, j, n, gid1, gid2, loc_lda, eid;
2634 NekDouble sign1, sign2, value;
2635 DNekScalMatSharedPtr loc_mat;
2636
2637 int totDofs = locToGloMap->GetNumGlobalCoeffs();
2638 int NumDirBCs = locToGloMap->GetNumGlobalDirBndCoeffs();
2639
2640 unsigned int rows = totDofs - NumDirBCs;
2641 unsigned int cols = totDofs - NumDirBCs;
2642 NekDouble zero = 0.0;
2643
2644 DNekMatSharedPtr Gmat;
2645 int bwidth = locToGloMap->GetFullSystemBandWidth();
2646
2647 int nvarcoeffs = mkey.GetNVarCoeffs();
2648 MatrixStorage matStorage;
2649
2650 map<int, RobinBCInfoSharedPtr> RobinBCInfo = GetRobinBCInfo();
2651
2652 switch (mkey.GetMatrixType())
2653 {
2654 // case for all symmetric matices
2657 if ((2 * (bwidth + 1)) < rows)
2658 {
2661 rows, cols, zero, matStorage, bwidth, bwidth);
2662 }
2663 else
2664 {
2665 matStorage = ePOSITIVE_DEFINITE_SYMMETRIC;
2667 rows, cols, zero, matStorage);
2668 }
2669
2670 break;
2671 default: // Assume general matrix - currently only set up
2672 // for full invert
2673 {
2674 matStorage = eFULL;
2676 rows, cols, zero, matStorage);
2677 }
2678 }
2679
2680 // fill global symmetric matrix
2681 for (n = 0; n < (*m_exp).size(); ++n)
2682 {
2683 // need to be initialised with zero size for non
2684 // variable coefficient case
2685 StdRegions::VarCoeffMap varcoeffs;
2686
2687 eid = n;
2688 if (nvarcoeffs > 0)
2689 {
2690 varcoeffs = StdRegions::RestrictCoeffMap(
2691 mkey.GetVarCoeffs(), m_phys_offset[eid],
2692 (*m_exp)[eid]->GetTotPoints());
2693 }
2694
2696 mkey.GetMatrixType(), (*m_exp)[eid]->DetShapeType(),
2697 *((*m_exp)[eid]), mkey.GetConstFactors(), varcoeffs);
2698
2699 loc_mat =
2700 std::dynamic_pointer_cast<LocalRegions::Expansion>((*m_exp)[n])
2701 ->GetLocMatrix(matkey);
2702
2703 if (RobinBCInfo.count(n) != 0) // add robin mass matrix
2704 {
2706
2707 // declare local matrix from scaled matrix.
2708 int rows = loc_mat->GetRows();
2709 int cols = loc_mat->GetColumns();
2710 const NekDouble *dat = loc_mat->GetRawPtr();
2711 DNekMatSharedPtr new_mat =
2713 Blas::Dscal(rows * cols, loc_mat->Scale(), new_mat->GetRawPtr(), 1);
2714
2715 // add local matrix contribution
2716 for (rBC = RobinBCInfo.find(n)->second; rBC; rBC = rBC->next)
2717 {
2718 (*m_exp)[n]->AddRobinMassMatrix(
2719 rBC->m_robinID, rBC->m_robinPrimitiveCoeffs, new_mat);
2720 }
2721
2722 NekDouble one = 1.0;
2723 // redeclare loc_mat to point to new_mat plus the scalar.
2724 loc_mat =
2726 }
2727
2728 loc_lda = loc_mat->GetColumns();
2729
2730 for (i = 0; i < loc_lda; ++i)
2731 {
2732 gid1 = locToGloMap->GetLocalToGlobalMap(m_coeff_offset[n] + i) -
2733 NumDirBCs;
2734 sign1 = locToGloMap->GetLocalToGlobalSign(m_coeff_offset[n] + i);
2735 if (gid1 >= 0)
2736 {
2737 for (j = 0; j < loc_lda; ++j)
2738 {
2739 gid2 = locToGloMap->GetLocalToGlobalMap(m_coeff_offset[n] +
2740 j) -
2741 NumDirBCs;
2742 sign2 = locToGloMap->GetLocalToGlobalSign(
2743 m_coeff_offset[n] + j);
2744 if (gid2 >= 0)
2745 {
2746 // When global matrix is symmetric,
2747 // only add the value for the upper
2748 // triangular part in order to avoid
2749 // entries to be entered twice
2750 if ((matStorage == eFULL) || (gid2 >= gid1))
2751 {
2752 value = Gmat->GetValue(gid1, gid2) +
2753 sign1 * sign2 * (*loc_mat)(i, j);
2754 Gmat->SetValue(gid1, gid2, value);
2755 }
2756 }
2757 }
2758 }
2759 }
2760 }
2761
2762 return Gmat;
2763}
2764
2765/**
2766 * Consider a linear system
2767 * \f$\boldsymbol{M\hat{u}}_g=\boldsymbol{f}\f$ to be solved. Dependent
2768 * on the solution method, this function constructs
2769 * - <b>The full linear system</b><BR>
2770 * A call to the function #GenGlobalLinSysFullDirect
2771 * - <b>The statically condensed linear system</b><BR>
2772 * A call to the function #GenGlobalLinSysStaticCond
2773 *
2774 * @param mkey A key which uniquely defines the global
2775 * matrix to be constructed.
2776 * @param locToGloMap Contains the mapping array and required
2777 * information for the transformation from
2778 * local to global degrees of freedom.
2779 * @return (A shared pointer to) the global linear system in
2780 * required format.
2781 */
2783 const GlobalLinSysKey &mkey, const AssemblyMapCGSharedPtr &locToGloMap)
2784{
2785 GlobalLinSysSharedPtr returnlinsys;
2786 std::shared_ptr<ExpList> vExpList = GetSharedThisPtr();
2787
2789
2790 if (vType >= eSIZE_GlobalSysSolnType)
2791 {
2792 NEKERROR(ErrorUtil::efatal, "Matrix solution type not defined");
2793 }
2794 std::string vSolnType = MultiRegions::GlobalSysSolnTypeMap[vType];
2795
2796 return GetGlobalLinSysFactory().CreateInstance(vSolnType, mkey, vExpList,
2797 locToGloMap);
2798}
2799
2801 const GlobalLinSysKey &mkey, const AssemblyMapSharedPtr &locToGloMap)
2802{
2803 std::shared_ptr<ExpList> vExpList = GetSharedThisPtr();
2804 const map<int, RobinBCInfoSharedPtr> vRobinBCInfo = GetRobinBCInfo();
2805
2807
2808 if (vType >= eSIZE_GlobalSysSolnType)
2809 {
2810 NEKERROR(ErrorUtil::efatal, "Matrix solution type not defined");
2811 }
2812 std::string vSolnType = MultiRegions::GlobalSysSolnTypeMap[vType];
2813
2814 return GetGlobalLinSysFactory().CreateInstance(vSolnType, mkey, vExpList,
2815 locToGloMap);
2816}
2817
2818/**
2819 * Given the elemental coefficients \f$\hat{u}_n^e\f$ of
2820 * an expansion, this function evaluates the spectral/hp
2821 * expansion \f$u^{\delta}(\boldsymbol{x})\f$ at the
2822 * quadrature points \f$\boldsymbol{x}_i\f$. The operation
2823 * is evaluated locally by the elemental function
2824 * StdRegions#StdExpansion#BwdTrans.
2825 *
2826 * @param inarray An array of size \f$N_{\mathrm{eof}}\f$
2827 * containing the local coefficients
2828 * \f$\hat{u}_n^e\f$.
2829 * @param outarray The resulting physical values at the
2830 * quadrature points
2831 * \f$u^{\delta}(\boldsymbol{x}_i)\f$
2832 * will be stored in this array of size
2833 * \f$Q_{\mathrm{tot}}\f$.
2834 */
2835
2837 Array<OneD, NekDouble> &outarray)
2838{
2839 LibUtilities::Timer timer;
2840
2841 if (m_expType == e0D)
2842 {
2843 Vmath::Vcopy(m_ncoeffs, inarray, 1, outarray, 1);
2844 }
2845 else
2846 {
2847 // initialise if required
2849 {
2850 for (int i = 0; i < m_collections.size(); ++i)
2851 {
2853 }
2855 }
2856
2857 LIKWID_MARKER_START("v_BwdTrans");
2858 timer.Start();
2859
2861 int input_offset{0};
2862 int output_offset{0};
2863 for (int i = 0; i < m_collections.size(); ++i)
2864 {
2865 m_collections[i].ApplyOperator(Collections::eBwdTrans,
2866 inarray + input_offset,
2867 tmp = outarray + output_offset);
2868 input_offset +=
2869 m_collections[i].GetInputSize(Collections::eBwdTrans);
2870 output_offset +=
2871 m_collections[i].GetOutputSize(Collections::eBwdTrans);
2872 }
2873
2874 timer.Stop();
2875 LIKWID_MARKER_STOP("v_BwdTrans");
2876 }
2877 // Elapsed time
2878 timer.AccumulateRegion("Collections:BwdTrans", 10);
2879}
2880
2882 const Array<OneD, const NekDouble> &gloCoord)
2883{
2884 return GetExp(GetExpIndex(gloCoord));
2885}
2886
2887/**
2888 * @todo need a smarter search here that first just looks at bounding
2889 * vertices - suggest first seeing if point is within 10% of
2890 * region defined by vertices. The do point search.
2891 */
2893 NekDouble tol, bool returnNearestElmt, int cachedId,
2894 NekDouble maxDistance)
2895{
2896 Array<OneD, NekDouble> Lcoords(gloCoord.size());
2897
2898 return GetExpIndex(gloCoord, Lcoords, tol, returnNearestElmt, cachedId,
2899 maxDistance);
2900}
2901
2903 Array<OneD, NekDouble> &locCoords, NekDouble tol,
2904 bool returnNearestElmt, int cachedId,
2905 NekDouble maxDistance)
2906{
2907 if (GetNumElmts() == 0)
2908 {
2909 return -1;
2910 }
2911
2912 if (m_elmtToExpId.size() == 0)
2913 {
2914 // Loop in reverse order so that in case where using a
2915 // Homogeneous expansion it sets geometry ids to first part of
2916 // m_exp list. Otherwise will set to second (complex) expansion
2917 for (int i = (*m_exp).size() - 1; i >= 0; --i)
2918 {
2919 m_elmtToExpId[(*m_exp)[i]->GetGeom()->GetGlobalID()] = i;
2920 }
2921 }
2922
2923 NekDouble nearpt = 1e6;
2924 NekDouble nearpt_min = 1e6;
2925 int min_id = -1;
2926 Array<OneD, NekDouble> savLocCoords(locCoords.size());
2927
2928 if (cachedId >= 0 && cachedId < (*m_exp).size())
2929 {
2930 nearpt = 1e12;
2931 if ((*m_exp)[cachedId]->GetGeom()->ContainsPoint(gloCoords, locCoords,
2932 tol, nearpt))
2933 {
2934 return cachedId;
2935 }
2936 else if (returnNearestElmt && (nearpt < nearpt_min))
2937 {
2938 // If it does not lie within, keep track of which element
2939 // is nearest.
2940 min_id = cachedId;
2941 nearpt_min = nearpt;
2942 Vmath::Vcopy(locCoords.size(), locCoords, 1, savLocCoords, 1);
2943 }
2944 }
2945
2946 NekDouble x = (gloCoords.size() > 0 ? gloCoords[0] : 0.0);
2947 NekDouble y = (gloCoords.size() > 1 ? gloCoords[1] : 0.0);
2948 NekDouble z = (gloCoords.size() > 2 ? gloCoords[2] : 0.0);
2951 GetExp(0)->GetCoordim(), -1, x, y, z);
2952
2953 // Get the list of elements whose bounding box contains the desired
2954 // point.
2955 std::vector<int> elmts = m_graph->GetElementsContainingPoint(p);
2956
2957 // Check each element in turn to see if point lies within it.
2958 for (int i = 0; i < elmts.size(); ++i)
2959 {
2960 int id = m_elmtToExpId[elmts[i]];
2961 if (id == cachedId)
2962 {
2963 continue;
2964 }
2965 if ((*m_exp)[id]->GetGeom()->ContainsPoint(gloCoords, locCoords, tol,
2966 nearpt))
2967 {
2968 return id;
2969 }
2970 else if (returnNearestElmt && (nearpt < nearpt_min))
2971 {
2972 // If it does not lie within, keep track of which element
2973 // is nearest.
2974 min_id = id;
2975 nearpt_min = nearpt;
2976 Vmath::Vcopy(locCoords.size(), locCoords, 1, savLocCoords, 1);
2977 }
2978 }
2979
2980 // If the calling function is with just the nearest element, return
2981 // that. Otherwise return -1 to indicate no matching elemenet found.
2982 if (returnNearestElmt && nearpt_min <= maxDistance)
2983 {
2984
2985 std::string msg = "Failed to find point within element to "
2986 "tolerance of " +
2987 boost::lexical_cast<std::string>(tol) +
2988 " using local point (" +
2989 boost::lexical_cast<std::string>(locCoords[0]) + "," +
2990 boost::lexical_cast<std::string>(locCoords[1]) + "," +
2991 boost::lexical_cast<std::string>(locCoords[1]) +
2992 ") in element: " + std::to_string(min_id);
2993 WARNINGL1(false, msg.c_str());
2994
2995 Vmath::Vcopy(locCoords.size(), savLocCoords, 1, locCoords, 1);
2996 return min_id;
2997 }
2998 else
2999 {
3000 return -1;
3001 }
3002}
3003
3004/**
3005 * Given some coordinates, output the expansion field value at that
3006 * point
3007 */
3009 const Array<OneD, const NekDouble> &phys)
3010{
3011 int dim = GetCoordim(0);
3012 ASSERTL0(dim == coords.size(), "Invalid coordinate dimension.");
3013
3014 // Grab the element index corresponding to coords.
3015 Array<OneD, NekDouble> xi(dim);
3016 int elmtIdx = GetExpIndex(coords, xi);
3017 ASSERTL0(elmtIdx > 0, "Unable to find element containing point.");
3018
3019 // Grab that element's physical storage.
3020 Array<OneD, NekDouble> elmtPhys = phys + m_phys_offset[elmtIdx];
3021
3022 // Evaluate the element at the appropriate point.
3023 return (*m_exp)[elmtIdx]->StdPhysEvaluate(xi, elmtPhys);
3024}
3025
3026/**
3027 * Configures geometric info, such as tangent direction, on each
3028 * expansion.
3029 * @param graph2D Mesh
3030 */
3032{
3033}
3034
3035/**
3036 * @brief Reset geometry information, metrics, matrix managers and
3037 * geometry information.
3038 *
3039 * This routine clears all matrix managers and resets all geometry
3040 * information, which allows the geometry information to be dynamically
3041 * updated as the solver is run.
3042 */
3044{
3045 // Reset matrix managers.
3047 LocalRegions::MatrixKey::opLess>::ClearManager();
3049 LocalRegions::MatrixKey::opLess>::ClearManager();
3050
3051 // Loop over all elements and reset geometry information.
3052 for (int i = 0; i < m_exp->size(); ++i)
3053 {
3054 (*m_exp)[i]->GetGeom()->Reset(m_graph->GetCurvedEdges(),
3055 m_graph->GetCurvedFaces());
3056 }
3057
3058 // Loop over all elements and rebuild geometric factors.
3059 for (int i = 0; i < m_exp->size(); ++i)
3060 {
3061 (*m_exp)[i]->Reset();
3062 }
3063}
3064
3065/**
3066 * Write Tecplot Files Header
3067 * @param outfile Output file name.
3068 * @param var variables names
3069 */
3070void ExpList::v_WriteTecplotHeader(std::ostream &outfile, std::string var)
3071{
3072 if (GetNumElmts() == 0)
3073 {
3074 return;
3075 }
3076
3077 int coordim = GetExp(0)->GetCoordim();
3078 char vars[3] = {'x', 'y', 'z'};
3079
3080 if (m_expType == e3DH1D)
3081 {
3082 coordim += 1;
3083 }
3084 else if (m_expType == e3DH2D)
3085 {
3086 coordim += 2;
3087 }
3088
3089 outfile << "Variables = x";
3090 for (int i = 1; i < coordim; ++i)
3091 {
3092 outfile << ", " << vars[i];
3093 }
3094
3095 if (var.size() > 0)
3096 {
3097 outfile << ", " << var;
3098 }
3099
3100 outfile << std::endl << std::endl;
3101}
3102
3103/**
3104 * Write Tecplot Files Zone
3105 * @param outfile Output file name.
3106 * @param expansion Expansion that is considered
3107 */
3108void ExpList::v_WriteTecplotZone(std::ostream &outfile, int expansion)
3109{
3110 int i, j;
3111 int coordim = GetCoordim(0);
3112 int nPoints = GetTotPoints();
3113 int nBases = (*m_exp)[0]->GetNumBases();
3114 int numBlocks = 0;
3115
3117
3118 if (expansion == -1)
3119 {
3120 nPoints = GetTotPoints();
3121
3122 coords[0] = Array<OneD, NekDouble>(nPoints);
3123 coords[1] = Array<OneD, NekDouble>(nPoints);
3124 coords[2] = Array<OneD, NekDouble>(nPoints);
3125
3126 GetCoords(coords[0], coords[1], coords[2]);
3127
3128 for (i = 0; i < m_exp->size(); ++i)
3129 {
3130 int numInt = 1;
3131
3132 for (j = 0; j < nBases; ++j)
3133 {
3134 numInt *= (*m_exp)[i]->GetNumPoints(j) - 1;
3135 }
3136
3137 numBlocks += numInt;
3138 }
3139 }
3140 else
3141 {
3142 nPoints = (*m_exp)[expansion]->GetTotPoints();
3143
3144 coords[0] = Array<OneD, NekDouble>(nPoints);
3145 coords[1] = Array<OneD, NekDouble>(nPoints);
3146 coords[2] = Array<OneD, NekDouble>(nPoints);
3147
3148 (*m_exp)[expansion]->GetCoords(coords[0], coords[1], coords[2]);
3149
3150 numBlocks = 1;
3151 for (j = 0; j < nBases; ++j)
3152 {
3153 numBlocks *= (*m_exp)[expansion]->GetNumPoints(j) - 1;
3154 }
3155 }
3156
3157 if (m_expType == e3DH1D)
3158 {
3159 nBases += 1;
3160 coordim += 1;
3161 int nPlanes = GetZIDs().size();
3162 NekDouble tmp = numBlocks * (nPlanes - 1.0) / nPlanes;
3163 numBlocks = (int)tmp;
3164 }
3165 else if (m_expType == e3DH2D)
3166 {
3167 nBases += 2;
3168 coordim += 1;
3169 }
3170
3171 outfile << "Zone, N=" << nPoints << ", E=" << numBlocks << ", F=FEBlock";
3172
3173 switch (nBases)
3174 {
3175 case 2:
3176 outfile << ", ET=QUADRILATERAL" << std::endl;
3177 break;
3178 case 3:
3179 outfile << ", ET=BRICK" << std::endl;
3180 break;
3181 default:
3182 NEKERROR(ErrorUtil::efatal, "Not set up for this type of output");
3183 break;
3184 }
3185
3186 // Write out coordinates
3187 for (j = 0; j < coordim; ++j)
3188 {
3189 for (i = 0; i < nPoints; ++i)
3190 {
3191 outfile << coords[j][i] << " ";
3192 if (i % 1000 == 0 && i)
3193 {
3194 outfile << std::endl;
3195 }
3196 }
3197 outfile << std::endl;
3198 }
3199}
3200
3201void ExpList::v_WriteTecplotConnectivity(std::ostream &outfile, int expansion)
3202{
3203 int i, j, k, l;
3204 int nbase = (*m_exp)[0]->GetNumBases();
3205 int cnt = 0;
3206
3207 std::shared_ptr<LocalRegions::ExpansionVector> exp = m_exp;
3208
3209 if (expansion != -1)
3210 {
3211 exp = std::shared_ptr<LocalRegions::ExpansionVector>(
3213 (*exp)[0] = (*m_exp)[expansion];
3214 }
3215
3216 if (nbase == 2)
3217 {
3218 for (i = 0; i < (*exp).size(); ++i)
3219 {
3220 const int np0 = (*exp)[i]->GetNumPoints(0);
3221 const int np1 = (*exp)[i]->GetNumPoints(1);
3222
3223 for (j = 1; j < np1; ++j)
3224 {
3225 for (k = 1; k < np0; ++k)
3226 {
3227 outfile << cnt + (j - 1) * np0 + k << " ";
3228 outfile << cnt + (j - 1) * np0 + k + 1 << " ";
3229 outfile << cnt + j * np0 + k + 1 << " ";
3230 outfile << cnt + j * np0 + k << endl;
3231 }
3232 }
3233
3234 cnt += np0 * np1;
3235 }
3236 }
3237 else if (nbase == 3)
3238 {
3239 for (i = 0; i < (*exp).size(); ++i)
3240 {
3241 const int np0 = (*exp)[i]->GetNumPoints(0);
3242 const int np1 = (*exp)[i]->GetNumPoints(1);
3243 const int np2 = (*exp)[i]->GetNumPoints(2);
3244 const int np01 = np0 * np1;
3245
3246 for (j = 1; j < np2; ++j)
3247 {
3248 for (k = 1; k < np1; ++k)
3249 {
3250 for (l = 1; l < np0; ++l)
3251 {
3252 outfile << cnt + (j - 1) * np01 + (k - 1) * np0 + l
3253 << " ";
3254 outfile << cnt + (j - 1) * np01 + (k - 1) * np0 + l + 1
3255 << " ";
3256 outfile << cnt + (j - 1) * np01 + k * np0 + l + 1
3257 << " ";
3258 outfile << cnt + (j - 1) * np01 + k * np0 + l << " ";
3259 outfile << cnt + j * np01 + (k - 1) * np0 + l << " ";
3260 outfile << cnt + j * np01 + (k - 1) * np0 + l + 1
3261 << " ";
3262 outfile << cnt + j * np01 + k * np0 + l + 1 << " ";
3263 outfile << cnt + j * np01 + k * np0 + l << endl;
3264 }
3265 }
3266 }
3267 cnt += np0 * np1 * np2;
3268 }
3269 }
3270 else
3271 {
3272 NEKERROR(ErrorUtil::efatal, "Not set up for this dimension");
3273 }
3274}
3275
3276/**
3277 * Write Tecplot Files Field
3278 * @param outfile Output file name.
3279 * @param expansion Expansion that is considered
3280 */
3281void ExpList::v_WriteTecplotField(std::ostream &outfile, int expansion)
3282{
3283 if (expansion == -1)
3284 {
3285 int totpoints = GetTotPoints();
3286 if (m_physState == false)
3287 {
3289 }
3290
3291 for (int i = 0; i < totpoints; ++i)
3292 {
3293 outfile << m_phys[i] << " ";
3294 if (i % 1000 == 0 && i)
3295 {
3296 outfile << std::endl;
3297 }
3298 }
3299 outfile << std::endl;
3300 }
3301 else
3302 {
3303 int nPoints = (*m_exp)[expansion]->GetTotPoints();
3304
3305 for (int i = 0; i < nPoints; ++i)
3306 {
3307 outfile << m_phys[i + m_phys_offset[expansion]] << " ";
3308 }
3309
3310 outfile << std::endl;
3311 }
3312}
3313
3314void ExpList::WriteVtkHeader(std::ostream &outfile)
3315{
3316 outfile << "<?xml version=\"1.0\"?>" << endl;
3317 outfile << R"(<VTKFile type="UnstructuredGrid" version="0.1" )"
3318 << "byte_order=\"LittleEndian\">" << endl;
3319 outfile << " <UnstructuredGrid>" << endl;
3320}
3321
3322void ExpList::WriteVtkFooter(std::ostream &outfile)
3323{
3324 outfile << " </UnstructuredGrid>" << endl;
3325 outfile << "</VTKFile>" << endl;
3326}
3327
3328void ExpList::v_WriteVtkPieceHeader(std::ostream &outfile, int expansion,
3329 [[maybe_unused]] int istrip)
3330{
3331 int i, j, k;
3332 int nbase = (*m_exp)[expansion]->GetNumBases();
3333 int ntot = (*m_exp)[expansion]->GetTotPoints();
3334 int nquad[3];
3335
3336 int ntotminus = 1;
3337 for (i = 0; i < nbase; ++i)
3338 {
3339 nquad[i] = (*m_exp)[expansion]->GetNumPoints(i);
3340 ntotminus *= (nquad[i] - 1);
3341 }
3342
3343 Array<OneD, NekDouble> coords[3];
3344 coords[0] = Array<OneD, NekDouble>(ntot, 0.0);
3345 coords[1] = Array<OneD, NekDouble>(ntot, 0.0);
3346 coords[2] = Array<OneD, NekDouble>(ntot, 0.0);
3347 (*m_exp)[expansion]->GetCoords(coords[0], coords[1], coords[2]);
3348
3349 outfile << " <Piece NumberOfPoints=\"" << ntot << "\" NumberOfCells=\""
3350 << ntotminus << "\">" << endl;
3351 outfile << " <Points>" << endl;
3352 outfile << " <DataArray type=\"Float64\" "
3353 << R"(NumberOfComponents="3" format="ascii">)" << endl;
3354 outfile << " ";
3355 for (i = 0; i < ntot; ++i)
3356 {
3357 for (j = 0; j < 3; ++j)
3358 {
3359 outfile << setprecision(8) << scientific << (float)coords[j][i]
3360 << " ";
3361 }
3362 outfile << endl;
3363 }
3364 outfile << endl;
3365 outfile << " </DataArray>" << endl;
3366 outfile << " </Points>" << endl;
3367 outfile << " <Cells>" << endl;
3368 outfile << " <DataArray type=\"Int32\" "
3369 << R"(Name="connectivity" format="ascii">)" << endl;
3370
3371 int ns = 0; // pow(2,dim) for later usage
3372 string ostr;
3373 switch (m_expType)
3374 {
3375 case e1D:
3376 {
3377 ns = 2;
3378 ostr = "3 ";
3379 for (i = 0; i < nquad[0] - 1; ++i)
3380 {
3381 outfile << i << " " << i + 1 << endl;
3382 }
3383 }
3384 break;
3385 case e2D:
3386 {
3387 ns = 4;
3388 ostr = "9 ";
3389 for (i = 0; i < nquad[0] - 1; ++i)
3390 {
3391 for (j = 0; j < nquad[1] - 1; ++j)
3392 {
3393 outfile << j * nquad[0] + i << " " << j * nquad[0] + i + 1
3394 << " " << (j + 1) * nquad[0] + i + 1 << " "
3395 << (j + 1) * nquad[0] + i << endl;
3396 }
3397 }
3398 }
3399 break;
3400 case e3D:
3401 {
3402 ns = 8;
3403 ostr = "12 ";
3404 for (i = 0; i < nquad[0] - 1; ++i)
3405 {
3406 for (j = 0; j < nquad[1] - 1; ++j)
3407 {
3408 for (k = 0; k < nquad[2] - 1; ++k)
3409 {
3410 outfile
3411 << k * nquad[0] * nquad[1] + j * nquad[0] + i << " "
3412 << k * nquad[0] * nquad[1] + j * nquad[0] + i + 1
3413 << " "
3414 << k * nquad[0] * nquad[1] + (j + 1) * nquad[0] +
3415 i + 1
3416 << " "
3417 << k * nquad[0] * nquad[1] + (j + 1) * nquad[0] + i
3418 << " "
3419 << (k + 1) * nquad[0] * nquad[1] + j * nquad[0] + i
3420 << " "
3421 << (k + 1) * nquad[0] * nquad[1] + j * nquad[0] +
3422 i + 1
3423 << " "
3424 << (k + 1) * nquad[0] * nquad[1] +
3425 (j + 1) * nquad[0] + i + 1
3426 << " "
3427 << (k + 1) * nquad[0] * nquad[1] +
3428 (j + 1) * nquad[0] + i
3429 << " " << endl;
3430 }
3431 }
3432 }
3433 }
3434 break;
3435 default:
3436 break;
3437 }
3438
3439 outfile << endl;
3440 outfile << " </DataArray>" << endl;
3441 outfile << " <DataArray type=\"Int32\" "
3442 << R"(Name="offsets" format="ascii">)" << endl;
3443 for (i = 0; i < ntotminus; ++i)
3444 {
3445 outfile << i * ns + ns << " ";
3446 }
3447 outfile << endl;
3448 outfile << " </DataArray>" << endl;
3449 outfile << " <DataArray type=\"UInt8\" "
3450 << R"(Name="types" format="ascii">)" << endl;
3451 for (i = 0; i < ntotminus; ++i)
3452 {
3453 outfile << ostr;
3454 }
3455 outfile << endl;
3456 outfile << " </DataArray>" << endl;
3457 outfile << " </Cells>" << endl;
3458 outfile << " <PointData>" << endl;
3459}
3460
3461void ExpList::WriteVtkPieceFooter(std::ostream &outfile,
3462 [[maybe_unused]] int expansion)
3463{
3464 outfile << " </PointData>" << endl;
3465 outfile << " </Piece>" << endl;
3466}
3467
3468void ExpList::v_WriteVtkPieceData(std::ostream &outfile, int expansion,
3469 std::string var)
3470{
3471 int i;
3472 int nq = (*m_exp)[expansion]->GetTotPoints();
3473
3474 // printing the fields of that zone
3475 outfile << R"( <DataArray type="Float64" Name=")" << var << "\">"
3476 << endl;
3477 outfile << " ";
3478
3479 const Array<OneD, NekDouble> phys = m_phys + m_phys_offset[expansion];
3480
3481 for (i = 0; i < nq; ++i)
3482 {
3483 outfile << (fabs(phys[i]) < NekConstants::kNekZeroTol ? 0 : phys[i])
3484 << " ";
3485 }
3486 outfile << endl;
3487 outfile << " </DataArray>" << endl;
3488}
3489
3490/**
3491 * Given a spectral/hp approximation
3492 * \f$u^{\delta}(\boldsymbol{x})\f$ evaluated at the quadrature points
3493 * (which should be contained in #m_phys), this function calculates the
3494 * \f$L_\infty\f$ error of this approximation with respect to an exact
3495 * solution. The local distribution of the quadrature points allows an
3496 * elemental evaluation of this operation through the functions
3497 * StdRegions#StdExpansion#Linf.
3498 *
3499 * The exact solution, also evaluated at the quadrature
3500 * points, should be contained in the variable #m_phys of
3501 * the ExpList object \a Sol.
3502 *
3503 * @param soln A 1D array, containing the discrete
3504 * evaluation of the exact solution at the
3505 * quadrature points in its array #m_phys.
3506 * @return The \f$L_\infty\f$ error of the approximation.
3507 */
3509 const Array<OneD, const NekDouble> &soln)
3510{
3511 NekDouble err = 0.0;
3512
3513 if (soln == NullNekDouble1DArray)
3514 {
3515 err = Vmath::Vmax(m_npoints, inarray, 1);
3516 }
3517 else
3518 {
3519 for (int i = 0; i < m_npoints; ++i)
3520 {
3521 err = max(err, abs(inarray[i] - soln[i]));
3522 }
3523 }
3524
3525 m_comm->GetRowComm()->AllReduce(err, LibUtilities::ReduceMax);
3526
3527 return err;
3528}
3529
3530/**
3531 * Given a spectral/hp approximation \f$u^{\delta}(\boldsymbol{x})\f$
3532 * evaluated at the quadrature points (which should be contained in
3533 * #m_phys), this function calculates the \f$L_2\f$ error of this
3534 * approximation with respect to an exact solution. The local
3535 * distribution of the quadrature points allows an elemental evaluation
3536 * of this operation through the functions StdRegions#StdExpansion#L2.
3537 *
3538 * The exact solution, also evaluated at the quadrature points, should
3539 * be contained in the variable #m_phys of the ExpList object \a Sol.
3540 *
3541 * @param Sol An ExpList, containing the discrete
3542 * evaluation of the exact solution at the
3543 * quadrature points in its array #m_phys.
3544 * @return The \f$L_2\f$ error of the approximation.
3545 */
3547 const Array<OneD, const NekDouble> &soln)
3548{
3549 NekDouble err = 0.0, errl2;
3550 int i;
3551
3552 if (soln == NullNekDouble1DArray)
3553 {
3554 for (i = 0; i < (*m_exp).size(); ++i)
3555 {
3556 errl2 = (*m_exp)[i]->L2(inarray + m_phys_offset[i]);
3557 err += errl2 * errl2;
3558 }
3559 }
3560 else
3561 {
3562 for (i = 0; i < (*m_exp).size(); ++i)
3563 {
3564 errl2 = (*m_exp)[i]->L2(inarray + m_phys_offset[i],
3565 soln + m_phys_offset[i]);
3566 err += errl2 * errl2;
3567 }
3568 }
3569
3570 m_comm->GetRowComm()->AllReduce(err, LibUtilities::ReduceSum);
3571
3572 return sqrt(err);
3573}
3574
3575/**
3576 * The integration is evaluated locally, that is
3577 * \f[\int
3578 * f(\boldsymbol{x})d\boldsymbol{x}=\sum_{e=1}^{{N_{\mathrm{el}}}}
3579 * \left\{\int_{\Omega_e}f(\boldsymbol{x})d\boldsymbol{x}\right\}, \f]
3580 * where the integration over the separate elements is done by the
3581 * function StdRegions#StdExpansion#Integral, which discretely
3582 * evaluates the integral using Gaussian quadrature.
3583 *
3584 * @param inarray An array of size \f$Q_{\mathrm{tot}}\f$
3585 * containing the values of the function
3586 * \f$f(\boldsymbol{x})\f$ at the quadrature
3587 * points \f$\boldsymbol{x}_i\f$.
3588 * @return The value of the discretely evaluated integral
3589 * \f$\int f(\boldsymbol{x})d\boldsymbol{x}\f$.
3590 */
3592{
3593 NekDouble sum = 0.0;
3594 int i = 0;
3595
3596 for (i = 0; i < (*m_exp).size(); ++i)
3597 {
3598 sum += (*m_exp)[i]->Integral(inarray + m_phys_offset[i]);
3599 }
3600 m_comm->GetRowComm()->AllReduce(sum, LibUtilities::ReduceSum);
3601
3602 return sum;
3603}
3604
3606 const Array<OneD, Array<OneD, NekDouble>> &inarray)
3607{
3608 NekDouble flux = 0.0;
3609 int i = 0;
3610 int j;
3611
3612 for (i = 0; i < (*m_exp).size(); ++i)
3613 {
3614 Array<OneD, Array<OneD, NekDouble>> tmp(inarray.size());
3615 for (j = 0; j < inarray.size(); ++j)
3616 {
3617 tmp[j] = Array<OneD, NekDouble>(inarray[j] + m_phys_offset[i]);
3618 }
3619 flux += (*m_exp)[i]->VectorFlux(tmp);
3620 }
3621
3622 return flux;
3623}
3624
3626{
3628 "This method is not defined or valid for this class type");
3629 Array<OneD, NekDouble> NoEnergy(1, 0.0);
3630 return NoEnergy;
3631}
3632
3634{
3636 "This method is not defined or valid for this class type");
3638 return trans;
3639}
3640
3642{
3644 "This method is not defined or valid for this class type");
3645 NekDouble len = 0.0;
3646 return len;
3647}
3648
3649void ExpList::v_SetHomoLen([[maybe_unused]] const NekDouble lhom)
3650{
3652 "This method is not defined or valid for this class type");
3653}
3654
3656{
3658 "This method is not defined or valid for this class type");
3659 Array<OneD, unsigned int> NoModes(1);
3660 return NoModes;
3661}
3662
3664{
3666 "This method is not defined or valid for this class type");
3667 Array<OneD, unsigned int> NoModes(1);
3668 return NoModes;
3669}
3670
3672{
3674 "ClearGlobalLinSysManager not implemented for ExpList.");
3675}
3676
3677int ExpList::v_GetPoolCount([[maybe_unused]] std::string poolName)
3678{
3679 NEKERROR(ErrorUtil::efatal, "GetPoolCount not implemented for ExpList.");
3680 return -1;
3681}
3682
3684 [[maybe_unused]] bool clearLocalMatrices)
3685{
3687 "UnsetGlobalLinSys not implemented for ExpList.");
3688}
3689
3692{
3694 "GetGlobalLinSysManager not implemented for ExpList.");
3696}
3697
3698void ExpList::ExtractCoeffsFromFile(const std::string &fileName,
3700 const std::string &varName,
3701 Array<OneD, NekDouble> &coeffs)
3702{
3703 string varString = fileName.substr(0, fileName.find_last_of("."));
3704 int j, k, len = varString.length();
3705 varString = varString.substr(len - 1, len);
3706
3707 std::vector<LibUtilities::FieldDefinitionsSharedPtr> FieldDef;
3708 std::vector<std::vector<NekDouble>> FieldData;
3709
3710 std::string ft = LibUtilities::FieldIO::GetFileType(fileName, comm);
3713 ft, comm, m_session->GetSharedFilesystem());
3714
3715 f->Import(fileName, FieldDef, FieldData);
3716
3717 bool found = false;
3718 for (j = 0; j < FieldDef.size(); ++j)
3719 {
3720 for (k = 0; k < FieldDef[j]->m_fields.size(); ++k)
3721 {
3722 if (FieldDef[j]->m_fields[k] == varName)
3723 {
3724 // Copy FieldData into locExpList
3725 ExtractDataToCoeffs(FieldDef[j], FieldData[j],
3726 FieldDef[j]->m_fields[k], coeffs);
3727 found = true;
3728 }
3729 }
3730 }
3731
3732 ASSERTL0(found, "Could not find variable '" + varName +
3733 "' in file boundary condition " + fileName);
3734}
3735
3736/**
3737 * Given a spectral/hp approximation
3738 * \f$u^{\delta}(\boldsymbol{x})\f$ evaluated at the quadrature points
3739 * (which should be contained in #m_phys), this function calculates the
3740 * \f$H^1_2\f$ error of this approximation with respect to an exact
3741 * solution. The local distribution of the quadrature points allows an
3742 * elemental evaluation of this operation through the functions
3743 * StdRegions#StdExpansion#H1.
3744 *
3745 * The exact solution, also evaluated at the quadrature points, should
3746 * be contained in the variable #m_phys of the ExpList object \a Sol.
3747 *
3748 * @param soln An 1D array, containing the discrete evaluation
3749 * of the exact solution at the quadrature points.
3750 *
3751 * @return The \f$H^1_2\f$ error of the approximation.
3752 */
3754 const Array<OneD, const NekDouble> &soln)
3755{
3756 NekDouble err = 0.0, errh1;
3757 int i;
3758
3759 for (i = 0; i < (*m_exp).size(); ++i)
3760 {
3761 errh1 = (*m_exp)[i]->H1(inarray + m_phys_offset[i],
3762 soln + m_phys_offset[i]);
3763 err += errh1 * errh1;
3764 }
3765
3766 m_comm->GetRowComm()->AllReduce(err, LibUtilities::ReduceSum);
3767
3768 return sqrt(err);
3769}
3770
3772 std::vector<LibUtilities::FieldDefinitionsSharedPtr> &fielddef,
3773 int NumHomoDir, Array<OneD, LibUtilities::BasisSharedPtr> &HomoBasis,
3774 std::vector<NekDouble> &HomoLen, bool homoStrips,
3775 std::vector<unsigned int> &HomoSIDs, std::vector<unsigned int> &HomoZIDs,
3776 std::vector<unsigned int> &HomoYIDs)
3777{
3778 int startenum = (int)LibUtilities::eSegment;
3779 int endenum = (int)LibUtilities::eHexahedron;
3780 int s = 0;
3782
3783 ASSERTL1(NumHomoDir == HomoBasis.size(),
3784 "Homogeneous basis is not the same length as NumHomoDir");
3785 ASSERTL1(NumHomoDir == HomoLen.size(),
3786 "Homogeneous length vector is not the same length as NumHomDir");
3787
3788 // count number of shapes
3789 switch ((*m_exp)[0]->GetShapeDimension())
3790 {
3791 case 1:
3792 startenum = (int)LibUtilities::eSegment;
3793 endenum = (int)LibUtilities::eSegment;
3794 break;
3795 case 2:
3796 startenum = (int)LibUtilities::eTriangle;
3797 endenum = (int)LibUtilities::eQuadrilateral;
3798 break;
3799 case 3:
3800 startenum = (int)LibUtilities::eTetrahedron;
3801 endenum = (int)LibUtilities::eHexahedron;
3802 break;
3803 }
3804
3805 for (s = startenum; s <= endenum; ++s)
3806 {
3807 std::vector<unsigned int> elementIDs;
3808 std::vector<LibUtilities::BasisType> basis;
3809 std::vector<unsigned int> numModes;
3810 std::vector<std::string> fields;
3811
3812 bool first = true;
3813 bool UniOrder = true;
3814 int n;
3815
3816 shape = (LibUtilities::ShapeType)s;
3817
3818 for (int i = 0; i < (*m_exp).size(); ++i)
3819 {
3820 if ((*m_exp)[i]->GetGeom()->GetShapeType() == shape)
3821 {
3822 elementIDs.push_back((*m_exp)[i]->GetGeom()->GetGlobalID());
3823 if (first)
3824 {
3825 for (int j = 0; j < (*m_exp)[i]->GetNumBases(); ++j)
3826 {
3827 basis.push_back(
3828 (*m_exp)[i]->GetBasis(j)->GetBasisType());
3829 numModes.push_back(
3830 (*m_exp)[i]->GetBasis(j)->GetNumModes());
3831 }
3832
3833 // add homogeneous direction details if defined
3834 for (n = 0; n < NumHomoDir; ++n)
3835 {
3836 basis.push_back(HomoBasis[n]->GetBasisType());
3837 numModes.push_back(HomoBasis[n]->GetNumModes());
3838 }
3839
3840 first = false;
3841 }
3842 else
3843 {
3844 ASSERTL0(
3845 (*m_exp)[i]->GetBasis(0)->GetBasisType() == basis[0],
3846 "Routine is not set up for multiple bases definitions");
3847
3848 for (int j = 0; j < (*m_exp)[i]->GetNumBases(); ++j)
3849 {
3850 numModes.push_back(
3851 (*m_exp)[i]->GetBasis(j)->GetNumModes());
3852 if (numModes[j] !=
3853 (*m_exp)[i]->GetBasis(j)->GetNumModes())
3854 {
3855 UniOrder = false;
3856 }
3857 }
3858 // add homogeneous direction details if defined
3859 for (n = 0; n < NumHomoDir; ++n)
3860 {
3861 numModes.push_back(HomoBasis[n]->GetNumModes());
3862 }
3863 }
3864 }
3865 }
3866
3867 if (elementIDs.size() > 0)
3868 {
3871 AllocateSharedPtr(shape, elementIDs, basis, UniOrder,
3872 numModes, fields, NumHomoDir, HomoLen,
3873 homoStrips, HomoSIDs, HomoZIDs, HomoYIDs);
3874 fielddef.push_back(fdef);
3875 }
3876 }
3877}
3878
3879//
3880// Virtual functions
3881//
3882std::vector<LibUtilities::FieldDefinitionsSharedPtr> ExpList::
3884{
3885 std::vector<LibUtilities::FieldDefinitionsSharedPtr> returnval;
3886 v_GetFieldDefinitions(returnval);
3887 return returnval;
3888}
3889
3891 std::vector<LibUtilities::FieldDefinitionsSharedPtr> &fielddef)
3892{
3894}
3895
3896// Append the element data listed in elements
3897// fielddef->m_ElementIDs onto fielddata
3900 std::vector<NekDouble> &fielddata)
3901{
3902 v_AppendFieldData(fielddef, fielddata, m_coeffs);
3903}
3904
3907 std::vector<NekDouble> &fielddata, Array<OneD, NekDouble> &coeffs)
3908{
3909 int i;
3910 // Determine mapping from element ids to location in
3911 // expansion list
3912 // Determine mapping from element ids to location in
3913 // expansion list
3914 map<int, int> ElmtID_to_ExpID;
3915 for (i = 0; i < (*m_exp).size(); ++i)
3916 {
3917 ElmtID_to_ExpID[(*m_exp)[i]->GetGeom()->GetGlobalID()] = i;
3918 }
3919
3920 for (i = 0; i < fielddef->m_elementIDs.size(); ++i)
3921 {
3922 int eid = ElmtID_to_ExpID[fielddef->m_elementIDs[i]];
3923 int datalen = (*m_exp)[eid]->GetNcoeffs();
3924 fielddata.insert(fielddata.end(), &coeffs[m_coeff_offset[eid]],
3925 &coeffs[m_coeff_offset[eid]] + datalen);
3926 }
3927}
3928
3929/// Extract the data in fielddata into the coeffs
3932 std::vector<NekDouble> &fielddata, std::string &field,
3933 Array<OneD, NekDouble> &coeffs, std::unordered_map<int, int> zIdToPlane)
3934{
3935 v_ExtractDataToCoeffs(fielddef, fielddata, field, coeffs, zIdToPlane);
3936}
3937
3939 const std::shared_ptr<ExpList> &fromExpList,
3940 const Array<OneD, const NekDouble> &fromCoeffs,
3941 Array<OneD, NekDouble> &toCoeffs)
3942{
3943 v_ExtractCoeffsToCoeffs(fromExpList, fromCoeffs, toCoeffs);
3944}
3945
3946/**
3947 * @brief Extract data from raw field data into expansion list.
3948 *
3949 * @param fielddef Field definitions.
3950 * @param fielddata Data for associated field.
3951 * @param field Field variable name.
3952 * @param coeffs Resulting coefficient array.
3953 */
3956 std::vector<NekDouble> &fielddata, std::string &field,
3957 Array<OneD, NekDouble> &coeffs,
3958 [[maybe_unused]] std::unordered_map<int, int> zIdToPlane)
3959{
3960 int i, expId;
3961 int offset = 0;
3962 int modes_offset = 0;
3963 int datalen = fielddata.size() / fielddef->m_fields.size();
3964
3965 // Find data location according to field definition
3966 for (i = 0; i < fielddef->m_fields.size(); ++i)
3967 {
3968 if (fielddef->m_fields[i] == field)
3969 {
3970 break;
3971 }
3972 offset += datalen;
3973 }
3974
3975 ASSERTL0(i != fielddef->m_fields.size(),
3976 "Field (" + field + ") not found in file.");
3977
3978 if (m_elmtToExpId.size() == 0)
3979 {
3980 // Loop in reverse order so that in case where using a
3981 // Homogeneous expansion it sets geometry ids to first part of
3982 // m_exp list. Otherwise will set to second (complex) expansion
3983 for (i = (*m_exp).size() - 1; i >= 0; --i)
3984 {
3985 m_elmtToExpId[(*m_exp)[i]->GetGeom()->GetGlobalID()] = i;
3986 }
3987 }
3988
3989 for (i = 0; i < fielddef->m_elementIDs.size(); ++i)
3990 {
3991 // Reset modes_offset in the case where all expansions of
3992 // the same order.
3993 if (fielddef->m_uniOrder == true)
3994 {
3995 modes_offset = 0;
3996 }
3997
3999 fielddef->m_shapeType, fielddef->m_numModes, modes_offset);
4000
4001 const int elmtId = fielddef->m_elementIDs[i];
4002 auto eIt = m_elmtToExpId.find(elmtId);
4003
4004 if (eIt == m_elmtToExpId.end())
4005 {
4006 offset += datalen;
4007 modes_offset += (*m_exp)[0]->GetNumBases();
4008 continue;
4009 }
4010
4011 expId = eIt->second;
4012
4013 bool sameBasis = true;
4014 for (int j = 0; j < fielddef->m_basis.size(); ++j)
4015 {
4016 if (fielddef->m_basis[j] != (*m_exp)[expId]->GetBasisType(j))
4017 {
4018 sameBasis = false;
4019 break;
4020 }
4021 }
4022
4023 if (datalen == (*m_exp)[expId]->GetNcoeffs() && sameBasis)
4024 {
4025 Vmath::Vcopy(datalen, &fielddata[offset], 1,
4026 &coeffs[m_coeff_offset[expId]], 1);
4027 }
4028 else
4029 {
4030 (*m_exp)[expId]->ExtractDataToCoeffs(
4031 &fielddata[offset], fielddef->m_numModes, modes_offset,
4032 &coeffs[m_coeff_offset[expId]], fielddef->m_basis);
4033 }
4034
4035 offset += datalen;
4036 modes_offset += (*m_exp)[0]->GetNumBases();
4037 }
4038
4039 return;
4040}
4041
4043 const std::shared_ptr<ExpList> &fromExpList,
4044 const Array<OneD, const NekDouble> &fromCoeffs,
4045 Array<OneD, NekDouble> &toCoeffs)
4046{
4047 int i;
4048 int offset = 0;
4049
4050 for (i = 0; i < (*m_exp).size(); ++i)
4051 {
4052 std::vector<unsigned int> nummodes;
4053 vector<LibUtilities::BasisType> basisTypes;
4054 for (int j = 0; j < fromExpList->GetExp(i)->GetNumBases(); ++j)
4055 {
4056 nummodes.push_back(fromExpList->GetExp(i)->GetBasisNumModes(j));
4057 basisTypes.push_back(fromExpList->GetExp(i)->GetBasisType(j));
4058 }
4059
4060 (*m_exp)[i]->ExtractDataToCoeffs(&fromCoeffs[offset], nummodes, 0,
4061 &toCoeffs[m_coeff_offset[i]],
4062 basisTypes);
4063
4064 offset += fromExpList->GetExp(i)->GetNcoeffs();
4065 }
4066}
4067
4068/**
4069 * Get the weight value on boundaries
4070 */
4072 Array<OneD, NekDouble> &weightJump)
4073{
4074 size_t nTracePts = weightAver.size();
4075 // average for interior traces
4076 for (int i = 0; i < nTracePts; ++i)
4077 {
4078 weightAver[i] = 0.5;
4079 weightJump[i] = 1.0;
4080 }
4081 FillBwdWithBwdWeight(weightAver, weightJump);
4082}
4083
4085 const Array<OneD, const NekDouble> &CircCentre,
4086 Array<OneD, Array<OneD, NekDouble>> &outarray)
4087{
4088 int npts;
4089
4090 int MFdim = 3;
4091 int nq = outarray[0].size() / MFdim;
4092
4093 // Assume whole array is of same coordinate dimension
4094 int coordim = (*m_exp)[0]->GetGeom()->GetCoordim();
4095
4096 Array<OneD, Array<OneD, NekDouble>> MFloc(MFdim * coordim);
4097 // Process each expansion.
4098 for (int i = 0; i < m_exp->size(); ++i)
4099 {
4100 npts = (*m_exp)[i]->GetTotPoints();
4101
4102 for (int j = 0; j < MFdim * coordim; ++j)
4103 {
4104 MFloc[j] = Array<OneD, NekDouble>(npts, 0.0);
4105 }
4106
4107 // MF from LOCALREGIONS
4108 (*m_exp)[i]->GetMetricInfo()->GetMovingFrames(
4109 (*m_exp)[i]->GetPointsKeys(), MMFdir, CircCentre, MFloc);
4110
4111 // Get the physical data offset for this expansion.
4112 for (int j = 0; j < MFdim; ++j)
4113 {
4114 for (int k = 0; k < coordim; ++k)
4115 {
4116 Vmath::Vcopy(npts, &MFloc[j * coordim + k][0], 1,
4117 &outarray[j][k * nq + m_phys_offset[i]], 1);
4118 }
4119 }
4120 }
4121}
4122
4123/**
4124 * @brief Generate vector v such that v[i] = scalar1 if i is in the
4125 * element < ElementID. Otherwise, v[i] = scalar2.
4126 *
4127 */
4128void ExpList::GenerateElementVector(const int ElementID,
4129 const NekDouble scalar1,
4130 const NekDouble scalar2,
4131 Array<OneD, NekDouble> &outarray)
4132{
4133 int npoints_e;
4134 NekDouble coeff;
4135
4136 Array<OneD, NekDouble> outarray_e;
4137
4138 for (int i = 0; i < (*m_exp).size(); ++i)
4139 {
4140 npoints_e = (*m_exp)[i]->GetTotPoints();
4141
4142 if (i <= ElementID)
4143 {
4144 coeff = scalar1;
4145 }
4146 else
4147 {
4148 coeff = scalar2;
4149 }
4150
4151 outarray_e = Array<OneD, NekDouble>(npoints_e, coeff);
4152 Vmath::Vcopy(npoints_e, &outarray_e[0], 1, &outarray[m_phys_offset[i]],
4153 1);
4154 }
4155}
4156
4159{
4161 "This method is not defined or valid for this class type");
4163 return result;
4164}
4165
4166std::shared_ptr<ExpList> &ExpList::v_UpdateBndCondExpansion(
4167 [[maybe_unused]] int i)
4168{
4170 "This method is not defined or valid for this class type");
4171 static std::shared_ptr<ExpList> result;
4172 return result;
4173}
4174
4175/**
4176 * Upwind the left and right states given by the Arrays Fwd and Bwd
4177 * using the vector quantity Vec and ouput the upwinded value in the
4178 * array upwind.
4179 *
4180 * @param Vec Velocity field.
4181 * @param Fwd Left state.
4182 * @param Bwd Right state.
4183 * @param Upwind Output vector.
4184 */
4188 Array<OneD, NekDouble> &Upwind)
4189{
4190 switch (m_expType)
4191 {
4192 case e1D:
4193 {
4194 int i, j, k, e_npoints, offset;
4195 Array<OneD, NekDouble> normals;
4196 NekDouble Vn;
4197
4198 // Assume whole array is of same coordimate dimension
4199 int coordim = GetCoordim(0);
4200
4201 ASSERTL1(Vec.size() >= coordim,
4202 "Input vector does not have sufficient dimensions to "
4203 "match coordim");
4204
4205 // Process each expansion
4206 for (i = 0; i < m_exp->size(); ++i)
4207 {
4208 // Get the number of points in the expansion and the normals.
4209 e_npoints = (*m_exp)[i]->GetNumPoints(0);
4210 normals = (*m_exp)[i]->GetPhysNormals();
4211
4212 // Get the physical data offset of the expansion in m_phys.
4213 offset = m_phys_offset[i];
4214
4215 // Compute each data point.
4216 for (j = 0; j < e_npoints; ++j)
4217 {
4218 // Calculate normal velocity.
4219 Vn = 0.0;
4220 for (k = 0; k < coordim; ++k)
4221 {
4222 Vn += Vec[k][offset + j] * normals[k * e_npoints + j];
4223 }
4224
4225 // Upwind based on direction of normal velocity.
4226 if (Vn > 0.0)
4227 {
4228 Upwind[offset + j] = Fwd[offset + j];
4229 }
4230 else
4231 {
4232 Upwind[offset + j] = Bwd[offset + j];
4233 }
4234 }
4235 }
4236 }
4237 break;
4238 default:
4240 "This method is not defined or valid for this class type");
4241 break;
4242 }
4243}
4244
4245/**
4246 * One-dimensional upwind.
4247 * \see ExpList::Upwind(
4248 * const Array<OneD, const Array<OneD, NekDouble> >,
4249 * const Array<OneD, const NekDouble>,
4250 * const Array<OneD, const NekDouble>,
4251 * Array<OneD, NekDouble>, int)
4252 *
4253 * @param Vn Velocity field.
4254 * @param Fwd Left state.
4255 * @param Bwd Right state.
4256 * @param Upwind Output vector.
4257 */
4261 Array<OneD, NekDouble> &Upwind)
4262{
4263 ASSERTL1(Vn.size() >= m_npoints, "Vn is not of sufficient length");
4264 ASSERTL1(Fwd.size() >= m_npoints, "Fwd is not of sufficient length");
4265 ASSERTL1(Bwd.size() >= m_npoints, "Bwd is not of sufficient length");
4266 ASSERTL1(Upwind.size() >= m_npoints, "Upwind is not of sufficient length");
4267
4268 // Process each point in the expansion.
4269 for (int j = 0; j < m_npoints; ++j)
4270 {
4271 // Upwind based on one-dimensional velocity.
4272 if (Vn[j] > 0.0)
4273 {
4274 Upwind[j] = Fwd[j];
4275 }
4276 else
4277 {
4278 Upwind[j] = Bwd[j];
4279 }
4280 }
4281}
4282
4283std::shared_ptr<ExpList> &ExpList::v_GetTrace()
4284{
4286 "This method is not defined or valid for this class type");
4287 static std::shared_ptr<ExpList> returnVal;
4288 return returnVal;
4289}
4290
4291std::shared_ptr<AssemblyMapDG> &ExpList::v_GetTraceMap()
4292{
4294 "This method is not defined or valid for this class type");
4295 static std::shared_ptr<AssemblyMapDG> result;
4296 return result;
4297}
4298
4300{
4301 return GetTraceMap()->GetBndCondIDToGlobalTraceID();
4302}
4303
4305{
4307 "This method is not defined or valid for this class type");
4308 static std::vector<bool> result;
4309 return result;
4310}
4311
4312/**
4313 * @brief Helper function to re-align face to a given orientation.
4314 */
4315void AlignFace(const StdRegions::Orientation orient, const int nquad1,
4316 const int nquad2, const Array<OneD, const NekDouble> &in,
4318{
4319 // Copy transpose.
4324 {
4325 for (int i = 0; i < nquad2; ++i)
4326 {
4327 for (int j = 0; j < nquad1; ++j)
4328 {
4329 out[i * nquad1 + j] = in[j * nquad2 + i];
4330 }
4331 }
4332 }
4333 else
4334 {
4335 for (int i = 0; i < nquad2; ++i)
4336 {
4337 for (int j = 0; j < nquad1; ++j)
4338 {
4339 out[i * nquad1 + j] = in[i * nquad1 + j];
4340 }
4341 }
4342 }
4343
4348 {
4349 // Reverse x direction
4350 for (int i = 0; i < nquad2; ++i)
4351 {
4352 for (int j = 0; j < nquad1 / 2; ++j)
4353 {
4354 swap(out[i * nquad1 + j], out[i * nquad1 + nquad1 - j - 1]);
4355 }
4356 }
4357 }
4358
4363 {
4364 // Reverse y direction
4365 for (int j = 0; j < nquad1; ++j)
4366 {
4367 for (int i = 0; i < nquad2 / 2; ++i)
4368 {
4369 swap(out[i * nquad1 + j], out[(nquad2 - i - 1) * nquad1 + j]);
4370 }
4371 }
4372 }
4373}
4374
4375/**
4376 * For each local element, copy the normals stored in the element list
4377 * into the array \a normals. This function should only be called by a
4378 * trace explist, which has setup the left and right adjacent elements.
4379 * @param normals Two dimensional array in which to copy normals
4380 * to. The first dimension is the coordim. The
4381 * second dimension is the same size as trace phys
4382 * space.
4383 */
4385{
4386 int i, j, k, e_npoints, offset;
4388
4389 // Assume whole array is of same coordinate dimension
4390 int coordim = GetCoordim(0);
4391
4392 ASSERTL1(normals.size() >= coordim,
4393 "Output vector does not have sufficient dimensions to "
4394 "match coordim");
4395
4396 switch (m_expType)
4397 {
4398 case e0D:
4399 {
4400 // Process each expansion.
4401 for (i = 0; i < m_exp->size(); ++i)
4402 {
4403 LocalRegions::ExpansionSharedPtr loc_exp = (*m_exp)[i];
4404
4406 loc_exp->GetLeftAdjacentElementExp();
4407
4408 // Get the number of points and normals for this expansion.
4409 e_npoints = 1;
4410 locnormals = loc_elmt->GetTraceNormal(
4411 loc_exp->GetLeftAdjacentElementTrace());
4412
4413 // Get the physical data offset for this expansion.
4414 offset = m_phys_offset[i];
4415
4416 // Process each point in the expansion.
4417 for (j = 0; j < e_npoints; ++j)
4418 {
4419 // Process each spatial dimension and copy the
4420 // values into the output array.
4421 for (k = 0; k < coordim; ++k)
4422 {
4423 normals[k][offset] = locnormals[k][0];
4424 }
4425 }
4426 }
4427 }
4428 break;
4429 case e1D:
4430 {
4431 // Process each (trace) expansion.
4432 for (i = 0; i < m_exp->size(); ++i)
4433 {
4434 LocalRegions::ExpansionSharedPtr traceExp = (*m_exp)[i];
4435 // location of this normal vector in the output array.
4436 int offset = m_phys_offset[i];
4437
4438 // Get number of points from left expansion.
4440 traceExp->GetLeftAdjacentElementExp();
4441 int edgeId = traceExp->GetLeftAdjacentElementTrace();
4442 LibUtilities::PointsKey edgePoints =
4443 exp2D->GetTraceBasisKey(edgeId).GetPointsKey();
4444 LibUtilities::PointsKey tracePoints =
4445 traceExp->GetBasis(0)->GetPointsKey();
4446
4447 // If right adjacent element exists, then we compare
4448 // the left and right side and take the one with
4449 // the highest number of points to compute the
4450 // local normals. However, it's a question whether
4451 // this effort pays off.
4452 bool useRight = false;
4453 if (traceExp->GetRightAdjacentElementTrace() >= 0)
4454 {
4456 traceExp->GetRightAdjacentElementExp();
4457 int RedgeId = traceExp->GetRightAdjacentElementTrace();
4458 LibUtilities::PointsKey RedgePoints =
4459 Rexp2D->GetTraceBasisKey(RedgeId).GetPointsKey();
4460
4461 if (RedgePoints.GetNumPoints() > edgePoints.GetNumPoints())
4462 {
4463 exp2D = Rexp2D;
4464 edgeId = RedgeId;
4465 edgePoints = RedgePoints;
4466 useRight = true;
4467 }
4468 }
4469
4470 const Array<OneD, const Array<OneD, NekDouble>> &locNormals =
4471 exp2D->GetTraceNormal(edgeId);
4472
4473 // For unknown reason, GetTraceNormal(2D) returns normals
4474 // that has been reoriented to trace order.
4475 // So here we don't need to reorient them again.
4476 for (int d = 0; d < coordim; ++d)
4477 {
4478 LibUtilities::Interp1D(edgePoints, locNormals[d].data(),
4479 tracePoints,
4480 normals[d].data() + offset);
4481 // Trace normal direction is always the outward
4482 // direction of the left element.
4483 if (useRight)
4484 {
4485 Vmath::Neg((int)tracePoints.GetNumPoints(),
4486 &normals[d][offset], 1);
4487 }
4488 }
4489 }
4490 }
4491 break;
4492 case e2D:
4493 {
4495
4496 // Process each expansion.
4497 for (i = 0; i < m_exp->size(); ++i)
4498 {
4499 LocalRegions::ExpansionSharedPtr traceExp = (*m_exp)[i];
4500 // location of this normal vector in the output array.
4501 int offset = m_phys_offset[i];
4502
4503 // Get the normals from left expansion.
4504 // NOTE:
4505 // One can choose to compare the left and right side and take
4506 // the one with the highest number of points to compute the
4507 // local normals. Here are 2 reasons why we don't do so:
4508 // 1.
4509 // in general two adjacent elements must share a common
4510 // cuerved edge/face, which can be precisely described even by
4511 // the lower-order side. Even if the two sides are not exactly
4512 // the same, it should not affect the convergence of solution.
4513 // 2.
4514 // In 3D, it's hard to define which is side has higher order.
4515 // The left-side may have higher order in axis 0 but lower in
4516 // axis 1. It's too complicated and not worth the effort.
4518 traceExp->GetLeftAdjacentElementExp();
4519 int faceId = traceExp->GetLeftAdjacentElementTrace();
4520 const Array<OneD, const Array<OneD, NekDouble>> &locNormals =
4521 exp3D->GetTraceNormal(faceId);
4522
4523 StdRegions::Orientation orient = exp3D->GetTraceOrient(faceId);
4524
4525 // swap local basiskey 0 and 1 if orientation is transposed
4526 // (>=9)
4527 int fromid0, fromid1;
4528
4530 {
4531 fromid0 = 0;
4532 fromid1 = 1;
4533 }
4534 else
4535 {
4536 fromid0 = 1;
4537 fromid1 = 0;
4538 }
4539
4540 LibUtilities::BasisKey faceBasis0 =
4541 exp3D->GetTraceBasisKey(faceId, fromid0);
4542 LibUtilities::BasisKey faceBasis1 =
4543 exp3D->GetTraceBasisKey(faceId, fromid1);
4544 LibUtilities::BasisKey traceBasis0 =
4545 traceExp->GetBasis(0)->GetBasisKey();
4546 LibUtilities::BasisKey traceBasis1 =
4547 traceExp->GetBasis(1)->GetBasisKey();
4548
4549 const int faceNq0 = faceBasis0.GetNumPoints();
4550 const int faceNq1 = faceBasis1.GetNumPoints();
4551
4552 // Reorient normals from stdExp definition onto the same
4553 // orientation as the trace expansion.(also match the
4554 // swapped local basiskey)
4555 Array<OneD, int> map;
4556 exp3D->ReOrientTracePhysMap(orient, map, faceNq0, faceNq1);
4557
4558 // Perform reorientation and interpolation.
4559 Array<OneD, NekDouble> traceNormals(faceNq0 * faceNq1);
4560 for (j = 0; j < coordim; ++j)
4561 {
4562 Vmath::Scatr(faceNq0 * faceNq1, locNormals[j], map,
4563 traceNormals);
4564
4566 faceBasis0.GetPointsKey(), faceBasis1.GetPointsKey(),
4567 traceNormals, traceBasis0.GetPointsKey(),
4568 traceBasis1.GetPointsKey(), tmp = normals[j] + offset);
4569 }
4570 }
4571 }
4572 break;
4573 default:
4574 {
4576 "This method is not defined or valid for this class type");
4577 }
4578 }
4579}
4580
4581/**
4582 * Returns the element normal length for each trace expansion. The array
4583 * has the same size as trace phys space. This function should only be
4584 * called by a trace explist, which has setup the left and right adjacent
4585 * elements.
4586 * This function is only used by DiffusionIP to commpute the penalty.
4587 * However, it's a question whether we need to calculate the lengthFwd
4588 * and lengthBwd separately, since in most cases, they are equavalent.
4589 * Same logic applies to v_GetNormals().
4590 * @param lengthsFwd Output array of normal lengths for left side.
4591 * @param lengthsBwd Output array of normal lengths for right side.
4592 */
4594 Array<OneD, NekDouble> &lengthsBwd)
4595{
4596 int e_npoints;
4597
4598 Array<OneD, NekDouble> locLeng;
4601 Array<OneD, int> LRbndnumbs(2);
4603 lengLR[0] = lengthsFwd;
4604 lengLR[1] = lengthsBwd;
4608 int e_npoints0 = -1;
4609 if (m_expType == e1D)
4610 {
4611 for (int i = 0; i < m_exp->size(); ++i)
4612 {
4613 loc_exp = (*m_exp)[i];
4614 int offset = m_phys_offset[i];
4615
4616 e_npoints = (*m_exp)[i]->GetNumPoints(0);
4617 if (e_npoints0 < e_npoints)
4618 {
4619 for (int nlr = 0; nlr < 2; nlr++)
4620 {
4621 lengintp[nlr] = Array<OneD, NekDouble>(e_npoints, 0.0);
4622 }
4623 e_npoints0 = e_npoints;
4624 }
4625
4626 LRelmts[0] = loc_exp->GetLeftAdjacentElementExp();
4627 LRelmts[1] = loc_exp->GetRightAdjacentElementExp();
4628
4629 LRbndnumbs[0] = loc_exp->GetLeftAdjacentElementTrace();
4630 LRbndnumbs[1] = loc_exp->GetRightAdjacentElementTrace();
4631 for (int nlr = 0; nlr < 2; ++nlr)
4632 {
4633 Vmath::Zero(e_npoints0, lengintp[nlr], 1);
4634 lengAdd[nlr] = lengintp[nlr];
4635 int bndNumber = LRbndnumbs[nlr];
4636 loc_elmt = LRelmts[nlr];
4637 if (bndNumber >= 0)
4638 {
4639 locLeng = loc_elmt->GetElmtBndNormDirElmtLen(bndNumber);
4640
4642 loc_exp->GetBasis(0)->GetPointsKey();
4643 LibUtilities::PointsKey from_key =
4644 loc_elmt->GetTraceBasisKey(bndNumber).GetPointsKey();
4645
4646 // For unknown reason, GetTraceNormal(2D) returns normals
4647 // that has been reoriented to trace order.
4648 // So here we don't need to reorient them again.
4649
4650 // Always do interpolation
4651 LibUtilities::Interp1D(from_key, locLeng, to_key,
4652 lengintp[nlr]);
4653 lengAdd[nlr] = lengintp[nlr];
4654 }
4655
4656 for (int j = 0; j < e_npoints; ++j)
4657 {
4658 lengLR[nlr][offset + j] = lengAdd[nlr][j];
4659 }
4660 }
4661 }
4662 }
4663 else if (m_expType == e2D)
4664 {
4665 for (int i = 0; i < m_exp->size(); ++i)
4666 {
4667 loc_exp = (*m_exp)[i];
4668 int offset = m_phys_offset[i];
4669
4670 LibUtilities::BasisKey traceBasis0 =
4671 loc_exp->GetBasis(0)->GetBasisKey();
4672 LibUtilities::BasisKey traceBasis1 =
4673 loc_exp->GetBasis(1)->GetBasisKey();
4674 const int TraceNq0 = traceBasis0.GetNumPoints();
4675 const int TraceNq1 = traceBasis1.GetNumPoints();
4676 e_npoints = TraceNq0 * TraceNq1;
4677 if (e_npoints0 < e_npoints)
4678 {
4679 for (int nlr = 0; nlr < 2; nlr++)
4680 {
4681 lengintp[nlr] = Array<OneD, NekDouble>(e_npoints, 0.0);
4682 }
4683 e_npoints0 = e_npoints;
4684 }
4685
4686 LRelmts[0] = loc_exp->GetLeftAdjacentElementExp();
4687 LRelmts[1] = loc_exp->GetRightAdjacentElementExp();
4688
4689 LRbndnumbs[0] = loc_exp->GetLeftAdjacentElementTrace();
4690 LRbndnumbs[1] = loc_exp->GetRightAdjacentElementTrace();
4691 for (int nlr = 0; nlr < 2; ++nlr)
4692 {
4693 Vmath::Zero(e_npoints0, lengintp[nlr], 1);
4694 int bndNumber = LRbndnumbs[nlr];
4695 loc_elmt = LRelmts[nlr];
4696 if (bndNumber >= 0)
4697 {
4698 locLeng = loc_elmt->GetElmtBndNormDirElmtLen(bndNumber);
4699 // Project normals from 3D element onto the
4700 // same orientation as the trace expansion.
4702 loc_elmt->GetTraceOrient(bndNumber);
4703
4704 int fromid0, fromid1;
4706 {
4707 fromid0 = 0;
4708 fromid1 = 1;
4709 }
4710 else
4711 {
4712 fromid0 = 1;
4713 fromid1 = 0;
4714 }
4715
4716 LibUtilities::BasisKey faceBasis0 =
4717 loc_elmt->GetTraceBasisKey(bndNumber, fromid0);
4718 LibUtilities::BasisKey faceBasis1 =
4719 loc_elmt->GetTraceBasisKey(bndNumber, fromid1);
4720 const int faceNq0 = faceBasis0.GetNumPoints();
4721 const int faceNq1 = faceBasis1.GetNumPoints();
4722 Array<OneD, NekDouble> alignedLeng(faceNq0 * faceNq1);
4723
4724 AlignFace(orient, faceNq0, faceNq1, locLeng, alignedLeng);
4726 faceBasis0.GetPointsKey(), faceBasis1.GetPointsKey(),
4727 alignedLeng, traceBasis0.GetPointsKey(),
4728 traceBasis1.GetPointsKey(), lengintp[nlr]);
4729 }
4730
4731 for (int j = 0; j < e_npoints; ++j)
4732 {
4733 lengLR[nlr][offset + j] = lengintp[nlr][j];
4734 }
4735 }
4736 }
4737 }
4738}
4739
4741 [[maybe_unused]] const Array<OneD, const NekDouble> &Fn,
4742 [[maybe_unused]] Array<OneD, NekDouble> &outarray)
4743{
4745 "This method is not defined or valid for this class type");
4746}
4747
4749 [[maybe_unused]] const Array<OneD, const NekDouble> &Fwd,
4750 [[maybe_unused]] const Array<OneD, const NekDouble> &Bwd,
4751 [[maybe_unused]] Array<OneD, NekDouble> &outarray)
4752{
4754 "This method is not defined or valid for this class type");
4755}
4756
4758 [[maybe_unused]] Array<OneD, NekDouble> &Bwd)
4759{
4761 "This method is not defined or valid for this class type");
4762}
4763
4765 [[maybe_unused]] const Array<OneD, const NekDouble> &field,
4766 [[maybe_unused]] Array<OneD, NekDouble> &Fwd,
4767 [[maybe_unused]] Array<OneD, NekDouble> &Bwd, [[maybe_unused]] bool FillBnd,
4768 [[maybe_unused]] bool PutFwdInBwdOnBCs, [[maybe_unused]] bool DoExchange)
4769{
4771 "This method is not defined or valid for this class type");
4772}
4773
4775 [[maybe_unused]] const Array<OneD, NekDouble> &Fwd,
4776 [[maybe_unused]] Array<OneD, NekDouble> &Bwd,
4777 [[maybe_unused]] bool PutFwdInBwdOnBCs)
4778{
4780 "This method is not defined or valid for this class type");
4781}
4782
4784 [[maybe_unused]] const Array<OneD, const NekDouble> &Fwd,
4785 [[maybe_unused]] const Array<OneD, const NekDouble> &Bwd,
4786 [[maybe_unused]] Array<OneD, NekDouble> &field)
4787{
4789 "v_AddTraceQuadPhysToField is not defined for this class type");
4790}
4791
4793 [[maybe_unused]] const Array<OneD, const NekDouble> &Fwd,
4794 [[maybe_unused]] const Array<OneD, const NekDouble> &Bwd,
4795 [[maybe_unused]] Array<OneD, NekDouble> &field)
4796{
4798 "v_AddTraceQuadPhysToOffDiag is not defined for this class");
4799}
4800
4802 [[maybe_unused]] const Array<OneD, const NekDouble> &Fwd,
4803 [[maybe_unused]] const Array<OneD, const NekDouble> &Bwd,
4804 [[maybe_unused]] Array<OneD, NekDouble> &locTraceFwd,
4805 [[maybe_unused]] Array<OneD, NekDouble> &locTraceBwd)
4806{
4808 "v_GetLocTraceFromTracePts is not defined for this class");
4809}
4810
4812{
4814 "v_GetBndCondBwdWeight is not defined for this class type");
4815 static Array<OneD, NekDouble> tmp;
4816 return tmp;
4817}
4818
4819void ExpList::v_SetBndCondBwdWeight([[maybe_unused]] const int index,
4820 [[maybe_unused]] const NekDouble value)
4821{
4823 "v_setBndCondBwdWeight is not defined for this class type");
4824}
4825
4826const vector<bool> &ExpList::v_GetLeftAdjacentFaces(void) const
4827{
4829 "This method is not defined or valid for this class type");
4830 static vector<bool> tmp;
4831 return tmp;
4832}
4833
4835 [[maybe_unused]] Array<OneD, NekDouble> &outarray)
4836{
4838 "This method is not defined or valid for this class type");
4839}
4840
4842 [[maybe_unused]] const Array<OneD, const NekDouble> &inarray,
4843 [[maybe_unused]] Array<OneD, NekDouble> &outarray)
4844{
4846 "This method is not defined or valid for this class type");
4847}
4848
4850 [[maybe_unused]] const Array<OneD, const NekDouble> &inarray,
4851 [[maybe_unused]] Array<OneD, NekDouble> &outarray)
4852{
4854 "This method is not defined or valid for this class type");
4855}
4856
4858 [[maybe_unused]] const Array<OneD, const NekDouble> &inarray,
4859 [[maybe_unused]] Array<OneD, NekDouble> &outarray,
4860 [[maybe_unused]] const StdRegions::ConstFactorMap &factors,
4861 [[maybe_unused]] const StdRegions::VarCoeffMap &varcoeff,
4862 [[maybe_unused]] const MultiRegions::VarFactorsMap &varfactors,
4863 [[maybe_unused]] const Array<OneD, const NekDouble> &dirForcing,
4864 [[maybe_unused]] const bool PhysSpaceForcing)
4865{
4866 NEKERROR(ErrorUtil::efatal, "HelmSolve not implemented.");
4867 return NullGlobalLinSysKey;
4868}
4869
4871 [[maybe_unused]] const Array<OneD, const NekDouble> &inarray,
4872 [[maybe_unused]] Array<OneD, NekDouble> &outarray,
4873 [[maybe_unused]] const StdRegions::ConstFactorMap &factors,
4874 [[maybe_unused]] const StdRegions::VarCoeffMap &varcoeff,
4875 [[maybe_unused]] const MultiRegions::VarFactorsMap &varfactors,
4876 [[maybe_unused]] const Array<OneD, const NekDouble> &dirForcing,
4877 [[maybe_unused]] const bool PhysSpaceForcing)
4878{
4880 "LinearAdvectionDiffusionReactionSolve not implemented.");
4881 return NullGlobalLinSysKey;
4882}
4883
4885 [[maybe_unused]] const Array<OneD, Array<OneD, NekDouble>> &velocity,
4886 [[maybe_unused]] const Array<OneD, const NekDouble> &inarray,
4887 [[maybe_unused]] Array<OneD, NekDouble> &outarray,
4888 [[maybe_unused]] const NekDouble lambda,
4889 [[maybe_unused]] const Array<OneD, const NekDouble> &dirForcing)
4890{
4892 "This method is not defined or valid for this class type");
4893}
4894
4896 [[maybe_unused]] const int npts,
4897 [[maybe_unused]] const Array<OneD, const NekDouble> &inarray,
4898 [[maybe_unused]] Array<OneD, NekDouble> &outarray,
4899 [[maybe_unused]] bool Shuff, [[maybe_unused]] bool UnShuff)
4900{
4902 "This method is not defined or valid for this class type");
4903}
4904
4906 [[maybe_unused]] const int npts,
4907 [[maybe_unused]] const Array<OneD, const NekDouble> &inarray,
4908 [[maybe_unused]] Array<OneD, NekDouble> &outarray,
4909 [[maybe_unused]] bool Shuff, [[maybe_unused]] bool UnShuff)
4910{
4912 "This method is not defined or valid for this class type");
4913}
4914
4916 [[maybe_unused]] const int npts,
4917 [[maybe_unused]] const Array<OneD, NekDouble> &inarray1,
4918 [[maybe_unused]] const Array<OneD, NekDouble> &inarray2,
4919 [[maybe_unused]] Array<OneD, NekDouble> &outarray)
4920{
4922 "This method is not defined or valid for this class type");
4923}
4924
4926 [[maybe_unused]] const int npts,
4927 [[maybe_unused]] const Array<OneD, Array<OneD, NekDouble>> &inarray1,
4928 [[maybe_unused]] const Array<OneD, Array<OneD, NekDouble>> &inarray2,
4929 [[maybe_unused]] Array<OneD, Array<OneD, NekDouble>> &outarray)
4930{
4932 "This method is not defined or valid for this class type");
4933}
4934
4936 [[maybe_unused]] Array<OneD, NekDouble> &BndVals,
4937 [[maybe_unused]] const Array<OneD, NekDouble> &TotField,
4938 [[maybe_unused]] int BndID)
4939{
4941 "This method is not defined or valid for this class type");
4942}
4943
4945 [[maybe_unused]] Array<OneD, const NekDouble> &V1,
4946 [[maybe_unused]] Array<OneD, const NekDouble> &V2,
4947 [[maybe_unused]] Array<OneD, NekDouble> &outarray,
4948 [[maybe_unused]] int BndID)
4949{
4951 "This method is not defined or valid for this class type");
4952}
4953
4956{
4958 switch (GetCoordim(0))
4959 {
4960 case 1:
4961 {
4962 for (int i = 0; i < GetExpSize(); ++i)
4963 {
4964 (*m_exp)[i]->NormVectorIProductWRTBase(
4965 V[0] + GetPhys_Offset(i),
4966 tmp = outarray + GetCoeff_Offset(i));
4967 }
4968 }
4969 break;
4970 case 2:
4971 {
4972 for (int i = 0; i < GetExpSize(); ++i)
4973 {
4974 (*m_exp)[i]->NormVectorIProductWRTBase(
4975 V[0] + GetPhys_Offset(i), V[1] + GetPhys_Offset(i),
4976 tmp = outarray + GetCoeff_Offset(i));
4977 }
4978 }
4979 break;
4980 case 3:
4981 {
4982 for (int i = 0; i < GetExpSize(); ++i)
4983 {
4984 (*m_exp)[i]->NormVectorIProductWRTBase(
4985 V[0] + GetPhys_Offset(i), V[1] + GetPhys_Offset(i),
4986 V[2] + GetPhys_Offset(i),
4987 tmp = outarray + GetCoeff_Offset(i));
4988 }
4989 }
4990 break;
4991 default:
4992 NEKERROR(ErrorUtil::efatal, "Dimension not supported");
4993 break;
4994 }
4995}
4996
4998 [[maybe_unused]] Array<OneD, NekDouble> &outarray)
4999{
5001 "This method is not defined or valid for this class type");
5002}
5003
5004/**
5005 */
5007 [[maybe_unused]] const Array<OneD, NekDouble> coeffs)
5008{
5010 "This method is not defined or valid for this class type");
5011}
5012
5013/**
5014 */
5016 [[maybe_unused]] const int nreg,
5017 [[maybe_unused]] const Array<OneD, NekDouble> coeffs)
5018{
5020 "This method is not defined or valid for this class type");
5021}
5022
5023void ExpList::v_LocalToGlobal([[maybe_unused]] bool useComm)
5024{
5026 "This method is not defined or valid for this class type");
5027}
5028
5030 [[maybe_unused]] const Array<OneD, const NekDouble> &inarray,
5031 [[maybe_unused]] Array<OneD, NekDouble> &outarray,
5032 [[maybe_unused]] bool useComm)
5033{
5035 "This method is not defined or valid for this class type");
5036}
5037
5039{
5041 "This method is not defined or valid for this class type");
5042}
5043
5045 [[maybe_unused]] const Array<OneD, const NekDouble> &inarray,
5046 [[maybe_unused]] Array<OneD, NekDouble> &outarray)
5047{
5049 "This method is not defined or valid for this class type");
5050}
5051
5053 Array<OneD, NekDouble> &outarray)
5054{
5055 v_FwdTransLocalElmt(inarray, outarray);
5056}
5057
5058/**
5059 * The operation is evaluated locally for every element by the function
5060 * StdRegions#StdExpansion#IProductWRTBase.
5061 *
5062 * @param inarray An array of size \f$Q_{\mathrm{tot}}\f$
5063 * containing the values of the function
5064 * \f$f(\boldsymbol{x})\f$ at the quadrature
5065 * points \f$\boldsymbol{x}_i\f$.
5066 * @param outarray An array of size \f$N_{\mathrm{eof}}\f$
5067 * used to store the result.
5068 */
5070 Array<OneD, NekDouble> &outarray)
5071{
5072 LibUtilities::Timer timer;
5073 timer.Start();
5074 // initialise if required
5076 {
5077 for (int i = 0; i < m_collections.size(); ++i)
5078 {
5080 }
5082 }
5083
5085 int input_offset{0};
5086 int output_offset{0};
5087 for (int i = 0; i < m_collections.size(); ++i)
5088 {
5090 inarray + input_offset,
5091 tmp = outarray + output_offset);
5092 input_offset +=
5094 output_offset +=
5096 }
5097 timer.Stop();
5098 // Elapsed time
5099 timer.AccumulateRegion("Collections:IProductWRTBase", 10);
5100}
5101
5102/**
5103 * The operation is evaluated locally by the elemental
5104 * function StdRegions#StdExpansion#GetCoords.
5105 *
5106 * @param coord_0 After calculation, the \f$x_1\f$ coordinate
5107 * will be stored in this array.
5108 * @param coord_1 After calculation, the \f$x_2\f$ coordinate
5109 * will be stored in this array.
5110 * @param coord_2 After calculation, the \f$x_3\f$ coordinate
5111 * will be stored in this array.
5112 */
5114 Array<OneD, NekDouble> &coord_1,
5115 Array<OneD, NekDouble> &coord_2)
5116{
5117 if (GetNumElmts() == 0)
5118 {
5119 return;
5120 }
5121
5122 int i;
5123 Array<OneD, NekDouble> e_coord_0;
5124 Array<OneD, NekDouble> e_coord_1;
5125 Array<OneD, NekDouble> e_coord_2;
5126
5127 switch (GetExp(0)->GetCoordim())
5128 {
5129 case 1:
5130 for (i = 0; i < (*m_exp).size(); ++i)
5131 {
5132 e_coord_0 = coord_0 + m_phys_offset[i];
5133 (*m_exp)[i]->GetCoords(e_coord_0);
5134 }
5135 break;
5136 case 2:
5137 ASSERTL0(coord_1.size() != 0, "output coord_1 is not defined");
5138
5139 for (i = 0; i < (*m_exp).size(); ++i)
5140 {
5141 e_coord_0 = coord_0 + m_phys_offset[i];
5142 e_coord_1 = coord_1 + m_phys_offset[i];
5143 (*m_exp)[i]->GetCoords(e_coord_0, e_coord_1);
5144 }
5145 break;
5146 case 3:
5147 ASSERTL0(coord_1.size() != 0, "output coord_1 is not defined");
5148 ASSERTL0(coord_2.size() != 0, "output coord_2 is not defined");
5149
5150 for (i = 0; i < (*m_exp).size(); ++i)
5151 {
5152 e_coord_0 = coord_0 + m_phys_offset[i];
5153 e_coord_1 = coord_1 + m_phys_offset[i];
5154 e_coord_2 = coord_2 + m_phys_offset[i];
5155 (*m_exp)[i]->GetCoords(e_coord_0, e_coord_1, e_coord_2);
5156 }
5157 break;
5158 }
5159}
5160
5164{
5165 (*m_exp)[eid]->GetCoords(xc0, xc1, xc2);
5166}
5167
5168/**
5169 * @brief: Set up a normal along the trace elements between
5170 * two elements at elemental level
5171 *
5172 */
5174{
5175 for (int i = 0; i < m_exp->size(); ++i)
5176 {
5177 for (int j = 0; j < (*m_exp)[i]->GetNtraces(); ++j)
5178 {
5179 (*m_exp)[i]->ComputeTraceNormal(j);
5180 }
5181 }
5182}
5183
5184/**
5185 */
5187 [[maybe_unused]] int i, [[maybe_unused]] std::shared_ptr<ExpList> &result,
5188 [[maybe_unused]] const bool DeclareCoeffPhysArrays)
5189{
5191 "This method is not defined or valid for this class type");
5192}
5193
5194/**
5195 */
5197 const Array<OneD, NekDouble> &element,
5198 Array<OneD, NekDouble> &boundary)
5199{
5200 int n, cnt;
5201 Array<OneD, NekDouble> tmp1, tmp2;
5203
5204 Array<OneD, int> ElmtID, EdgeID;
5205 GetBoundaryToElmtMap(ElmtID, EdgeID);
5206
5207 // Initialise result
5208 boundary =
5210
5211 // Skip other boundary regions
5212 for (cnt = n = 0; n < i; ++n)
5213 {
5214 cnt += GetBndCondExpansions()[n]->GetExpSize();
5215 }
5216
5217 int offsetBnd;
5218 int offsetElmt = 0;
5219 for (n = 0; n < GetBndCondExpansions()[i]->GetExpSize(); ++n)
5220 {
5221 offsetBnd = GetBndCondExpansions()[i]->GetPhys_Offset(n);
5222
5223 elmt = GetExp(ElmtID[cnt + n]);
5224 elmt->GetTracePhysVals(
5225 EdgeID[cnt + n], GetBndCondExpansions()[i]->GetExp(n),
5226 tmp1 = element + offsetElmt, tmp2 = boundary + offsetBnd);
5227
5228 offsetElmt += elmt->GetTotPoints();
5229 }
5230}
5231
5232/**
5233 */
5235 const Array<OneD, const NekDouble> &phys,
5236 Array<OneD, NekDouble> &bndElmt)
5237{
5238 int n, cnt, nq;
5239
5240 Array<OneD, int> ElmtID, EdgeID;
5241 GetBoundaryToElmtMap(ElmtID, EdgeID);
5242
5243 // Skip other boundary regions
5244 for (cnt = n = 0; n < i; ++n)
5245 {
5246 cnt += GetBndCondExpansions()[n]->GetExpSize();
5247 }
5248
5249 // Count number of points
5250 int npoints = 0;
5251 for (n = 0; n < GetBndCondExpansions()[i]->GetExpSize(); ++n)
5252 {
5253 npoints += GetExp(ElmtID[cnt + n])->GetTotPoints();
5254 }
5255
5256 // Initialise result
5257 bndElmt = Array<OneD, NekDouble>(npoints, 0.0);
5258
5259 // Extract data
5260 int offsetPhys;
5261 int offsetElmt = 0;
5262 for (n = 0; n < GetBndCondExpansions()[i]->GetExpSize(); ++n)
5263 {
5264 nq = GetExp(ElmtID[cnt + n])->GetTotPoints();
5265 offsetPhys = GetPhys_Offset(ElmtID[cnt + n]);
5266 Vmath::Vcopy(nq, &phys[offsetPhys], 1, &bndElmt[offsetElmt], 1);
5267 offsetElmt += nq;
5268 }
5269}
5270
5271/**
5272 */
5274 const Array<OneD, const NekDouble> &phys,
5276{
5277 int n, cnt;
5280
5281 Array<OneD, int> ElmtID, EdgeID;
5282 GetBoundaryToElmtMap(ElmtID, EdgeID);
5283
5284 // Initialise result
5285 bnd =
5287
5288 // Skip other boundary regions
5289 for (cnt = n = 0; n < i; ++n)
5290 {
5291 cnt += GetBndCondExpansions()[n]->GetExpSize();
5292 }
5293
5294 int offsetBnd;
5295 int offsetPhys;
5296 for (n = 0; n < GetBndCondExpansions()[i]->GetExpSize(); ++n)
5297 {
5298 offsetPhys = GetPhys_Offset(ElmtID[cnt + n]);
5299 offsetBnd = GetBndCondExpansions()[i]->GetPhys_Offset(n);
5300
5301 elmt = GetExp(ElmtID[cnt + n]);
5302 elmt->GetTracePhysVals(EdgeID[cnt + n],
5304 phys + offsetPhys, tmp1 = bnd + offsetBnd);
5305 }
5306}
5307
5308/**
5309 */
5312{
5313 int j, n, cnt, nq;
5314 int coordim = GetCoordim(0);
5317
5318 Array<OneD, int> ElmtID, EdgeID;
5319 GetBoundaryToElmtMap(ElmtID, EdgeID);
5320
5321 // Initialise result
5322 normals = Array<OneD, Array<OneD, NekDouble>>(coordim);
5323 for (j = 0; j < coordim; ++j)
5324 {
5325 normals[j] = Array<OneD, NekDouble>(
5326 GetBndCondExpansions()[i]->GetTotPoints(), 0.0);
5327 }
5328
5329 // Skip other boundary regions
5330 for (cnt = n = 0; n < i; ++n)
5331 {
5332 cnt += GetBndCondExpansions()[n]->GetExpSize();
5333 }
5334
5335 int offset;
5336 for (n = 0; n < GetBndCondExpansions()[i]->GetExpSize(); ++n)
5337 {
5338 offset = GetBndCondExpansions()[i]->GetPhys_Offset(n);
5339 nq = GetBndCondExpansions()[i]->GetExp(n)->GetTotPoints();
5340
5341 elmt = GetExp(ElmtID[cnt + n]);
5342 const Array<OneD, const Array<OneD, NekDouble>> normalsElmt =
5343 elmt->GetTraceNormal(EdgeID[cnt + n]);
5344 // Copy to result
5345 for (j = 0; j < coordim; ++j)
5346 {
5347 Vmath::Vcopy(nq, normalsElmt[j], 1, tmp = normals[j] + offset, 1);
5348 }
5349 }
5350}
5351
5352/**
5353 */
5355 [[maybe_unused]] Array<OneD, int> &EdgeID)
5356{
5358 "This method is not defined or valid for this class type");
5359}
5360
5362 [[maybe_unused]] Array<OneD, NekDouble> &weightave,
5363 [[maybe_unused]] Array<OneD, NekDouble> &weightjmp)
5364{
5365 NEKERROR(ErrorUtil::efatal, "v_FillBwdWithBwdWeight not defined");
5366}
5367
5369 [[maybe_unused]] const Array<OneD, const NekDouble> &Fwd,
5370 [[maybe_unused]] Array<OneD, NekDouble> &Bwd)
5371{
5372 NEKERROR(ErrorUtil::efatal, "v_PeriodicBwdCopy not defined");
5373}
5374
5375/**
5376 */
5379{
5381 "This method is not defined or valid for this class type");
5383 return result;
5384}
5385
5386/**
5387 */
5390{
5392 "This method is not defined or valid for this class type");
5394 return result;
5395}
5396
5397/**
5398 */
5400 [[maybe_unused]] const NekDouble time,
5401 [[maybe_unused]] const std::string varName,
5402 [[maybe_unused]] const NekDouble x2_in,
5403 [[maybe_unused]] const NekDouble x3_in)
5404{
5406 "This method is not defined or valid for this class type");
5407}
5408
5409/**
5410 */
5411map<int, RobinBCInfoSharedPtr> ExpList::v_GetRobinBCInfo(void)
5412{
5414 "This method is not defined or valid for this class type");
5415 static map<int, RobinBCInfoSharedPtr> result;
5416 return result;
5417}
5418
5419/**
5420 */
5421void ExpList::v_GetPeriodicEntities([[maybe_unused]] PeriodicMap &periodicVerts,
5422 [[maybe_unused]] PeriodicMap &periodicEdges,
5423 [[maybe_unused]] PeriodicMap &periodicFaces)
5424{
5426 "This method is not defined or valid for this class type");
5427}
5428
5431 unsigned int regionId, const std::string &variable)
5432{
5433 auto collectionIter = collection.find(regionId);
5434 ASSERTL1(collectionIter != collection.end(),
5435 "Unable to locate collection " +
5436 boost::lexical_cast<string>(regionId));
5437
5439 (*collectionIter).second;
5440 auto conditionMapIter = bndCondMap->find(variable);
5441 ASSERTL1(conditionMapIter != bndCondMap->end(),
5442 "Unable to locate condition map.");
5443
5444 const SpatialDomains::BoundaryConditionShPtr boundaryCondition =
5445 (*conditionMapIter).second;
5446
5447 return boundaryCondition;
5448}
5449
5451{
5453 "This method is not defined or valid for this class type");
5454 return NullExpListSharedPtr;
5455}
5456
5457/**
5458 * @brief Construct collections of elements containing a single element
5459 * type and polynomial order from the list of expansions.
5460 */
5462{
5463 // Set up initialisation flags
5465 std::vector<bool>(Collections::SIZE_OperatorType, true);
5466
5467 // Figure out optimisation parameters if provided in
5468 // session file or default given
5470 m_session, (*m_exp)[0]->GetShapeDimension(), ImpType);
5471
5472 // turn on autotuning if explicitly specified in xml file
5473 // or command line option is set but only do optimisation
5474 // for volumetric elements (not boundary condition)
5475 bool autotuning = colOpt.IsUsingAutotuning();
5476 if ((autotuning == false) && (ImpType == Collections::eNoImpType))
5477 {
5478 // turn on autotuning if write-opt-file specified
5479 // if m_graph available
5480 if (m_session->GetUpdateOptFile() && m_graph)
5481 {
5482 // only turn on autotuning for volumetric elements
5483 // where Mesh Dimension is equal to the Shape
5484 // Dimension of element.
5485 if (m_graph->GetMeshDimension() == (*m_exp)[0]->GetShapeDimension())
5486 {
5487 autotuning = true;
5488 }
5489 }
5490 }
5491 bool verbose = (m_session->DefinesCmdLineArgument("verbose")) &&
5492 (m_session->GetComm()->GetRank() == 0);
5493
5494 // clear vectors in case previously called
5495 m_collections.clear();
5496 m_coll_coeff_offset.clear();
5497 m_coll_phys_offset.clear();
5498
5499 /*-------------------------------------------------------------------------
5500 Dividing m_exp into sub groups (collections): original exp order is kept.
5501 Use 3 basiskey + deformed flag to determine if two exp belong to the same
5502 collection or not.
5503 -------------------------------------------------------------------------*/
5504 // the maximum size is either explicitly specified, or set to very large
5505 // value which will not affect the actual collection size
5506 int collmax =
5507 (colOpt.GetMaxCollectionSize() > 0 ? colOpt.GetMaxCollectionSize()
5508 : 2 * m_exp->size());
5509
5510 vector<StdRegions::StdExpansionSharedPtr> collExp;
5511 LocalRegions::ExpansionSharedPtr exp = (*m_exp)[0];
5512 Collections::OperatorImpMap impTypes = colOpt.GetOperatorImpMap(exp);
5513 // storing the offset for the modes and quadrature points for the 1st
5514 // element in the collection
5515 m_coll_coeff_offset.push_back(m_coeff_offset[0]);
5516 m_coll_phys_offset.push_back(m_phys_offset[0]);
5517
5518 // add the first element to the collection - initialization
5519 collExp.push_back(exp);
5520 // collcnt is the number of elements in current collection
5521 int collcnt = 1;
5522 // initialize the basisKeys to NullBasisKey
5523 std::vector<LibUtilities::BasisKey> thisbasisKeys(
5525 std::vector<LibUtilities::BasisKey> prevbasisKeys(
5527 // fetch basiskeys of the first element
5528 for (int d = 0; d < exp->GetNumBases(); d++)
5529 {
5530 prevbasisKeys[d] = exp->GetBasis(d)->GetBasisKey();
5531 }
5532
5533 // initialize the deformed flag based on the first element
5534 bool prevDef =
5535 exp->GetMetricInfo()->GetGtype() == SpatialDomains::eDeformed;
5536 // collsize is the maximum size among all collections
5537 int collsize = 0;
5538
5539 for (int i = 1; i < (*m_exp).size(); i++)
5540 {
5541 exp = (*m_exp)[i];
5542
5543 // fetch basiskeys of current element
5544 for (int d = 0; d < exp->GetNumBases(); d++)
5545 {
5546 thisbasisKeys[d] = exp->GetBasis(d)->GetBasisKey();
5547 }
5548 // fetch deformed flag of current element
5549 bool Deformed =
5550 (exp->GetMetricInfo()->GetGtype() == SpatialDomains::eDeformed);
5551
5552 // Check if this element is the same type as the previous one or
5553 // if we have reached the maximum collection size
5554 if (thisbasisKeys != prevbasisKeys || prevDef != Deformed ||
5555 collcnt >= collmax)
5556 {
5557 // if no Imp Type provided and No
5558 // setting in xml file. reset
5559 // impTypes using timings
5560 if (autotuning)
5561 {
5562 // if current collection is larger than previous one
5563 // update impTypes; otherwise, use previous impTypes
5564 if (collExp.size() > collsize)
5565 {
5566 impTypes =
5567 colOpt.SetWithTimings(collExp, impTypes, verbose);
5568 collsize = collExp.size();
5569 }
5570 }
5572 colOpt.GetOperatorImpMap(exp);
5573
5574 Collections::Collection tmp(collExp, impTypes);
5575 m_collections.push_back(tmp);
5576 // store the offsets of the current element
5577 m_coll_coeff_offset.push_back(m_coeff_offset[i]);
5578 m_coll_phys_offset.push_back(m_phys_offset[i]);
5579
5580 // for the new collection calling the optimization routine based on
5581 // its first element
5582 impTypes = colOpt.GetOperatorImpMap((*m_exp)[i]);
5583
5584 // clean-up current element list - temporary collection
5585 collExp.clear();
5586 collcnt = 0;
5587 collsize = 0;
5588 }
5589
5590 // insert exp and increment count
5591 collExp.push_back(exp);
5592 collcnt++;
5593 // update previous info
5594 prevbasisKeys = thisbasisKeys;
5595 prevDef = Deformed;
5596 }
5597
5598 // execute autotuning for the last collection
5599 if (autotuning)
5600 {
5601 if (collExp.size() > collsize)
5602 {
5603 impTypes = colOpt.SetWithTimings(collExp, impTypes, verbose);
5604 collsize = collExp.size();
5605 }
5606 }
5607 Collections::Collection tmp(collExp, impTypes);
5608 m_collections.push_back(tmp);
5609
5610 // clean-up current element list - temporary collection
5611 collExp.clear();
5612 collcnt = 0;
5613 collsize = 0;
5614
5615 // update optimisation file
5616 if ((m_session->GetUpdateOptFile()) && (ImpType == Collections::eNoImpType))
5617 {
5618 colOpt.UpdateOptFile(m_session->GetSessionName(), m_comm);
5619 // turn off write-opt-file option so only first
5620 // instance is timed
5621 m_session->SetUpdateOptFile(false);
5622 }
5623}
5624
5626{
5628}
5629
5630/**
5631 * Added for access to the pool count by external code (e.g. UnitTests)
5632 * which can't access the static pool across compilation units on
5633 * Windows builds.
5634 */
5635int ExpList::GetPoolCount(std::string poolName)
5636{
5637 return v_GetPoolCount(poolName);
5638}
5639
5640void ExpList::UnsetGlobalLinSys(GlobalLinSysKey key, bool clearLocalMatrices)
5641{
5642 v_UnsetGlobalLinSys(key, clearLocalMatrices);
5643}
5644
5647{
5648 return v_GetGlobalLinSysManager();
5649}
5650
5651void ExpList::v_PhysInterp1DScaled([[maybe_unused]] const NekDouble scale,
5652 const Array<OneD, NekDouble> &inarray,
5653 Array<OneD, NekDouble> &outarray)
5654{
5655 // the scaling factor for the PhysInterp1DScaled is given as NekDouble
5656 // however inside Collections it is treated as a FactorMap
5657 // defining needed FactorMap to pass the scaling factor as an input to
5658 // Collections
5660 // Updating the FactorMap according to the scale input
5662 LibUtilities::Timer timer;
5663
5664 // initialise if required
5665 if (m_collections.size() &&
5667 {
5668 for (int i = 0; i < m_collections.size(); ++i)
5669 {
5672 }
5673 }
5674 // once the collections are initialized, check for the scaling factor
5675 for (int i = 0; i < m_collections.size(); ++i)
5676
5677 {
5680 }
5681 LIKWID_MARKER_START("v_PhysInterp1DScaled");
5682 timer.Start();
5684 int input_offset{0};
5685 int output_offset{0};
5686 for (int i = 0; i < m_collections.size(); ++i)
5687 {
5689 inarray + input_offset,
5690 tmp = outarray + output_offset);
5691 input_offset +=
5693 output_offset +=
5695 }
5696 timer.Stop();
5697 LIKWID_MARKER_STOP("v_PhysInterp1DScaled");
5698 timer.AccumulateRegion("Collections:PhysInterp1DScaled", 10);
5699}
5701 [[maybe_unused]] const Array<OneD, const NekDouble> &FwdFlux,
5702 [[maybe_unused]] const Array<OneD, const NekDouble> &BwdFlux,
5703 [[maybe_unused]] Array<OneD, NekDouble> &outarray)
5704{
5705 NEKERROR(ErrorUtil::efatal, "AddTraceIntegralToOffDiag not defined");
5706}
5707
5709 const Array<OneD, const Array<OneD, NekDouble>> &inarray, const int nDirctn,
5711{
5712 int nTotElmt = (*m_exp).size();
5713 int nElmtPnt = (*m_exp)[0]->GetTotPoints();
5714 int nElmtCoef = (*m_exp)[0]->GetNcoeffs();
5715
5716 Array<OneD, NekDouble> tmpCoef(nElmtCoef, 0.0);
5717 Array<OneD, NekDouble> tmpPhys(nElmtPnt, 0.0);
5718
5719 for (int nelmt = 0; nelmt < nTotElmt; nelmt++)
5720 {
5721 nElmtCoef = (*m_exp)[nelmt]->GetNcoeffs();
5722 nElmtPnt = (*m_exp)[nelmt]->GetTotPoints();
5723
5724 if (tmpPhys.size() != nElmtPnt || tmpCoef.size() != nElmtCoef)
5725 {
5726 tmpPhys = Array<OneD, NekDouble>(nElmtPnt, 0.0);
5727 tmpCoef = Array<OneD, NekDouble>(nElmtCoef, 0.0);
5728 }
5729
5730 for (int ncl = 0; ncl < nElmtPnt; ncl++)
5731 {
5732 tmpPhys[ncl] = inarray[nelmt][ncl];
5733
5734 (*m_exp)[nelmt]->IProductWRTDerivBase(nDirctn, tmpPhys, tmpCoef);
5735
5736 for (int nrw = 0; nrw < nElmtCoef; nrw++)
5737 {
5738 (*mtxPerVar[nelmt])(nrw, ncl) = tmpCoef[nrw];
5739 }
5740 // to maintain all the other columes are zero.
5741 tmpPhys[ncl] = 0.0;
5742 }
5743 }
5744}
5745
5748{
5749 int nTotElmt = (*m_exp).size();
5750
5751 int nspacedim = m_graph->GetSpaceDimension();
5752 Array<OneD, Array<OneD, NekDouble>> projectedpnts(nspacedim);
5753 Array<OneD, Array<OneD, NekDouble>> tmppnts(nspacedim);
5754 Array<OneD, DNekMatSharedPtr> ArrayStdMat(nspacedim);
5755 Array<OneD, Array<OneD, NekDouble>> ArrayStdMat_data(nspacedim);
5756
5757 Array<OneD, NekDouble> clmnArray, clmnStdMatArray;
5758
5760 int nElmtPntPrevious = 0;
5761 int nElmtCoefPrevious = 0;
5762
5763 int nElmtPnt, nElmtCoef;
5764 for (int nelmt = 0; nelmt < nTotElmt; nelmt++)
5765 {
5766 nElmtCoef = (*m_exp)[nelmt]->GetNcoeffs();
5767 nElmtPnt = (*m_exp)[nelmt]->GetTotPoints();
5768 LibUtilities::ShapeType ElmtTypeNow = (*m_exp)[nelmt]->DetShapeType();
5769
5770 if (nElmtPntPrevious != nElmtPnt || nElmtCoefPrevious != nElmtCoef ||
5771 (ElmtTypeNow != ElmtTypePrevious))
5772 {
5773 if (nElmtPntPrevious != nElmtPnt)
5774 {
5775 for (int ndir = 0; ndir < nspacedim; ndir++)
5776 {
5777 projectedpnts[ndir] = Array<OneD, NekDouble>(nElmtPnt, 0.0);
5778 tmppnts[ndir] = Array<OneD, NekDouble>(nElmtPnt, 0.0);
5779 }
5780 }
5782 stdExp = (*m_exp)[nelmt]->GetStdExp();
5784 stdExp->DetShapeType(), *stdExp);
5785
5786 ArrayStdMat[0] = stdExp->GetStdMatrix(matkey);
5787 ArrayStdMat_data[0] = ArrayStdMat[0]->GetPtr();
5788
5789 if (nspacedim > 1)
5790 {
5792 StdRegions::eDerivBase1, stdExp->DetShapeType(), *stdExp);
5793
5794 ArrayStdMat[1] = stdExp->GetStdMatrix(matkey);
5795 ArrayStdMat_data[1] = ArrayStdMat[1]->GetPtr();
5796
5797 if (nspacedim > 2)
5798 {
5800 stdExp->DetShapeType(),
5801 *stdExp);
5802
5803 ArrayStdMat[2] = stdExp->GetStdMatrix(matkey);
5804 ArrayStdMat_data[2] = ArrayStdMat[2]->GetPtr();
5805 }
5806 }
5807
5808 ElmtTypePrevious = ElmtTypeNow;
5809 nElmtPntPrevious = nElmtPnt;
5810 nElmtCoefPrevious = nElmtCoef;
5811 }
5812 else
5813 {
5814 for (int ndir = 0; ndir < nspacedim; ndir++)
5815 {
5816 Vmath::Zero(nElmtPnt, projectedpnts[ndir], 1);
5817 }
5818 }
5819
5820 for (int ndir = 0; ndir < nspacedim; ndir++)
5821 {
5822 (*m_exp)[nelmt]->AlignVectorToCollapsedDir(
5823 ndir, inarray[ndir][nelmt], tmppnts);
5824 for (int n = 0; n < nspacedim; n++)
5825 {
5826 Vmath::Vadd(nElmtPnt, tmppnts[n], 1, projectedpnts[n], 1,
5827 projectedpnts[n], 1);
5828 }
5829 }
5830
5831 for (int ndir = 0; ndir < nspacedim; ndir++)
5832 {
5833 // weight with metric
5834 (*m_exp)[nelmt]->MultiplyByQuadratureMetric(projectedpnts[ndir],
5835 projectedpnts[ndir]);
5836 Array<OneD, NekDouble> MatDataArray = mtxPerVar[nelmt]->GetPtr();
5837
5838 for (int np = 0; np < nElmtPnt; np++)
5839 {
5840 NekDouble factor = projectedpnts[ndir][np];
5841 clmnArray = MatDataArray + np * nElmtCoef;
5842 clmnStdMatArray = ArrayStdMat_data[ndir] + np * nElmtCoef;
5843 Vmath::Svtvp(nElmtCoef, factor, clmnStdMatArray, 1, clmnArray,
5844 1, clmnArray, 1);
5845 }
5846 }
5847 }
5848}
5849
5850// TODO: Reduce cost by getting Bwd Matrix directly
5852 const Array<OneD, const Array<OneD, NekDouble>> &inarray,
5854{
5856 int nElmtPntPrevious = 0;
5857 int nElmtCoefPrevious = 0;
5858 int nTotElmt = (*m_exp).size();
5859 int nElmtPnt = (*m_exp)[0]->GetTotPoints();
5860 int nElmtCoef = (*m_exp)[0]->GetNcoeffs();
5861
5862 Array<OneD, NekDouble> tmpPhys;
5863 Array<OneD, NekDouble> clmnArray, clmnStdMatArray;
5864 Array<OneD, NekDouble> stdMat_data;
5865
5866 for (int nelmt = 0; nelmt < nTotElmt; nelmt++)
5867 {
5868 nElmtCoef = (*m_exp)[nelmt]->GetNcoeffs();
5869 nElmtPnt = (*m_exp)[nelmt]->GetTotPoints();
5870 LibUtilities::ShapeType ElmtTypeNow = (*m_exp)[nelmt]->DetShapeType();
5871
5872 if (nElmtPntPrevious != nElmtPnt || nElmtCoefPrevious != nElmtCoef ||
5873 (ElmtTypeNow != ElmtTypePrevious))
5874 {
5876 stdExp = (*m_exp)[nelmt]->GetStdExp();
5878 stdExp->DetShapeType(), *stdExp);
5879
5880 DNekMatSharedPtr BwdMat = stdExp->GetStdMatrix(matkey);
5881 stdMat_data = BwdMat->GetPtr();
5882
5883 if (nElmtPntPrevious != nElmtPnt)
5884 {
5885 tmpPhys = Array<OneD, NekDouble>(nElmtPnt, 0.0);
5886 }
5887
5888 ElmtTypePrevious = ElmtTypeNow;
5889 nElmtPntPrevious = nElmtPnt;
5890 nElmtCoefPrevious = nElmtCoef;
5891 }
5892
5893 (*m_exp)[nelmt]->MultiplyByQuadratureMetric(
5894 inarray[nelmt],
5895 tmpPhys); // weight with metric
5896
5897 Array<OneD, NekDouble> MatDataArray = mtxPerVar[nelmt]->GetPtr();
5898
5899 for (int np = 0; np < nElmtPnt; np++)
5900 {
5901 NekDouble factor = tmpPhys[np];
5902 clmnArray = MatDataArray + np * nElmtCoef;
5903 clmnStdMatArray = stdMat_data + np * nElmtCoef;
5904 Vmath::Smul(nElmtCoef, factor, clmnStdMatArray, 1, clmnArray, 1);
5905 }
5906 }
5907}
5908
5909/**
5910 * @brief inverse process of v_GetFwdBwdTracePhys. Given Trace integration of
5911 * Fwd and Bwd Jacobian, with dimension NtotalTrace*TraceCoef*TracePhys.
5912 * return Elemental Jacobian matrix with dimension
5913 * NtotalElement*ElementCoef*ElementPhys.
5914 *
5915 *
5916 * @param field is a NekDouble array which contains the 2D data
5917 * from which we wish to extract the backward and
5918 * forward orientated trace/edge arrays.
5919 * @param Fwd The resulting forwards space.
5920 * @param Bwd The resulting backwards space.
5921 */
5926{
5928 std::shared_ptr<LocalRegions::ExpansionVector> traceExp =
5929 tracelist->GetExp();
5930 int ntotTrace = (*traceExp).size();
5931 int nTracePnt, nTraceCoef;
5932
5933 std::shared_ptr<LocalRegions::ExpansionVector> fieldExp = GetExp();
5934 int nElmtCoef;
5935
5936 const MultiRegions::LocTraceToTraceMapSharedPtr locTraceToTraceMap =
5938 const Array<OneD, const Array<OneD, int>> LRAdjExpid =
5939 locTraceToTraceMap->GetLeftRightAdjacentExpId();
5940 const Array<OneD, const Array<OneD, bool>> LRAdjflag =
5941 locTraceToTraceMap->GetLeftRightAdjacentExpFlag();
5942
5944 locTraceToTraceMap->GetTraceCoeffToLeftRightExpCoeffMap();
5946 locTraceToTraceMap->GetTraceCoeffToLeftRightExpCoeffSign();
5947 DNekMatSharedPtr ElmtMat;
5948 Array<OneD, NekDouble> ElmtMat_data;
5949 // int nclAdjExp;
5950 int nrwAdjExp;
5951 int MatIndex, nPnts;
5952 NekDouble sign = 1.0;
5953
5954 int nTracePntsTtl = tracelist->GetTotPoints();
5955 int nlocTracePts = locTraceToTraceMap->GetNLocTracePts();
5956 int nlocTracePtsFwd = locTraceToTraceMap->GetNFwdLocTracePts();
5957 int nlocTracePtsBwd = nlocTracePts - nlocTracePtsFwd;
5958
5959 Array<OneD, int> nlocTracePtsLR(2);
5960 nlocTracePtsLR[0] = nlocTracePtsFwd;
5961 nlocTracePtsLR[1] = nlocTracePtsBwd;
5962
5963 size_t nFwdBwdNonZero = 0;
5964 Array<OneD, int> tmpIndex{2, -1};
5965 for (int i = 0; i < 2; ++i)
5966 {
5967 if (nlocTracePtsLR[i] > 0)
5968 {
5969 tmpIndex[nFwdBwdNonZero] = i;
5970 nFwdBwdNonZero++;
5971 }
5972 }
5973
5974 Array<OneD, int> nlocTracePtsNonZeroIndex{nFwdBwdNonZero};
5975 for (int i = 0; i < nFwdBwdNonZero; ++i)
5976 {
5977 nlocTracePtsNonZeroIndex[i] = tmpIndex[i];
5978 }
5979
5980 Array<OneD, NekDouble> TraceFwdPhy(nTracePntsTtl);
5981 Array<OneD, NekDouble> TraceBwdPhy(nTracePntsTtl);
5982 Array<OneD, Array<OneD, NekDouble>> tmplocTrace(2);
5983 for (int k = 0; k < 2; ++k)
5984 {
5985 tmplocTrace[k] = NullNekDouble1DArray;
5986 }
5987
5988 for (int k = 0; k < nFwdBwdNonZero; ++k)
5989 {
5990 size_t i = nlocTracePtsNonZeroIndex[k];
5991 tmplocTrace[i] = Array<OneD, NekDouble>(nlocTracePtsLR[i]);
5992 }
5993
5994 int nNumbElmt = fieldMat.size();
5995 Array<OneD, Array<OneD, NekDouble>> ElmtMatDataArray(nNumbElmt);
5996 Array<OneD, int> ElmtCoefArray(nNumbElmt);
5997 for (int i = 0; i < nNumbElmt; i++)
5998 {
5999 ElmtMatDataArray[i] = fieldMat[i]->GetPtr();
6000 ElmtCoefArray[i] = GetNcoeffs(i);
6001 }
6002
6003 int nTraceCoefMax = 0;
6004 int nTraceCoefMin = std::numeric_limits<int>::max();
6005 Array<OneD, int> TraceCoefArray(ntotTrace);
6006 Array<OneD, int> TracePntArray(ntotTrace);
6007 Array<OneD, int> TraceOffArray(ntotTrace);
6008 Array<OneD, Array<OneD, NekDouble>> FwdMatData(ntotTrace);
6009 Array<OneD, Array<OneD, NekDouble>> BwdMatData(ntotTrace);
6010 for (int nt = 0; nt < ntotTrace; nt++)
6011 {
6012 nTraceCoef = (*traceExp)[nt]->GetNcoeffs();
6013 nTracePnt = tracelist->GetTotPoints(nt);
6014 int noffset = tracelist->GetPhys_Offset(nt);
6015 TraceCoefArray[nt] = nTraceCoef;
6016 TracePntArray[nt] = nTracePnt;
6017 TraceOffArray[nt] = noffset;
6018 FwdMatData[nt] = FwdMat[nt]->GetPtr();
6019 BwdMatData[nt] = BwdMat[nt]->GetPtr();
6020 if (nTraceCoef > nTraceCoefMax)
6021 {
6022 nTraceCoefMax = nTraceCoef;
6023 }
6024 if (nTraceCoef < nTraceCoefMin)
6025 {
6026 nTraceCoefMin = nTraceCoef;
6027 }
6028 }
6029 WARNINGL1(nTraceCoefMax == nTraceCoefMin,
6030 "nTraceCoefMax!=nTraceCoefMin: Effeciency may be low ");
6031
6032 int traceID, nfieldPnts, ElmtId, noffset;
6033 const Array<OneD, const Array<OneD, int>> LocTracephysToTraceIDMap =
6034 locTraceToTraceMap->GetLocTracephysToTraceIDMap();
6035 const Array<OneD, const int> fieldToLocTraceMap =
6036 locTraceToTraceMap->GetLocTraceToFieldMap();
6037 Array<OneD, Array<OneD, int>> fieldToLocTraceMapLR(2);
6038 noffset = 0;
6039 for (int k = 0; k < nFwdBwdNonZero; ++k)
6040 {
6041 size_t i = nlocTracePtsNonZeroIndex[k];
6042 fieldToLocTraceMapLR[i] = Array<OneD, int>(nlocTracePtsLR[i]);
6043 Vmath::Vcopy(nlocTracePtsLR[i], &fieldToLocTraceMap[0] + noffset, 1,
6044 &fieldToLocTraceMapLR[i][0], 1);
6045 noffset += nlocTracePtsLR[i];
6046 }
6047
6048 Array<OneD, Array<OneD, int>> MatIndexArray(2);
6049 for (int k = 0; k < nFwdBwdNonZero; ++k)
6050 {
6051 size_t nlr = nlocTracePtsNonZeroIndex[k];
6052 MatIndexArray[nlr] = Array<OneD, int>(nlocTracePtsLR[nlr]);
6053 for (int nloc = 0; nloc < nlocTracePtsLR[nlr]; nloc++)
6054 {
6055 traceID = LocTracephysToTraceIDMap[nlr][nloc];
6056 nTraceCoef = TraceCoefArray[traceID];
6057 ElmtId = LRAdjExpid[nlr][traceID];
6058 noffset = GetPhys_Offset(ElmtId);
6059 nElmtCoef = ElmtCoefArray[ElmtId];
6060 nfieldPnts = fieldToLocTraceMapLR[nlr][nloc];
6061 nPnts = nfieldPnts - noffset;
6062
6063 MatIndexArray[nlr][nloc] = nPnts * nElmtCoef;
6064 }
6065 }
6066
6067 for (int nc = 0; nc < nTraceCoefMin; nc++)
6068 {
6069 for (int nt = 0; nt < ntotTrace; nt++)
6070 {
6071 nTraceCoef = TraceCoefArray[nt];
6072 nTracePnt = TracePntArray[nt];
6073 noffset = TraceOffArray[nt];
6074 Vmath::Vcopy(nTracePnt, &FwdMatData[nt][nc], nTraceCoef,
6075 &TraceFwdPhy[noffset], 1);
6076 Vmath::Vcopy(nTracePnt, &BwdMatData[nt][nc], nTraceCoef,
6077 &TraceBwdPhy[noffset], 1);
6078 }
6079
6080 for (int k = 0; k < nFwdBwdNonZero; ++k)
6081 {
6082 size_t i = nlocTracePtsNonZeroIndex[k];
6083 Vmath::Zero(nlocTracePtsLR[i], tmplocTrace[i], 1);
6084 }
6085
6086 GetLocTraceFromTracePts(TraceFwdPhy, TraceBwdPhy, tmplocTrace[0],
6087 tmplocTrace[1]);
6088
6089 for (int k = 0; k < nFwdBwdNonZero; ++k)
6090 {
6091 size_t nlr = nlocTracePtsNonZeroIndex[k];
6092 for (int nloc = 0; nloc < nlocTracePtsLR[nlr]; nloc++)
6093 {
6094 traceID = LocTracephysToTraceIDMap[nlr][nloc];
6095 nTraceCoef = TraceCoefArray[traceID];
6096 ElmtId = LRAdjExpid[nlr][traceID];
6097 nrwAdjExp = elmtLRMap[nlr][traceID][nc];
6098 sign = elmtLRSign[nlr][traceID][nc];
6099 MatIndex = MatIndexArray[nlr][nloc] + nrwAdjExp;
6100
6101 ElmtMatDataArray[ElmtId][MatIndex] -=
6102 sign * tmplocTrace[nlr][nloc];
6103 }
6104 }
6105 }
6106
6107 for (int nc = nTraceCoefMin; nc < nTraceCoefMax; nc++)
6108 {
6109 for (int nt = 0; nt < ntotTrace; nt++)
6110 {
6111 nTraceCoef = TraceCoefArray[nt];
6112 nTracePnt = TracePntArray[nt];
6113 noffset = TraceOffArray[nt];
6114 if (nc < nTraceCoef)
6115 {
6116 Vmath::Vcopy(nTracePnt, &FwdMatData[nt][nc], nTraceCoef,
6117 &TraceFwdPhy[noffset], 1);
6118 Vmath::Vcopy(nTracePnt, &BwdMatData[nt][nc], nTraceCoef,
6119 &TraceBwdPhy[noffset], 1);
6120 }
6121 else
6122 {
6123 Vmath::Zero(nTracePnt, &TraceFwdPhy[noffset], 1);
6124 Vmath::Zero(nTracePnt, &TraceBwdPhy[noffset], 1);
6125 }
6126 }
6127
6128 for (int k = 0; k < nFwdBwdNonZero; ++k)
6129 {
6130 size_t i = nlocTracePtsNonZeroIndex[k];
6131 Vmath::Zero(nlocTracePtsLR[i], tmplocTrace[i], 1);
6132 }
6133 GetLocTraceFromTracePts(TraceFwdPhy, TraceBwdPhy, tmplocTrace[0],
6134 tmplocTrace[1]);
6135
6136 for (int k = 0; k < nFwdBwdNonZero; ++k)
6137 {
6138 size_t nlr = nlocTracePtsNonZeroIndex[k];
6139 for (int nloc = 0; nloc < nlocTracePtsLR[nlr]; nloc++)
6140 {
6141 traceID = LocTracephysToTraceIDMap[nlr][nloc];
6142 nTraceCoef = TraceCoefArray[traceID];
6143 if (nc < nTraceCoef)
6144 {
6145 ElmtId = LRAdjExpid[nlr][traceID];
6146 nrwAdjExp = elmtLRMap[nlr][traceID][nc];
6147 sign = -elmtLRSign[nlr][traceID][nc];
6148 MatIndex = MatIndexArray[nlr][nloc] + nrwAdjExp;
6149
6150 ElmtMatDataArray[ElmtId][MatIndex] +=
6151 sign * tmplocTrace[nlr][nloc];
6152 }
6153 }
6154 }
6155 }
6156}
6157
6159 const int dir, const Array<OneD, const DNekMatSharedPtr> ElmtJacQuad,
6161{
6162 int nelmt;
6163 int nelmtcoef, nelmtpnts, nelmtcoef0, nelmtpnts0;
6164
6165 nelmtcoef = GetNcoeffs(0);
6166 nelmtpnts = GetTotPoints(0);
6167
6168 Array<OneD, NekDouble> innarray(nelmtpnts, 0.0);
6169 Array<OneD, NekDouble> outarray(nelmtcoef, 0.0);
6170
6171 Array<OneD, NekDouble> MatQ_data;
6172 Array<OneD, NekDouble> MatC_data;
6173
6174 DNekMatSharedPtr tmpMatQ, tmpMatC;
6175
6176 nelmtcoef0 = nelmtcoef;
6177 nelmtpnts0 = nelmtpnts;
6178
6179 for (nelmt = 0; nelmt < (*m_exp).size(); ++nelmt)
6180 {
6181 nelmtcoef = GetNcoeffs(nelmt);
6182 nelmtpnts = GetTotPoints(nelmt);
6183
6184 tmpMatQ = ElmtJacQuad[nelmt];
6185 tmpMatC = ElmtJacCoef[nelmt];
6186
6187 MatQ_data = tmpMatQ->GetPtr();
6188 MatC_data = tmpMatC->GetPtr();
6189
6190 if (nelmtcoef != nelmtcoef0)
6191 {
6192 outarray = Array<OneD, NekDouble>(nelmtcoef, 0.0);
6193 nelmtcoef0 = nelmtcoef;
6194 }
6195
6196 if (nelmtpnts != nelmtpnts0)
6197 {
6198 innarray = Array<OneD, NekDouble>(nelmtpnts, 0.0);
6199 nelmtpnts0 = nelmtpnts;
6200 }
6201
6202 for (int np = 0; np < nelmtcoef; np++)
6203 {
6204 Vmath::Vcopy(nelmtpnts, &MatQ_data[0] + np, nelmtcoef, &innarray[0],
6205 1);
6206 (*m_exp)[nelmt]->DivideByQuadratureMetric(innarray, innarray);
6207 (*m_exp)[nelmt]->IProductWRTDerivBase(dir, innarray, outarray);
6208
6209 Vmath::Vadd(nelmtcoef, &outarray[0], 1, &MatC_data[0] + np,
6210 nelmtcoef, &MatC_data[0] + np, nelmtcoef);
6211 }
6212 }
6213}
6214
6216 const Array<OneD, const DNekMatSharedPtr> ElmtJacQuad,
6218{
6219 int nelmt;
6220 int nelmtcoef, nelmtpnts, nelmtcoef0, nelmtpnts0;
6221
6222 nelmtcoef = GetNcoeffs(0);
6223 nelmtpnts = GetTotPoints(0);
6224
6225 Array<OneD, NekDouble> innarray(nelmtpnts, 0.0);
6226 Array<OneD, NekDouble> outarray(nelmtcoef, 0.0);
6227
6228 Array<OneD, NekDouble> MatQ_data;
6229 Array<OneD, NekDouble> MatC_data;
6230
6231 DNekMatSharedPtr tmpMatQ, tmpMatC;
6232
6233 nelmtcoef0 = nelmtcoef;
6234 nelmtpnts0 = nelmtpnts;
6235
6236 for (nelmt = 0; nelmt < (*m_exp).size(); ++nelmt)
6237 {
6238 nelmtcoef = GetNcoeffs(nelmt);
6239 nelmtpnts = GetTotPoints(nelmt);
6240
6241 tmpMatQ = ElmtJacQuad[nelmt];
6242 tmpMatC = ElmtJacCoef[nelmt];
6243
6244 MatQ_data = tmpMatQ->GetPtr();
6245 MatC_data = tmpMatC->GetPtr();
6246
6247 if (nelmtcoef != nelmtcoef0)
6248 {
6249 outarray = Array<OneD, NekDouble>(nelmtcoef, 0.0);
6250 nelmtcoef0 = nelmtcoef;
6251 }
6252
6253 if (nelmtpnts != nelmtpnts0)
6254 {
6255 innarray = Array<OneD, NekDouble>(nelmtpnts, 0.0);
6256 nelmtpnts0 = nelmtpnts;
6257 }
6258
6259 for (int np = 0; np < nelmtcoef; np++)
6260 {
6261 Vmath::Vcopy(nelmtpnts, &MatQ_data[0] + np, nelmtcoef, &innarray[0],
6262 1);
6263 (*m_exp)[nelmt]->DivideByQuadratureMetric(innarray, innarray);
6264 (*m_exp)[nelmt]->IProductWRTBase(innarray, outarray);
6265
6266 Vmath::Vadd(nelmtcoef, &outarray[0], 1, &MatC_data[0] + np,
6267 nelmtcoef, &MatC_data[0] + np, nelmtcoef);
6268 }
6269 }
6270}
6271
6273 const NekDouble scale, const Array<OneD, NekDouble> &inarray,
6274 Array<OneD, NekDouble> &outarray)
6275{
6276 int cnt, cnt1;
6277
6278 cnt = cnt1 = 0;
6279
6280 switch (m_expType)
6281 {
6282 case e2D:
6283 {
6284 for (int i = 0; i < GetExpSize(); ++i)
6285 {
6286 // get new points key
6287 int pt0 = (*m_exp)[i]->GetNumPoints(0);
6288 int pt1 = (*m_exp)[i]->GetNumPoints(1);
6289 int npt0 = (int)pt0 * scale;
6290 int npt1 = (int)pt1 * scale;
6291
6292 LibUtilities::PointsKey newPointsKey0(
6293 npt0, (*m_exp)[i]->GetPointsType(0));
6294 LibUtilities::PointsKey newPointsKey1(
6295 npt1, (*m_exp)[i]->GetPointsType(1));
6296
6297 // Project points;
6299 newPointsKey0, newPointsKey1, &inarray[cnt],
6300 (*m_exp)[i]->GetBasis(0)->GetPointsKey(),
6301 (*m_exp)[i]->GetBasis(1)->GetPointsKey(), &outarray[cnt1]);
6302
6303 cnt += npt0 * npt1;
6304 cnt1 += pt0 * pt1;
6305 }
6306 }
6307 break;
6308 case e3D:
6309 {
6310 for (int i = 0; i < GetExpSize(); ++i)
6311 {
6312 // get new points key
6313 int pt0 = (*m_exp)[i]->GetNumPoints(0);
6314 int pt1 = (*m_exp)[i]->GetNumPoints(1);
6315 int pt2 = (*m_exp)[i]->GetNumPoints(2);
6316 int npt0 = (int)pt0 * scale;
6317 int npt1 = (int)pt1 * scale;
6318 int npt2 = (int)pt2 * scale;
6319
6320 LibUtilities::PointsKey newPointsKey0(
6321 npt0, (*m_exp)[i]->GetPointsType(0));
6322 LibUtilities::PointsKey newPointsKey1(
6323 npt1, (*m_exp)[i]->GetPointsType(1));
6324 LibUtilities::PointsKey newPointsKey2(
6325 npt2, (*m_exp)[i]->GetPointsType(2));
6326
6327 // Project points;
6329 newPointsKey0, newPointsKey1, newPointsKey2, &inarray[cnt],
6330 (*m_exp)[i]->GetBasis(0)->GetPointsKey(),
6331 (*m_exp)[i]->GetBasis(1)->GetPointsKey(),
6332 (*m_exp)[i]->GetBasis(2)->GetPointsKey(), &outarray[cnt1]);
6333
6334 cnt += npt0 * npt1 * npt2;
6335 cnt1 += pt0 * pt1 * pt2;
6336 }
6337 }
6338 break;
6339 default:
6340 {
6341 NEKERROR(ErrorUtil::efatal, "not setup for this expansion");
6342 }
6343 break;
6344 }
6345}
6346
6348{
6349 NEKERROR(ErrorUtil::efatal, "v_GetLocTraceToTraceMap not coded");
6351}
6352
6353} // namespace Nektar::MultiRegions
#define WARNINGL1(condition, msg)
Definition: ErrorUtil.hpp:243
#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 LIKWID_MARKER_START(regionTag)
Definition: Likwid.hpp:46
#define LIKWID_MARKER_STOP(regionTag)
Definition: Likwid.hpp:47
#define sign(a, b)
return the sign(b)*a
Definition: Polylib.cpp:47
COLLECTIONS_EXPORT OperatorImpMap SetWithTimings(std::vector< StdRegions::StdExpansionSharedPtr > pGeom, OperatorImpMap &impTypes, bool verbose=true)
COLLECTIONS_EXPORT void UpdateOptFile(std::string sessName, LibUtilities::CommSharedPtr &comm)
COLLECTIONS_EXPORT OperatorImpMap GetOperatorImpMap(StdRegions::StdExpansionSharedPtr pExp)
Get Operator Implementation Map from XMl or using default;.
Describes the specification for a Basis.
Definition: Basis.h:45
int GetNumPoints() const
Return points order at which basis is defined.
Definition: Basis.h:120
BasisType GetBasisType() const
Return type of expansion basis.
Definition: Basis.h:131
PointsKey GetPointsKey() const
Return distribution of points.
Definition: Basis.h:137
int GetNumModes() const
Returns the order of the basis.
Definition: Basis.h:74
static const std::string GetFileType(const std::string &filename, CommSharedPtr comm)
Determine file type of given input file.
Definition: FieldIO.cpp:95
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:143
Defines a specification for a set of points.
Definition: Points.h:50
size_t GetNumPoints() const
Definition: Points.h:85
void AccumulateRegion(std::string, int iolevel=0)
Accumulate elapsed time for a region.
Definition: Timer.cpp:70
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.
Base class for all multi-elemental spectral/hp expansions.
Definition: ExpList.h:98
virtual void v_Reset()
Reset geometry information, metrics, matrix managers and geometry information.
Definition: ExpList.cpp:3043
Array< OneD, NekDouble > m_coeffs
Concatenation of all local expansion coefficients.
Definition: ExpList.h:1080
void AddTraceJacToElmtJac(const Array< OneD, const DNekMatSharedPtr > &FwdMat, const Array< OneD, const DNekMatSharedPtr > &BwdMat, Array< OneD, DNekMatSharedPtr > &fieldMat)
inverse process of v_GetFwdBwdTracePhys. Given Trace integration of Fwd and Bwd Jacobian,...
Definition: ExpList.cpp:5922
void IProductWRTBase(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
This function calculates the inner product of a function with respect to all local expansion modes .
Definition: ExpList.h:1650
const Array< OneD, const std::shared_ptr< ExpList > > & GetBndCondExpansions()
Definition: ExpList.h:2121
std::shared_ptr< ExpList > & GetTrace()
Definition: ExpList.h:2162
int GetNcoeffs(void) const
Returns the total number of local degrees of freedom .
Definition: ExpList.h:1512
virtual void v_ExtractCoeffsToCoeffs(const std::shared_ptr< ExpList > &fromExpList, const Array< OneD, const NekDouble > &fromCoeffs, Array< OneD, NekDouble > &toCoeffs)
Definition: ExpList.cpp:4042
const DNekScalBlkMatSharedPtr & GetBlockMatrix(const GlobalMatrixKey &gkey)
Definition: ExpList.cpp:2374
virtual void v_AddFwdBwdTraceIntegral(const Array< OneD, const NekDouble > &Fwd, const Array< OneD, const NekDouble > &Bwd, Array< OneD, NekDouble > &outarray)
Definition: ExpList.cpp:4748
LibUtilities::NekManager< GlobalLinSysKey, GlobalLinSys > & GetGlobalLinSysManager(void)
Definition: ExpList.cpp:5646
ExpList(const ExpansionType Type=eNoType)
The default constructor using a type.
Definition: ExpList.cpp:90
void CreateCollections(Collections::ImplementationType ImpType=Collections::eNoImpType)
Construct collections of elements containing a single element type and polynomial order from the list...
Definition: ExpList.cpp:5461
virtual void v_GetBoundaryToElmtMap(Array< OneD, int > &ElmtID, Array< OneD, int > &EdgeID)
Definition: ExpList.cpp:5354
void ExponentialFilter(Array< OneD, NekDouble > &array, const NekDouble alpha, const NekDouble exponent, const NekDouble cutoff)
Definition: ExpList.cpp:2109
std::shared_ptr< GlobalMatrix > GenGlobalMatrix(const GlobalMatrixKey &mkey, const std::shared_ptr< AssemblyMapCG > &locToGloMap)
Generates a global matrix from the given key and map.
Definition: ExpList.cpp:2497
virtual void v_IProductWRTBase(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
Definition: ExpList.cpp:5069
void AddRightIPTPhysDerivBase(const int dir, const Array< OneD, const DNekMatSharedPtr > ElmtJacQuad, Array< OneD, DNekMatSharedPtr > ElmtJacCoef)
Definition: ExpList.cpp:6158
virtual void v_ExtractTracePhys(Array< OneD, NekDouble > &outarray)
Definition: ExpList.cpp:4834
int GetExpIndex(const Array< OneD, const NekDouble > &gloCoord, NekDouble tol=0.0, bool returnNearestElmt=false, int cachedId=-1, NekDouble maxDistance=1e6)
This function returns the index of the local elemental expansion containing the arbitrary point given...
Definition: ExpList.cpp:2892
virtual GlobalLinSysKey v_HelmSolve(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const StdRegions::ConstFactorMap &factors, const StdRegions::VarCoeffMap &varcoeff, const MultiRegions::VarFactorsMap &varfactors, const Array< OneD, const NekDouble > &dirForcing, const bool PhysSpaceForcing)
Definition: ExpList.cpp:4857
virtual void v_WriteTecplotConnectivity(std::ostream &outfile, int expansion)
Definition: ExpList.cpp:3201
BlockMatrixMapShPtr m_blockMat
Definition: ExpList.h:1129
virtual Array< OneD, const unsigned int > v_GetYIDs(void)
Definition: ExpList.cpp:3663
void MultiplyByQuadratureMetric(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
multiply the metric jacobi and quadrature weights
Definition: ExpList.cpp:1647
virtual void v_LinearAdvectionReactionSolve(const Array< OneD, Array< OneD, NekDouble > > &velocity, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const NekDouble lambda, const Array< OneD, const NekDouble > &dirForcing=NullNekDouble1DArray)
Definition: ExpList.cpp:4884
void GetBoundaryToElmtMap(Array< OneD, int > &ElmtID, Array< OneD, int > &EdgeID)
Definition: ExpList.h:2266
void WriteVtkPieceFooter(std::ostream &outfile, int expansion)
Definition: ExpList.cpp:3461
virtual void v_ExtractPhysToBnd(const int i, const Array< OneD, const NekDouble > &phys, Array< OneD, NekDouble > &bnd)
Definition: ExpList.cpp:5273
void GetBwdWeight(Array< OneD, NekDouble > &weightAver, Array< OneD, NekDouble > &weightJump)
Get the weight value for boundary conditions for boundary average and jump calculations.
Definition: ExpList.cpp:4071
virtual void v_AddTraceIntegralToOffDiag(const Array< OneD, const NekDouble > &FwdFlux, const Array< OneD, const NekDouble > &BwdFlux, Array< OneD, NekDouble > &outarray)
Definition: ExpList.cpp:5700
virtual std::vector< bool > & v_GetLeftAdjacentTraces(void)
Definition: ExpList.cpp:4304
void InitialiseExpVector(const SpatialDomains::ExpansionInfoMap &expmap)
Define a list of elements using the geometry and basis key information in expmap;.
Definition: ExpList.cpp:1446
void SetupCoeffPhys(bool DeclareCoeffPhysArrays=true, bool SetupOffsets=true)
Definition of the total number of degrees of freedom and quadrature points and offsets to access data...
Definition: ExpList.cpp:1403
static SpatialDomains::BoundaryConditionShPtr GetBoundaryCondition(const SpatialDomains::BoundaryConditionCollection &collection, unsigned int index, const std::string &variable)
Definition: ExpList.cpp:5429
virtual void v_PhysDirectionalDeriv(const Array< OneD, const NekDouble > &direction, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
Definition: ExpList.cpp:2079
virtual void v_GetBCValues(Array< OneD, NekDouble > &BndVals, const Array< OneD, NekDouble > &TotField, int BndID)
Definition: ExpList.cpp:4935
virtual void v_GetLocTraceFromTracePts(const Array< OneD, const NekDouble > &Fwd, const Array< OneD, const NekDouble > &Bwd, Array< OneD, NekDouble > &locTraceFwd, Array< OneD, NekDouble > &locTraceBwd)
Definition: ExpList.cpp:4801
virtual void v_WriteTecplotHeader(std::ostream &outfile, std::string var="")
Definition: ExpList.cpp:3070
virtual std::shared_ptr< ExpList > & v_GetPlane(int n)
Definition: ExpList.cpp:5450
int GetCoeff_Offset(int n) const
Get the start offset position for a local contiguous list of coeffs correspoinding to element n.
Definition: ExpList.h:2087
int GetExpSize(void)
This function returns the number of elements in the expansion.
Definition: ExpList.h:2046
virtual void v_AddTraceQuadPhysToOffDiag(const Array< OneD, const NekDouble > &Fwd, const Array< OneD, const NekDouble > &Bwd, Array< OneD, NekDouble > &field)
Definition: ExpList.cpp:4792
virtual void v_ClearGlobalLinSysManager(void)
Definition: ExpList.cpp:3671
virtual void v_UnsetGlobalLinSys(GlobalLinSysKey, bool)
Definition: ExpList.cpp:3683
void GeneralGetFieldDefinitions(std::vector< LibUtilities::FieldDefinitionsSharedPtr > &fielddef, int NumHomoDir=0, Array< OneD, LibUtilities::BasisSharedPtr > &HomoBasis=LibUtilities::NullBasisSharedPtr1DArray, std::vector< NekDouble > &HomoLen=LibUtilities::NullNekDoubleVector, bool homoStrips=false, std::vector< unsigned int > &HomoSIDs=LibUtilities::NullUnsignedIntVector, std::vector< unsigned int > &HomoZIDs=LibUtilities::NullUnsignedIntVector, std::vector< unsigned int > &HomoYIDs=LibUtilities::NullUnsignedIntVector)
Definition: ExpList.cpp:3771
virtual void v_GetPeriodicEntities(PeriodicMap &periodicVerts, PeriodicMap &periodicEdges, PeriodicMap &periodicFaces)
Definition: ExpList.cpp:5421
virtual void v_CurlCurl(Array< OneD, Array< OneD, NekDouble > > &Vel, Array< OneD, Array< OneD, NekDouble > > &Q)
Definition: ExpList.cpp:2011
virtual void v_LocalToGlobal(bool UseComm)
Definition: ExpList.cpp:5023
virtual const Array< OneD, const SpatialDomains::BoundaryConditionShPtr > & v_GetBndConditions()
Definition: ExpList.cpp:5378
virtual LibUtilities::NekManager< GlobalLinSysKey, GlobalLinSys > & v_GetGlobalLinSysManager(void)
Definition: ExpList.cpp:3691
virtual 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)
Definition: ExpList.cpp:4925
virtual ~ExpList()
The default destructor.
Definition: ExpList.cpp:1615
virtual void v_FwdTransLocalElmt(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
Definition: ExpList.cpp:2168
int GetPoolCount(std::string)
Definition: ExpList.cpp:5635
virtual void v_ImposeDirichletConditions(Array< OneD, NekDouble > &outarray)
Definition: ExpList.cpp:4997
Array< OneD, const unsigned int > GetZIDs(void)
This function returns a vector containing the wave numbers in z-direction associated with the 3D homo...
Definition: ExpList.h:585
virtual void v_EvaluateBoundaryConditions(const NekDouble time=0.0, const std::string varName="", const NekDouble x2_in=NekConstants::kNekUnsetDouble, const NekDouble x3_in=NekConstants::kNekUnsetDouble)
Definition: ExpList.cpp:5399
virtual const std::vector< bool > & v_GetLeftAdjacentFaces(void) const
Definition: ExpList.cpp:4826
Array< OneD, int > m_coeff_offset
Offset of elemental data into the array m_coeffs.
Definition: ExpList.h:1124
std::shared_ptr< AssemblyMapDG > & GetTraceMap(void)
Definition: ExpList.h:2166
virtual void v_GetMovingFrames(const SpatialDomains::GeomMMF MMFdir, const Array< OneD, const NekDouble > &CircCentre, Array< OneD, Array< OneD, NekDouble > > &outarray)
Definition: ExpList.cpp:4084
size_t GetNumElmts(void)
This function returns the number of elements in the expansion which may be different for a homogeoeno...
Definition: ExpList.h:648
virtual std::shared_ptr< AssemblyMapDG > & v_GetTraceMap()
Definition: ExpList.cpp:4291
Array< OneD, std::pair< int, int > > m_coeffsToElmt
m_coeffs to elemental value map
Definition: ExpList.h:1128
virtual void v_GetFwdBwdTracePhys(Array< OneD, NekDouble > &Fwd, Array< OneD, NekDouble > &Bwd)
Definition: ExpList.cpp:4757
NekDouble PhysEvaluate(const Array< OneD, const NekDouble > &coords, const Array< OneD, const NekDouble > &phys)
Definition: ExpList.cpp:3008
virtual GlobalLinSysKey v_LinearAdvectionDiffusionReactionSolve(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const StdRegions::ConstFactorMap &factors, const StdRegions::VarCoeffMap &varcoeff, const MultiRegions::VarFactorsMap &varfactors, const Array< OneD, const NekDouble > &dirForcing, const bool PhysSpaceForcing)
Definition: ExpList.cpp:4870
virtual NekDouble v_Integral(const Array< OneD, const NekDouble > &inarray)
Definition: ExpList.cpp:3591
virtual void v_ExtractDataToCoeffs(LibUtilities::FieldDefinitionsSharedPtr &fielddef, std::vector< NekDouble > &fielddata, std::string &field, Array< OneD, NekDouble > &coeffs, std::unordered_map< int, int > zIdToPlane)
Extract data from raw field data into expansion list.
Definition: ExpList.cpp:3954
virtual std::map< int, RobinBCInfoSharedPtr > v_GetRobinBCInfo(void)
Definition: ExpList.cpp:5411
virtual const Array< OneD, const int > & v_GetTraceBndMap()
Definition: ExpList.cpp:4299
virtual void v_GetBoundaryNormals(int i, Array< OneD, Array< OneD, NekDouble > > &normals)
Definition: ExpList.cpp:5310
virtual Array< OneD, const NekDouble > v_HomogeneousEnergy(void)
Definition: ExpList.cpp:3625
virtual NekDouble v_GetHomoLen(void)
Definition: ExpList.cpp:3641
const LocTraceToTraceMapSharedPtr & GetLocTraceToTraceMap() const
Definition: ExpList.h:2132
virtual Array< OneD, const unsigned int > v_GetZIDs(void)
Definition: ExpList.cpp:3655
void ExtractCoeffsToCoeffs(const std::shared_ptr< ExpList > &fromExpList, const Array< OneD, const NekDouble > &fromCoeffs, Array< OneD, NekDouble > &toCoeffs)
Extract the data from fromField using fromExpList the coeffs using the basic ExpList Elemental expans...
Definition: ExpList.cpp:3938
void GetCoords(Array< OneD, NekDouble > &coord_0, Array< OneD, NekDouble > &coord_1=NullNekDouble1DArray, Array< OneD, NekDouble > &coord_2=NullNekDouble1DArray)
This function calculates the coordinates of all the elemental quadrature points .
Definition: ExpList.h:1770
std::shared_ptr< GlobalLinSys > GenGlobalBndLinSys(const GlobalLinSysKey &mkey, const AssemblyMapSharedPtr &locToGloMap)
Generate a GlobalLinSys from information provided by the key "mkey" and the mapping provided in LocTo...
Definition: ExpList.cpp:2800
virtual void v_SetBndCondBwdWeight(const int index, const NekDouble value)
Definition: ExpList.cpp:4819
void UnsetGlobalLinSys(GlobalLinSysKey, bool)
Definition: ExpList.cpp:5640
virtual void v_SmoothField(Array< OneD, NekDouble > &field)
Definition: ExpList.cpp:2200
virtual void v_AppendFieldData(LibUtilities::FieldDefinitionsSharedPtr &fielddef, std::vector< NekDouble > &fielddata)
Definition: ExpList.cpp:3898
std::vector< bool > m_collectionsDoInit
Vector of bools to act as an initialise on first call flag.
Definition: ExpList.h:1118
bool m_physState
The state of the array m_phys.
Definition: ExpList.h:1104
virtual void v_HomogeneousFwdTrans(const int npts, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, bool Shuff=true, bool UnShuff=true)
Definition: ExpList.cpp:4895
void ExtractCoeffsFromFile(const std::string &fileName, LibUtilities::CommSharedPtr comm, const std::string &varName, Array< OneD, NekDouble > &coeffs)
Definition: ExpList.cpp:3698
virtual void v_DealiasedProd(const int num_dofs, const Array< OneD, NekDouble > &inarray1, const Array< OneD, NekDouble > &inarray2, Array< OneD, NekDouble > &outarray)
Definition: ExpList.cpp:4915
void AddRightIPTBaseMatrix(const Array< OneD, const DNekMatSharedPtr > ElmtJacQuad, Array< OneD, DNekMatSharedPtr > ElmtJacCoef)
Definition: ExpList.cpp:6215
void GetLocTraceFromTracePts(const Array< OneD, const NekDouble > &Fwd, const Array< OneD, const NekDouble > &Bwd, Array< OneD, NekDouble > &locTraceFwd, Array< OneD, NekDouble > &locTraceBwd)
Definition: ExpList.h:2214
virtual void v_WriteVtkPieceData(std::ostream &outfile, int expansion, std::string var)
Definition: ExpList.cpp:3468
virtual void v_WriteVtkPieceHeader(std::ostream &outfile, int expansion, int istrip)
Definition: ExpList.cpp:3328
std::shared_ptr< ExpList > GetSharedThisPtr()
Returns a shared pointer to the current object.
Definition: ExpList.h:954
int GetShapeDimension()
This function returns the dimension of the shape of the element eid.
Definition: ExpList.h:1920
NekDouble H1(const Array< OneD, const NekDouble > &inarray, const Array< OneD, const NekDouble > &soln=NullNekDouble1DArray)
Calculates the error of the global spectral/hp element approximation.
Definition: ExpList.cpp:3753
std::vector< int > m_coll_phys_offset
Offset of elemental data into the array m_phys.
Definition: ExpList.h:1122
LibUtilities::CommSharedPtr m_comm
Communicator.
Definition: ExpList.h:1053
std::shared_ptr< GlobalLinSys > GenGlobalLinSys(const GlobalLinSysKey &mkey, const std::shared_ptr< AssemblyMapCG > &locToGloMap)
This operation constructs the global linear system of type mkey.
Definition: ExpList.cpp:2782
void WriteVtkHeader(std::ostream &outfile)
Definition: ExpList.cpp:3314
std::shared_ptr< LocalRegions::ExpansionVector > m_exp
The list of local expansions.
Definition: ExpList.h:1115
int m_ncoeffs
The total number of local degrees of freedom. m_ncoeffs .
Definition: ExpList.h:1060
void GenerateElementVector(const int ElementID, const NekDouble scalar1, const NekDouble scalar2, Array< OneD, NekDouble > &outarray)
Generate vector v such that v[i] = scalar1 if i is in the element < ElementID. Otherwise,...
Definition: ExpList.cpp:4128
std::shared_ptr< DNekMat > GenGlobalMatrixFull(const GlobalLinSysKey &mkey, const std::shared_ptr< AssemblyMapCG > &locToGloMap)
Definition: ExpList.cpp:2630
virtual void v_NormVectorIProductWRTBase(Array< OneD, const NekDouble > &V1, Array< OneD, const NekDouble > &V2, Array< OneD, NekDouble > &outarray, int BndID)
Definition: ExpList.cpp:4944
virtual void v_ExtractElmtToBndPhys(const int i, const Array< OneD, NekDouble > &elmt, Array< OneD, NekDouble > &boundary)
Definition: ExpList.cpp:5196
virtual void v_ExtractPhysToBndElmt(const int i, const Array< OneD, const NekDouble > &phys, Array< OneD, NekDouble > &bndElmt)
Definition: ExpList.cpp:5234
std::map< int, RobinBCInfoSharedPtr > GetRobinBCInfo()
Definition: ExpList.h:883
virtual void v_Upwind(const Array< OneD, const Array< OneD, NekDouble > > &Vec, const Array< OneD, const NekDouble > &Fwd, const Array< OneD, const NekDouble > &Bwd, Array< OneD, NekDouble > &Upwind)
Definition: ExpList.cpp:4185
virtual void v_FillBwdWithBwdWeight(Array< OneD, NekDouble > &weightave, Array< OneD, NekDouble > &weightjmp)
Definition: ExpList.cpp:5361
virtual void v_Curl(Array< OneD, Array< OneD, NekDouble > > &Vel, Array< OneD, Array< OneD, NekDouble > > &Q)
Definition: ExpList.cpp:1962
virtual void v_PhysGalerkinProjection1DScaled(const NekDouble scale, const Array< OneD, NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
Definition: ExpList.cpp:6272
void GeneralMatrixOp(const GlobalMatrixKey &gkey, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
This function calculates the result of the multiplication of a matrix of type specified by mkey with ...
Definition: ExpList.cpp:2418
virtual void v_SetUpPhysNormals()
: Set up a normal along the trace elements between two elements at elemental level
Definition: ExpList.cpp:5173
virtual void v_GlobalToLocal(void)
Definition: ExpList.cpp:5038
virtual LibUtilities::TranspositionSharedPtr v_GetTransposition(void)
Definition: ExpList.cpp:3633
const std::shared_ptr< LocalRegions::ExpansionVector > GetExp() const
This function returns the vector of elements in the expansion.
Definition: ExpList.h:2079
SpatialDomains::MeshGraphSharedPtr m_graph
Mesh associated with this expansion list.
Definition: ExpList.h:1057
virtual void v_MultiplyByInvMassMatrix(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
Definition: ExpList.cpp:4849
virtual void v_AddTraceQuadPhysToField(const Array< OneD, const NekDouble > &Fwd, const Array< OneD, const NekDouble > &Bwd, Array< OneD, NekDouble > &field)
Definition: ExpList.cpp:4783
virtual const Array< OneD, const NekDouble > & v_GetBndCondBwdWeight()
Definition: ExpList.cpp:4811
virtual NekDouble v_L2(const Array< OneD, const NekDouble > &phys, const Array< OneD, const NekDouble > &soln=NullNekDouble1DArray)
Definition: ExpList.cpp:3546
void WriteVtkFooter(std::ostream &outfile)
Definition: ExpList.cpp:3322
void MultiplyByBlockMatrix(const GlobalMatrixKey &gkey, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
Definition: ExpList.cpp:1627
virtual std::shared_ptr< ExpList > & v_GetTrace()
Definition: ExpList.cpp:4283
void GetElmtNormalLength(Array< OneD, NekDouble > &lengthsFwd, Array< OneD, NekDouble > &lengthsBwd)
Get the length of elements in boundary normal direction.
Definition: ExpList.cpp:4593
virtual NekDouble v_VectorFlux(const Array< OneD, Array< OneD, NekDouble > > &inarray)
Definition: ExpList.cpp:3605
virtual std::vector< LibUtilities::FieldDefinitionsSharedPtr > v_GetFieldDefinitions(void)
Definition: ExpList.cpp:3883
std::vector< int > m_coll_coeff_offset
Offset of elemental data into the array m_coeffs.
Definition: ExpList.h:1120
void IProductWRTDirectionalDerivBase(const Array< OneD, const NekDouble > &direction, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
Directional derivative along a given direction.
Definition: ExpList.cpp:1710
void FillBwdWithBwdWeight(Array< OneD, NekDouble > &weightave, Array< OneD, NekDouble > &weightjmp)
Fill Bwd with boundary conditions.
Definition: ExpList.h:2221
virtual void v_BwdTrans(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
Definition: ExpList.cpp:2836
virtual Array< OneD, SpatialDomains::BoundaryConditionShPtr > & v_UpdateBndConditions()
Definition: ExpList.cpp:5389
void GetMatIpwrtDeriveBase(const Array< OneD, const Array< OneD, NekDouble > > &inarray, const int nDirctn, Array< OneD, DNekMatSharedPtr > &mtxPerVar)
Definition: ExpList.cpp:5708
virtual void v_GetCoords(Array< OneD, NekDouble > &coord_0, Array< OneD, NekDouble > &coord_1=NullNekDouble1DArray, Array< OneD, NekDouble > &coord_2=NullNekDouble1DArray)
Definition: ExpList.cpp:5113
virtual void v_WriteTecplotField(std::ostream &outfile, int expansion)
Definition: ExpList.cpp:3281
virtual void v_FillBndCondFromField(const Array< OneD, NekDouble > coeffs)
Definition: ExpList.cpp:5006
Collections::CollectionVector m_collections
Definition: ExpList.h:1116
virtual int v_GetPoolCount(std::string)
Definition: ExpList.cpp:3677
virtual void v_PhysInterp1DScaled(const NekDouble scale, const Array< OneD, NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
Definition: ExpList.cpp:5651
virtual void v_HomogeneousBwdTrans(const int npts, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, bool Shuff=true, bool UnShuff=true)
Definition: ExpList.cpp:4905
void ApplyGeomInfo()
Apply geometry information to each expansion.
Definition: ExpList.cpp:3031
virtual void v_PhysDeriv(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &out_d0, Array< OneD, NekDouble > &out_d1, Array< OneD, NekDouble > &out_d2)
Definition: ExpList.cpp:1864
virtual void v_FwdTransBndConstrained(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
Definition: ExpList.cpp:2177
std::unordered_map< int, int > m_elmtToExpId
Mapping from geometry ID of element to index inside m_exp.
Definition: ExpList.h:1136
virtual void v_WriteTecplotZone(std::ostream &outfile, int expansion)
Definition: ExpList.cpp:3108
LibUtilities::SessionReaderSharedPtr m_session
Session.
Definition: ExpList.h:1055
virtual void v_PeriodicBwdCopy(const Array< OneD, const NekDouble > &Fwd, Array< OneD, NekDouble > &Bwd)
Definition: ExpList.cpp:5368
virtual void v_FillBwdWithBoundCond(const Array< OneD, NekDouble > &Fwd, Array< OneD, NekDouble > &Bwd, bool PutFwdInBwdOnBCs)
Definition: ExpList.cpp:4774
void DivideByQuadratureMetric(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
Divided by the metric jacobi and quadrature weights.
Definition: ExpList.cpp:1664
virtual const Array< OneD, const std::shared_ptr< ExpList > > & v_GetBndCondExpansions(void)
Definition: ExpList.cpp:4158
Array< OneD, int > m_phys_offset
Offset of elemental data into the array m_phys.
Definition: ExpList.h:1126
virtual void v_SetHomoLen(const NekDouble lhom)
Definition: ExpList.cpp:3649
void Upwind(const Array< OneD, const NekDouble > &Vn, const Array< OneD, const NekDouble > &Fwd, const Array< OneD, const NekDouble > &Bwd, Array< OneD, NekDouble > &Upwind)
Definition: ExpList.h:2155
virtual void v_GetNormals(Array< OneD, Array< OneD, NekDouble > > &normals)
Populate normals with the normals of all expansions.
Definition: ExpList.cpp:4384
const DNekScalBlkMatSharedPtr GenBlockMatrix(const GlobalMatrixKey &gkey)
This function assembles the block diagonal matrix of local matrices of the type mtype.
Definition: ExpList.cpp:2239
void PhysDeriv(Direction edir, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &out_d)
Definition: ExpList.h:1813
void MultiplyByElmtInvMass(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
This function elementally mulplies the coefficient space of Sin my the elemental inverse of the mass ...
Definition: ExpList.cpp:2130
void BwdTrans(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
This function elementally evaluates the backward transformation of the global spectral/hp element exp...
Definition: ExpList.h:1717
virtual void v_GetBndElmtExpansion(int i, std::shared_ptr< ExpList > &result, const bool DeclareCoeffPhysArrays)
Definition: ExpList.cpp:5186
virtual void v_FwdTrans(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
Definition: ExpList.cpp:5052
virtual std::shared_ptr< ExpList > & v_UpdateBndCondExpansion(int i)
Definition: ExpList.cpp:4166
int GetPhys_Offset(int n) const
Get the start offset position for a local contiguous list of quadrature points in a full array corres...
Definition: ExpList.h:2094
virtual const std::shared_ptr< LocTraceToTraceMap > & v_GetLocTraceToTraceMap(void) const
Definition: ExpList.cpp:6347
virtual void v_IProductWRTDerivBase(const int dir, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
Definition: ExpList.cpp:1691
void ExtractDataToCoeffs(LibUtilities::FieldDefinitionsSharedPtr &fielddef, std::vector< NekDouble > &fielddata, std::string &field, Array< OneD, NekDouble > &coeffs, std::unordered_map< int, int > zIdToPlane=std::unordered_map< int, int >())
Extract the data in fielddata into the coeffs.
Definition: ExpList.cpp:3930
ExpansionType m_expType
Exapnsion type.
Definition: ExpList.h:1048
virtual void v_AddTraceIntegral(const Array< OneD, const NekDouble > &Fn, Array< OneD, NekDouble > &outarray)
Definition: ExpList.cpp:4740
Array< OneD, NekDouble > m_phys
The global expansion evaluated at the quadrature points.
Definition: ExpList.h:1096
ExpansionType GetExpType(void)
Returns the type of the expansion.
Definition: ExpList.cpp:1610
NekDouble Linf(const Array< OneD, const NekDouble > &inarray, const Array< OneD, const NekDouble > &soln=NullNekDouble1DArray)
This function calculates the error of the global spectral/hp element approximation.
Definition: ExpList.cpp:3508
int GetTotPoints(void) const
Returns the total number of quadrature points m_npoints .
Definition: ExpList.h:1557
int GetCoordim(int eid)
This function returns the dimension of the coordinates of the element eid.
Definition: ExpList.h:1911
void GetDiagMatIpwrtBase(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, DNekMatSharedPtr > &mtxPerVar)
Definition: ExpList.cpp:5851
GlobalSysSolnType GetGlobalSysSolnType() const
Return the associated solution type.
Describes a matrix with ordering defined by a local to global map.
const StdRegions::ConstFactorMap & GetConstFactors() const
Returns all the constants.
LibUtilities::ShapeType GetShapeType() const
Return the expansion type associated with key.
const StdRegions::VarCoeffMap & GetVarCoeffs() const
StdRegions::MatrixType GetMatrixType() const
Return the matrix type.
Class representing a prismatic element in reference space.
Definition: StdPrismExp.h:45
static void Dscal(const int &n, const double &alpha, double *x, const int &incx)
BLAS level 1: x = alpha x.
Definition: Blas.hpp:149
std::map< OperatorType, ImplementationType > OperatorImpMap
Definition: Operator.h:126
void PhysGalerkinProject3D(const BasisKey &fbasis0, const BasisKey &fbasis1, const BasisKey &fbasis2, const Array< OneD, const NekDouble > &from, const BasisKey &tbasis0, const BasisKey &tbasis1, const BasisKey &tbasis2, Array< OneD, NekDouble > &to)
std::shared_ptr< FieldIO > FieldIOSharedPtr
Definition: FieldIO.h:322
static const BasisKey NullBasisKey(eNoBasisType, 0, NullPointsKey)
Defines a null basis with no type or points.
void Interp1D(const BasisKey &fbasis0, const Array< OneD, const NekDouble > &from, const BasisKey &tbasis0, Array< OneD, NekDouble > &to)
this function interpolates a 1D function evaluated at the quadrature points of the basis fbasis0 to ...
Definition: Interp.cpp:47
std::shared_ptr< SessionReader > SessionReaderSharedPtr
std::shared_ptr< FieldDefinitions > FieldDefinitionsSharedPtr
Definition: FieldIO.h:184
void Interp2D(const BasisKey &fbasis0, const BasisKey &fbasis1, const Array< OneD, const NekDouble > &from, const BasisKey &tbasis0, const BasisKey &tbasis1, Array< OneD, NekDouble > &to)
this function interpolates a 2D function evaluated at the quadrature points of the 2D basis,...
Definition: Interp.cpp:101
int GetNumberOfCoefficients(ShapeType shape, std::vector< unsigned int > &modes, int offset=0)
Definition: ShapeType.hpp:305
FieldIOFactory & GetFieldIOFactory()
Returns the FieldIO factory.
Definition: FieldIO.cpp:70
std::shared_ptr< Transposition > TranspositionSharedPtr
@ eNodalTriElec
2D Nodal Electrostatic Points on a Triangle
Definition: PointsType.h:81
@ eGaussLobattoLegendre
1D Gauss-Lobatto-Legendre quadrature points
Definition: PointsType.h:51
std::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition: Comm.h:55
void PhysGalerkinProject2D(const BasisKey &fbasis0, const BasisKey &fbasis1, const Array< OneD, const NekDouble > &from, const BasisKey &tbasis0, const BasisKey &tbasis1, Array< OneD, NekDouble > &to)
@ eGauss_Lagrange
Lagrange Polynomials using the Gauss points.
Definition: BasisType.h:57
@ eOrtho_A
Principle Orthogonal Functions .
Definition: BasisType.h:42
@ eGLL_Lagrange
Lagrange for SEM basis .
Definition: BasisType.h:56
std::shared_ptr< PointExp > PointExpSharedPtr
Definition: PointExp.h:132
std::shared_ptr< Expansion > ExpansionSharedPtr
Definition: Expansion.h:66
std::shared_ptr< Expansion2D > Expansion2DSharedPtr
Definition: Expansion1D.h:46
std::shared_ptr< Expansion0D > Expansion0DSharedPtr
Definition: Expansion0D.h:47
std::shared_ptr< Expansion1D > Expansion1DSharedPtr
Definition: Expansion1D.h:50
std::shared_ptr< Expansion3D > Expansion3DSharedPtr
Definition: Expansion2D.h:47
std::vector< ExpansionSharedPtr > ExpansionVector
Definition: Expansion.h:68
const std::vector< NekDouble > velocity
MultiRegions::Direction const DirCartesianMap[]
Definition: ExpList.h:86
void AlignFace(const StdRegions::Orientation orient, const int nquad1, const int nquad2, const Array< OneD, const NekDouble > &in, Array< OneD, NekDouble > &out)
Helper function to re-align face to a given orientation.
Definition: ExpList.cpp:4315
static ExpListSharedPtr NullExpListSharedPtr
Definition: ExpList.h:1499
std::shared_ptr< AssemblyMapCG > AssemblyMapCGSharedPtr
Definition: AssemblyMapCG.h:50
std::shared_ptr< RobinBCInfo > RobinBCInfoSharedPtr
const char *const GlobalSysSolnTypeMap[]
static LibUtilities::NekManager< GlobalLinSysKey, GlobalLinSys > NullGlobalLinSysManager
Definition: ExpList.h:1503
std::shared_ptr< GlobalLinSys > GlobalLinSysSharedPtr
Pointer to a GlobalLinSys object.
Definition: GlobalLinSys.h:51
std::shared_ptr< GlobalMatrix > GlobalMatrixSharedPtr
Shared pointer to a GlobalMatrix object.
Definition: GlobalMatrix.h:84
GlobalLinSysFactory & GetGlobalLinSysFactory()
static LocTraceToTraceMapSharedPtr NullLocTraceToTraceMapSharedPtr
std::shared_ptr< ExpList > ExpListSharedPtr
Shared pointer to an ExpList object.
static GlobalLinSysKey NullGlobalLinSysKey(StdRegions::eNoMatrixType)
std::shared_ptr< LocTraceToTraceMap > LocTraceToTraceMapSharedPtr
std::map< StdRegions::ConstFactorType, Array< OneD, NekDouble > > VarFactorsMap
std::shared_ptr< AssemblyMap > AssemblyMapSharedPtr
Definition: AssemblyMap.h:50
std::map< int, std::vector< PeriodicEntity > > PeriodicMap
std::map< GlobalMatrixKey, DNekScalBlkMatSharedPtr > BlockMatrixMap
A map between global matrix keys and their associated block matrices.
Definition: ExpList.h:90
static const NekDouble kNekZeroTol
std::shared_ptr< QuadGeom > QuadGeomSharedPtr
Definition: HexGeom.h:45
GeomMMF
Principle direction for MMF.
std::shared_ptr< BoundaryConditionBase > BoundaryConditionShPtr
Definition: Conditions.h:212
std::shared_ptr< PrismGeom > PrismGeomSharedPtr
Definition: PrismGeom.h:82
std::shared_ptr< std::vector< std::pair< GeometrySharedPtr, int > > > GeometryLinkSharedPtr
Definition: MeshGraph.h:166
std::map< int, BoundaryConditionMapShPtr > BoundaryConditionCollection
Definition: Conditions.h:219
@ eDeformed
Geometry is curved or has non-constant factors.
std::shared_ptr< HexGeom > HexGeomSharedPtr
Definition: HexGeom.h:84
std::shared_ptr< SegGeom > SegGeomSharedPtr
Definition: Geometry2D.h:59
std::shared_ptr< PyrGeom > PyrGeomSharedPtr
Definition: PyrGeom.h:75
std::shared_ptr< ExpansionInfo > ExpansionInfoShPtr
Definition: MeshGraph.h:140
std::shared_ptr< TetGeom > TetGeomSharedPtr
Definition: TetGeom.h:82
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition: MeshGraph.h:174
std::shared_ptr< BoundaryConditionMap > BoundaryConditionMapShPtr
Definition: Conditions.h:218
std::shared_ptr< PointGeom > PointGeomSharedPtr
Definition: Geometry.h:57
std::shared_ptr< Geometry2D > Geometry2DSharedPtr
Definition: Geometry.h:62
std::shared_ptr< Geometry > GeometrySharedPtr
Definition: Geometry.h:51
std::shared_ptr< TriGeom > TriGeomSharedPtr
Definition: TriGeom.h:56
std::shared_ptr< Geometry1D > Geometry1DSharedPtr
Definition: Geometry.h:61
std::map< int, ExpansionInfoShPtr > ExpansionInfoMap
Definition: MeshGraph.h:141
std::map< int, CompositeSharedPtr > CompositeMap
Definition: MeshGraph.h:136
std::shared_ptr< StdExpansion > StdExpansionSharedPtr
VarCoeffMap RestrictCoeffMap(const VarCoeffMap &m, size_t offset, size_t cnt)
Definition: StdRegions.hpp:349
std::map< ConstFactorType, NekDouble > ConstFactorMap
Definition: StdRegions.hpp:402
std::map< StdRegions::VarCoeffType, VarCoeffEntry > VarCoeffMap
Definition: StdRegions.hpp:346
std::vector< double > z(NPUPPER)
std::vector< double > d(NPUPPER *NPUPPER)
StdRegions::ConstFactorMap factors
NekMatrix< NekMatrix< NekMatrix< NekDouble, StandardMatrixTag >, ScaledMatrixTag >, BlockMatrixTag > DNekScalBlkMat
Definition: NekTypeDefs.hpp:68
NekMatrix< NekMatrix< NekDouble, StandardMatrixTag >, ScaledMatrixTag > DNekScalMat
std::shared_ptr< DNekScalMat > DNekScalMatSharedPtr
std::pair< IndexType, IndexType > CoordType
std::shared_ptr< DNekScalBlkMat > DNekScalBlkMatSharedPtr
Definition: NekTypeDefs.hpp:79
@ ePOSITIVE_DEFINITE_SYMMETRIC_BANDED
@ ePOSITIVE_DEFINITE_SYMMETRIC
std::map< CoordType, NekDouble > COOMatType
static Array< OneD, NekDouble > NullNekDouble1DArray
std::shared_ptr< DNekMat > DNekMatSharedPtr
Definition: NekTypeDefs.hpp:75
double NekDouble
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 Neg(int n, T *x, const int incx)
Negate x = -x.
Definition: Vmath.hpp:292
T Vsum(int n, const T *x, const int incx)
Subtract return sum(x)
Definition: Vmath.hpp:608
void Scatr(int n, const T *x, const int *y, T *z)
Scatter vector z[y[i]] = x[i].
Definition: Vmath.hpp:539
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
T Vmax(int n, const T *x, const int incx)
Return the maximum element in x – called vmax to avoid conflict with max.
Definition: Vmath.hpp:644
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.hpp:825
void Vsub(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Subtract vector z = x-y.
Definition: Vmath.hpp:220
scalarT< T > abs(scalarT< T > in)
Definition: scalar.hpp:298
scalarT< T > sqrt(scalarT< T > in)
Definition: scalar.hpp:294
Used to lookup the create function in NekManager.
Definition: MatrixKey.h:69
std::shared_ptr< RobinBCInfo > next