Nektar++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
DisContField3D.cpp
Go to the documentation of this file.
1  //////////////////////////////////////////////////////////////////////////////
2  //
3  // File DisContField3D.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  // License for the specific language governing rights and limitations under
14  // Permission is hereby granted, free of charge, to any person obtaining a
15  // copy of this software and associated documentation files (the "Software"),
16  // to deal in the Software without restriction, including without limitation
17  // the rights to use, copy, modify, merge, publish, distribute, sublicense,
18  // and/or sell copies of the Software, and to permit persons to whom the
19  // Software is furnished to do so, subject to the following conditions:
20  //
21  // The above copyright notice and this permission notice shall be included
22  // in all copies or substantial portions of the Software.
23  //
24  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25  // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27  // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29  // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30  // DEALINGS IN THE SOFTWARE.
31  //
32  // Description: Field definition for 3D domain with boundary
33  // conditions using LDG flux
34  //
35  ///////////////////////////////////////////////////////////////////////////////
36 
41 #include <LocalRegions/HexExp.h>
42 #include <LocalRegions/TetExp.h>
43 #include <LocalRegions/PrismExp.h>
46 #include <boost/assign/std/vector.hpp>
47 #include <boost/tuple/tuple.hpp>
48 
49  using namespace boost::assign;
50 
51  namespace Nektar
52  {
53  namespace MultiRegions
54  {
55  /**
56  * @class DisContField3D
57  * Abstraction of a global discontinuous three-dimensional spectral/hp
58  * element expansion which approximates the solution of a set of
59  * partial differential equations.
60  */
61 
62  /**
63  * @brief Default constructor.
64  */
65  DisContField3D::DisContField3D() :
66  ExpList3D (),
67  m_bndCondExpansions (),
68  m_bndConditions (),
69  m_trace(NullExpListSharedPtr)
70  {
71  }
72 
73  /**
74  * @brief Constructs a global discontinuous field based on an input
75  * mesh with boundary conditions.
76  */
80  const std::string &variable,
81  const bool SetUpJustDG)
82  : ExpList3D (pSession, graph3D, variable),
83  m_bndCondExpansions(),
84  m_bndConditions (),
85  m_trace(NullExpListSharedPtr)
86  {
87  // do not set up BCs if default variable
88  if (variable.compare("DefaultVar") != 0)
89  {
91 
92  GenerateBoundaryConditionExpansion(graph3D,bcs,variable);
93  EvaluateBoundaryConditions(0.0, variable);
94 
95  // Find periodic edges for this variable.
96  FindPeriodicFaces(bcs, variable);
97  }
98 
99  if(SetUpJustDG)
100  {
101  SetUpDG();
102  }
103  else
104  {
105  // Set element edges to point to Robin BC edges if required.
106  int i, cnt, f;
107  Array<OneD, int> ElmtID, FaceID;
108  GetBoundaryToElmtMap(ElmtID, FaceID);
109 
110  for(cnt = i = 0; i < m_bndCondExpansions.num_elements(); ++i)
111  {
113  locExpList = m_bndCondExpansions[i];
114 
115  for(f = 0; f < locExpList->GetExpSize(); ++f)
116  {
118  = (*m_exp)[ElmtID[cnt+f]]->
119  as<LocalRegions::Expansion3D>();
121  = locExpList->GetExp(f)->
122  as<LocalRegions::Expansion2D>();
123 
124  exp3d->SetFaceExp(FaceID[cnt+f],exp2d);
125  exp2d->SetAdjacentElementExp(FaceID[cnt+f],exp3d);
126  }
127  cnt += m_bndCondExpansions[i]->GetExpSize();
128  }
129  }
130  }
131 
132  /*
133  * @brief Copy type constructor which declares new boundary conditions
134  * and re-uses mapping info and trace space if possible
135  */
137  const DisContField3D &In,
138  const SpatialDomains::MeshGraphSharedPtr &graph3D,
139  const std::string &variable,
140  const bool SetUpJustDG)
141  : ExpList3D(In),
142  m_trace(NullExpListSharedPtr)
143  {
145 
146  GenerateBoundaryConditionExpansion(graph3D,bcs,variable);
147  EvaluateBoundaryConditions(0.0, variable);
148  ApplyGeomInfo();
149 
151  {
152  // Find periodic edges for this variable.
153  FindPeriodicFaces(bcs, variable);
154 
155  if (SetUpJustDG)
156  {
157  SetUpDG(variable);
158  }
159  else
160  {
161  int i,cnt,f;
162  Array<OneD, int> ElmtID,FaceID;
163  GetBoundaryToElmtMap(ElmtID,FaceID);
164 
165  for(cnt = i = 0; i < m_bndCondExpansions.num_elements(); ++i)
166  {
168  locExpList = m_bndCondExpansions[i];
169 
170  for(f = 0; f < locExpList->GetExpSize(); ++f)
171  {
173  = (*m_exp)[ElmtID[cnt+f]]->
174  as<LocalRegions::Expansion3D>();
176  = locExpList->GetExp(f)->
177  as<LocalRegions::Expansion2D>();
178 
179  exp3d->SetFaceExp(FaceID[cnt+f],exp2d);
180  exp2d->SetAdjacentElementExp(FaceID[cnt+f],exp3d);
181  }
182 
183  cnt += m_bndCondExpansions[i]->GetExpSize();
184  }
186  }
187 
188  }
189  //else if we have the same boundary condition
190  else
191  {
193  m_trace = In.m_trace;
194  m_traceMap = In.m_traceMap;
199 
200  if(SetUpJustDG)
201  {
202  }
203  else
204  {
205  int i,cnt,f;
206  Array<OneD, int> ElmtID,FaceID;
207  GetBoundaryToElmtMap(ElmtID,FaceID);
208 
209  for (cnt = i = 0;
210  i < m_bndCondExpansions.num_elements(); ++i)
211  {
213  locExpList = m_bndCondExpansions[i];
214 
215  for(f = 0; f < locExpList->GetExpSize(); ++f)
216  {
218  = (*m_exp)[ElmtID[cnt+f]]->
219  as<LocalRegions::Expansion3D>();
221  = locExpList->GetExp(f)->
222  as<LocalRegions::Expansion2D>();
223 
224  exp3d->SetFaceExp(FaceID[cnt+f], exp2d);
225  exp2d->SetAdjacentElementExp(FaceID[cnt+f], exp3d);
226  }
227 
228  cnt += m_bndCondExpansions[i]->GetExpSize();
229  }
230 
231  if (m_session->DefinesSolverInfo("PROJECTION"))
232  {
233  std::string ProjectStr =
234  m_session->GetSolverInfo("PROJECTION");
235  if (ProjectStr == "MixedCGDG" ||
236  ProjectStr == "Mixed_CG_Discontinuous")
237  {
238  SetUpDG(variable);
239  }
240  else
241  {
243  }
244  }
245  else
246  {
248  }
249  }
250  }
251  }
252 
253  /**
254  *
255  */
257  ExpList3D(In),
258  m_bndCondExpansions (In.m_bndCondExpansions),
259  m_bndConditions (In.m_bndConditions),
260  m_globalBndMat (In.m_globalBndMat),
261  m_trace (In.m_trace),
262  m_traceMap (In.m_traceMap),
263  m_locTraceToTraceMap (In.m_locTraceToTraceMap),
264  m_periodicFaces (In.m_periodicFaces),
265  m_periodicEdges (In.m_periodicEdges),
266  m_periodicVerts (In.m_periodicVerts)
267  {
268  }
269 
270  /**
271  * @brief Destructor.
272  */
274  {
275  }
276 
278  const GlobalLinSysKey &mkey)
279  {
281  "Routine currently only tested for HybridDGHelmholtz");
282  ASSERTL1(mkey.GetGlobalSysSolnType() ==
283  m_traceMap->GetGlobalSysSolnType(),
284  "The local to global map is not set up for the requested "
285  "solution type");
286 
287  GlobalLinSysSharedPtr glo_matrix;
288  GlobalLinSysMap::iterator matrixIter = m_globalBndMat->find(mkey);
289 
290  if (matrixIter == m_globalBndMat->end())
291  {
292  glo_matrix = GenGlobalBndLinSys(mkey, m_traceMap);
293  (*m_globalBndMat)[mkey] = glo_matrix;
294  }
295  else
296  {
297  glo_matrix = matrixIter->second;
298  }
299 
300  return glo_matrix;
301  }
302 
303  /**
304  * @brief Set up all DG member variables and maps.
305  */
306  void DisContField3D::SetUpDG(const std::string variable)
307  {
309  {
310  return;
311  }
312 
313  ExpList2DSharedPtr trace;
314 
316  boost::dynamic_pointer_cast<SpatialDomains::MeshGraph3D>(
317  m_graph);
318 
319  // Set up matrix map
322 
323  // Set up Trace space
324  bool UseGenSegExp = true;
327  *m_exp,graph3D, m_periodicFaces, UseGenSegExp);
328 
329  m_trace = trace;
330 
332  m_session,graph3D,trace,*this,m_bndCondExpansions,
333  m_bndConditions, m_periodicFaces,variable);
334 
336  &elmtToTrace = m_traceMap->GetElmtToTrace();
337 
338  // Scatter trace segments to 3D elements. For each element, we
339  // find the trace segment associated to each edge. The element
340  // then retains a pointer to the trace space segments, to ensure
341  // uniqueness of normals when retrieving from two adjoining
342  // elements which do not lie in a plane.
343  for (int i = 0; i < m_exp->size(); ++i)
344  {
345  for (int j = 0; j < (*m_exp)[i]->GetNfaces(); ++j)
346  {
348  (*m_exp)[i]->as<LocalRegions::Expansion3D>();
350  elmtToTrace[i][j]->as<LocalRegions::Expansion2D>();
351  exp3d->SetFaceExp (j, exp2d);
352  exp2d->SetAdjacentElementExp(j, exp3d);
353  }
354  }
355 
356  // Set up physical normals
358 
359  // Set up information for parallel jobs.
360  for (int i = 0; i < m_trace->GetExpSize(); ++i)
361  {
363  m_trace->GetExp(i)->as<LocalRegions::Expansion2D>();
364 
365  int offset = m_trace->GetPhys_Offset(i);
366  int traceGeomId = traceEl->GetGeom2D()->GetGlobalID();
368  traceGeomId);
369 
370  if (pIt != m_periodicFaces.end() && !pIt->second[0].isLocal)
371  {
372  if (traceGeomId != min(pIt->second[0].id, traceGeomId))
373  {
374  traceEl->GetLeftAdjacentElementExp()->NegateFaceNormal(
375  traceEl->GetLeftAdjacentElementFace());
376  }
377  }
378  else if (m_traceMap->GetTraceToUniversalMapUnique(offset) < 0)
379  {
380  traceEl->GetLeftAdjacentElementExp()->NegateFaceNormal(
381  traceEl->GetLeftAdjacentElementFace());
382  }
383  }
384 
385  int cnt, n, e;
386 
387  // Identify boundary faces
388  for(cnt = 0, n = 0; n < m_bndCondExpansions.num_elements(); ++n)
389  {
390  if (m_bndConditions[n]->GetBoundaryConditionType() !=
392  {
393  for(e = 0; e < m_bndCondExpansions[n]->GetExpSize(); ++e)
394  {
395  m_boundaryFaces.insert(
396  m_traceMap->GetBndCondTraceToGlobalTraceMap(cnt+e));
397  }
398  }
399  cnt += m_bndCondExpansions[n]->GetExpSize();
400  }
401 
402  // Set up information for periodic boundary conditions.
403  boost::unordered_map<int,pair<int,int> > perFaceToExpMap;
404  boost::unordered_map<int,pair<int,int> >::iterator it2;
405  cnt = 0;
407  for (int n = 0; n < m_exp->size(); ++n)
408  {
409  exp3d = (*m_exp)[n]->as<LocalRegions::Expansion3D>();
410  for (int e = 0; e < exp3d->GetNfaces(); ++e, ++cnt)
411  {
413  exp3d->GetGeom3D()->GetFid(e));
414 
415  if (it != m_periodicFaces.end())
416  {
417  perFaceToExpMap[it->first] = make_pair(n, e);
418  }
419  }
420  }
421 
422  // Set up left-adjacent face list.
423  m_leftAdjacentFaces.resize(cnt);
424  cnt = 0;
425  for (int i = 0; i < m_exp->size(); ++i)
426  {
427  for (int j = 0; j < (*m_exp)[i]->GetNfaces(); ++j, ++cnt)
428  {
430  }
431  }
432 
433  // Set up mapping to copy Fwd of periodic bcs to Bwd of other edge.
434  cnt = 0;
435  for (int n = 0; n < m_exp->size(); ++n)
436  {
437  exp3d = (*m_exp)[n]->as<LocalRegions::Expansion3D>();
438  for (int e = 0; e < exp3d->GetNfaces(); ++e, ++cnt)
439  {
440  int faceGeomId = exp3d->GetGeom3D()->GetFid(e);
441  int offset = m_trace->GetPhys_Offset(
442  elmtToTrace[n][e]->GetElmtId());
443 
444  // Check to see if this face is periodic.
445  PeriodicMap::iterator it = m_periodicFaces.find(faceGeomId);
446 
447  if (it != m_periodicFaces.end())
448  {
449  const PeriodicEntity &ent = it->second[0];
450  it2 = perFaceToExpMap.find(ent.id);
451 
452  if (it2 == perFaceToExpMap.end())
453  {
454  if (m_session->GetComm()->GetSize() > 1 &&
455  !ent.isLocal)
456  {
457  continue;
458  }
459  else
460  {
461  ASSERTL1(false, "Periodic edge not found!");
462  }
463  }
464 
466  "Periodic face in non-forward space?");
467 
468  int offset2 = m_trace->GetPhys_Offset(
469  elmtToTrace[it2->second.first][it2->second.second]->
470  GetElmtId());
471 
472  // Calculate relative orientations between faces to
473  // calculate copying map.
474  int nquad1 = elmtToTrace[n][e]->GetNumPoints(0);
475  int nquad2 = elmtToTrace[n][e]->GetNumPoints(1);
476 
477  vector<int> tmpBwd(nquad1*nquad2);
478  vector<int> tmpFwd(nquad1*nquad2);
479 
484  {
485  for (int i = 0; i < nquad2; ++i)
486  {
487  for (int j = 0; j < nquad1; ++j)
488  {
489  tmpBwd[i*nquad1+j] = offset2 + i*nquad1+j;
490  tmpFwd[i*nquad1+j] = offset + j*nquad2+i;
491  }
492  }
493  }
494  else
495  {
496  for (int i = 0; i < nquad2; ++i)
497  {
498  for (int j = 0; j < nquad1; ++j)
499  {
500  tmpBwd[i*nquad1+j] = offset2 + i*nquad1+j;
501  tmpFwd[i*nquad1+j] = offset + i*nquad1+j;
502  }
503  }
504  }
505 
510  {
511  // Reverse x direction
512  for (int i = 0; i < nquad2; ++i)
513  {
514  for (int j = 0; j < nquad1/2; ++j)
515  {
516  swap(tmpFwd[i*nquad1 + j],
517  tmpFwd[i*nquad1 + nquad1-j-1]);
518  }
519  }
520  }
521 
526  {
527  // Reverse y direction
528  for (int j = 0; j < nquad1; ++j)
529  {
530  for (int i = 0; i < nquad2/2; ++i)
531  {
532  swap(tmpFwd[i*nquad1 + j],
533  tmpFwd[(nquad2-i-1)*nquad1 + j]);
534  }
535  }
536  }
537 
538  for (int i = 0; i < nquad1*nquad2; ++i)
539  {
540  m_periodicFwdCopy.push_back(tmpFwd[i]);
541  m_periodicBwdCopy.push_back(tmpBwd[i]);
542  }
543  }
544  }
545  }
546 
548  AllocateSharedPtr(*this, m_trace, elmtToTrace,
550 
551  }
552 
553  /**
554  * For each boundary region, checks that the types and number of
555  * boundary expansions in that region match.
556  *
557  * @param In ContField3D to compare with.
558  * @return true if boundary conditions match.
559  */
561  const DisContField3D &In)
562  {
563  int i;
564  bool returnval = true;
565 
566  for(i = 0; i < m_bndConditions.num_elements(); ++i)
567  {
568 
569  // check to see if boundary condition type is the same
570  // and there are the same number of boundary
571  // conditions in the boundary definition.
572  if((m_bndConditions[i]->GetBoundaryConditionType()
573  != In.m_bndConditions[i]->GetBoundaryConditionType())||
575  != In.m_bndCondExpansions[i]->GetExpSize()))
576  {
577  returnval = false;
578  break;
579  }
580  }
581 
582  // Compare with all other processes. Return true only if all
583  // processes report having the same boundary conditions.
584  int vSame = returnval ? 1 : 0;
585  m_comm->AllReduce(vSame, LibUtilities::ReduceMin);
586 
587  return (vSame == 1);
588  }
589 
590  /**
591  * According to their boundary region, the separate segmental boundary
592  * expansions are bundled together in an object of the class
593  * MultiRegions#ExpList2D.
594  *
595  * \param graph3D A mesh, containing information about the domain and
596  * the spectral/hp element expansion.
597  * \param bcs An entity containing information about the boundaries and
598  * boundary conditions.
599  * \param variable An optional parameter to indicate for which variable
600  * the boundary conditions should be discretised.
601  */
603  const SpatialDomains::MeshGraphSharedPtr &graph3D,
605  const std::string &variable)
606  {
607  int cnt = 0;
610 
612  bcs.GetBoundaryRegions();
613  const SpatialDomains::BoundaryConditionCollection &bconditions =
614  bcs.GetBoundaryConditions();
615  SpatialDomains::BoundaryRegionCollection::const_iterator it;
616 
617  // count the number of non-periodic boundary regions
618  for (it = bregions.begin(); it != bregions.end(); ++it)
619  {
620  SpatialDomains::BoundaryConditionShPtr boundaryCondition =
621  GetBoundaryCondition(bconditions, it->first, variable);
622  if (boundaryCondition->GetBoundaryConditionType() !=
624  {
625  cnt++;
626  }
627  }
628 
631 
632  cnt = 0;
633 
634  // list Dirichlet boundaries first
635  for (it = bregions.begin(); it != bregions.end(); ++it)
636  {
637  locBCond = GetBoundaryCondition(
638  bconditions, it->first, variable);
639 
640  if(locBCond->GetBoundaryConditionType()
642  {
644  ::AllocateSharedPtr(m_session, *(it->second),
645  graph3D, variable);
646 
647  // Set up normals on non-Dirichlet boundary conditions
648  if(locBCond->GetBoundaryConditionType() !=
650  {
652  }
653 
654  m_bndCondExpansions[cnt] = locExpList;
655  m_bndConditions[cnt++] = locBCond;
656  }
657  }
658  }
659 
660  /**
661  * @brief Determine the periodic faces, edges and vertices for the given
662  * graph.
663  *
664  * @param bcs Information about the boundary conditions.
665  * @param variable Specifies the field.
666  */
669  const std::string &variable)
670  {
672  = bcs.GetBoundaryRegions();
674  = bcs.GetBoundaryConditions();
676  = boost::dynamic_pointer_cast<
678  SpatialDomains::BoundaryRegionCollection::const_iterator it;
679 
681  m_session->GetComm()->GetRowComm();
683  m_session->GetCompositeOrdering();
684  LibUtilities::BndRegionOrdering bndRegOrder =
685  m_session->GetBndRegionOrdering();
687  m_graph->GetComposites();
688 
689  // perComps: Stores a unique collection of pairs of periodic
690  // composites (i.e. if composites 1 and 2 are periodic then this map
691  // will contain either the pair (1,2) or (2,1) but not both).
692  //
693  // The four maps allVerts, allCoord, allEdges and allOrient map a
694  // periodic face to a vector containing the vertex ids of the face;
695  // their coordinates; the edge ids of the face; and their
696  // orientation within that face respectively.
697  //
698  // Finally the three sets locVerts, locEdges and locFaces store any
699  // vertices, edges and faces that belong to a periodic composite and
700  // lie on this process.
701  map<int,int> perComps;
702  map<int,vector<int> > allVerts;
703  map<int,SpatialDomains::PointGeomVector> allCoord;
704  map<int,vector<int> > allEdges;
705  map<int,vector<StdRegions::Orientation> > allOrient;
706  set<int> locVerts;
707  set<int> locEdges;
708  set<int> locFaces;
709 
710  int region1ID, region2ID, i, j, k, cnt;
712 
713  // Set up a set of all local verts and edges.
714  for(i = 0; i < (*m_exp).size(); ++i)
715  {
716  for(j = 0; j < (*m_exp)[i]->GetNverts(); ++j)
717  {
718  int id = (*m_exp)[i]->GetGeom()->GetVid(j);
719  locVerts.insert(id);
720  }
721 
722  for(j = 0; j < (*m_exp)[i]->GetNedges(); ++j)
723  {
724  int id = (*m_exp)[i]->GetGeom()->GetEid(j);
725  locEdges.insert(id);
726  }
727  }
728 
729  // Begin by populating the perComps map. We loop over all periodic
730  // boundary conditions and determine the composite associated with
731  // it, then fill out the all* maps.
732  for (it = bregions.begin(); it != bregions.end(); ++it)
733  {
734  locBCond = GetBoundaryCondition(
735  bconditions, it->first, variable);
736 
737  if (locBCond->GetBoundaryConditionType()
739  {
740  continue;
741  }
742 
743  // Identify periodic boundary region IDs.
744  region1ID = it->first;
745  region2ID = boost::static_pointer_cast<
747  locBCond)->m_connectedBoundaryRegion;
748 
749  // Check the region only contains a single composite.
750  ASSERTL0(it->second->size() == 1,
751  "Boundary region "+boost::lexical_cast<string>(
752  region1ID)+" should only contain 1 composite.");
753 
754  // From this identify composites by looking at the original
755  // boundary region ordering. Note that in serial the mesh
756  // partitioner is not run, so this map will be empty and
757  // therefore needs to be populated by using the corresponding
758  // boundary region.
759  int cId1, cId2;
760  if (vComm->GetSize() == 1)
761  {
762  cId1 = it->second->begin()->first;
763  cId2 = bregions.find(region2ID)->second->begin()->first;
764  }
765  else
766  {
767  cId1 = bndRegOrder.find(region1ID)->second[0];
768  cId2 = bndRegOrder.find(region2ID)->second[0];
769  }
770 
771  SpatialDomains::Composite c = it->second->begin()->second;
772  vector<unsigned int> tmpOrder;
773 
774  // From the composite, we now construct the allVerts, allEdges
775  // and allCoord map so that they can be transferred across
776  // processors. We also populate the locFaces set to store a
777  // record of all faces local to this process.
778  for (i = 0; i < c->size(); ++i)
779  {
781  boost::dynamic_pointer_cast<
782  SpatialDomains::Geometry2D>((*c)[i]);
783  ASSERTL1(faceGeom, "Unable to cast to shared ptr");
784 
785  // Get geometry ID of this face and store in locFaces.
786  int faceId = (*c)[i]->GetGlobalID();
787  locFaces.insert(faceId);
788 
789  // In serial, mesh partitioning will not have occurred so
790  // need to fill composite ordering map manually.
791  if (vComm->GetSize() == 1)
792  {
793  tmpOrder.push_back((*c)[i]->GetGlobalID());
794  }
795 
796  // Loop over vertices and edges of the face to populate
797  // allVerts, allEdges and allCoord maps.
798  vector<int> vertList, edgeList;
800  vector<StdRegions::Orientation> orientVec;
801  for (j = 0; j < faceGeom->GetNumVerts(); ++j)
802  {
803  vertList .push_back(faceGeom->GetVid (j));
804  edgeList .push_back(faceGeom->GetEid (j));
805  coordVec .push_back(faceGeom->GetVertex(j));
806  orientVec.push_back(faceGeom->GetEorient(j));
807  }
808 
809  allVerts [faceId] = vertList;
810  allEdges [faceId] = edgeList;
811  allCoord [faceId] = coordVec;
812  allOrient[faceId] = orientVec;
813  }
814 
815  // In serial, record the composite ordering in compOrder for
816  // later in the routine.
817  if (vComm->GetSize() == 1)
818  {
819  compOrder[it->second->begin()->first] = tmpOrder;
820  }
821 
822  // See if we already have either region1 or region2 stored in
823  // perComps map already and do a sanity check to ensure regions
824  // are mutually periodic.
825  if (perComps.count(cId1) == 0)
826  {
827  if (perComps.count(cId2) == 0)
828  {
829  perComps[cId1] = cId2;
830  }
831  else
832  {
833  std::stringstream ss;
834  ss << "Boundary region " << cId2 << " should be "
835  << "periodic with " << perComps[cId2] << " but "
836  << "found " << cId1 << " instead!";
837  ASSERTL0(perComps[cId2] == cId1, ss.str());
838  }
839  }
840  else
841  {
842  std::stringstream ss;
843  ss << "Boundary region " << cId1 << " should be "
844  << "periodic with " << perComps[cId1] << " but "
845  << "found " << cId2 << " instead!";
846  ASSERTL0(perComps[cId1] == cId1, ss.str());
847  }
848  }
849 
850  // The next routines process local face lists to exchange vertices,
851  // edges and faces.
852  int n = vComm->GetSize();
853  int p = vComm->GetRank();
854  int totFaces;
855  Array<OneD, int> facecounts(n,0);
856  Array<OneD, int> vertcounts(n,0);
857  Array<OneD, int> faceoffset(n,0);
858  Array<OneD, int> vertoffset(n,0);
859 
860  // First exchange the number of faces on each process.
861  facecounts[p] = locFaces.size();
862  vComm->AllReduce(facecounts, LibUtilities::ReduceSum);
863 
864  // Set up an offset map to allow us to distribute face IDs to all
865  // processors.
866  faceoffset[0] = 0;
867  for (i = 1; i < n; ++i)
868  {
869  faceoffset[i] = faceoffset[i-1] + facecounts[i-1];
870  }
871 
872  // Calculate total number of faces.
873  totFaces = Vmath::Vsum(n, facecounts, 1);
874 
875  // faceIds holds face IDs for each periodic face. faceVerts holds
876  // the number of vertices in this face.
877  Array<OneD, int> faceIds (totFaces, 0);
878  Array<OneD, int> faceVerts(totFaces, 0);
879 
880  // Process p writes IDs of its faces into position faceoffset[p] of
881  // faceIds which allows us to perform an AllReduce to distribute
882  // information amongst processors.
883  set<int>::iterator sIt;
884  for (i = 0, sIt = locFaces.begin(); sIt != locFaces.end(); ++sIt)
885  {
886  faceIds [faceoffset[p] + i ] = *sIt;
887  faceVerts[faceoffset[p] + i++] = allVerts[*sIt].size();
888  }
889 
890  vComm->AllReduce(faceIds, LibUtilities::ReduceSum);
891  vComm->AllReduce(faceVerts, LibUtilities::ReduceSum);
892 
893  // procVerts holds number of vertices (and also edges since each
894  // face is 2D) on each process.
895  Array<OneD, int> procVerts(n,0);
896  int nTotVerts;
897 
898  // Note if there are no periodic faces at all calling Vsum will
899  // cause a segfault.
900  if (totFaces > 0)
901  {
902  // Calculate number of vertices on each processor.
903  nTotVerts = Vmath::Vsum(totFaces, faceVerts, 1);
904  }
905  else
906  {
907  nTotVerts = 0;
908  }
909 
910  for (i = 0; i < n; ++i)
911  {
912  if (facecounts[i] > 0)
913  {
914  procVerts[i] = Vmath::Vsum(
915  facecounts[i], faceVerts + faceoffset[i], 1);
916  }
917  else
918  {
919  procVerts[i] = 0;
920  }
921  }
922 
923  // vertoffset is defined in the same manner as edgeoffset
924  // beforehand.
925  vertoffset[0] = 0;
926  for (i = 1; i < n; ++i)
927  {
928  vertoffset[i] = vertoffset[i-1] + procVerts[i-1];
929  }
930 
931  // At this point we exchange all vertex IDs, edge IDs and vertex
932  // coordinates for each face. The coordinates are necessary because
933  // we need to calculate relative face orientations between periodic
934  // faces to determined edge and vertex connectivity.
935  Array<OneD, int> vertIds(nTotVerts, 0);
936  Array<OneD, int> edgeIds(nTotVerts, 0);
937  Array<OneD, int> edgeOrt(nTotVerts, 0);
938  Array<OneD, NekDouble> vertX (nTotVerts, 0.0);
939  Array<OneD, NekDouble> vertY (nTotVerts, 0.0);
940  Array<OneD, NekDouble> vertZ (nTotVerts, 0.0);
941 
942  for (cnt = 0, sIt = locFaces.begin();
943  sIt != locFaces.end(); ++sIt)
944  {
945  for (j = 0; j < allVerts[*sIt].size(); ++j)
946  {
947  int vertId = allVerts[*sIt][j];
948  vertIds[vertoffset[p] + cnt ] = vertId;
949  vertX [vertoffset[p] + cnt ] = (*allCoord[*sIt][j])(0);
950  vertY [vertoffset[p] + cnt ] = (*allCoord[*sIt][j])(1);
951  vertZ [vertoffset[p] + cnt ] = (*allCoord[*sIt][j])(2);
952  edgeIds[vertoffset[p] + cnt ] = allEdges [*sIt][j];
953  edgeOrt[vertoffset[p] + cnt++] = allOrient[*sIt][j];
954  }
955  }
956 
957  vComm->AllReduce(vertIds, LibUtilities::ReduceSum);
958  vComm->AllReduce(vertX, LibUtilities::ReduceSum);
959  vComm->AllReduce(vertY, LibUtilities::ReduceSum);
960  vComm->AllReduce(vertZ, LibUtilities::ReduceSum);
961  vComm->AllReduce(edgeIds, LibUtilities::ReduceSum);
962  vComm->AllReduce(edgeOrt, LibUtilities::ReduceSum);
963 
964  // Finally now we have all of this information, we construct maps
965  // which make accessing the information easier. These are
966  // conceptually the same as all* maps at the beginning of the
967  // routine, but now hold information for all periodic vertices.
968  map<int, vector<int> > vertMap;
969  map<int, vector<int> > edgeMap;
970  map<int, SpatialDomains::PointGeomVector> coordMap;
971 
972  // These final two maps are required for determining the relative
973  // orientation of periodic edges. vCoMap associates vertex IDs with
974  // their coordinates, and eIdMap maps an edge ID to the two vertices
975  // which construct it.
976  map<int, SpatialDomains::PointGeomSharedPtr> vCoMap;
977  map<int, pair<int, int> > eIdMap;
978 
979  for (cnt = i = 0; i < totFaces; ++i)
980  {
981  vector<int> edges(faceVerts[i]);
982  vector<int> verts(faceVerts[i]);
983  SpatialDomains::PointGeomVector coord(faceVerts[i]);
984 
985  // Keep track of cnt to enable correct edge vertices to be
986  // inserted into eIdMap.
987  int tmp = cnt;
988  for (j = 0; j < faceVerts[i]; ++j, ++cnt)
989  {
990  edges[j] = edgeIds[cnt];
991  verts[j] = vertIds[cnt];
994  3, verts[j], vertX[cnt], vertY[cnt], vertZ[cnt]);
995  vCoMap[vertIds[cnt]] = coord[j];
996 
997  // Try to insert edge into the eIdMap to avoid re-inserting.
998  pair<map<int, pair<int, int> >::iterator, bool> testIns =
999  eIdMap.insert(make_pair(
1000  edgeIds[cnt],
1001  make_pair(vertIds[tmp+j],
1002  vertIds[tmp+((j+1) % faceVerts[i])])));
1003 
1004  if (testIns.second == false)
1005  {
1006  continue;
1007  }
1008 
1009  // If the edge is reversed with respect to the face, then
1010  // swap the edges so that we have the original ordering of
1011  // the edge in the 3D element. This is necessary to properly
1012  // determine edge orientation.
1013  if ((StdRegions::Orientation)edgeOrt[cnt]
1015  {
1016  swap(testIns.first->second.first,
1017  testIns.first->second.second);
1018  }
1019  }
1020 
1021  vertMap [faceIds[i]] = verts;
1022  edgeMap [faceIds[i]] = edges;
1023  coordMap[faceIds[i]] = coord;
1024  }
1025 
1026  // Go through list of composites and figure out which edges are
1027  // parallel from original ordering in session file. This includes
1028  // composites which are not necessarily on this process.
1029  map<int,int>::iterator cIt, pIt;
1030  map<int,int>::const_iterator oIt;
1031 
1032  // Store temporary map of periodic vertices which will hold all
1033  // periodic vertices on the entire mesh so that doubly periodic
1034  // vertices/edges can be counted properly across partitions. Local
1035  // vertices/edges are copied into m_periodicVerts and
1036  // m_periodicEdges at the end of the function.
1037  PeriodicMap periodicVerts;
1038  PeriodicMap periodicEdges;
1039 
1040  // Construct two maps which determine how vertices and edges of
1041  // faces connect given a specific face orientation. The key of the
1042  // map is the number of vertices in the face, used to determine
1043  // difference between tris and quads.
1044  map<int, map<StdRegions::Orientation, vector<int> > > vmap;
1045  map<int, map<StdRegions::Orientation, vector<int> > > emap;
1046 
1047  map<StdRegions::Orientation, vector<int> > quadVertMap;
1048  quadVertMap[StdRegions::eDir1FwdDir1_Dir2FwdDir2] += 0,1,2,3;
1049  quadVertMap[StdRegions::eDir1FwdDir1_Dir2BwdDir2] += 3,2,1,0;
1050  quadVertMap[StdRegions::eDir1BwdDir1_Dir2FwdDir2] += 1,0,3,2;
1051  quadVertMap[StdRegions::eDir1BwdDir1_Dir2BwdDir2] += 2,3,0,1;
1052  quadVertMap[StdRegions::eDir1FwdDir2_Dir2FwdDir1] += 0,3,2,1;
1053  quadVertMap[StdRegions::eDir1FwdDir2_Dir2BwdDir1] += 1,2,3,0;
1054  quadVertMap[StdRegions::eDir1BwdDir2_Dir2FwdDir1] += 3,0,1,2;
1055  quadVertMap[StdRegions::eDir1BwdDir2_Dir2BwdDir1] += 2,1,0,3;
1056 
1057  map<StdRegions::Orientation, vector<int> > quadEdgeMap;
1058  quadEdgeMap[StdRegions::eDir1FwdDir1_Dir2FwdDir2] += 0,1,2,3;
1059  quadEdgeMap[StdRegions::eDir1FwdDir1_Dir2BwdDir2] += 2,1,0,3;
1060  quadEdgeMap[StdRegions::eDir1BwdDir1_Dir2FwdDir2] += 0,3,2,1;
1061  quadEdgeMap[StdRegions::eDir1BwdDir1_Dir2BwdDir2] += 2,3,0,1;
1062  quadEdgeMap[StdRegions::eDir1FwdDir2_Dir2FwdDir1] += 3,2,1,0;
1063  quadEdgeMap[StdRegions::eDir1FwdDir2_Dir2BwdDir1] += 1,2,3,0;
1064  quadEdgeMap[StdRegions::eDir1BwdDir2_Dir2FwdDir1] += 3,0,1,2;
1065  quadEdgeMap[StdRegions::eDir1BwdDir2_Dir2BwdDir1] += 1,0,3,2;
1066 
1067  map<StdRegions::Orientation, vector<int> > triVertMap;
1068  triVertMap[StdRegions::eDir1FwdDir1_Dir2FwdDir2] += 0,1,2;
1069  triVertMap[StdRegions::eDir1BwdDir1_Dir2FwdDir2] += 1,0,2;
1070 
1071  map<StdRegions::Orientation, vector<int> > triEdgeMap;
1072  triEdgeMap[StdRegions::eDir1FwdDir1_Dir2FwdDir2] += 0,1,2;
1073  triEdgeMap[StdRegions::eDir1BwdDir1_Dir2FwdDir2] += 0,2,1;
1074 
1075  vmap[3] = triVertMap;
1076  vmap[4] = quadVertMap;
1077  emap[3] = triEdgeMap;
1078  emap[4] = quadEdgeMap;
1079 
1080  map<int,int> allCompPairs;
1081 
1082  // Finally we have enough information to populate the periodic
1083  // vertex, edge and face maps. Begin by looping over all pairs of
1084  // periodic composites to determine pairs of periodic faces.
1085  for (cIt = perComps.begin(); cIt != perComps.end(); ++cIt)
1086  {
1088  const int id1 = cIt->first;
1089  const int id2 = cIt->second;
1090  std::string id1s = boost::lexical_cast<string>(id1);
1091  std::string id2s = boost::lexical_cast<string>(id2);
1092 
1093  if (compMap.count(id1) > 0)
1094  {
1095  c[0] = compMap[id1];
1096  }
1097 
1098  if (compMap.count(id2) > 0)
1099  {
1100  c[1] = compMap[id2];
1101  }
1102 
1103  ASSERTL0(c[0] || c[1],
1104  "Neither composite not found on this process!");
1105 
1106  // Loop over composite ordering to construct list of all
1107  // periodic faces, regardless of whether they are on this
1108  // process.
1109  map<int,int> compPairs;
1110 
1111  ASSERTL0(compOrder.count(id1) > 0,
1112  "Unable to find composite "+id1s+" in order map.");
1113  ASSERTL0(compOrder.count(id2) > 0,
1114  "Unable to find composite "+id2s+" in order map.");
1115  ASSERTL0(compOrder[id1].size() == compOrder[id2].size(),
1116  "Periodic composites "+id1s+" and "+id2s+
1117  " should have the same number of elements.");
1118  ASSERTL0(compOrder[id1].size() > 0,
1119  "Periodic composites "+id1s+" and "+id2s+
1120  " are empty!");
1121 
1122  // Look up composite ordering to determine pairs.
1123  for (i = 0; i < compOrder[id1].size(); ++i)
1124  {
1125  int eId1 = compOrder[id1][i];
1126  int eId2 = compOrder[id2][i];
1127 
1128  ASSERTL0(compPairs.count(eId1) == 0,
1129  "Already paired.");
1130 
1131  // Sanity check that the faces are mutually periodic.
1132  if (compPairs.count(eId2) != 0)
1133  {
1134  ASSERTL0(compPairs[eId2] == eId1, "Pairing incorrect");
1135  }
1136  compPairs[eId1] = eId2;
1137  }
1138 
1139  // Now that we have all pairs of periodic faces, loop over the
1140  // ones local to this process and populate face/edge/vertex
1141  // maps.
1142  for (pIt = compPairs.begin(); pIt != compPairs.end(); ++pIt)
1143  {
1144  int ids [2] = {pIt->first, pIt->second};
1145  bool local[2] = {locFaces.count(pIt->first) > 0,
1146  locFaces.count(pIt->second) > 0};
1147 
1148  ASSERTL0(coordMap.count(ids[0]) > 0 &&
1149  coordMap.count(ids[1]) > 0,
1150  "Unable to find face in coordinate map");
1151 
1152  allCompPairs[pIt->first ] = pIt->second;
1153  allCompPairs[pIt->second] = pIt->first;
1154 
1155  // Loop up coordinates of the faces, check they have the
1156  // same number of vertices.
1158  = { coordMap[ids[0]], coordMap[ids[1]] };
1159 
1160  ASSERTL0(tmpVec[0].size() == tmpVec[1].size(),
1161  "Two periodic faces have different number "
1162  "of vertices!");
1163 
1164  // o will store relative orientation of faces. Note that in
1165  // some transpose cases (Dir1FwdDir2_Dir2BwdDir1 and
1166  // Dir1BwdDir1_Dir2FwdDir1) it seems orientation will be
1167  // different going from face1->face2 instead of face2->face1
1168  // (check this).
1170 
1171  // Record periodic faces.
1172  for (i = 0; i < 2; ++i)
1173  {
1174  if (!local[i])
1175  {
1176  continue;
1177  }
1178 
1179  // Reference to the other face.
1180  int other = (i+1) % 2;
1181 
1182  // Calculate relative face orientation.
1183  if (tmpVec[0].size() == 3)
1184  {
1186  tmpVec[i], tmpVec[other]);
1187  }
1188  else
1189  {
1191  tmpVec[i], tmpVec[other]);
1192  }
1193 
1194  // Record face ID, orientation and whether other face is
1195  // local.
1196  PeriodicEntity ent(ids [other], o,
1197  local[other]);
1198  m_periodicFaces[ids[i]].push_back(ent);
1199  }
1200 
1201  int nFaceVerts = vertMap[ids[0]].size();
1202 
1203  // Determine periodic vertices.
1204  for (i = 0; i < 2; ++i)
1205  {
1206  int other = (i+1) % 2;
1207 
1208  // Calculate relative face orientation.
1209  if (tmpVec[0].size() == 3)
1210  {
1212  tmpVec[i], tmpVec[other]);
1213  }
1214  else
1215  {
1217  tmpVec[i], tmpVec[other]);
1218  }
1219 
1220  if (nFaceVerts == 3)
1221  {
1222  ASSERTL0(
1225  "Unsupported face orientation for face "+
1226  boost::lexical_cast<string>(ids[i]));
1227  }
1228 
1229  // Look up vertices for this face.
1230  vector<int> per1 = vertMap[ids[i]];
1231  vector<int> per2 = vertMap[ids[other]];
1232 
1233  // tmpMap will hold the pairs of vertices which are
1234  // periodic.
1235  map<int, pair<int, bool> > tmpMap;
1236  map<int, pair<int, bool> >::iterator mIt;
1237 
1238  // Use vmap to determine which vertices connect given
1239  // the orientation o.
1240  for (j = 0; j < nFaceVerts; ++j)
1241  {
1242  int v = vmap[nFaceVerts][o][j];
1243  tmpMap[per1[j]] = make_pair(
1244  per2[v], locVerts.count(per2[v]) > 0);
1245  }
1246 
1247  // Now loop over tmpMap to associate periodic vertices.
1248  for (mIt = tmpMap.begin(); mIt != tmpMap.end(); ++mIt)
1249  {
1250  PeriodicEntity ent2(mIt->second.first,
1252  mIt->second.second);
1253 
1254  // See if this vertex has been recorded already.
1255  PeriodicMap::iterator perIt = periodicVerts.find(
1256  mIt->first);
1257 
1258  if (perIt == periodicVerts.end())
1259  {
1260  // Vertex is new - just record this entity as
1261  // usual.
1262  periodicVerts[mIt->first].push_back(ent2);
1263  perIt = periodicVerts.find(mIt->first);
1264  }
1265  else
1266  {
1267  // Vertex is known - loop over the vertices
1268  // inside the record and potentially add vertex
1269  // mIt->second to the list.
1270  for (k = 0; k < perIt->second.size(); ++k)
1271  {
1272  if (perIt->second[k].id == mIt->second.first)
1273  {
1274  break;
1275  }
1276  }
1277 
1278  if (k == perIt->second.size())
1279  {
1280  perIt->second.push_back(ent2);
1281  }
1282  }
1283  }
1284  }
1285 
1286  // Determine periodic edges. Logic is the same as above,
1287  // and perhaps should be condensed to avoid replication.
1288  for (i = 0; i < 2; ++i)
1289  {
1290  int other = (i+1) % 2;
1291 
1292  if (tmpVec[0].size() == 3)
1293  {
1295  tmpVec[i], tmpVec[other]);
1296  }
1297  else
1298  {
1300  tmpVec[i], tmpVec[other]);
1301  }
1302 
1303  vector<int> per1 = edgeMap[ids[i]];
1304  vector<int> per2 = edgeMap[ids[other]];
1305 
1306  map<int, pair<int, bool> > tmpMap;
1307  map<int, pair<int, bool> >::iterator mIt;
1308 
1309  for (j = 0; j < nFaceVerts; ++j)
1310  {
1311  int e = emap[nFaceVerts][o][j];
1312  tmpMap[per1[j]] = make_pair(
1313  per2[e], locEdges.count(per2[e]) > 0);
1314  }
1315 
1316  for (mIt = tmpMap.begin(); mIt != tmpMap.end(); ++mIt)
1317  {
1318  // Note we assume orientation of edges is forwards -
1319  // this may be reversed later.
1320  PeriodicEntity ent2(mIt->second.first,
1322  mIt->second.second);
1323  PeriodicMap::iterator perIt = periodicEdges.find(
1324  mIt->first);
1325 
1326  if (perIt == periodicEdges.end())
1327  {
1328  periodicEdges[mIt->first].push_back(ent2);
1329  perIt = periodicEdges.find(mIt->first);
1330  }
1331  else
1332  {
1333  for (k = 0; k < perIt->second.size(); ++k)
1334  {
1335  if (perIt->second[k].id == mIt->second.first)
1336  {
1337  break;
1338  }
1339  }
1340 
1341  if (k == perIt->second.size())
1342  {
1343  perIt->second.push_back(ent2);
1344  }
1345  }
1346  }
1347  }
1348  }
1349  }
1350 
1351  Array<OneD, int> pairSizes(n, 0);
1352  pairSizes[p] = allCompPairs.size();
1353  vComm->AllReduce(pairSizes, LibUtilities::ReduceSum);
1354 
1355  int totPairSizes = Vmath::Vsum(n, pairSizes, 1);
1356 
1357  Array<OneD, int> pairOffsets(n, 0);
1358  pairOffsets[0] = 0;
1359 
1360  for (i = 1; i < n; ++i)
1361  {
1362  pairOffsets[i] = pairOffsets[i-1] + pairSizes[i-1];
1363  }
1364 
1365  Array<OneD, int> first (totPairSizes, 0);
1366  Array<OneD, int> second(totPairSizes, 0);
1367 
1368  cnt = pairOffsets[p];
1369 
1370  for (pIt = allCompPairs.begin(); pIt != allCompPairs.end(); ++pIt)
1371  {
1372  first [cnt ] = pIt->first;
1373  second[cnt++] = pIt->second;
1374  }
1375 
1376  vComm->AllReduce(first, LibUtilities::ReduceSum);
1377  vComm->AllReduce(second, LibUtilities::ReduceSum);
1378 
1379  allCompPairs.clear();
1380 
1381  for(cnt = 0; cnt < totPairSizes; ++cnt)
1382  {
1383  allCompPairs[first[cnt]] = second[cnt];
1384  }
1385 
1386  // Search for periodic vertices and edges which are not
1387  // in a periodic composite but lie in this process. First,
1388  // loop over all information we have from other
1389  // processors.
1390  for (cnt = i = 0; i < totFaces; ++i)
1391  {
1392  int faceId = faceIds[i];
1393 
1394  ASSERTL0(allCompPairs.count(faceId) > 0,
1395  "Unable to find matching periodic face.");
1396 
1397  int perFaceId = allCompPairs[faceId];
1398 
1399  for (j = 0; j < faceVerts[i]; ++j, ++cnt)
1400  {
1401  int vId = vertIds[cnt];
1402 
1403  PeriodicMap::iterator perId = periodicVerts.find(vId);
1404 
1405  if (perId == periodicVerts.end())
1406  {
1407 
1408  // This vertex is not included in the map. Figure out which
1409  // vertex it is supposed to be periodic with. perFaceId is
1410  // the face ID which is periodic with faceId. The logic is
1411  // much the same as the loop above.
1413  = { coordMap[faceId], coordMap[perFaceId] };
1414 
1415  int nFaceVerts = tmpVec[0].size();
1416  StdRegions::Orientation o = nFaceVerts == 3 ?
1418  tmpVec[0], tmpVec[1]) :
1420  tmpVec[0], tmpVec[1]);
1421 
1422  // Use vmap to determine which vertex of the other face
1423  // should be periodic with this one.
1424  int perVertexId = vertMap[perFaceId][vmap[nFaceVerts][o][j]];
1425 
1426 
1427  PeriodicEntity ent(perVertexId,
1429  locVerts.count(perVertexId) > 0);
1430 
1431  periodicVerts[vId].push_back(ent);
1432  }
1433 
1434  int eId = edgeIds[cnt];
1435 
1436  perId = periodicEdges.find(eId);
1437 
1438  if (perId == periodicEdges.end())
1439  {
1440  // This edge is not included in the map. Figure
1441  // out which edge it is supposed to be periodic
1442  // with. perFaceId is the face ID which is
1443  // periodic with faceId. The logic is much the
1444  // same as the loop above.
1446  = { coordMap[faceId], coordMap[perFaceId] };
1447 
1448  int nFaceEdges = tmpVec[0].size();
1449  StdRegions::Orientation o = nFaceEdges == 3 ?
1451  tmpVec[0], tmpVec[1]) :
1453  tmpVec[0], tmpVec[1]);
1454 
1455  // Use emap to determine which edge of the other
1456  // face should be periodic with this one.
1457  int perEdgeId = edgeMap[perFaceId][emap[nFaceEdges][o][j]];
1458 
1459 
1460  PeriodicEntity ent(perEdgeId,
1462  locEdges.count(perEdgeId) > 0);
1463 
1464  periodicEdges[eId].push_back(ent);
1465  }
1466  }
1467  }
1468 
1469  // Finally, we must loop over the periodicVerts and periodicEdges
1470  // map to complete connectivity information.
1471  PeriodicMap::iterator perIt, perIt2;
1472  for (perIt = periodicVerts.begin();
1473  perIt != periodicVerts.end(); ++perIt)
1474  {
1475  // For each vertex that is periodic with this one...
1476  for (i = 0; i < perIt->second.size(); ++i)
1477  {
1478  // Find the vertex in the periodicVerts map...
1479  perIt2 = periodicVerts.find(perIt->second[i].id);
1480  ASSERTL0(perIt2 != periodicVerts.end(),
1481  "Couldn't find periodic vertex.");
1482 
1483  // Now search through this vertex's list and make sure that
1484  // we have a record of any vertices which aren't in the
1485  // original list.
1486  for (j = 0; j < perIt2->second.size(); ++j)
1487  {
1488  if (perIt2->second[j].id == perIt->first)
1489  {
1490  continue;
1491  }
1492 
1493  for (k = 0; k < perIt->second.size(); ++k)
1494  {
1495  if (perIt2->second[j].id == perIt->second[k].id)
1496  {
1497  break;
1498  }
1499  }
1500 
1501  if (k == perIt->second.size())
1502  {
1503  perIt->second.push_back(perIt2->second[j]);
1504  }
1505  }
1506  }
1507  }
1508 
1509  for (perIt = periodicEdges.begin();
1510  perIt != periodicEdges.end(); ++perIt)
1511  {
1512  for (i = 0; i < perIt->second.size(); ++i)
1513  {
1514  perIt2 = periodicEdges.find(perIt->second[i].id);
1515  ASSERTL0(perIt2 != periodicEdges.end(),
1516  "Couldn't find periodic edge.");
1517 
1518  for (j = 0; j < perIt2->second.size(); ++j)
1519  {
1520  if (perIt2->second[j].id == perIt->first)
1521  {
1522  continue;
1523  }
1524 
1525  for (k = 0; k < perIt->second.size(); ++k)
1526  {
1527  if (perIt2->second[j].id == perIt->second[k].id)
1528  {
1529  break;
1530  }
1531  }
1532 
1533  if (k == perIt->second.size())
1534  {
1535  perIt->second.push_back(perIt2->second[j]);
1536  }
1537  }
1538  }
1539  }
1540 
1541  // Loop over periodic edges to determine relative edge orientations.
1542  for (perIt = periodicEdges.begin();
1543  perIt != periodicEdges.end(); perIt++)
1544  {
1545  // Find edge coordinates
1546  map<int, pair<int, int> >::iterator eIt
1547  = eIdMap.find(perIt->first);
1548  SpatialDomains::PointGeom v[2] = {
1549  *vCoMap[eIt->second.first],
1550  *vCoMap[eIt->second.second]
1551  };
1552 
1553  // Loop over each edge, and construct a vector that takes us
1554  // from one vertex to another. Use this to figure out which
1555  // vertex maps to which.
1556  for (i = 0; i < perIt->second.size(); ++i)
1557  {
1558  eIt = eIdMap.find(perIt->second[i].id);
1559 
1560  SpatialDomains::PointGeom w[2] = {
1561  *vCoMap[eIt->second.first],
1562  *vCoMap[eIt->second.second]
1563  };
1564 
1565  NekDouble cx = 0.5*(w[0](0)-v[0](0)+w[1](0)-v[1](0));
1566  NekDouble cy = 0.5*(w[0](1)-v[0](1)+w[1](1)-v[1](1));
1567  NekDouble cz = 0.5*(w[0](2)-v[0](2)+w[1](2)-v[1](2));
1568 
1569  int vMap[2] = {-1,-1};
1570  for (j = 0; j < 2; ++j)
1571  {
1572  NekDouble x = v[j](0);
1573  NekDouble y = v[j](1);
1574  NekDouble z = v[j](2);
1575  for (k = 0; k < 2; ++k)
1576  {
1577  NekDouble x1 = w[k](0)-cx;
1578  NekDouble y1 = w[k](1)-cy;
1579  NekDouble z1 = w[k](2)-cz;
1580 
1581  if (sqrt((x1-x)*(x1-x)+(y1-y)*(y1-y)+(z1-z)*(z1-z))
1582  < 1e-8)
1583  {
1584  vMap[k] = j;
1585  break;
1586  }
1587  }
1588  }
1589 
1590  // Sanity check the map.
1591  ASSERTL0(vMap[0] >= 0 && vMap[1] >= 0,
1592  "Unable to align periodic vertices.");
1593  ASSERTL0((vMap[0] == 0 || vMap[0] == 1) &&
1594  (vMap[1] == 0 || vMap[1] == 1) &&
1595  (vMap[0] != vMap[1]),
1596  "Unable to align periodic vertices.");
1597 
1598  // If 0 -> 0 then edges are aligned already; otherwise
1599  // reverse the orientation.
1600  if (vMap[0] != 0)
1601  {
1602  perIt->second[i].orient = StdRegions::eBackwards;
1603  }
1604  }
1605  }
1606 
1607  // Do one final loop over periodic vertices/edges to remove
1608  // non-local vertices/edges from map.
1609  for (perIt = periodicVerts.begin();
1610  perIt != periodicVerts.end(); ++perIt)
1611  {
1612  if (locVerts.count(perIt->first) > 0)
1613  {
1614  m_periodicVerts.insert(*perIt);
1615  }
1616  }
1617 
1618  for (perIt = periodicEdges.begin();
1619  perIt != periodicEdges.end(); ++perIt)
1620  {
1621  if (locEdges.count(perIt->first) > 0)
1622  {
1623  m_periodicEdges.insert(*perIt);
1624  }
1625  }
1626  }
1627 
1628  bool DisContField3D::IsLeftAdjacentFace(const int n, const int e)
1629  {
1630  set<int>::iterator it;
1632  m_traceMap->GetElmtToTrace()[n][e]->
1633  as<LocalRegions::Expansion2D>();
1634 
1635  int offset = m_trace->GetPhys_Offset(traceEl->GetElmtId());
1636 
1637  bool fwd = true;
1638  if (traceEl->GetLeftAdjacentElementFace () == -1 ||
1639  traceEl->GetRightAdjacentElementFace() == -1)
1640  {
1641  // Boundary edge (1 connected element). Do nothing in
1642  // serial.
1643  it = m_boundaryFaces.find(traceEl->GetElmtId());
1644 
1645  // If the edge does not have a boundary condition set on
1646  // it, then assume it is a partition edge.
1647  if (it == m_boundaryFaces.end())
1648  {
1649  int traceGeomId = traceEl->GetGeom2D()->GetGlobalID();
1651  traceGeomId);
1652 
1653  if (pIt != m_periodicFaces.end() && !pIt->second[0].isLocal)
1654  {
1655  fwd = traceGeomId == min(traceGeomId,pIt->second[0].id);
1656  }
1657  else
1658  {
1659  fwd = m_traceMap->
1660  GetTraceToUniversalMapUnique(offset) >= 0;
1661  }
1662  }
1663  }
1664  else if (traceEl->GetLeftAdjacentElementFace () != -1 &&
1665  traceEl->GetRightAdjacentElementFace() != -1)
1666  {
1667  // Non-boundary edge (2 connected elements).
1668  fwd = dynamic_cast<Nektar::StdRegions::StdExpansion*>
1669  (traceEl->GetLeftAdjacentElementExp().get()) ==
1670  (*m_exp)[n].get();
1671  }
1672  else
1673  {
1674  ASSERTL2(false, "Unconnected trace element!");
1675  }
1676 
1677  return fwd;
1678  }
1679 
1680  /**
1681  * \brief This method extracts the "forward" and "backward" trace
1682  * data from the array \a field and puts the data into output
1683  * vectors \a Fwd and \a Bwd.
1684  *
1685  * We first define the convention which defines "forwards" and
1686  * "backwards". First an association is made between the face of
1687  * each element and its corresponding face in the trace space
1688  * using the mapping #m_traceMap. The element can either be
1689  * left-adjacent or right-adjacent to this trace face (see
1690  * Expansion2D::GetLeftAdjacentElementExp). Boundary faces are
1691  * always left-adjacent since left-adjacency is populated first.
1692  *
1693  * If the element is left-adjacent we extract the face trace data
1694  * from \a field into the forward trace space \a Fwd; otherwise,
1695  * we place it in the backwards trace space \a Bwd. In this way,
1696  * we form a unique set of trace normals since these are always
1697  * extracted from left-adjacent elements.
1698  *
1699  * \param field is a NekDouble array which contains the 3D data
1700  * from which we wish to extract the backward and forward
1701  * orientated trace/face arrays.
1702  *
1703  * \return Updates a NekDouble array \a Fwd and \a Bwd
1704  */
1707  {
1708  v_GetFwdBwdTracePhys(m_phys, Fwd, Bwd);
1709  }
1710 
1712  const Array<OneD, const NekDouble> &field,
1715  {
1716  int n, cnt, npts, e;
1717 
1718  // Zero vectors.
1719  Vmath::Zero(Fwd.num_elements(), Fwd, 1);
1720  Vmath::Zero(Bwd.num_elements(), Bwd, 1);
1721 
1723  GetNLocTracePts());
1724  m_locTraceToTraceMap->LocTracesFromField(field,facevals);
1725  m_locTraceToTraceMap->InterpLocFacesToTrace(0, facevals, Fwd);
1726 
1727  Array<OneD, NekDouble> invals = facevals + m_locTraceToTraceMap->
1728  GetNFwdLocTracePts();
1729  m_locTraceToTraceMap->InterpLocFacesToTrace(1, invals, Bwd);
1730 
1731  // Fill boundary conditions into missing elements
1732  int id1, id2 = 0;
1733  cnt = 0;
1734 
1735  for(n = 0; n < m_bndCondExpansions.num_elements(); ++n)
1736  {
1737  if(m_bndConditions[n]->GetBoundaryConditionType() ==
1739  {
1740  for(e = 0; e < m_bndCondExpansions[n]->GetExpSize(); ++e)
1741  {
1742  npts = m_bndCondExpansions[n]->GetExp(e)->GetTotPoints();
1743  id1 = m_bndCondExpansions[n]->GetPhys_Offset(e);
1744  id2 = m_trace->GetPhys_Offset(
1745  m_traceMap->GetBndCondTraceToGlobalTraceMap(cnt+e));
1746  Vmath::Vcopy(npts,
1747  &(m_bndCondExpansions[n]->GetPhys())[id1], 1,
1748  &Bwd[id2], 1);
1749  }
1750 
1751  cnt += e;
1752  }
1753  else if (m_bndConditions[n]->GetBoundaryConditionType() ==
1755  m_bndConditions[n]->GetBoundaryConditionType() ==
1757  {
1758  for(e = 0; e < m_bndCondExpansions[n]->GetExpSize(); ++e)
1759  {
1760  npts = m_bndCondExpansions[n]->GetExp(e)->GetTotPoints();
1761  id1 = m_bndCondExpansions[n]->GetPhys_Offset(e);
1762  id2 = m_trace->GetPhys_Offset(
1763  m_traceMap->GetBndCondTraceToGlobalTraceMap(cnt+e));
1764 
1765  // Turning this off since we can have non-zero
1766  //Neumann in mixed CG-DG method
1767  //ASSERTL1((m_bndCondExpansions[n]->GetPhys())[id1]
1768  //== 0.0, "method not set up for non-zero
1769  //Neumann " "boundary condition");
1770 
1771  Vmath::Vcopy(npts,&Fwd[id2],1,&Bwd[id2],1);
1772  }
1773 
1774  cnt += e;
1775  }
1776  else
1777  {
1778  ASSERTL0(false, "Method only set up for Dirichlet, Neumann "
1779  "and Robin conditions.");
1780  }
1781  }
1782 
1783  // Copy any periodic boundary conditions.
1784  for (n = 0; n < m_periodicFwdCopy.size(); ++n)
1785  {
1786  Bwd[m_periodicBwdCopy[n]] = Fwd[m_periodicFwdCopy[n]];
1787  }
1788 
1789  // Do parallel exchange for forwards/backwards spaces.
1790  m_traceMap->UniversalTraceAssemble(Fwd);
1791  m_traceMap->UniversalTraceAssemble(Bwd);
1792  }
1793 
1794  const vector<bool> &DisContField3D::v_GetLeftAdjacentFaces(void) const
1795  {
1796  return m_leftAdjacentFaces;
1797  }
1798 
1800  Array<OneD, NekDouble> &outarray)
1801  {
1802  ASSERTL1(m_physState == true,
1803  "Field is not in physical space.");
1804 
1805  v_ExtractTracePhys(m_phys, outarray);
1806  }
1807 
1809  const Array<OneD, const NekDouble> &inarray,
1810  Array<OneD, NekDouble> &outarray)
1811  {
1812 
1813  Vmath::Zero(outarray.num_elements(), outarray, 1);
1814 
1815  Array<OneD, NekDouble> facevals(m_locTraceToTraceMap->GetNFwdLocTracePts());
1816  m_locTraceToTraceMap->FwdLocTracesFromField(inarray,facevals);
1817  m_locTraceToTraceMap->InterpLocFacesToTrace(0,facevals,outarray);
1818 
1819  // gather entries along parallel partitions which have
1820  // only filled in Fwd part on their own partition
1821  m_traceMap->UniversalTraceAssemble(outarray);
1822 
1823  }
1824 
1825  /**
1826  * @brief Add trace contributions into elemental coefficient spaces.
1827  *
1828  * Given some quantity \f$ \vec{Fn} \f$, which conatins this
1829  * routine calculates the integral
1830  *
1831  * \f[
1832  * \int_{\Omega^e} \vec{Fn}, \mathrm{d}S
1833  * \f]
1834  *
1835  * and adds this to the coefficient space provided by outarray.
1836  *
1837  * @see Expansion3D::AddFaceNormBoundaryInt
1838  *
1839  * @param Fn The trace quantities.
1840  * @param outarray Resulting 3D coefficient space.
1841  *
1842  */
1844  const Array<OneD, const NekDouble> &Fn,
1845  Array<OneD, NekDouble> &outarray)
1846  {
1847 
1848  Array<OneD, NekDouble> Fcoeffs(m_trace->GetNcoeffs());
1849  m_trace->IProductWRTBase(Fn, Fcoeffs);
1850 
1851  m_locTraceToTraceMap->AddTraceCoeffsToFieldCoeffs(Fcoeffs,
1852  outarray);
1853  }
1854  /**
1855  * @brief Add trace contributions into elemental coefficient spaces.
1856  *
1857  * Given some quantity \f$ \vec{Fn} \f$, which conatins this
1858  * routine calculates the integral
1859  *
1860  * \f[
1861  * \int_{\Omega^e} \vec{Fn}, \mathrm{d}S
1862  * \f]
1863  *
1864  * and adds this to the coefficient space provided by
1865  * outarray. The value of q is determined from the routine
1866  * IsLeftAdjacentFace() which if true we use Fwd else we use
1867  * Bwd
1868  *
1869  * @see Expansion3D::AddFaceNormBoundaryInt
1870  *
1871  * @param Fwd The trace quantities associated with left (fwd)
1872  * adjancent elmt.
1873  * @param Bwd The trace quantities associated with right (bwd)
1874  * adjacent elet.
1875  * @param outarray Resulting 3D coefficient space.
1876  */
1878  const Array<OneD, const NekDouble> &Fwd,
1879  const Array<OneD, const NekDouble> &Bwd,
1880  Array<OneD, NekDouble> &outarray)
1881  {
1882  Array<OneD, NekDouble> Coeffs(m_trace->GetNcoeffs());
1883 
1884  m_trace->IProductWRTBase(Fwd,Coeffs);
1885  m_locTraceToTraceMap->AddTraceCoeffsToFieldCoeffs(0,Coeffs,outarray);
1886  m_trace->IProductWRTBase(Bwd,Coeffs);
1887  m_locTraceToTraceMap->AddTraceCoeffsToFieldCoeffs(1,Coeffs,outarray);
1888  }
1889 
1890  /**
1891  * @brief Set up a list of elemeent IDs and edge IDs that link to the
1892  * boundary conditions.
1893  */
1895  Array<OneD, int> &ElmtID,
1896  Array<OneD, int> &FaceID)
1897  {
1898  map<int,int> globalIdMap;
1899  int i, n;
1900  int cnt;
1901  int nbcs = 0;
1902 
1904  boost::dynamic_pointer_cast<SpatialDomains::MeshGraph3D>(
1905  m_graph);
1906 
1907  // Populate global ID map (takes global geometry ID to local
1908  // expansion list ID).
1910  for (i = 0; i < GetExpSize(); ++i)
1911  {
1912  exp3d = (*m_exp)[i]->as<LocalRegions::Expansion3D>();
1913  globalIdMap[exp3d->GetGeom3D()->GetGlobalID()] = i;
1914  }
1915 
1916  // Determine number of boundary condition expansions.
1917  for(i = 0; i < m_bndConditions.num_elements(); ++i)
1918  {
1919  nbcs += m_bndCondExpansions[i]->GetExpSize();
1920  }
1921 
1922  // make sure arrays are of sufficient length
1923  if(ElmtID.num_elements() != nbcs)
1924  {
1925  ElmtID = Array<OneD, int>(nbcs);
1926  }
1927 
1928  if(FaceID.num_elements() != nbcs)
1929  {
1930  FaceID = Array<OneD, int>(nbcs);
1931  }
1932 
1934  for(cnt = n = 0; n < m_bndCondExpansions.num_elements(); ++n)
1935  {
1936  for(i = 0; i < m_bndCondExpansions[n]->GetExpSize(); ++i, ++cnt)
1937  {
1938  exp2d = m_bndCondExpansions[n]->GetExp(i)->
1939  as<LocalRegions::Expansion2D>();
1940  // Use face to element map from MeshGraph3D.
1942  graph3D->GetElementsFromFace(exp2d->GetGeom2D());
1943 
1944  ElmtID[cnt] = globalIdMap[(*tmp)[0]->
1945  m_Element->GetGlobalID()];
1946  FaceID[cnt] = (*tmp)[0]->m_FaceIndx;
1947  }
1948  }
1949  }
1950 
1952  boost::shared_ptr<ExpList> &result)
1953  {
1954  int n, cnt, nq;
1955  int offsetOld, offsetNew;
1956  Array<OneD, NekDouble> tmp1, tmp2;
1957  std::vector<unsigned int> eIDs;
1958 
1959  Array<OneD, int> ElmtID,EdgeID;
1960  GetBoundaryToElmtMap(ElmtID,EdgeID);
1961 
1962  // Skip other boundary regions
1963  for (cnt = n = 0; n < i; ++n)
1964  {
1965  cnt += m_bndCondExpansions[n]->GetExpSize();
1966  }
1967 
1968  // Populate eIDs with information from BoundaryToElmtMap
1969  for (n = 0; n < m_bndCondExpansions[i]->GetExpSize(); ++n)
1970  {
1971  eIDs.push_back(ElmtID[cnt+n]);
1972  }
1973 
1974  // Create expansion list
1975  result =
1977 
1978  // Copy phys and coeffs to new explist
1979  for (n = 0; n < result->GetExpSize(); ++n)
1980  {
1981  nq = GetExp(ElmtID[cnt+n])->GetTotPoints();
1982  offsetOld = GetPhys_Offset(ElmtID[cnt+n]);
1983  offsetNew = result->GetPhys_Offset(n);
1984  Vmath::Vcopy(nq, tmp1 = GetPhys()+ offsetOld, 1,
1985  tmp2 = result->UpdatePhys()+ offsetNew, 1);
1986 
1987  nq = GetExp(ElmtID[cnt+n])->GetNcoeffs();
1988  offsetOld = GetCoeff_Offset(ElmtID[cnt+n]);
1989  offsetNew = result->GetCoeff_Offset(n);
1990  Vmath::Vcopy(nq, tmp1 = GetCoeffs()+ offsetOld, 1,
1991  tmp2 = result->UpdateCoeffs()+ offsetNew, 1);
1992  }
1993  }
1994 
1995  /**
1996  * @brief Reset this field, so that geometry information can be updated.
1997  */
1999  {
2000  ExpList::v_Reset();
2001 
2002  // Reset boundary condition expansions.
2003  for (int n = 0; n < m_bndCondExpansions.num_elements(); ++n)
2004  {
2005  m_bndCondExpansions[n]->Reset();
2006  }
2007  }
2008 
2009  /**
2010  * Solving Helmholtz Equation in 3D
2011  */
2013  const Array<OneD, const NekDouble> &inarray,
2014  Array<OneD, NekDouble> &outarray,
2015  const FlagList &flags,
2016  const StdRegions::ConstFactorMap &factors,
2017  const StdRegions::VarCoeffMap &varcoeff,
2018  const Array<OneD, const NekDouble> &dirForcing)
2019  {
2020  int i,j,n,cnt,cnt1,nbndry;
2021  int nexp = GetExpSize();
2023 
2025  DNekVec F(m_ncoeffs,f,eWrapper);
2026  Array<OneD,NekDouble> e_f, e_l;
2027 
2028  //----------------------------------
2029  // Setup RHS Inner product
2030  //----------------------------------
2031  IProductWRTBase(inarray,f);
2032  Vmath::Neg(m_ncoeffs,f,1);
2033 
2034  //----------------------------------
2035  // Solve continuous flux System
2036  //----------------------------------
2037  int GloBndDofs = m_traceMap->GetNumGlobalBndCoeffs();
2038  int NumDirichlet = m_traceMap->GetNumLocalDirBndCoeffs();
2039  int e_ncoeffs,id;
2040 
2041  // Retrieve block matrix of U^e
2043  const DNekScalBlkMatSharedPtr &HDGLamToU = GetBlockMatrix(HDGLamToUKey);
2044 
2045  // Retrieve global trace space storage, \Lambda, from trace expansion
2046  Array<OneD,NekDouble> BndSol = m_trace->UpdateCoeffs();
2047 
2048  // Create trace space forcing, F
2049  Array<OneD,NekDouble> BndRhs(GloBndDofs,0.0);
2050 
2051  // Zero \Lambda
2052  Vmath::Zero(GloBndDofs,BndSol,1);
2053 
2054  // Retrieve number of local trace space coefficients N_{\lambda},
2055  // and set up local elemental trace solution \lambda^e.
2056  int LocBndCoeffs = m_traceMap->GetNumLocalBndCoeffs();
2057  Array<OneD, NekDouble> loc_lambda(LocBndCoeffs);
2058  DNekVec LocLambda(LocBndCoeffs,loc_lambda,eWrapper);
2059 
2060  //----------------------------------
2061  // Evaluate Trace Forcing vector F
2062  // Kirby et al, 2010, P23, Step 5.
2063  //----------------------------------
2064  // Loop over all expansions in the domain
2065  for(cnt = cnt1 = n = 0; n < nexp; ++n)
2066  {
2067  nbndry = (*m_exp)[m_offset_elmt_id[n]]->NumDGBndryCoeffs();
2068 
2069  e_ncoeffs = (*m_exp)[m_offset_elmt_id[n]]->GetNcoeffs();
2070  e_f = f + cnt;
2071  e_l = loc_lambda + cnt1;
2072 
2073  // Local trace space \lambda^e
2074  DNekVec Floc (nbndry, e_l, eWrapper);
2075  // Local forcing f^e
2076  DNekVec ElmtFce (e_ncoeffs, e_f, eWrapper);
2077  // Compute local (U^e)^{\top} f^e
2078  Floc = Transpose(*(HDGLamToU->GetBlock(n,n)))*ElmtFce;
2079 
2080  cnt += e_ncoeffs;
2081  cnt1 += nbndry;
2082  }
2083 
2084  // Assemble local \lambda_e into global \Lambda
2085  m_traceMap->AssembleBnd(loc_lambda,BndRhs);
2086 
2087  // Copy Dirichlet boundary conditions and weak forcing into trace
2088  // space
2089  cnt = 0;
2090  for(i = 0; i < m_bndCondExpansions.num_elements(); ++i)
2091  {
2092  if(m_bndConditions[i]->GetBoundaryConditionType() == SpatialDomains::eDirichlet)
2093  {
2094  for(j = 0; j < (m_bndCondExpansions[i])->GetNcoeffs(); ++j)
2095  {
2096  id = m_traceMap->GetBndCondCoeffsToGlobalCoeffsMap(cnt++);
2097  BndSol[id] = m_bndCondExpansions[i]->GetCoeffs()[j];
2098  }
2099  }
2100  else
2101  {
2102  //Add weak boundary condition to trace forcing
2103  for(j = 0; j < (m_bndCondExpansions[i])->GetNcoeffs(); ++j)
2104  {
2105  id = m_traceMap->GetBndCondCoeffsToGlobalCoeffsMap(cnt++);
2106  BndRhs[id] += m_bndCondExpansions[i]->GetCoeffs()[j];
2107  }
2108  }
2109  }
2110 
2111  //----------------------------------
2112  // Solve trace problem: \Lambda = K^{-1} F
2113  // K is the HybridDGHelmBndLam matrix.
2114  //----------------------------------
2115  if(GloBndDofs - NumDirichlet > 0)
2116  {
2118  m_traceMap,factors,varcoeff);
2120  LinSys->Solve(BndRhs,BndSol,m_traceMap);
2121  }
2122 
2123  //----------------------------------
2124  // Internal element solves
2125  //----------------------------------
2127  const DNekScalBlkMatSharedPtr& InvHDGHelm = GetBlockMatrix(invHDGhelmkey);
2128  DNekVec out(m_ncoeffs,outarray,eWrapper);
2129  Vmath::Zero(m_ncoeffs,outarray,1);
2130 
2131  // get local trace solution from BndSol
2132  m_traceMap->GlobalToLocalBnd(BndSol,loc_lambda);
2133 
2134  // out = u_f + u_lam = (*InvHDGHelm)*f + (LamtoU)*Lam
2135  out = (*InvHDGHelm)*F + (*HDGLamToU)*LocLambda;
2136  }
2137 
2138  /**
2139  * @brief Calculates the result of the multiplication of a global matrix
2140  * of type specified by @a mkey with a vector given by @a inarray.
2141  *
2142  * @param mkey Key representing desired matrix multiplication.
2143  * @param inarray Input vector.
2144  * @param outarray Resulting multiplication.
2145  */
2147  const GlobalMatrixKey &gkey,
2148  const Array<OneD,const NekDouble> &inarray,
2149  Array<OneD, NekDouble> &outarray,
2150  CoeffState coeffstate)
2151  {
2152  int LocBndCoeffs = m_traceMap->GetNumLocalBndCoeffs();
2153  Array<OneD, NekDouble> loc_lambda(LocBndCoeffs);
2154  DNekVec LocLambda(LocBndCoeffs,loc_lambda,eWrapper);
2155  const DNekScalBlkMatSharedPtr& HDGHelm = GetBlockMatrix(gkey);
2156 
2157  m_traceMap->GlobalToLocalBnd(inarray, loc_lambda);
2158  LocLambda = (*HDGHelm) * LocLambda;
2159  m_traceMap->AssembleBnd(loc_lambda,outarray);
2160  }
2161 
2162  /**
2163  * Search through the edge expansions and identify which ones have
2164  * Robin/Mixed type boundary conditions. If find a Robin boundary then
2165  * store the edge id of the boundary condition and the array of points
2166  * of the physical space boundary condition which are hold the boundary
2167  * condition primitive variable coefficient at the quatrature points
2168  *
2169  * \return std map containing the robin boundary condition
2170  * info using a key of the element id
2171  *
2172  * There is a next member to allow for more than one Robin
2173  * boundary condition per element
2174  */
2175  map<int, RobinBCInfoSharedPtr> DisContField3D::v_GetRobinBCInfo(void)
2176  {
2177  int i,cnt;
2178  map<int, RobinBCInfoSharedPtr> returnval;
2179  Array<OneD, int> ElmtID,FaceID;
2180  GetBoundaryToElmtMap(ElmtID,FaceID);
2181 
2182  for(cnt = i = 0; i < m_bndCondExpansions.num_elements(); ++i)
2183  {
2184  MultiRegions::ExpListSharedPtr locExpList;
2185 
2186  if(m_bndConditions[i]->GetBoundaryConditionType() == SpatialDomains::eRobin)
2187  {
2188  int e,elmtid;
2189  Array<OneD, NekDouble> Array_tmp;
2190 
2191  locExpList = m_bndCondExpansions[i];
2192 
2193  for(e = 0; e < locExpList->GetExpSize(); ++e)
2194  {
2195  RobinBCInfoSharedPtr rInfo = MemoryManager<RobinBCInfo>::AllocateSharedPtr(FaceID[cnt+e],Array_tmp = locExpList->GetPhys() + locExpList->GetPhys_Offset(e));
2196  elmtid = ElmtID[cnt+e];
2197  // make link list if necessary
2198  if(returnval.count(elmtid) != 0)
2199  {
2200  rInfo->next = returnval.find(elmtid)->second;
2201  }
2202  returnval[elmtid] = rInfo;
2203  }
2204  }
2205  cnt += m_bndCondExpansions[i]->GetExpSize();
2206  }
2207 
2208  return returnval;
2209  }
2210 
2211  /**
2212  * @brief Evaluate HDG post-processing to increase polynomial order of
2213  * solution.
2214  *
2215  * This function takes the solution (assumed to be one order lower) in
2216  * physical space, and postprocesses at the current polynomial order by
2217  * solving the system:
2218  *
2219  * \f[
2220  * \begin{aligned}
2221  * (\nabla w, \nabla u^*) &= (\nabla w, u), \\
2222  * \langle \nabla u^*, 1 \rangle &= \langle \nabla u, 1 \rangle
2223  * \end{aligned}
2224  * \f]
2225  *
2226  * where \f$ u \f$ corresponds with the current solution as stored
2227  * inside #m_coeffs.
2228  *
2229  * @param outarray The resulting field \f$ u^* \f$.
2230  */
2232  Array<OneD, NekDouble> &outarray)
2233  {
2234  int i,cnt,f,ncoeff_face;
2235  Array<OneD, NekDouble> force, out_tmp,qrhs,qrhs1;
2237  &elmtToTrace = m_traceMap->GetElmtToTrace();
2238 
2239  int eid,nq_elmt, nm_elmt;
2240  int LocBndCoeffs = m_traceMap->GetNumLocalBndCoeffs();
2241  Array<OneD, NekDouble> loc_lambda(LocBndCoeffs), face_lambda;
2242  Array<OneD, NekDouble> tmp_coeffs;
2243  m_traceMap->GlobalToLocalBnd(m_trace->GetCoeffs(),loc_lambda);
2244 
2245  face_lambda = loc_lambda;
2246 
2247  // Calculate Q using standard DG formulation.
2248  for(i = cnt = 0; i < GetExpSize(); ++i)
2249  {
2251  (*m_exp)[i]->as<LocalRegions::Expansion3D>();
2252 
2253  eid = m_offset_elmt_id[i];
2254  nq_elmt = (*m_exp)[eid]->GetTotPoints();
2255  nm_elmt = (*m_exp)[eid]->GetNcoeffs();
2256  qrhs = Array<OneD, NekDouble>(nq_elmt);
2257  qrhs1 = Array<OneD, NekDouble>(nq_elmt);
2258  force = Array<OneD, NekDouble>(2*nm_elmt);
2259  out_tmp = force + nm_elmt;
2261 
2262  int num_points0 = (*m_exp)[eid]->GetBasis(0)->GetNumPoints();
2263  int num_points1 = (*m_exp)[eid]->GetBasis(1)->GetNumPoints();
2264  int num_points2 = (*m_exp)[eid]->GetBasis(2)->GetNumPoints();
2265  int num_modes0 = (*m_exp)[eid]->GetBasis(0)->GetNumModes();
2266  int num_modes1 = (*m_exp)[eid]->GetBasis(1)->GetNumModes();
2267  int num_modes2 = (*m_exp)[eid]->GetBasis(2)->GetNumModes();
2268 
2269  // Probably a better way of setting up lambda than this. Note
2270  // cannot use PutCoeffsInToElmts since lambda space is mapped
2271  // during the solve.
2272  int nFaces = (*m_exp)[eid]->GetNfaces();
2273  Array<OneD, Array<OneD, NekDouble> > faceCoeffs(nFaces);
2274  for(f = 0; f < nFaces; ++f)
2275  {
2276  ncoeff_face = elmtToTrace[eid][f]->GetNcoeffs();
2277  faceCoeffs[f] = Array<OneD, NekDouble>(ncoeff_face);
2278  Vmath::Vcopy(ncoeff_face, face_lambda, 1, faceCoeffs[f], 1);
2279  exp->SetFaceToGeomOrientation(f, faceCoeffs[f]);
2280  face_lambda = face_lambda + ncoeff_face;
2281  }
2282 
2283  //creating orthogonal expansion (checking if we have quads or triangles)
2284  LibUtilities::ShapeType shape = (*m_exp)[eid]->DetShapeType();
2285  switch(shape)
2286  {
2288  {
2292  LibUtilities::BasisKey BkeyH1(LibUtilities::eOrtho_A, num_modes0, PkeyH1);
2293  LibUtilities::BasisKey BkeyH2(LibUtilities::eOrtho_A, num_modes1, PkeyH2);
2294  LibUtilities::BasisKey BkeyH3(LibUtilities::eOrtho_A, num_modes2, PkeyH3);
2295  SpatialDomains::HexGeomSharedPtr hGeom = boost::dynamic_pointer_cast<SpatialDomains::HexGeom>((*m_exp)[eid]->GetGeom());
2296  ppExp = MemoryManager<LocalRegions::HexExp>::AllocateSharedPtr(BkeyH1, BkeyH2, BkeyH3, hGeom);
2297  }
2298  break;
2300  {
2304  LibUtilities::BasisKey BkeyT1(LibUtilities::eOrtho_A, num_modes0, PkeyT1);
2305  LibUtilities::BasisKey BkeyT2(LibUtilities::eOrtho_B, num_modes1, PkeyT2);
2306  LibUtilities::BasisKey BkeyT3(LibUtilities::eOrtho_C, num_modes2, PkeyT3);
2307  SpatialDomains::TetGeomSharedPtr tGeom = boost::dynamic_pointer_cast<SpatialDomains::TetGeom>((*m_exp)[eid]->GetGeom());
2308  ppExp = MemoryManager<LocalRegions::TetExp>::AllocateSharedPtr(BkeyT1, BkeyT2, BkeyT3, tGeom);
2309  }
2310  break;
2311  case LibUtilities::ePrism:
2312  {
2316  LibUtilities::BasisKey BkeyP1(LibUtilities::eOrtho_A, num_modes0, PkeyP1);
2317  LibUtilities::BasisKey BkeyP2(LibUtilities::eOrtho_A, num_modes1, PkeyP2);
2318  LibUtilities::BasisKey BkeyP3(LibUtilities::eOrtho_B, num_modes2, PkeyP3);
2319  SpatialDomains::PrismGeomSharedPtr pGeom = boost::dynamic_pointer_cast<SpatialDomains::PrismGeom>((*m_exp)[eid]->GetGeom());
2320  ppExp = MemoryManager<LocalRegions::PrismExp>::AllocateSharedPtr(BkeyP1, BkeyP2, BkeyP3, pGeom);
2321  }
2322  break;
2323  default:
2324  ASSERTL0(false, "Wrong shape type, HDG postprocessing is not implemented");
2325  };
2326 
2327 
2328  //DGDeriv
2329  // (d/dx w, q_0)
2330  (*m_exp)[eid]->DGDeriv(
2331  0,tmp_coeffs = m_coeffs + m_coeff_offset[eid],
2332  elmtToTrace[eid], faceCoeffs, out_tmp);
2333  (*m_exp)[eid]->BwdTrans(out_tmp,qrhs);
2334  ppExp->IProductWRTDerivBase(0,qrhs,force);
2335 
2336 
2337  // + (d/dy w, q_1)
2338  (*m_exp)[eid]->DGDeriv(
2339  1,tmp_coeffs = m_coeffs + m_coeff_offset[eid],
2340  elmtToTrace[eid], faceCoeffs, out_tmp);
2341  (*m_exp)[eid]->BwdTrans(out_tmp,qrhs);
2342  ppExp->IProductWRTDerivBase(1,qrhs,out_tmp);
2343 
2344  Vmath::Vadd(nm_elmt,force,1,out_tmp,1,force,1);
2345 
2346  // + (d/dz w, q_2)
2347  (*m_exp)[eid]->DGDeriv(
2348  2,tmp_coeffs = m_coeffs + m_coeff_offset[eid],
2349  elmtToTrace[eid], faceCoeffs, out_tmp);
2350  (*m_exp)[eid]->BwdTrans(out_tmp,qrhs);
2351  ppExp->IProductWRTDerivBase(2,qrhs,out_tmp);
2352 
2353  Vmath::Vadd(nm_elmt,force,1,out_tmp,1,force,1);
2354  // determine force[0] = (1,u)
2355  (*m_exp)[eid]->BwdTrans(
2356  tmp_coeffs = m_coeffs + m_coeff_offset[eid],qrhs);
2357  force[0] = (*m_exp)[eid]->Integral(qrhs);
2358 
2359  // multiply by inverse Laplacian matrix
2360  // get matrix inverse
2361  LocalRegions::MatrixKey lapkey(StdRegions::eInvLaplacianWithUnityMean, ppExp->DetShapeType(), *ppExp);
2362  DNekScalMatSharedPtr lapsys = ppExp->GetLocMatrix(lapkey);
2363 
2364  NekVector<NekDouble> in (nm_elmt, force, eWrapper);
2365  NekVector<NekDouble> out(nm_elmt);
2366 
2367  out = (*lapsys)*in;
2368 
2369  // Transforming back to modified basis
2370  Array<OneD, NekDouble> work(nq_elmt);
2371  ppExp->BwdTrans(out.GetPtr(), work);
2372  (*m_exp)[eid]->FwdTrans(work,
2373  tmp_coeffs = outarray + m_coeff_offset[eid]);
2374  }
2375  }
2376 
2377  /**
2378  * \brief This function evaluates the boundary conditions at a certain
2379  * time-level.
2380  *
2381  * Based on the boundary condition \f$g(\boldsymbol{x},t)\f$ evaluated
2382  * at a given time-level \a t, this function transforms the boundary
2383  * conditions onto the coefficients of the (one-dimensional) boundary
2384  * expansion. Depending on the type of boundary conditions, these
2385  * expansion coefficients are calculated in different ways:
2386  * - <b>Dirichlet boundary conditions</b><BR>
2387  * In order to ensure global \f$C^0\f$ continuity of the spectral/hp
2388  * approximation, the Dirichlet boundary conditions are projected onto
2389  * the boundary expansion by means of a modified \f$C^0\f$ continuous
2390  * Galerkin projection. This projection can be viewed as a collocation
2391  * projection at the vertices, followed by an \f$L^2\f$ projection on
2392  * the interior modes of the edges. The resulting coefficients
2393  * \f$\boldsymbol{\hat{u}}^{\mathcal{D}}\f$ will be stored for the
2394  * boundary expansion.
2395  * - <b>Neumann boundary conditions</b>
2396  * In the discrete Galerkin formulation of the problem to be solved,
2397  * the Neumann boundary conditions appear as the set of surface
2398  * integrals: \f[\boldsymbol{\hat{g}}=\int_{\Gamma}
2399  * \phi^e_n(\boldsymbol{x})g(\boldsymbol{x})d(\boldsymbol{x})\quad
2400  * \forall n \f]
2401  * As a result, it are the coefficients \f$\boldsymbol{\hat{g}}\f$
2402  * that will be stored in the boundary expansion
2403  *
2404  * @param time The time at which the boundary conditions
2405  * should be evaluated.
2406  * @param bndCondExpansions List of boundary conditions.
2407  * @param bndConditions Information about the boundary conditions.
2408  */
2410  const NekDouble time,
2411  const std::string varName,
2412  const NekDouble x2_in,
2413  const NekDouble x3_in)
2414  {
2415  int i;
2416  int npoints;
2417  int nbnd = m_bndCondExpansions.num_elements();
2418  MultiRegions::ExpListSharedPtr locExpList;
2419 
2420  for (i = 0; i < nbnd; ++i)
2421  {
2422  if (time == 0.0 || m_bndConditions[i]->IsTimeDependent())
2423  {
2424  locExpList = m_bndCondExpansions[i];
2425  npoints = locExpList->GetNpoints();
2426 
2427  Array<OneD, NekDouble> x0(npoints, 0.0);
2428  Array<OneD, NekDouble> x1(npoints, 0.0);
2429  Array<OneD, NekDouble> x2(npoints, 0.0);
2430  Array<OneD, NekDouble> valuesFile(npoints, 1.0), valuesExp(npoints, 1.0);
2431 
2432  locExpList->GetCoords(x0, x1, x2);
2433 
2434  if (m_bndConditions[i]->GetBoundaryConditionType()
2436  {
2437  string filebcs = boost::static_pointer_cast<
2439  m_bndConditions[i])->m_filename;
2440 
2441  string exprbcs = boost::static_pointer_cast<
2443  m_bndConditions[i])->m_expr;
2444 
2445  if (filebcs != "")
2446  {
2447  ExtractFileBCs(filebcs, varName, locExpList);
2448  valuesFile = locExpList->GetPhys();
2449  }
2450 
2451  if (exprbcs != "")
2452  {
2453  LibUtilities::Equation condition = boost::static_pointer_cast<SpatialDomains::
2455  m_bndConditions[i])->m_dirichletCondition;
2456 
2457  condition.Evaluate(x0, x1, x2, time, valuesExp);
2458  }
2459 
2460  Vmath::Vmul(npoints, valuesExp, 1, valuesFile, 1, locExpList->UpdatePhys(), 1);
2461 
2462  locExpList->FwdTrans_BndConstrained(
2463  locExpList->GetPhys(),
2464  locExpList->UpdateCoeffs());
2465  }
2466  else if (m_bndConditions[i]->GetBoundaryConditionType()
2468  {
2469  string filebcs = boost::static_pointer_cast<
2471  m_bndConditions[i])->m_filename;
2472 
2473  if (filebcs != "")
2474  {
2475  ExtractFileBCs(filebcs, varName, locExpList);
2476  }
2477  else
2478  {
2479 
2480  LibUtilities::Equation condition = boost::
2481  static_pointer_cast<SpatialDomains::
2483  m_bndConditions[i])->m_neumannCondition;
2484 
2485  condition.Evaluate(x0, x1, x2, time,
2486  locExpList->UpdatePhys());
2487 
2488  locExpList->IProductWRTBase(locExpList->GetPhys(),
2489  locExpList->UpdateCoeffs());
2490  }
2491  }
2492  else if (m_bndConditions[i]->GetBoundaryConditionType()
2494  {
2495 
2496  string filebcs = boost::static_pointer_cast<
2498  (m_bndConditions[i])->m_filename;
2499 
2500  if (filebcs != "")
2501  {
2502  ExtractFileBCs(filebcs, varName, locExpList);
2503  }
2504  else
2505  {
2506  LibUtilities::Equation condition = boost::
2507  static_pointer_cast<SpatialDomains::
2509  m_bndConditions[i])->m_robinFunction;
2510 
2511  condition.Evaluate(x0, x1, x2, time,
2512  locExpList->UpdatePhys());
2513 
2514  }
2515 
2516  LibUtilities::Equation coeff = boost::
2517  static_pointer_cast<SpatialDomains::
2519  m_bndConditions[i])->m_robinPrimitiveCoeff;
2520 
2521  locExpList->IProductWRTBase(locExpList->GetPhys(),
2522  locExpList->UpdateCoeffs());
2523 
2524  // Put primitive coefficient into the physical
2525  // space storage
2526  coeff.Evaluate(x0, x1, x2, time,
2527  locExpList->UpdatePhys());
2528 
2529  }
2530  else
2531  {
2532  ASSERTL0(false, "This type of BC not implemented yet");
2533  }
2534  }
2535  }
2536  }
2537  } // end of namespace
2538 } // end of namespace
GlobalSysSolnType GetGlobalSysSolnType() const
Return the associated solution type.
const DNekScalBlkMatSharedPtr & GetBlockMatrix(const GlobalMatrixKey &gkey)
Definition: ExpList.cpp:812
boost::shared_ptr< MeshGraph3D > MeshGraph3DSharedPtr
Definition: MeshGraph3D.h:224
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:1834
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:161
virtual void v_Reset()
Reset geometry information, metrics, matrix managers and geometry information.
Definition: ExpList.cpp:1435
GlobalLinSysSharedPtr GetGlobalBndLinSys(const GlobalLinSysKey &mkey)
boost::shared_ptr< ElementFaceVector > ElementFaceVectorSharedPtr
Definition: MeshGraph.h:138
virtual void v_ExtractTracePhys(Array< OneD, NekDouble > &outarray)
Array< OneD, MultiRegions::ExpListSharedPtr > m_bndCondExpansions
An object which contains the discretised boundary conditions.
int GetCoeff_Offset(int n) const
Get the start offset position for a global list of m_coeffs correspoinding to element n...
Definition: ExpList.h:1926
virtual void v_GetBndElmtExpansion(int i, boost::shared_ptr< ExpList > &result)
static ExpListSharedPtr NullExpListSharedPtr
Definition: ExpList.h:1395
void EvaluateBoundaryConditions(const NekDouble time=0.0, const std::string varName="", const NekDouble=NekConstants::kNekUnsetDouble, const NekDouble=NekConstants::kNekUnsetDouble)
Definition: ExpList.h:2091
static boost::shared_ptr< DataType > AllocateSharedPtr()
Allocate a shared pointer from the memory pool.
std::map< int, vector< PeriodicEntity > > PeriodicMap
std::vector< PointGeomSharedPtr > PointGeomVector
Definition: Geometry3D.h:61
void SetAdjacentElementExp(int face, Expansion3DSharedPtr &f)
Definition: Expansion2D.h:249
bool isLocal
Flag specifying if this entity is local to this partition.
int GetPhys_Offset(int n) const
Get the start offset position for a global list of m_phys correspoinding to element n...
Definition: ExpList.h:1934
bool IsLeftAdjacentFace(const int n, const int e)
const BoundaryConditionCollection & GetBoundaryConditions(void) const
Definition: Conditions.h:237
void ExtractFileBCs(const std::string &fileName, const std::string &varName, const boost::shared_ptr< ExpList > locExpList)
Definition: ExpList.cpp:1909
boost::shared_ptr< RobinBCInfo > RobinBCInfoSharedPtr
SpatialDomains::Geometry3DSharedPtr GetGeom3D() const
Definition: Expansion3D.h:180
const boost::shared_ptr< LocalRegions::ExpansionVector > GetExp() const
This function returns the vector of elements in the expansion.
Definition: ExpList.h:1917
std::set< int > m_boundaryFaces
A set storing the global IDs of any boundary faces.
PeriodicMap m_periodicFaces
A map which identifies pairs of periodic faces.
virtual void v_GetFwdBwdTracePhys(Array< OneD, NekDouble > &Fwd, Array< OneD, NekDouble > &Bwd)
This method extracts the "forward" and "backward" trace data from the array field and puts the data i...
std::map< int, std::vector< unsigned int > > BndRegionOrdering
Definition: MeshPartition.h:54
std::map< ConstFactorType, NekDouble > ConstFactorMap
Definition: StdRegions.hpp:251
void GetBoundaryToElmtMap(Array< OneD, int > &ElmtID, Array< OneD, int > &EdgeID)
Definition: ExpList.h:2144
Array< OneD, NekDouble > m_phys
The global expansion evaluated at the quadrature points.
Definition: ExpList.h:956
void EvaluateHDGPostProcessing(Array< OneD, NekDouble > &outarray)
Evaluate HDG post-processing to increase polynomial order of solution.
std::map< int, std::vector< unsigned int > > CompositeOrdering
Definition: MeshPartition.h:53
virtual void v_AddFwdBwdTraceIntegral(const Array< OneD, const NekDouble > &Fwd, const Array< OneD, const NekDouble > &Bwd, Array< OneD, NekDouble > &outarray)
Add trace contributions into elemental coefficient spaces.
void ApplyGeomInfo()
Apply geometry information to each expansion.
Definition: ExpList.cpp:1422
boost::shared_ptr< HexGeom > HexGeomSharedPtr
Definition: HexGeom.h:110
Array< OneD, NekDouble > m_coeffs
Concatenation of all local expansion coefficients.
Definition: ExpList.h:939
int GetExpSize(void)
This function returns the number of elements in the expansion.
Definition: ExpList.h:1896
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)
This function evaluates the boundary conditions at a certain time-level.
boost::shared_ptr< SessionReader > SessionReaderSharedPtr
Definition: MeshPartition.h:51
boost::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:1192
boost::shared_ptr< DNekScalMat > DNekScalMatSharedPtr
Gauss Radau pinned at x=-1, .
Definition: PointsType.h:57
Principle Orthogonal Functions .
Definition: BasisType.h:47
void FindPeriodicFaces(const SpatialDomains::BoundaryConditions &bcs, const std::string &variable)
Determine the periodic faces, edges and vertices for the given graph.
Array< OneD, int > m_coeff_offset
Offset of elemental data into the array m_coeffs.
Definition: ExpList.h:988
virtual map< int, RobinBCInfoSharedPtr > v_GetRobinBCInfo()
boost::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition: Comm.h:53
static StdRegions::Orientation GetFaceOrientation(const QuadGeom &face1, const QuadGeom &face2)
Get the orientation of face1.
Definition: QuadGeom.cpp:253
The base class for all shapes.
Definition: StdExpansion.h:69
boost::shared_ptr< LocalRegions::ExpansionVector > m_exp
The list of local expansions.
Definition: ExpList.h:977
DisContField3D()
Default constructor.
virtual const vector< bool > & v_GetLeftAdjacentFaces(void) const
std::map< StdRegions::VarCoeffType, Array< OneD, NekDouble > > VarCoeffMap
Definition: StdRegions.hpp:226
boost::shared_ptr< Expansion3D > Expansion3DSharedPtr
Definition: Expansion2D.h:48
LocTraceToTraceMapSharedPtr m_locTraceToTraceMap
Map of local trace (the points at the face of the element) to the trace space discretisation.
int id
Geometry ID of entity.
bool m_physState
The state of the array m_phys.
Definition: ExpList.h:965
NekDouble Evaluate() const
Definition: Equation.h:102
int m_ncoeffs
The total number of local degrees of freedom. m_ncoeffs .
Definition: ExpList.h:917
Array< OneD, int > m_offset_elmt_id
Array containing the element id m_offset_elmt_id[n] that the n^th consecutive block of data in m_coef...
Definition: ExpList.h:999
std::map< int, BoundaryRegionShPtr > BoundaryRegionCollection
Definition: Conditions.h:206
boost::shared_ptr< DNekScalBlkMat > DNekScalBlkMatSharedPtr
Definition: NekTypeDefs.hpp:74
boost::shared_ptr< ExpList > ExpListSharedPtr
Shared pointer to an ExpList object.
static std::string npts
Definition: InputFld.cpp:43
Principle Orthogonal Functions .
Definition: BasisType.h:48
Principle Orthogonal Functions .
Definition: BasisType.h:46
NekMatrix< InnerMatrixType, BlockMatrixTag > Transpose(NekMatrix< InnerMatrixType, BlockMatrixTag > &rhs)
SpatialDomains::MeshGraphSharedPtr m_graph
Mesh associated with this expansion list.
Definition: ExpList.h:913
void GenerateBoundaryConditionExpansion(const SpatialDomains::MeshGraphSharedPtr &graph3D, const SpatialDomains::BoundaryConditions &bcs, const std::string &variable)
virtual void v_GeneralMatrixOp(const GlobalMatrixKey &gkey, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, CoeffState coeffstate=eLocal)
Calculates the result of the multiplication of a global matrix of type specified by mkey with a vecto...
LibUtilities::SessionReaderSharedPtr m_session
Session.
Definition: ExpList.h:910
Defines a specification for a set of points.
Definition: Points.h:58
void Neg(int n, T *x, const int incx)
Negate x = -x.
Definition: Vmath.cpp:382
double NekDouble
void SetUpDG(const std::string="DefaultVar")
Set up all DG member variables and maps.
boost::shared_ptr< Expansion > ExpansionSharedPtr
Definition: Expansion.h:68
bool SameTypeOfBoundaryConditions(const DisContField3D &In)
Defines a list of flags.
std::map< int, BoundaryConditionMapShPtr > BoundaryConditionCollection
Definition: Conditions.h:215
boost::shared_ptr< ExpList2D > ExpList2DSharedPtr
Shared pointer to an ExpList2D object.
Definition: ExpList2D.h:49
boost::shared_ptr< GeometryVector > Composite
Definition: MeshGraph.h:114
Describe a linear system.
std::map< int, Composite > CompositeMap
Definition: MeshGraph.h:115
StdRegions::Orientation orient
Orientation of entity within higher dimensional entity.
StdRegions::MatrixType GetMatrixType() const
Return the matrix type.
Describes a matrix with ordering defined by a local to global map.
const Array< OneD, const NekDouble > & GetPhys() const
This function returns (a reference to) the array (implemented as m_phys) containing the function ev...
Definition: ExpList.h:1887
boost::shared_ptr< Geometry2D > Geometry2DSharedPtr
Definition: Geometry2D.h:59
StandardMatrixTag boost::call_traits< LhsDataType >::const_reference rhs typedef NekMatrix< LhsDataType, StandardMatrixTag >::iterator iterator
LibUtilities::CommSharedPtr m_comm
Communicator.
Definition: ExpList.h:907
static AssemblyMapSharedPtr NullAssemblyMapSharedPtr
Definition: AssemblyMap.h:55
PeriodicMap m_periodicVerts
A map which identifies groups of periodic vertices.
2D geometry information
Definition: Geometry2D.h:65
virtual void v_HelmSolve(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const FlagList &flags, const StdRegions::ConstFactorMap &factors, const StdRegions::VarCoeffMap &varcoeff, const Array< OneD, const NekDouble > &dirForcing)
virtual void v_GetBoundaryToElmtMap(Array< OneD, int > &ElmtID, Array< OneD, int > &FaceID)
Set up a list of elemeent IDs and edge IDs that link to the boundary conditions.
#define ASSERTL2(condition, msg)
Assert Level 2 – Debugging which is used FULLDEBUG compilation mode. This level assert is designed t...
Definition: ErrorUtil.hpp:213
virtual void v_Reset()
Reset this field, so that geometry information can be updated.
void IProductWRTBase(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, CoeffState coeffstate=eLocal)
Definition: ExpList.h:1559
boost::shared_ptr< PrismGeom > PrismGeomSharedPtr
Definition: PrismGeom.h:109
vector< int > m_periodicFwdCopy
A vector indicating degress of freedom which need to be copied from forwards to backwards space in ca...
Gauss Radau pinned at x=-1, .
Definition: PointsType.h:58
Array< OneD, SpatialDomains::BoundaryConditionShPtr > m_bndConditions
An array which contains the information about the boundary condition on the different boundary region...
int GetNcoeffs(void) const
Returns the total number of local degrees of freedom .
Definition: ExpList.h:1403
boost::shared_ptr< TetGeom > TetGeomSharedPtr
Definition: TetGeom.h:106
Abstraction of a three-dimensional multi-elemental expansion which is merely a collection of local ex...
Definition: ExpList3D.h:49
static SpatialDomains::BoundaryConditionShPtr GetBoundaryCondition(const SpatialDomains::BoundaryConditionCollection &collection, unsigned int index, const std::string &variable)
Definition: ExpList.cpp:2858
boost::shared_ptr< GlobalLinSys > GlobalLinSysSharedPtr
Pointer to a GlobalLinSys object.
Definition: GlobalLinSys.h:52
static StdRegions::Orientation GetFaceOrientation(const TriGeom &face1, const TriGeom &face2)
Definition: TriGeom.cpp:236
const BoundaryRegionCollection & GetBoundaryRegions(void) const
Definition: Conditions.h:227
boost::shared_ptr< BoundaryConditionBase > BoundaryConditionShPtr
Definition: Conditions.h:208
T Vsum(int n, const T *x, const int incx)
Subtract return sum(x)
Definition: Vmath.cpp:723
void Zero(int n, T *x, const int incx)
Zero vector.
Definition: Vmath.cpp:359
boost::shared_ptr< StdExpansion > StdExpansionSharedPtr
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode...
Definition: ErrorUtil.hpp:191
boost::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition: MeshGraph.h:442
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.cpp:1047
Describes the specification for a Basis.
Definition: Basis.h:50
Array< OneD, DataType > & GetPtr()
Definition: NekVector.cpp:230
1D Gauss-Lobatto-Legendre quadrature points
Definition: PointsType.h:50
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:285
virtual void v_AddTraceIntegral(const Array< OneD, const NekDouble > &Fn, Array< OneD, NekDouble > &outarray)
Add trace contributions into elemental coefficient spaces.
void Vmul(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Multiply vector z = x*y.
Definition: Vmath.cpp:169
PeriodicMap m_periodicEdges
A map which identifies groups of periodic edges.
boost::shared_ptr< Expansion2D > Expansion2DSharedPtr
Definition: Expansion1D.h:49