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