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