Nektar++
ExpList1D.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File ExpList1D.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 1D definition
32 //
33 ///////////////////////////////////////////////////////////////////////////////
34 
35 #include <iomanip>
36 
37 #include <boost/core/ignore_unused.hpp>
38 
39 #include <MultiRegions/ExpList1D.h>
41 #include <LocalRegions/SegExp.h>
42 #include <LocalRegions/QuadExp.h>
44 #include <LibUtilities/Foundations/ManagerAccess.h> // for PointsManager, etc
46 
47 using namespace std;
48 
49 namespace Nektar
50 {
51  namespace MultiRegions
52  {
53  /**
54  * @class ExpList1D
55  * This multi-elemental expansion, which does not exhibit any coupling
56  * between the expansion on the separate elements, can be formulated
57  * as, \f[u^{\delta}(x_i)=\sum_{e=1}^{{N_{\mathrm{el}}}}
58  * \sum_{n=0}^{N^{e}_m-1}\hat{u}_n^e\phi_n^e(x_i).\f]
59  * where \f${N_{\mathrm{el}}}\f$ is the number of elements and
60  * \f$N^{e}_m\f$ is the local elemental number of expansion modes.
61  *
62  * Instances of this class may be optionally constructed which use
63  * generalised segment expansions (LocalRegions#GenSegExp), rather than
64  * the standard segment expansions (LocalRegions#SegExp).
65  * LocalRegions#GenSegExp provides additional spatial
66  * data including segment normals and is enabled using the \a
67  * UseGenSegExp flag.
68  *
69  * This class inherits all its variables and member functions from the
70  * base class MultiRegions#ExpList.
71  */
72 
73  /**
74  * Assumes use of standard segment expansions only. All data storage
75  * areas are initialised to empty arrays by the default ExpList
76  * constructor.
77  */
78  ExpList1D::ExpList1D():
79  ExpList()
80  {
81  SetExpType(e1D);
82  }
83 
84 
85  /**
86  * Creates an identical copy of another ExpList1D object.
87  */
88  ExpList1D::ExpList1D(const ExpList1D &In, const bool DeclareCoeffPhysArrays):
89  ExpList(In,DeclareCoeffPhysArrays)
90  {
91  SetExpType(e1D);
92  }
93 
94  /**
95  *
96  */
98  const std::vector<unsigned int> &eIDs,
99  const bool DeclareCoeffPhysArrays,
100  const Collections::ImplementationType ImpType):
101  ExpList(In, eIDs, DeclareCoeffPhysArrays)
102  {
103  SetExpType(e1D);
104 
105  // Setup Default optimisation information.
106  int nel = GetExpSize();
109 
110  // Allocate storage for data and populate element offset lists.
112 
114  CreateCollections(ImpType);
115  }
116 
117 
118  /**
119  * After initialising the data inherited through MultiRegions#ExpList,
120  * populate the expansion list from the segments defined in the supplied
121  * SpatialDomains#MeshGraph1D. All expansions in the graph are defined
122  * using the same LibUtilities#BasisKey which overrides that specified
123  * in \a graph1D.
124  *
125  * @see ExpList1D#ExpList1D(SpatialDomains::MeshGraph1D&, bool)
126  * for details.
127  * @deprecated This constructor is no longer required since
128  * the basis key is now available from the graph.
129  * @param Ba BasisKey describing quadrature points and
130  * number of modes.
131  * @param graph1D Domain and expansion definitions.
132  */
134  const LibUtilities::BasisKey &Ba,
135  const SpatialDomains::MeshGraphSharedPtr &graph1D,
136  const Collections::ImplementationType ImpType):
137  ExpList(pSession,graph1D)
138  {
139  SetExpType(e1D);
140 
141  int id=0;
144 
145  const SpatialDomains::ExpansionMap &expansions
146  = graph1D->GetExpansions();
147 
148  // For each element in the mesh, create a segment expansion using
149  // the supplied BasisKey and segment geometry.
150  for (auto &expIt : expansions)
151  {
152  if ((SegmentGeom = std::dynamic_pointer_cast<
154  expIt.second->m_geomShPtr)))
155  {
157  ::AllocateSharedPtr(Ba,SegmentGeom);
158  seg->SetElmtId(id++);
159  (*m_exp).push_back(seg);
160  }
161  else
162  {
163  ASSERTL0(false,"dynamic cast to a SegGeom failed");
164  }
165  }
166 
167  // Setup Default optimisation information.
168  int nel = GetExpSize();
171 
172  // Allocate storage for data and populate element offset lists.
174 
177 
179  CreateCollections(ImpType);
180  }
181 
182 
183  /**
184  * Given a mesh \a graph1D, containing information about the domain and
185  * the spectral/hp element expansion, this constructor fills the list
186  * of local expansions \texttt{m_exp} with the proper expansions,
187  * calculates the total number of quadrature points \f$x_i\f$ and local
188  * expansion coefficients \f$\hat{u}^e_n\f$ and allocates memory for
189  * the arrays #m_coeffs and #m_phys.
190  *
191  * For each element its corresponding LibUtilities#BasisKey is
192  * retrieved and this is used to construct either a standard segment
193  * (LocalRegions#SegExp) or a generalised segment
194  * (LocalRegions#GenSegExp) which is stored in the list #m_exp.
195  * Finally, ExpList#SetCoeffPhys is called to initialise the data
196  * storage areas and set up the offset arrays.
197  *
198  * @param graph1D A mesh, containing information about the
199  * domain and the spectral/hp element expansion.
200  * @param UseGenSegExp If true, create general segment expansions
201  * instead of just normal segment expansions.
202  */
204  const SpatialDomains::MeshGraphSharedPtr &graph1D,
205  const bool DeclareCoeffPhysArrays,
206  const Collections::ImplementationType ImpType):
207  ExpList(pSession,graph1D)
208  {
209  SetExpType(e1D);
210 
211  int id=0;
214 
215  // Retrieve the list of expansions
216  const SpatialDomains::ExpansionMap &expansions
217  = graph1D->GetExpansions();
218 
219  // Process each expansion in the graph
220  for (auto &expIt : expansions)
221  {
222  // Retrieve basis key from expansion
223  LibUtilities::BasisKey bkey = expIt.second->m_basisKeyVector[0];
224 
225  if ((SegmentGeom = std::dynamic_pointer_cast<
227  expIt.second->m_geomShPtr)))
228  {
230  ::AllocateSharedPtr(bkey, SegmentGeom);
231 
232  // Assign next ID
233  seg->SetElmtId(id++);
234 
235  // Add the expansion
236  (*m_exp).push_back(seg);
237  }
238  else
239  {
240  ASSERTL0(false,"dynamic cast to a SegGeom failed");
241  }
242  }
243 
244  // Setup Default optimisation information.
245  int nel = GetExpSize();
248 
249  // set up offset arrays.
251 
252  if(DeclareCoeffPhysArrays)
253  {
254  // Set up m_coeffs, m_phys.
257  }
258 
260  CreateCollections(ImpType);
261  }
262 
263 
264 
265  /**
266  * Given a mesh \a graph1D, and the spectral/hp element
267  * expansion as well as and separate information about a \a
268  * domain, this constructor fills the list of local
269  * expansions \texttt{m_exp} with the proper expansions,
270  * calculates the total number of quadrature points \f$x_i\f$
271  * and local expansion coefficients \f$\hat{u}^e_n\f$ and
272  * allocates memory for the arrays #m_coeffs and #m_phys.
273  *
274  * For each element its corresponding LibUtilities#BasisKey is
275  * retrieved and this is used to construct either a standard segment
276  * (LocalRegions#SegExp) or a generalised segment
277  * (LocalRegions#GenSegExp) which is stored in the list #m_exp.
278  * Finally, ExpList#SetCoeffPhys is called to initialise the data
279  * storage areas and set up the offset arrays.
280  *
281  * @param graph1D A mesh, containing information about the
282  * domain and the spectral/hp element expansion.
283  * @param UseGenSegExp If true, create general segment expansions
284  * instead of just normal segment expansions.
285  */
287  const SpatialDomains::MeshGraphSharedPtr &graph1D,
288  const SpatialDomains::CompositeMap &domain,
289  const bool DeclareCoeffPhysArrays,
290  const std::string var,
291  bool SetToOneSpaceDimension,
292  const Collections::ImplementationType ImpType):
293  ExpList(pSession,graph1D)
294  {
295  int j,id=0;
299 
300  // Retrieve the list of expansions
301  const SpatialDomains::ExpansionMap &expansions
302  = graph1D->GetExpansions(var);
303 
304  // Process each composite region in domain
305  for(auto &compIt : domain)
306  {
307  // Process each expansion in the graph
308  for(j = 0; j < compIt.second->m_geomVec.size(); ++j)
309  {
310  if((SegmentGeom = std::dynamic_pointer_cast<
312  compIt.second->m_geomVec[j])))
313  {
314  // Retrieve basis key from expansion and define expansion
315  auto expIt = expansions.find(SegmentGeom->GetGlobalID());
316  if(expIt != expansions.end())
317  {
318  LibUtilities::BasisKey bkey = expIt->second->m_basisKeyVector[0];
319 
320  if(SetToOneSpaceDimension)
321  {
322  SpatialDomains::SegGeomSharedPtr OneDSegmentGeom =
323  SegmentGeom->GenerateOneSpaceDimGeom();
324 
326  ::AllocateSharedPtr(bkey, OneDSegmentGeom);
327  }
328  else
329  {
331  ::AllocateSharedPtr(bkey, SegmentGeom);
332  }
333  }
334  else
335  {
336  ASSERTL0(false,"Failed to find basis key");
337  }
338  }
339  else
340  {
341  ASSERTL0(false,"Failed to dynamic cast geometry to SegGeom");
342  }
343 
344  // Assign next ID
345  seg->SetElmtId(id++);
346 
347  // Add the expansion
348  (*m_exp).push_back(seg);
349  }
350  }
351 
352  // Setup Default optimisation information.
353  int nel = GetExpSize();
356 
357  // set up offset arrays.
359 
360  if(DeclareCoeffPhysArrays)
361  {
362  // Set up m_coeffs, m_phys.
365  }
366 
368  CreateCollections(ImpType);
369  }
370 
371 
372  /**
373  * Fills the list of local expansions with the segments from the 2D
374  * mesh specified by \a domain. This CompositeMap contains a list of
375  * Composites which define the Neumann boundary.
376  * @see ExpList1D#ExpList1D(SpatialDomains::MeshGraph1D&, bool)
377  * for details.
378  * @param domain A domain, comprising of one or more composite
379  * regions,
380  * @param graph2D A mesh, containing information about the
381  * domain and the spectral/hp element expansion.
382  * @param UseGenSegExp If true, create general segment expansions
383  * instead of just normal segment expansions.
384  */
386  const SpatialDomains::CompositeMap &domain,
387  const SpatialDomains::MeshGraphSharedPtr &graph2D,
388  const bool DeclareCoeffPhysArrays,
389  const std::string variable,
390  const LibUtilities::CommSharedPtr comm,
391  const Collections::ImplementationType ImpType)
392  : ExpList(pSession,graph2D)
393  {
394  SetExpType(e1D);
395 
396  m_graph = graph2D;
397 
398  if (comm)
399  {
400  m_comm = comm;
401  }
402 
403  int j, id=0;
407 
408  // Process each composite region.
409  for(auto &compIt : domain)
410  {
411  // Process each expansion in the region.
412  for(j = 0; j < compIt.second->m_geomVec.size(); ++j)
413  {
414  if((SegmentGeom = std::dynamic_pointer_cast<
416  compIt.second->m_geomVec[j])))
417  {
418  // Retrieve the basis key from the expansion.
419  LibUtilities::BasisKey bkey = graph2D->GetEdgeBasisKey(
420  SegmentGeom, variable);
421 
423  ::AllocateSharedPtr(bkey, SegmentGeom);
424 
425  // Add the segment to the expansion list.
426  seg->SetElmtId(id++);
427  (*m_exp).push_back(seg);
428  }
429  else
430  {
431  ASSERTL0(false,"dynamic cast to a SegGeom failed");
432  }
433  }
434 
435  }
436 
437  // Setup Default optimisation information.
438  int nel = GetExpSize();
441 
442  // Allocate storage for data and populate element offset lists.
444 
445  // Set up m_coeffs, m_phys.
446  if(DeclareCoeffPhysArrays)
447  {
450  }
451 
452  CreateCollections(ImpType);
453  }
454 
455  /**
456  * Store expansions for the trace space expansions used in
457  * DisContField2D.
458  *
459  * @param bndConstraint Array of ExpList1D objects each containing a
460  * 1D spectral/hp element expansion on a single
461  * boundary region.
462  * @param bndCond Array of BoundaryCondition objects which contain
463  * information about the boundary conditions on the
464  * different boundary regions.
465  * @param locexp Complete domain expansion list.
466  * @param graph2D 2D mesh corresponding to the expansion list.
467  * @param periodicEdges List of periodic edges.
468  * @param UseGenSegExp If true, create general segment expansions
469  * instead of just normal segment expansions.
470  */
472  const LibUtilities::SessionReaderSharedPtr &pSession,
473  const Array<OneD,const ExpListSharedPtr> &bndConstraint,
475  const LocalRegions::ExpansionVector &locexp,
476  const SpatialDomains::MeshGraphSharedPtr &graph2D,
477  const PeriodicMap &periodicEdges,
478  const bool DeclareCoeffPhysArrays,
479  const std::string variable,
480  const Collections::ImplementationType ImpType):
481  ExpList(pSession,graph2D)
482  {
483  boost::ignore_unused(periodicEdges, variable);
484 
485  int i, j, id, elmtid = 0;
486  set<int> edgesDone;
487 
494 
495  SetExpType(e1D);
496 
497  map<int,int> EdgeDone;
498  map<int,int> NormalSet;
499 
501 
502  // First loop over boundary conditions to renumber
503  // Dirichlet boundaries
504  for(i = 0; i < bndCond.num_elements(); ++i)
505  {
506  if(bndCond[i]->GetBoundaryConditionType()
508  {
509  for(j = 0; j < bndConstraint[i]->GetExpSize(); ++j)
510  {
511  LibUtilities::BasisKey bkey = bndConstraint[i]
512  ->GetExp(j)->GetBasis(0)->GetBasisKey();
513  exp1D = bndConstraint[i]->GetExp(j)->
514  as<LocalRegions::Expansion1D>();
515  segGeom = exp1D->GetGeom1D();
516 
518  ::AllocateSharedPtr(bkey, segGeom);
519  edgesDone.insert(segGeom->GetGlobalID());
520 
521  seg->SetElmtId(elmtid++);
522  (*m_exp).push_back(seg);
523  }
524  }
525  }
526 
528  LibUtilities::BasisKey> > edgeOrders;
529 
530  for(i = 0; i < locexp.size(); ++i)
531  {
532  exp2D = locexp[i]->as<LocalRegions::Expansion2D>();
533 
534  for(j = 0; j < locexp[i]->GetNedges(); ++j)
535  {
536  segGeom = exp2D->GetGeom2D()->GetEdge(j);
537  id = segGeom->GetGlobalID();
538  // Ignore Dirichlet edges
539  if (edgesDone.count(id) != 0)
540  {
541  continue;
542  }
543 
544  auto it = edgeOrders.find(id);
545 
546  if (it == edgeOrders.end())
547  {
548  edgeOrders.insert(std::make_pair(id, std::make_pair(
549  segGeom, locexp[i]->DetEdgeBasisKey(j))));
550  }
551  else // variable modes/points
552  {
554  = locexp[i]->DetEdgeBasisKey(j);
555  LibUtilities::BasisKey existing
556  = it->second.second;
557 
558  int np1 = edge .GetNumPoints();
559  int np2 = existing.GetNumPoints();
560  int nm1 = edge .GetNumModes ();
561  int nm2 = existing.GetNumModes ();
562 
563  if (np2 >= np1 && nm2 >= nm1)
564  {
565  continue;
566  }
567  else if (np2 < np1 && nm2 < nm1)
568  {
569  it->second.second = edge;
570  }
571  else
572  {
573  ASSERTL0(false,
574  "inappropriate number of points/modes (max "
575  "num of points is not set with max order)");
576  }
577  }
578  }
579  }
580 
582  pSession->GetComm()->GetRowComm();
583  int nproc = vComm->GetSize(); // number of processors
584  int edgepr = vComm->GetRank(); // ID processor
585 
586  if (nproc > 1)
587  {
588  int eCnt = 0;
589 
590  // Count the number of edges on each partition
591  for(i = 0; i < locexp.size(); ++i)
592  {
593  eCnt += locexp[i]->GetNedges();
594  }
595 
596  // Set up the offset and the array that will contain the list of
597  // edge IDs, then reduce this across processors.
598  Array<OneD, int> edgesCnt(nproc, 0);
599  edgesCnt[edgepr] = eCnt;
600  vComm->AllReduce(edgesCnt, LibUtilities::ReduceSum);
601 
602  // Set up offset array.
603  int totEdgeCnt = Vmath::Vsum(nproc, edgesCnt, 1);
604  Array<OneD, int> eTotOffsets(nproc,0);
605  for (i = 1; i < nproc; ++i)
606  {
607  eTotOffsets[i] = eTotOffsets[i-1] + edgesCnt[i-1];
608  }
609 
610  // Local list of the edges per element
611  Array<OneD, int> EdgesTotID(totEdgeCnt, 0);
612  Array<OneD, int> EdgesTotNm(totEdgeCnt, 0);
613  Array<OneD, int> EdgesTotPnts(totEdgeCnt, 0);
614 
615  int cntr = eTotOffsets[edgepr];
616 
617  for(i = 0; i < locexp.size(); ++i)
618  {
619  exp2D = locexp[i]->as<LocalRegions::Expansion2D>();
620 
621  int nedges = locexp[i]->GetNedges();
622 
623  for(j = 0; j < nedges; ++j, ++cntr)
624  {
625  LibUtilities::BasisKey bkeyEdge =
626  locexp[i]->DetEdgeBasisKey(j);
627  EdgesTotID [cntr] = exp2D->GetGeom2D()->GetEid(j);
628  EdgesTotNm [cntr] = bkeyEdge.GetNumModes();
629  EdgesTotPnts[cntr] = bkeyEdge.GetNumPoints();
630  }
631  }
632 
633  vComm->AllReduce(EdgesTotID, LibUtilities::ReduceSum);
634  vComm->AllReduce(EdgesTotNm, LibUtilities::ReduceSum);
635  vComm->AllReduce(EdgesTotPnts, LibUtilities::ReduceSum);
636 
637  for (i = 0; i < totEdgeCnt; ++i)
638  {
639  auto it = edgeOrders.find(EdgesTotID[i]);
640 
641  if (it == edgeOrders.end())
642  {
643  continue;
644  }
645 
646  LibUtilities::BasisKey existing
647  = it->second.second;
649  existing.GetBasisType(), EdgesTotNm[i],
650  LibUtilities::PointsKey(EdgesTotPnts[i],
651  existing.GetPointsType()));
652 
653 
654  int np1 = edge .GetNumPoints();
655  int np2 = existing.GetNumPoints();
656  int nm1 = edge .GetNumModes ();
657  int nm2 = existing.GetNumModes ();
658 
659  if (np2 >= np1 && nm2 >= nm1)
660  {
661  continue;
662  }
663  else if (np2 < np1 && nm2 < nm1)
664  {
665  it->second.second = edge;
666  }
667  else
668  {
669  ASSERTL0(false,
670  "inappropriate number of points/modes (max "
671  "num of points is not set with max order)");
672  }
673  }
674  }
675 
676  for (auto &it : edgeOrders)
677  {
679  ::AllocateSharedPtr(it.second.second, it.second.first);
680  seg->SetElmtId(elmtid++);
681  (*m_exp).push_back(seg);
682  }
683 
684  // Setup Default optimisation information.
685  int nel = GetExpSize();
688 
689  // Set up offset information and array sizes
691 
692  // Set up m_coeffs, m_phys.
693  if(DeclareCoeffPhysArrays)
694  {
697  }
698 
699  CreateCollections(ImpType);
700  }
701 
702  /**
703  *
704  */
706  {
707  }
708 
709  /**
710  * To perform post-processing on the entire domain use \a elmtId = 0.
711  * @param kernel The post-processing kernel.
712  * @param inarray The set of evaluation points.
713  * @param outarray Contains the resulting post-processed
714  * solution for element \a elmId.
715  * @param h The mesh spacing.
716  * @param elmId Optionally specifies which element to perform
717  * the post-processing on (0=whole domain).
718  */
720  Array<OneD,NekDouble> &inarray,
721  Array<OneD,NekDouble> &outarray,
722  NekDouble h,
723  int elmId)
724 
725  {
726  int i,j,r;
727 
728  // get the local element expansion of the elmId element
729  LocalRegions::ExpansionSharedPtr elmExp = GetExp( elmId );
730 
731  // Get the quadrature points and weights required for integration
732  int quad_npoints = elmExp->GetTotPoints();
733  LibUtilities::PointsKey quadPointsKey(quad_npoints,
734  elmExp->GetPointsType(0));
735  Array<OneD,NekDouble> quad_points
736  = LibUtilities::PointsManager()[quadPointsKey]->GetZ();
737  Array<OneD,NekDouble> quad_weights
738  = LibUtilities::PointsManager()[quadPointsKey]->GetW();
739 
740  // Declare variable for the local kernel breaks
741  int kernel_width = kernel->GetKernelWidth();
742  Array<OneD,NekDouble> local_kernel_breaks(kernel_width+1);
743 
744  // Declare variable for the transformed quadrature points
745  Array<OneD,NekDouble> mapped_quad_points(quad_npoints);
746 
747  // For each evaluation point
748  for(i = 0; i < inarray.num_elements(); i++)
749  {
750  // Move the center of the kernel to the current point
751  kernel->MoveKernelCenter(inarray[i],local_kernel_breaks);
752 
753  // Find the mesh breaks under the kernel support
754  Array<OneD,NekDouble> mesh_breaks;
755  kernel->FindMeshUnderKernel(local_kernel_breaks,h,mesh_breaks);
756 
757  // Sort the total breaks for integration purposes
758  int total_nbreaks = local_kernel_breaks.num_elements() +
759  mesh_breaks.num_elements();
760  // number of the total breaks
761  Array<OneD,NekDouble> total_breaks(total_nbreaks);
762  kernel->Sort(local_kernel_breaks,mesh_breaks,total_breaks);
763 
764  // Integrate the product of kernel and function over the total
765  // breaks
766  NekDouble integral_value = 0.0;
767  for(j = 0; j < total_breaks.num_elements()-1; j++)
768  {
769  NekDouble a = total_breaks[j];
770  NekDouble b = total_breaks[j+1];
771 
772  // Map the quadrature points to the appropriate interval
773  for(r = 0; r < quad_points.num_elements(); r++)
774  {
775  mapped_quad_points[r]
776  = (quad_points[r] + 1.0) * 0.5 * (b - a) + a;
777  }
778 
779  // Evaluate the function at the transformed quadrature
780  // points
781  Array<OneD,NekDouble> u_value(quad_npoints);
782  Array<OneD,NekDouble> coeffs = GetCoeffs();
783 
784  PeriodicEval(coeffs,mapped_quad_points,h,
785  elmExp->GetBasisNumModes(0),u_value);
786 
787  // Evaluate the kernel at the transformed quadrature points
788  Array<OneD,NekDouble> k_value(quad_npoints);
789  kernel->EvaluateKernel(mapped_quad_points,h,k_value);
790 
791  // Integrate
792  for(r = 0; r < quad_npoints; r++)
793  {
794  integral_value += (b - a) * 0.5 * k_value[r]
795  * u_value[r] * quad_weights[r];
796  }
797  }
798  outarray[i] = integral_value/h;
799  }
800  }
801 
802 
803  /**
804  * Given the elemental coefficients \f$\hat{u}_n^e\f$ of an expansion,
805  * periodically evaluate the spectral/hp expansion
806  * \f$u^{\delta}(\boldsymbol{x})\f$ at arbitrary points.
807  * @param inarray1 An array of size \f$N_{\mathrm{eof}}\f$
808  * containing the local coefficients
809  * \f$\hat{u}_n^e\f$.
810  * @param inarray2 Contains the set of evaluation points.
811  * @param h The mesh spacing.
812  * @param nmodes The number of polynomial modes for each element
813  * (we consider that each element has the same
814  * number of polynomial modes).
815  * @param outarray Contains the resulting values at the
816  * evaluation points
817  */
819  Array<OneD,NekDouble> &inarray2,
820  NekDouble h, int nmodes,
821  Array<OneD,NekDouble> &outarray)
822  {
823  int i,j,r;
824 
825  // Get the number of elements in the domain
826  int num_elm = GetExpSize();
827 
828  // initializing the outarray
829  for(i = 0; i < outarray.num_elements(); i++)
830  {
831  outarray[i] = 0.0;
832  }
833 
834  // Make a copy for further modification
835  int x_size = inarray2.num_elements();
836  Array<OneD,NekDouble> x_values_cp(x_size);
837 
838  // Determining the element to which the x belongs
839  Array<OneD,int> x_elm(x_size);
840  for(i = 0; i < x_size; i++ )
841  {
842  x_elm[i] = (int)floor(inarray2[i]/h);
843  }
844 
845  // Clamp indices periodically
846  for(i = 0; i < x_size; i++)
847  {
848  while(x_elm[i] < 0)
849  {
850  x_elm[i] += num_elm;
851  }
852  while(x_elm[i] >= num_elm)
853  {
854  x_elm[i] -= num_elm ;
855  }
856  }
857 
858  // Map the values of x to [-1 1] on its interval
859  for(i = 0; i < x_size; i++)
860  {
861  x_values_cp[i] = (inarray2[i]/h - floor(inarray2[i]/h))*2 - 1.0;
862  }
863 
864  // Evaluate the jocobi polynomials
865  // (Evaluating the base at some points other than the quadrature
866  // points). Should it be added to the base class????
867  Array<TwoD,NekDouble> jacobi_poly(nmodes,x_size);
868  for(i = 0; i < nmodes; i++)
869  {
870  Polylib::jacobfd(x_size,x_values_cp.get(),
871  jacobi_poly.get()+i*x_size,NULL,i,0.0,0.0);
872  }
873 
874  // Evaluate the function values
875  for(r = 0; r < nmodes; r++)
876  {
877  for(j = 0; j < x_size; j++)
878  {
879  int index = ((x_elm[j])*nmodes)+r;
880  outarray[j] += inarray1[index]*jacobi_poly[r][j];
881  }
882  }
883 
884  }
885 
886 
887  /**
888  * Sets up the normals on all edges of expansions in the domain.
889  * @param locexp Complete list of domain expansions.
890  */
891 // void ExpList1D::SetUpPhysNormals(
892 // const StdRegions::StdExpansionVector &locexp)
893 // {
894 // map<int, int> EdgeGID;
895 // int i,cnt,n,id;
896 //
897 // // setup map of all global ids along boundary
898 // for(cnt = i = 0; i < (*m_exp).size(); ++i)
899 // {
900 // id = (*m_exp)[i]->GetGeom1D()->GetEid();
901 // EdgeGID[id] = cnt++;
902 // }
903 //
904 // // Loop over elements and find edges that match;
905 // for(cnt = n = 0; n < locexp.size(); ++n)
906 // {
907 // for(i = 0; i < locexp[n]->GetNedges(); ++i)
908 // {
909 // id = locexp[n]->GetGeom2D()->GetEid(i);
910 //
911 // if(EdgeGID.count(id) > 0)
912 // {
913 // (*m_exp)[EdgeGID.find(id)->second]
914 // ->SetUpPhysNormals(locexp[n],i);
915 // }
916 // }
917 // }
918 // }
919 
920  //croth
922  {
923  int i, j;
924  for (i = 0; i < m_exp->size(); ++i)
925  {
926  for (j = 0; j < (*m_exp)[i]->GetNverts(); ++j)
927  {
928  (*m_exp)[i]->ComputeVertexNormal(j);
929  }
930  }
931  }
932 
933  /**
934  * Upwind the left and right states given by the Arrays Fwd and Bwd
935  * using the vector quantity Vec and ouput the upwinded value in the
936  * array upwind.
937  *
938  * @param Vec Velocity field.
939  * @param Fwd Left state.
940  * @param Bwd Right state.
941  * @param Upwind Output vector.
942  */
944  const Array<OneD, const Array<OneD, NekDouble> > &Vec,
945  const Array<OneD, const NekDouble> &Fwd,
946  const Array<OneD, const NekDouble> &Bwd,
948  {
949  int i,j,k,e_npoints,offset;
950  Array<OneD,NekDouble> normals;
951  NekDouble Vn;
952 
953  // Assume whole array is of same coordimate dimension
954  int coordim = GetCoordim(0);
955 
956  ASSERTL1(Vec.num_elements() >= coordim,
957  "Input vector does not have sufficient dimensions to "
958  "match coordim");
959 
960  // Process each expansion
961  for(i = 0; i < m_exp->size(); ++i)
962  {
963  // Get the number of points in the expansion and the normals.
964  e_npoints = (*m_exp)[i]->GetNumPoints(0);
965  normals = (*m_exp)[i]->GetPhysNormals();
966 
967  // Get the physical data offset of the expansion in m_phys.
968  offset = m_phys_offset[i];
969 
970  // Compute each data point.
971  for(j = 0; j < e_npoints; ++j)
972  {
973  // Calculate normal velocity.
974  Vn = 0.0;
975  for(k = 0; k < coordim; ++k)
976  {
977  Vn += Vec[k][offset+j]*normals[k*e_npoints + j];
978  }
979 
980  // Upwind based on direction of normal velocity.
981  if(Vn > 0.0)
982  {
983  Upwind[offset + j] = Fwd[offset + j];
984  }
985  else
986  {
987  Upwind[offset + j] = Bwd[offset + j];
988  }
989  }
990  }
991  }
992 
993  /**
994  * One-dimensional upwind.
995  * \see ExpList1D::Upwind(
996  * const Array<OneD, const Array<OneD, NekDouble> >,
997  * const Array<OneD, const NekDouble>,
998  * const Array<OneD, const NekDouble>,
999  * Array<OneD, NekDouble>, int)
1000  *
1001  * @param Vn Velocity field.
1002  * @param Fwd Left state.
1003  * @param Bwd Right state.
1004  * @param Upwind Output vector.
1005  */
1007  const Array<OneD, const NekDouble> &Vn,
1008  const Array<OneD, const NekDouble> &Fwd,
1009  const Array<OneD, const NekDouble> &Bwd,
1011  {
1012  int i,j,e_npoints,offset;
1013  Array<OneD,NekDouble> normals;
1014 
1015  // Process each expansion.
1016  for(i = 0; i < m_exp->size(); ++i)
1017  {
1018  // Get the number of points and the data offset.
1019  e_npoints = (*m_exp)[i]->GetNumPoints(0);
1020  offset = m_phys_offset[i];
1021 
1022  // Process each point in the expansion.
1023  for(j = 0; j < e_npoints; ++j)
1024  {
1025  // Upwind based on one-dimensional velocity.
1026  if(Vn[offset + j] > 0.0)
1027  {
1028  Upwind[offset + j] = Fwd[offset + j];
1029  }
1030  else
1031  {
1032  Upwind[offset + j] = Bwd[offset + j];
1033  }
1034  }
1035  }
1036  }
1037 
1038 
1039  /**
1040  * For each local element, copy the normals stored in the element list
1041  * into the array \a normals.
1042  * @param normals Multidimensional array in which to copy normals
1043  * to. Must have dimension equal to or larger than
1044  * the spatial dimension of the elements.
1045  */
1047  Array<OneD, Array<OneD, NekDouble> > &normals)
1048  {
1049  int i,j,k,e_npoints,offset;
1051  Array<OneD,Array<OneD,NekDouble> > locnormals;
1052  Array<OneD,Array<OneD,NekDouble> > locnormals2;
1054  // Assume whole array is of same coordinate dimension
1055  int coordim = GetCoordim(0);
1056 
1057  ASSERTL1(normals.num_elements() >= coordim,
1058  "Output vector does not have sufficient dimensions to "
1059  "match coordim");
1060 
1061  for (i = 0; i < m_exp->size(); ++i)
1062  {
1064 
1066  loc_exp->GetLeftAdjacentElementExp();
1067 
1068  int edgeNumber = loc_exp->GetLeftAdjacentElementEdge();
1069 
1070  // Get the number of points and normals for this expansion.
1071  e_npoints = (*m_exp)[i]->GetNumPoints(0);
1072 
1073  locnormals = loc_elmt->GetEdgeNormal(edgeNumber);
1074  int e_nmodes = loc_exp->GetBasis(0)->GetNumModes();
1075  int loc_nmodes = loc_elmt->GetBasis(0)->GetNumModes();
1076 
1077  if (e_nmodes != loc_nmodes)
1078  {
1079  if (loc_exp->GetRightAdjacentElementEdge() >= 0)
1080  {
1082  loc_exp->GetRightAdjacentElementExp();
1083 
1084  int EdgeNumber = loc_exp->GetRightAdjacentElementEdge();
1085  // Serial case: right element is connected so we can
1086  // just grab that normal.
1087  locnormals = loc_elmt->GetEdgeNormal(EdgeNumber);
1088 
1089  offset = m_phys_offset[i];
1090 
1091  // Process each point in the expansion.
1092  for (j = 0; j < e_npoints; ++j)
1093  {
1094  // Process each spatial dimension and copy the values
1095  // into the output array.
1096  for (k = 0; k < coordim; ++k)
1097  {
1098  normals[k][offset + j] = -locnormals[k][j];
1099  }
1100  }
1101  }
1102  else
1103  {
1104  // Parallel case: need to interpolate normal.
1105  Array<OneD, Array<OneD, NekDouble> > normal(coordim);
1106 
1107  for (int p = 0; p < coordim; ++p)
1108  {
1109  normal[p] = Array<OneD, NekDouble>(e_npoints,0.0);
1110  LibUtilities::PointsKey to_key =
1111  loc_exp->GetBasis(0)->GetPointsKey();
1112  LibUtilities::PointsKey from_key =
1113  loc_elmt->GetBasis(0)->GetPointsKey();
1114  LibUtilities::Interp1D(from_key,
1115  locnormals[p],
1116  to_key,
1117  normal[p]);
1118  }
1119 
1120  offset = m_phys_offset[i];
1121 
1122  // Process each point in the expansion.
1123  for (j = 0; j < e_npoints; ++j)
1124  {
1125  // Process each spatial dimension and copy the values
1126  // into the output array.
1127  for (k = 0; k < coordim; ++k)
1128  {
1129  normals[k][offset + j] = normal[k][j];
1130  }
1131  }
1132  }
1133  }
1134  else
1135  {
1136  // Get the physical data offset for this expansion.
1137  offset = m_phys_offset[i];
1138 
1139  // Process each point in the expansion.
1140  for (j = 0; j < e_npoints; ++j)
1141  {
1142  // Process each spatial dimension and copy the values
1143  // into the output array.
1144  for (k = 0; k < coordim; ++k)
1145  {
1146  normals[k][offset + j] = locnormals[k][j];
1147  }
1148  }
1149  }
1150  }
1151  }
1152 
1153  /**
1154  *
1155  */
1157  {
1158 // Array<OneD, int> NumShape(1,0);
1159 // NumShape[0] = GetExpSize();
1160 //
1161 // int one = 1;
1162 // m_globalOptParam = MemoryManager<NekOptimize::GlobalOptParam>
1163 // ::AllocateSharedPtr(m_session,one,NumShape);
1164  }
1165 
1166 
1167  /**
1168  * Writes out the header for a <PIECE> VTK XML segment describing the
1169  * geometric information which comprises this element. This includes
1170  * vertex coordinates for each quadrature point, vertex connectivity
1171  * information, cell types and cell offset data.
1172  *
1173  * @param outfile Output stream to write data to.
1174  */
1175  void ExpList1D::v_WriteVtkPieceHeader(std::ostream &outfile, int expansion, int)
1176  {
1177  int i,j;
1178  int nquad0 = (*m_exp)[expansion]->GetNumPoints(0);
1179  int ntot = nquad0;
1180  int ntotminus = (nquad0-1);
1181 
1182  Array<OneD,NekDouble> coords[3];
1183  coords[0] = Array<OneD,NekDouble>(ntot, 0.0);
1184  coords[1] = Array<OneD,NekDouble>(ntot, 0.0);
1185  coords[2] = Array<OneD,NekDouble>(ntot, 0.0);
1186  (*m_exp)[expansion]->GetCoords(coords[0],coords[1],coords[2]);
1187 
1188  outfile << " <Piece NumberOfPoints=\""
1189  << ntot << "\" NumberOfCells=\""
1190  << ntotminus << "\">" << endl;
1191  outfile << " <Points>" << endl;
1192  outfile << " <DataArray type=\"Float64\" "
1193  << "NumberOfComponents=\"3\" format=\"ascii\">" << endl;
1194  outfile << " ";
1195  for (i = 0; i < ntot; ++i)
1196  {
1197  for (j = 0; j < 3; ++j)
1198  {
1199  outfile << setprecision(8) << scientific
1200  << (float)coords[j][i] << " ";
1201  }
1202  outfile << endl;
1203  }
1204  outfile << endl;
1205  outfile << " </DataArray>" << endl;
1206  outfile << " </Points>" << endl;
1207  outfile << " <Cells>" << endl;
1208  outfile << " <DataArray type=\"Int32\" "
1209  << "Name=\"connectivity\" format=\"ascii\">" << endl;
1210  for (i = 0; i < nquad0-1; ++i)
1211  {
1212  outfile << i << " " << i+1 << endl;
1213  }
1214  outfile << endl;
1215  outfile << " </DataArray>" << endl;
1216  outfile << " <DataArray type=\"Int32\" "
1217  << "Name=\"offsets\" format=\"ascii\">" << endl;
1218  for (i = 0; i < ntotminus; ++i)
1219  {
1220  outfile << i*2+2 << " ";
1221  }
1222  outfile << endl;
1223  outfile << " </DataArray>" << endl;
1224  outfile << " <DataArray type=\"UInt8\" "
1225  << "Name=\"types\" format=\"ascii\">" << endl;
1226  for (i = 0; i < ntotminus; ++i)
1227  {
1228  outfile << "3 ";
1229  }
1230  outfile << endl;
1231  outfile << " </DataArray>" << endl;
1232  outfile << " </Cells>" << endl;
1233  outfile << " <PointData>" << endl;
1234  }
1235 
1236  } //end of namespace
1237 } //end of namespace
int GetNumPoints() const
Return points order at which basis is defined.
Definition: Basis.h:133
ExpList1D()
The default constructor.
Definition: ExpList1D.cpp:78
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition: MeshGraph.h:163
ExpList()
The default constructor.
Definition: ExpList.cpp:96
std::shared_ptr< Geometry2D > Geometry2DSharedPtr
Definition: Geometry.h:65
std::shared_ptr< LocalRegions::ExpansionVector > m_exp
The list of local expansions.
Definition: ExpList.h:1090
NekOptimize::GlobalOptParamSharedPtr m_globalOptParam
Definition: ExpList.h:1106
const Array< OneD, const NekDouble > & GetCoeffs() const
This function returns (a reference to) the array (implemented as m_coeffs) containing all local expa...
Definition: ExpList.h:2062
std::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition: Comm.h:53
BasisType GetBasisType() const
Return type of expansion basis.
Definition: Basis.h:144
STL namespace.
std::map< int, CompositeSharedPtr > CompositeMap
Definition: MeshGraph.h:137
std::shared_ptr< Kernel > KernelSharedPtr
Definition: kernel.h:214
Array< OneD, NekDouble > m_phys
The global expansion evaluated at the quadrature points.
Definition: ExpList.h:1069
Array< OneD, NekDouble > m_coeffs
Concatenation of all local expansion coefficients.
Definition: ExpList.h:1052
int GetExpSize(void)
This function returns the number of elements in the expansion.
Definition: ExpList.h:2170
virtual void v_SetUpPhysNormals()
Set up the normals on each expansion.
Definition: ExpList1D.cpp:921
const std::shared_ptr< LocalRegions::ExpansionVector > GetExp() const
This function returns the vector of elements in the expansion.
Definition: ExpList.h:2191
std::vector< ExpansionSharedPtr > ExpansionVector
Definition: Expansion.h:67
void 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.h:2249
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)
Upwind the Fwd and Bwd states based on the velocity field given by Vec.
Definition: ExpList1D.cpp:943
Base class for all multi-elemental spectral/hp expansions.
Definition: ExpList.h:103
int GetNumModes() const
Returns the order of the basis.
Definition: Basis.h:86
SpatialDomains::Geometry2DSharedPtr GetGeom2D() const
Definition: Expansion2D.h:291
Array< OneD, int > m_phys_offset
Offset of elemental data into the array m_phys.
Definition: ExpList.h:1104
PointsType GetPointsType() const
Return type of quadrature.
Definition: Basis.h:156
void PeriodicEval(Array< OneD, NekDouble > &inarray1, Array< OneD, NekDouble > &inarray2, NekDouble h, int nmodes, Array< OneD, NekDouble > &outarray)
Evaluates the global spectral/hp expansion at some arbitray set of points.
Definition: ExpList1D.cpp:818
int m_ncoeffs
The total number of local degrees of freedom. m_ncoeffs .
Definition: ExpList.h:1030
void SetCoeffPhysOffsets()
Definition of the total number of degrees of freedom and quadrature points and offsets to access data...
Definition: ExpList.cpp:249
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
PointsManagerT & PointsManager(void)
SpatialDomains::MeshGraphSharedPtr m_graph
Mesh associated with this expansion list.
Definition: ExpList.h:1026
Defines a specification for a set of points.
Definition: Points.h:59
double NekDouble
int GetNedges() const
This function returns the number of edges of the expansion domain.
Definition: StdExpansion.h:271
std::map< int, std::vector< PeriodicEntity > > PeriodicMap
std::shared_ptr< Expansion > ExpansionSharedPtr
Definition: Expansion.h:65
LibUtilities::CommSharedPtr m_comm
Communicator.
Definition: ExpList.h:1020
void v_GetNormals(Array< OneD, Array< OneD, NekDouble > > &normals)
Populate normals with the normals of all expansions.
Definition: ExpList1D.cpp:1046
std::shared_ptr< Expansion2D > Expansion2DSharedPtr
Definition: Expansion1D.h:47
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:53
std::shared_ptr< SegExp > SegExpSharedPtr
Definition: SegExp.h:266
This class is the abstraction of a one-dimensional multi-elemental expansions which is merely a colle...
Definition: ExpList1D.h:58
void PostProcess(LibUtilities::KernelSharedPtr kernel, Array< OneD, NekDouble > &inarray, Array< OneD, NekDouble > &outarray, NekDouble h, int elmId=0)
Performs the post-processing on a specified element.
Definition: ExpList1D.cpp:719
virtual void v_ReadGlobalOptimizationParameters()
Definition: ExpList1D.cpp:1156
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:3295
std::shared_ptr< Geometry1D > Geometry1DSharedPtr
Definition: Geometry.h:63
int GetCoordim(int eid)
This function returns the dimension of the coordinates of the element eid.
Definition: ExpList.h:2013
Expansion2DSharedPtr GetLeftAdjacentElementExp() const
Definition: Expansion1D.h:127
virtual void v_WriteVtkPieceHeader(std::ostream &outfile, int expansion, int istrip)
const StdRegions::StdExpansionVector &locexp);
Definition: ExpList1D.cpp:1175
void SetExpType(ExpansionType Type)
Returns the type of the expansion.
Definition: ExpList.cpp:279
T Vsum(int n, const T *x, const int incx)
Subtract return sum(x)
Definition: Vmath.cpp:740
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode...
Definition: ErrorUtil.hpp:250
std::shared_ptr< SegGeom > SegGeomSharedPtr
Definition: Geometry2D.h:62
virtual ~ExpList1D()
Destructor.
Definition: ExpList1D.cpp:705
std::shared_ptr< Expansion1D > Expansion1DSharedPtr
Definition: Expansion1D.h:51
Describes the specification for a Basis.
Definition: Basis.h:49
std::shared_ptr< SessionReader > SessionReaderSharedPtr
void jacobfd(const int np, const double *z, double *poly_in, double *polyd, const int n, const double alpha, const double beta)
Routine to calculate Jacobi polynomials, , and their first derivative, .
Definition: Polylib.cpp:1031
std::map< int, ExpansionShPtr > ExpansionMap
Definition: MeshGraph.h:152