Nektar++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
DisContField2D.cpp
Go to the documentation of this file.
1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // File DisContField2D.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 2D domain with boundary conditions using
33 // LDG flux.
34 //
35 ///////////////////////////////////////////////////////////////////////////////
36 
38 #include <LocalRegions/MatrixKey.h>
40 #include <LocalRegions/Expansion.h>
41 #include <LocalRegions/QuadExp.h>
42 #include <LocalRegions/TriExp.h>
46 
47 
48 namespace Nektar
49 {
50  namespace MultiRegions
51  {
52  /**
53  * @class DisContField2D
54  * Abstraction of a global discontinuous two-dimensional spectral/hp
55  * element expansion which approximates the solution of a set of
56  * partial differential equations.
57  */
58 
59  /**
60  * @brief Default constructor.
61  */
63  : ExpList2D (),
64  m_bndCondExpansions(),
65  m_bndConditions (),
66  m_trace (NullExpListSharedPtr)
67  {
68  }
69 
71  const DisContField2D &In,
72  const bool DeclareCoeffPhysArrays)
73  : ExpList2D (In,DeclareCoeffPhysArrays),
74  m_bndCondExpansions (In.m_bndCondExpansions),
75  m_bndConditions (In.m_bndConditions),
76  m_globalBndMat (In.m_globalBndMat),
77  m_traceMap (In.m_traceMap),
78  m_locTraceToTraceMap (In.m_locTraceToTraceMap),
79  m_boundaryEdges (In.m_boundaryEdges),
80  m_periodicVerts (In.m_periodicVerts),
81  m_periodicEdges (In.m_periodicEdges),
82  m_periodicFwdCopy (In.m_periodicFwdCopy),
83  m_periodicBwdCopy (In.m_periodicBwdCopy),
84  m_leftAdjacentEdges (In.m_leftAdjacentEdges)
85  {
86  if (In.m_trace)
87  {
89  *boost::dynamic_pointer_cast<ExpList1D>(In.m_trace),
90  DeclareCoeffPhysArrays);
91  }
92  }
93 
94  /**
95  * @brief Constructs a global discontinuous field based on an input
96  * mesh with boundary conditions.
97  */
100  const SpatialDomains::MeshGraphSharedPtr &graph2D,
101  const std::string &variable,
102  const bool SetUpJustDG,
103  const bool DeclareCoeffPhysArrays)
104  : ExpList2D(pSession, graph2D, DeclareCoeffPhysArrays, variable),
105  m_bndCondExpansions(),
106  m_bndConditions(),
107  m_trace(NullExpListSharedPtr),
108  m_periodicVerts(),
109  m_periodicEdges(),
110  m_periodicFwdCopy(),
111  m_periodicBwdCopy()
112  {
113 
114  if (variable.compare("DefaultVar") != 0) // do not set up BCs if default variable
115  {
117  GenerateBoundaryConditionExpansion(graph2D, bcs, variable,
118  DeclareCoeffPhysArrays);
119 
120  if (DeclareCoeffPhysArrays)
121  {
122  EvaluateBoundaryConditions(0.0, variable);
123  }
124 
125  // Find periodic edges for this variable.
126  FindPeriodicEdges(bcs, variable);
127  }
128 
129  if (SetUpJustDG)
130  {
131  SetUpDG(variable);
132  }
133  else
134  {
135  // Set element edges to point to Robin BC edges if required.
136  int i, cnt;
137  Array<OneD, int> ElmtID, EdgeID;
138  GetBoundaryToElmtMap(ElmtID, EdgeID);
139 
140  for(cnt = i = 0; i < m_bndCondExpansions.num_elements(); ++i)
141  {
143  int e;
144  locExpList = m_bndCondExpansions[i];
145 
146  for(e = 0; e < locExpList->GetExpSize(); ++e)
147  {
149  (*m_exp)[ElmtID[cnt+e]]->
150  as<LocalRegions::Expansion2D>();
152  locExpList->GetExp(e)->
153  as<LocalRegions::Expansion1D>();
155  locExpList->GetExp(e)->
156  as<LocalRegions::Expansion> ();
157 
158  exp2d->SetEdgeExp(EdgeID[cnt+e], exp1d);
159  exp1d->SetAdjacentElementExp(EdgeID[cnt+e], exp2d);
160  }
161  cnt += m_bndCondExpansions[i]->GetExpSize();
162  }
163 
164  if(m_session->DefinesSolverInfo("PROJECTION"))
165  {
166  std::string ProjectStr =
167  m_session->GetSolverInfo("PROJECTION");
168  if((ProjectStr == "MixedCGDG") ||
169  (ProjectStr == "Mixed_CG_Discontinuous"))
170  {
171  SetUpDG();
172  }
173  else
174  {
176  }
177  }
178  else
179  {
181  }
182  }
183  }
184 
185 
186  /*
187  * @brief Copy type constructor which declares new boundary conditions
188  * and re-uses mapping info and trace space if possible
189  */
191  const DisContField2D &In,
192  const SpatialDomains::MeshGraphSharedPtr &graph2D,
193  const std::string &variable,
194  const bool SetUpJustDG,
195  const bool DeclareCoeffPhysArrays)
196  : ExpList2D(In,DeclareCoeffPhysArrays),
197  m_trace(NullExpListSharedPtr)
198  {
199  // Set up boundary conditions for this variable.
200  // Do not set up BCs if default variable
201  if(variable.compare("DefaultVar") != 0)
202  {
204  GenerateBoundaryConditionExpansion(graph2D, bcs, variable);
205 
206  if (DeclareCoeffPhysArrays)
207  {
208  EvaluateBoundaryConditions(0.0, variable);
209  }
210 
212  {
213  // Find periodic edges for this variable.
214  FindPeriodicEdges(bcs, variable);
215 
216  if(SetUpJustDG)
217  {
218  SetUpDG();
219  }
220  else
221  {
222  // set elmt edges to point to robin bc edges if required
223  int i, cnt = 0;
224  Array<OneD, int> ElmtID,EdgeID;
225  GetBoundaryToElmtMap(ElmtID,EdgeID);
226 
227  for (i = 0; i < m_bndCondExpansions.num_elements(); ++i)
228  {
230 
231  int e;
232  locExpList = m_bndCondExpansions[i];
233 
234  for(e = 0; e < locExpList->GetExpSize(); ++e)
235  {
237  = (*m_exp)[ElmtID[cnt+e]]->
238  as<LocalRegions::Expansion2D>();
240  = locExpList->GetExp(e)->
241  as<LocalRegions::Expansion1D>();
243  = locExpList->GetExp(e)->
244  as<LocalRegions::Expansion> ();
245 
246  exp2d->SetEdgeExp(EdgeID[cnt+e], exp1d);
247  exp1d->SetAdjacentElementExp(EdgeID[cnt+e],
248  exp2d);
249  }
250 
251  cnt += m_bndCondExpansions[i]->GetExpSize();
252  }
253 
254 
255  if (m_session->DefinesSolverInfo("PROJECTION"))
256  {
257  std::string ProjectStr =
258  m_session->GetSolverInfo("PROJECTION");
259 
260  if ((ProjectStr == "MixedCGDG") ||
261  (ProjectStr == "Mixed_CG_Discontinuous"))
262  {
263  SetUpDG();
264  }
265  else
266  {
268  }
269  }
270  else
271  {
273  }
274  }
275  }
276  else
277  {
278  if (SetUpJustDG)
279  {
281  m_trace = In.m_trace;
282  m_traceMap = In.m_traceMap;
290  }
291  else
292  {
294  m_trace = In.m_trace;
295  m_traceMap = In.m_traceMap;
303 
304  // set elmt edges to point to robin bc edges if required
305  int i, cnt = 0;
306  Array<OneD, int> ElmtID, EdgeID;
307  GetBoundaryToElmtMap(ElmtID, EdgeID);
308 
309  for (i = 0; i < m_bndCondExpansions.num_elements(); ++i)
310  {
312 
313  int e;
314  locExpList = m_bndCondExpansions[i];
315 
316  for (e = 0; e < locExpList->GetExpSize(); ++e)
317  {
319  = (*m_exp)[ElmtID[cnt+e]]->
320  as<LocalRegions::Expansion2D>();
322  = locExpList->GetExp(e)->
323  as<LocalRegions::Expansion1D>();
325  = locExpList->GetExp(e)->
326  as<LocalRegions::Expansion> ();
327 
328  exp2d->SetEdgeExp(EdgeID[cnt+e], exp1d);
329  exp1d->SetAdjacentElementExp(EdgeID[cnt+e],
330  exp2d);
331  }
332  cnt += m_bndCondExpansions[i]->GetExpSize();
333  }
334 
336  }
337  }
338  }
339  }
340 
341  /**
342  * @brief Default destructor.
343  */
345  {
346  }
347 
349  const GlobalLinSysKey &mkey)
350  {
352  "Routine currently only tested for HybridDGHelmholtz");
353  ASSERTL1(mkey.GetGlobalSysSolnType() ==
354  m_traceMap->GetGlobalSysSolnType(),
355  "The local to global map is not set up for the requested "
356  "solution type");
357 
358  GlobalLinSysSharedPtr glo_matrix;
359  GlobalLinSysMap::iterator matrixIter = m_globalBndMat->find(mkey);
360 
361  if(matrixIter == m_globalBndMat->end())
362  {
363  glo_matrix = GenGlobalBndLinSys(mkey,m_traceMap);
364  (*m_globalBndMat)[mkey] = glo_matrix;
365  }
366  else
367  {
368  glo_matrix = matrixIter->second;
369  }
370 
371  return glo_matrix;
372  }
373 
374  /**
375  * @brief Set up all DG member variables and maps.
376  */
377  void DisContField2D::SetUpDG(const std::string variable)
378  {
379  // Check for multiple calls
381  {
382  return;
383  }
384 
385  ExpList1DSharedPtr trace;
387  boost::dynamic_pointer_cast<SpatialDomains::MeshGraph2D>(
388  m_graph);
389 
390  // Set up matrix map
393 
394  // Set up trace space
397  graph2D, m_periodicEdges);
398 
399  m_trace = boost::dynamic_pointer_cast<ExpList>(trace);
401  AllocateSharedPtr(m_session, graph2D, trace, *this,
404  variable);
405 
407  &elmtToTrace = m_traceMap->GetElmtToTrace();
408 
409  // Scatter trace segments to 2D elements. For each element,
410  // we find the trace segment associated to each edge. The
411  // element then retains a pointer to the trace space segments,
412  // to ensure uniqueness of normals when retrieving from two
413  //adjoining elements which do not lie in a plane.
414  for (int i = 0; i < m_exp->size(); ++i)
415  {
416  for (int j = 0; j < (*m_exp)[i]->GetNedges(); ++j)
417  {
419  (*m_exp)[i]->as<LocalRegions::Expansion2D>();
421  elmtToTrace[i][j]->as<LocalRegions::Expansion1D>();
422  LocalRegions::ExpansionSharedPtr exp = elmtToTrace[i][j];;
423  exp2d->SetEdgeExp (j, exp1d);
424  exp1d->SetAdjacentElementExp(j, exp2d);
425  }
426  }
427 
428  // Set up physical normals
430 
431  // Set up information for parallel and periodic problems.
432  for (int i = 0; i < m_trace->GetExpSize(); ++i)
433  {
435  m_trace->GetExp(i)->as<LocalRegions::Expansion1D>();
436 
437  int offset = m_trace->GetPhys_Offset(i);
438  int traceGeomId = traceEl->GetGeom1D()->GetGlobalID();
439  PeriodicMap::iterator pIt = m_periodicEdges.find(traceGeomId);
440 
441  if (pIt != m_periodicEdges.end() && !pIt->second[0].isLocal)
442  {
443  if (traceGeomId != min(pIt->second[0].id, traceGeomId))
444  {
445  traceEl->GetLeftAdjacentElementExp()->NegateEdgeNormal(
446  traceEl->GetLeftAdjacentElementEdge());
447  }
448  }
449  else if (m_traceMap->GetTraceToUniversalMapUnique(offset) < 0)
450  {
451  traceEl->GetLeftAdjacentElementExp()->NegateEdgeNormal(
452  traceEl->GetLeftAdjacentElementEdge());
453  }
454  }
455 
456  int cnt, n, e;
457 
458  // Identify boundary edges
459  for (cnt = 0, n = 0; n < m_bndCondExpansions.num_elements(); ++n)
460  {
461  if (m_bndConditions[n]->GetBoundaryConditionType() !=
463  {
464  for (e = 0; e < m_bndCondExpansions[n]->GetExpSize(); ++e)
465  {
466  m_boundaryEdges.insert(
467  m_traceMap->GetBndCondTraceToGlobalTraceMap(cnt+e));
468  }
469  }
470  cnt += m_bndCondExpansions[n]->GetExpSize();
471  }
472 
473  // Set up information for periodic boundary conditions.
474  boost::unordered_map<int,pair<int,int> > perEdgeToExpMap;
475  boost::unordered_map<int,pair<int,int> >::iterator it2;
476  for (cnt = n = 0; n < m_exp->size(); ++n)
477  {
478  for (e = 0; e < (*m_exp)[n]->GetNedges(); ++e, ++cnt)
479  {
481  (*m_exp)[n]->GetGeom()->GetEid(e));
482 
483  if (it != m_periodicEdges.end())
484  {
485  perEdgeToExpMap[it->first] = make_pair(n, e);
486  }
487  }
488  }
489 
490  // Set up left-adjacent edge list.
491  m_leftAdjacentEdges.resize(cnt);
492  cnt = 0;
493  for (int i = 0; i < m_exp->size(); ++i)
494  {
495  for (int j = 0; j < (*m_exp)[i]->GetNedges(); ++j, ++cnt)
496  {
498  }
499  }
500 
501  // Set up mapping to copy Fwd of periodic bcs to Bwd of other edge.
502  cnt = 0;
503  for (int n = 0; n < m_exp->size(); ++n)
504  {
505  for (int e = 0; e < (*m_exp)[n]->GetNedges(); ++e, ++cnt)
506  {
507  int edgeGeomId = (*m_exp)[n]->GetGeom()->GetEid(e);
508  int offset = m_trace->GetPhys_Offset(
509  elmtToTrace[n][e]->GetElmtId());
510 
511  // Check to see if this face is periodic.
512  PeriodicMap::iterator it = m_periodicEdges.find(edgeGeomId);
513 
514  if (it != m_periodicEdges.end())
515  {
516  const PeriodicEntity &ent = it->second[0];
517  it2 = perEdgeToExpMap.find(ent.id);
518 
519  if (it2 == perEdgeToExpMap.end())
520  {
521  if (m_session->GetComm()->
522  GetRowComm()->GetSize() > 1 && !ent.isLocal)
523  {
524  continue;
525  }
526  else
527  {
528  ASSERTL1(false, "Periodic edge not found!");
529  }
530  }
531 
533  "Periodic edge in non-forward space?");
534 
535  int offset2 = m_trace->GetPhys_Offset(
536  elmtToTrace[it2->second.first][it2->second.second]->
537  GetElmtId());
538 
539  // Calculate relative orientations between edges to
540  // calculate copying map.
541  int nquad = elmtToTrace[n][e]->GetNumPoints(0);
542 
543  vector<int> tmpBwd(nquad);
544  vector<int> tmpFwd(nquad);
545 
546  if (ent.orient == StdRegions::eForwards)
547  {
548  for (int i = 0; i < nquad; ++i)
549  {
550  tmpBwd[i] = offset2 + i;
551  tmpFwd[i] = offset + i;
552  }
553  }
554  else
555  {
556  for (int i = 0; i < nquad; ++i)
557  {
558  tmpBwd[i] = offset2 + i;
559  tmpFwd[i] = offset + nquad - i - 1;
560  }
561  }
562 
563  for (int i = 0; i < nquad; ++i)
564  {
565  m_periodicFwdCopy.push_back(tmpFwd[i]);
566  m_periodicBwdCopy.push_back(tmpBwd[i]);
567  }
568  }
569  }
570  }
571 
573  AllocateSharedPtr(*this, m_trace, elmtToTrace,
575  }
576 
577  /**
578  * For each boundary region, checks that the types and number of
579  * boundary expansions in that region match.
580  * @param In ContField2D to compare with.
581  * @return True if boundary conditions match.
582  */
584  const DisContField2D &In)
585  {
586  int i;
587  bool returnval = true;
588 
589  for(i = 0; i < m_bndConditions.num_elements(); ++i)
590  {
591 
592  // check to see if boundary condition type is the same
593  // and there are the same number of boundary
594  // conditions in the boundary definition.
595  if((m_bndConditions[i]->GetBoundaryConditionType()
596  != In.m_bndConditions[i]->GetBoundaryConditionType())||
598  != In.m_bndCondExpansions[i]->GetExpSize()))
599  {
600  returnval = false;
601  break;
602  }
603  }
604 
605  // Compare with all other processes. Return true only if all
606  // processes report having the same boundary conditions.
607  int vSame = (returnval?1:0);
608  m_comm->GetRowComm()->AllReduce(vSame, LibUtilities::ReduceMin);
609 
610  return (vSame == 1);
611  }
612 
613  /**
614  * \brief This function discretises the boundary conditions by setting
615  * up a list of one-dimensional boundary expansions.
616  *
617  * According to their boundary region, the separate segmental boundary
618  * expansions are bundled together in an object of the class
619  * MultiRegions#ExpList1D.
620  *
621  * \param graph2D A mesh, containing information about the domain and
622  * the spectral/hp element expansion.
623  * \param bcs An entity containing information about the
624  * boundaries and boundary conditions.
625  * \param variable An optional parameter to indicate for which variable
626  * the boundary conditions should be discretised.
627  */
629  const SpatialDomains::MeshGraphSharedPtr &graph2D,
631  const std::string &variable,
632  const bool DeclareCoeffPhysArrays)
633  {
634  int cnt = 0;
638  bcs.GetBoundaryRegions();
639  const SpatialDomains::BoundaryConditionCollection &bconditions =
640  bcs.GetBoundaryConditions();
641  SpatialDomains::BoundaryRegionCollection::const_iterator it;
642 
643  // count the number of non-periodic boundary regions
644  for (it = bregions.begin(); it != bregions.end(); ++it)
645  {
646  bc = GetBoundaryCondition(bconditions, it->first, variable);
647 
648  if (bc->GetBoundaryConditionType() != SpatialDomains::ePeriodic)
649  {
650  cnt++;
651  }
652  }
653 
656  m_bndConditions =
658 
659  cnt = 0;
660 
661  // list non-periodic boundaries
662  for (it = bregions.begin(); it != bregions.end(); ++it)
663  {
664  bc = GetBoundaryCondition(bconditions, it->first, variable);
665 
666  if (bc->GetBoundaryConditionType() != SpatialDomains::ePeriodic)
667  {
669  ::AllocateSharedPtr(m_session, *(it->second), graph2D,
670  DeclareCoeffPhysArrays, variable);
671 
672  m_bndCondExpansions[cnt] = locExpList;
673  m_bndConditions[cnt] = bc;
674 
675 
676  std::string type = m_bndConditions[cnt]->GetUserDefined();
677 
678  // Set up normals on non-Dirichlet boundary
679  // conditions. Second two conditions ideally
680  // should be in local solver setup (when made into factory)
681  if((bc->GetBoundaryConditionType() !=
683  boost::iequals(type,"I") ||
684  boost::iequals(type,"CalcBC"))
685  {
687  }
688 
689  cnt++;
690  }
691  }
692  }
693 
694  /**
695  * @brief Determine the periodic edges and vertices for the given graph.
696  *
697  * Note that much of this routine is the same as the three-dimensional
698  * version, which therefore has much better documentation.
699  *
700  * @param bcs Information about the boundary conditions.
701  * @param variable Specifies the field.
702  *
703  * @see DisContField3D::FindPeriodicFaces
704  */
707  const std::string &variable)
708  {
710  = bcs.GetBoundaryRegions();
712  = bcs.GetBoundaryConditions();
714  = boost::dynamic_pointer_cast<
716  SpatialDomains::BoundaryRegionCollection::const_iterator it;
717 
719  m_session->GetComm()->GetRowComm();
721  m_session->GetCompositeOrdering();
722  LibUtilities::BndRegionOrdering bndRegOrder =
723  m_session->GetBndRegionOrdering();
725  m_graph->GetComposites();
726 
727  // Unique collection of pairs of periodic composites (i.e. if
728  // composites 1 and 2 are periodic then this map will contain either
729  // the pair (1,2) or (2,1) but not both).
730  map<int,int> perComps;
731  map<int,vector<int> > allVerts;
732  set<int> locVerts;
733  map<int,StdRegions::Orientation> allEdges;
734 
735  int region1ID, region2ID, i, j, k, cnt;
737 
738  // Set up a set of all local verts and edges.
739  for(i = 0; i < (*m_exp).size(); ++i)
740  {
741  for(j = 0; j < (*m_exp)[i]->GetNverts(); ++j)
742  {
743  int id = (*m_exp)[i]->GetGeom()->GetVid(j);
744  locVerts.insert(id);
745  }
746  }
747 
748  // Construct list of all periodic pairs local to this process.
749  for (it = bregions.begin(); it != bregions.end(); ++it)
750  {
751  locBCond = GetBoundaryCondition(
752  bconditions, it->first, variable);
753 
754  if (locBCond->GetBoundaryConditionType()
756  {
757  continue;
758  }
759 
760  // Identify periodic boundary region IDs.
761  region1ID = it->first;
762  region2ID = boost::static_pointer_cast<
764  locBCond)->m_connectedBoundaryRegion;
765 
766  // From this identify composites. Note that in serial this will
767  // be an empty map.
768  int cId1, cId2;
769  if (vComm->GetSize() == 1)
770  {
771  cId1 = it->second->begin()->first;
772  cId2 = bregions.find(region2ID)->second->begin()->first;
773  }
774  else
775  {
776  cId1 = bndRegOrder.find(region1ID)->second[0];
777  cId2 = bndRegOrder.find(region2ID)->second[0];
778  }
779 
780  ASSERTL0(it->second->size() == 1,
781  "Boundary region "+boost::lexical_cast<string>(
782  region1ID)+" should only contain 1 composite.");
783 
784  // Construct set containing all periodic edges on this process
785  SpatialDomains::Composite c = it->second->begin()->second;
786 
787  vector<unsigned int> tmpOrder;
788 
789  for (i = 0; i < c->size(); ++i)
790  {
792  boost::dynamic_pointer_cast<
793  SpatialDomains::SegGeom>((*c)[i]);
794  ASSERTL0(segGeom, "Unable to cast to shared ptr");
795 
797  graph2D->GetElementsFromEdge(segGeom);
798  ASSERTL0(elmt->size() == 1,
799  "The periodic boundaries belong to "
800  "more than one element of the mesh");
801 
803  boost::dynamic_pointer_cast<SpatialDomains::Geometry2D>(
804  (*elmt)[0]->m_Element);
805 
806  allEdges[(*c)[i]->GetGlobalID()] =
807  geom->GetEorient((*elmt)[0]->m_EdgeIndx);
808 
809  // In serial mesh partitioning will not have occurred so
810  // need to fill composite ordering map manually.
811  if (vComm->GetSize() == 1)
812  {
813  tmpOrder.push_back((*c)[i]->GetGlobalID());
814  }
815 
816  vector<int> vertList(2);
817  vertList[0] = segGeom->GetVid(0);
818  vertList[1] = segGeom->GetVid(1);
819  allVerts[(*c)[i]->GetGlobalID()] = vertList;
820  }
821 
822  if (vComm->GetSize() == 1)
823  {
824  compOrder[it->second->begin()->first] = tmpOrder;
825  }
826 
827  // See if we already have either region1 or region2 stored in
828  // perComps map.
829  if (perComps.count(cId1) == 0)
830  {
831  if (perComps.count(cId2) == 0)
832  {
833  perComps[cId1] = cId2;
834  }
835  else
836  {
837  std::stringstream ss;
838  ss << "Boundary region " << cId2 << " should be "
839  << "periodic with " << perComps[cId2] << " but "
840  << "found " << cId1 << " instead!";
841  ASSERTL0(perComps[cId2] == cId1, ss.str());
842  }
843  }
844  else
845  {
846  std::stringstream ss;
847  ss << "Boundary region " << cId1 << " should be "
848  << "periodic with " << perComps[cId1] << " but "
849  << "found " << cId2 << " instead!";
850  ASSERTL0(perComps[cId1] == cId1, ss.str());
851  }
852  }
853 
854  // Process local edge list to obtain relative edge orientations.
855  int n = vComm->GetSize();
856  int p = vComm->GetRank();
857  int totEdges;
858  Array<OneD, int> edgecounts(n,0);
859  Array<OneD, int> edgeoffset(n,0);
860  Array<OneD, int> vertoffset(n,0);
861 
862  edgecounts[p] = allEdges.size();
863  vComm->AllReduce(edgecounts, LibUtilities::ReduceSum);
864 
865  edgeoffset[0] = 0;
866  for (i = 1; i < n; ++i)
867  {
868  edgeoffset[i] = edgeoffset[i-1] + edgecounts[i-1];
869  }
870 
871  totEdges = Vmath::Vsum(n, edgecounts, 1);
872  Array<OneD, int> edgeIds (totEdges, 0);
873  Array<OneD, int> edgeOrient(totEdges, 0);
874  Array<OneD, int> edgeVerts (totEdges, 0);
875 
877 
878  for (i = 0, sIt = allEdges.begin(); sIt != allEdges.end(); ++sIt)
879  {
880  edgeIds [edgeoffset[p] + i ] = sIt->first;
881  edgeOrient[edgeoffset[p] + i ] = sIt->second;
882  edgeVerts [edgeoffset[p] + i++] = allVerts[sIt->first].size();
883  }
884 
885  vComm->AllReduce(edgeIds, LibUtilities::ReduceSum);
886  vComm->AllReduce(edgeOrient, LibUtilities::ReduceSum);
887  vComm->AllReduce(edgeVerts, LibUtilities::ReduceSum);
888 
889  // Calculate number of vertices on each processor.
890  Array<OneD, int> procVerts(n,0);
891  int nTotVerts;
892 
893  // Note if there are no periodic edges at all calling Vsum will
894  // cause a segfault.
895  if (totEdges > 0)
896  {
897  nTotVerts = Vmath::Vsum(totEdges, edgeVerts, 1);
898  }
899  else
900  {
901  nTotVerts = 0;
902  }
903 
904  for (i = 0; i < n; ++i)
905  {
906  if (edgecounts[i] > 0)
907  {
908  procVerts[i] = Vmath::Vsum(
909  edgecounts[i], edgeVerts + edgeoffset[i], 1);
910  }
911  else
912  {
913  procVerts[i] = 0;
914  }
915  }
916  vertoffset[0] = 0;
917 
918  for (i = 1; i < n; ++i)
919  {
920  vertoffset[i] = vertoffset[i-1] + procVerts[i-1];
921  }
922 
923  Array<OneD, int> vertIds(nTotVerts, 0);
924  for (i = 0, sIt = allEdges.begin(); sIt != allEdges.end(); ++sIt)
925  {
926  for (j = 0; j < allVerts[sIt->first].size(); ++j)
927  {
928  vertIds[vertoffset[p] + i++] = allVerts[sIt->first][j];
929  }
930  }
931 
932  vComm->AllReduce(vertIds, LibUtilities::ReduceSum);
933 
934  // For simplicity's sake create a map of edge id -> orientation.
935  map<int, StdRegions::Orientation> orientMap;
936  map<int, vector<int> > vertMap;
937 
938  for (cnt = i = 0; i < totEdges; ++i)
939  {
940  ASSERTL0(orientMap.count(edgeIds[i]) == 0,
941  "Already found edge in orientation map!");
942  orientMap[edgeIds[i]] = (StdRegions::Orientation)edgeOrient[i];
943 
944  vector<int> verts(edgeVerts[i]);
945 
946  for (j = 0; j < edgeVerts[i]; ++j)
947  {
948  verts[j] = vertIds[cnt++];
949  }
950  vertMap[edgeIds[i]] = verts;
951  }
952 
953  // Go through list of composites and figure out which edges are
954  // parallel from original ordering in session file. This includes
955  // composites which are not necessarily on this process.
956  map<int,int>::iterator cIt, pIt;
957  map<int,int>::const_iterator oIt;
958 
959  map<int,int> allCompPairs;
960 
961  // Store temporary map of periodic vertices which will hold all
962  // periodic vertices on the entire mesh so that doubly periodic
963  // vertices can be counted properly across partitions. Local
964  // vertices are copied into m_periodicVerts at the end of the
965  // function.
966  PeriodicMap periodicVerts;
967 
968  for (cIt = perComps.begin(); cIt != perComps.end(); ++cIt)
969  {
971  const int id1 = cIt->first;
972  const int id2 = cIt->second;
973  std::string id1s = boost::lexical_cast<string>(id1);
974  std::string id2s = boost::lexical_cast<string>(id2);
975 
976  if (compMap.count(id1) > 0)
977  {
978  c[0] = compMap[id1];
979  }
980 
981  if (compMap.count(id2) > 0)
982  {
983  c[1] = compMap[id2];
984  }
985 
986  ASSERTL0(c[0] || c[1],
987  "Both composites not found on this process!");
988 
989  // Loop over composite ordering to construct list of all
990  // periodic edges regardless of whether they are on this
991  // process.
992  map<int,int> compPairs;
993 
994  ASSERTL0(compOrder.count(id1) > 0,
995  "Unable to find composite "+id1s+" in order map.");
996  ASSERTL0(compOrder.count(id2) > 0,
997  "Unable to find composite "+id2s+" in order map.");
998  ASSERTL0(compOrder[id1].size() == compOrder[id2].size(),
999  "Periodic composites "+id1s+" and "+id2s+
1000  " should have the same number of elements.");
1001  ASSERTL0(compOrder[id1].size() > 0,
1002  "Periodic composites "+id1s+" and "+id2s+
1003  " are empty!");
1004 
1005  // TODO: Add more checks.
1006  for (i = 0; i < compOrder[id1].size(); ++i)
1007  {
1008  int eId1 = compOrder[id1][i];
1009  int eId2 = compOrder[id2][i];
1010 
1011  ASSERTL0(compPairs.count(eId1) == 0,
1012  "Already paired.");
1013 
1014  if (compPairs.count(eId2) != 0)
1015  {
1016  ASSERTL0(compPairs[eId2] == eId1, "Pairing incorrect");
1017  }
1018  compPairs[eId1] = eId2;
1019  }
1020 
1021  // Construct set of all edges that we have locally on this
1022  // processor.
1023  set<int> locEdges;
1024  set<int>::iterator sIt;
1025  for (i = 0; i < 2; ++i)
1026  {
1027  if (!c[i])
1028  {
1029  continue;
1030  }
1031 
1032  if (c[i]->size() > 0)
1033  {
1034  for (j = 0; j < c[i]->size(); ++j)
1035  {
1036  locEdges.insert(c[i]->at(j)->GetGlobalID());
1037  }
1038  }
1039  }
1040 
1041  // Loop over all edges in the geometry composite.
1042  for (pIt = compPairs.begin(); pIt != compPairs.end(); ++pIt)
1043  {
1044  int ids [2] = {pIt->first, pIt->second};
1045  bool local[2] = {locEdges.count(pIt->first) > 0,
1046  locEdges.count(pIt->second) > 0};
1047 
1048  ASSERTL0(orientMap.count(ids[0]) > 0 &&
1049  orientMap.count(ids[1]) > 0,
1050  "Unable to find edge in orientation map.");
1051 
1052  allCompPairs[pIt->first ] = pIt->second;
1053  allCompPairs[pIt->second] = pIt->first;
1054 
1055  for (i = 0; i < 2; ++i)
1056  {
1057  if (!local[i])
1058  {
1059  continue;
1060  }
1061 
1062  int other = (i+1) % 2;
1063 
1065  orientMap[ids[i]] == orientMap[ids[other]] ?
1068 
1069  PeriodicEntity ent(ids [other], o,
1070  local[other]);
1071  m_periodicEdges[ids[i]].push_back(ent);
1072  }
1073 
1074  for (i = 0; i < 2; ++i)
1075  {
1076  int other = (i+1) % 2;
1077 
1079  orientMap[ids[i]] == orientMap[ids[other]] ?
1082 
1083  // Determine periodic vertices.
1084  vector<int> perVerts1 = vertMap[ids[i]];
1085  vector<int> perVerts2 = vertMap[ids[other]];
1086 
1087  map<int, pair<int, bool> > tmpMap;
1088  map<int, pair<int, bool> >::iterator mIt;
1089  if (o == StdRegions::eForwards)
1090  {
1091  tmpMap[perVerts1[0]] = make_pair(
1092  perVerts2[0], locVerts.count(perVerts2[0]) > 0);
1093  tmpMap[perVerts1[1]] = make_pair(
1094  perVerts2[1], locVerts.count(perVerts2[1]) > 0);
1095  }
1096  else
1097  {
1098  tmpMap[perVerts1[0]] = make_pair(
1099  perVerts2[1], locVerts.count(perVerts2[1]) > 0);
1100  tmpMap[perVerts1[1]] = make_pair(
1101  perVerts2[0], locVerts.count(perVerts2[0]) > 0);
1102  }
1103 
1104  for (mIt = tmpMap.begin(); mIt != tmpMap.end(); ++mIt)
1105  {
1106  // See if this vertex has been recorded already.
1107  PeriodicEntity ent2(mIt->second.first,
1109  mIt->second.second);
1110  PeriodicMap::iterator perIt = periodicVerts.find(
1111  mIt->first);
1112 
1113  if (perIt == periodicVerts.end())
1114  {
1115  periodicVerts[mIt->first].push_back(ent2);
1116  perIt = periodicVerts.find(mIt->first);
1117  }
1118  else
1119  {
1120  bool doAdd = true;
1121  for (j = 0; j < perIt->second.size(); ++j)
1122  {
1123  if (perIt->second[j].id == mIt->second.first)
1124  {
1125  doAdd = false;
1126  break;
1127  }
1128  }
1129 
1130  if (doAdd)
1131  {
1132  perIt->second.push_back(ent2);
1133  }
1134  }
1135  }
1136  }
1137  }
1138  }
1139 
1140  Array<OneD, int> pairSizes(n, 0);
1141  pairSizes[p] = allCompPairs.size();
1142  vComm->AllReduce(pairSizes, LibUtilities::ReduceSum);
1143 
1144  int totPairSizes = Vmath::Vsum(n, pairSizes, 1);
1145 
1146  Array<OneD, int> pairOffsets(n, 0);
1147  pairOffsets[0] = 0;
1148 
1149  for (i = 1; i < n; ++i)
1150  {
1151  pairOffsets[i] = pairOffsets[i-1] + pairSizes[i-1];
1152  }
1153 
1154  Array<OneD, int> first (totPairSizes, 0);
1155  Array<OneD, int> second(totPairSizes, 0);
1156 
1157  cnt = pairOffsets[p];
1158 
1159  for (pIt = allCompPairs.begin(); pIt != allCompPairs.end(); ++pIt)
1160  {
1161  first [cnt ] = pIt->first;
1162  second[cnt++] = pIt->second;
1163  }
1164 
1165  vComm->AllReduce(first, LibUtilities::ReduceSum);
1166  vComm->AllReduce(second, LibUtilities::ReduceSum);
1167 
1168  allCompPairs.clear();
1169 
1170  for(cnt = 0; cnt < totPairSizes; ++cnt)
1171  {
1172  allCompPairs[first[cnt]] = second[cnt];
1173  }
1174 
1175  // Search for periodic vertices and edges which are not in
1176  // a periodic composite but lie in this process. First, loop
1177  // over all information we have from other processors.
1178  for (cnt = i = 0; i < totEdges; ++i)
1179  {
1180  int edgeId = edgeIds[i];
1181 
1182  ASSERTL0(allCompPairs.count(edgeId) > 0,
1183  "Unable to find matching periodic edge.");
1184 
1185  int perEdgeId = allCompPairs[edgeId];
1186 
1187  for (j = 0; j < edgeVerts[i]; ++j, ++cnt)
1188  {
1189  int vId = vertIds[cnt];
1190 
1191  PeriodicMap::iterator perId = periodicVerts.find(vId);
1192 
1193  if (perId == periodicVerts.end())
1194  {
1195  // This vertex is not included in the map. Figure
1196  // out which vertex it is supposed to be periodic
1197  // with. perEdgeId is the edge ID which is periodic with
1198  // edgeId. The logic is much the same as the loop above.
1199  int perVertexId =
1200  orientMap[edgeId] == orientMap[perEdgeId] ?
1201  vertMap[perEdgeId][(j+1)%2] : vertMap[perEdgeId][j];
1202 
1203  PeriodicEntity ent(perVertexId,
1205  locVerts.count(perVertexId) > 0);
1206 
1207  periodicVerts[vId].push_back(ent);
1208  }
1209  }
1210  }
1211 
1212  // Loop over all periodic vertices to complete connectivity
1213  // information.
1214  PeriodicMap::iterator perIt, perIt2;
1215  for (perIt = periodicVerts.begin();
1216  perIt != periodicVerts.end(); ++perIt)
1217  {
1218  // Loop over associated vertices.
1219  for (i = 0; i < perIt->second.size(); ++i)
1220  {
1221  perIt2 = periodicVerts.find(perIt->second[i].id);
1222  ASSERTL0(perIt2 != periodicVerts.end(),
1223  "Couldn't find periodic vertex.");
1224 
1225  for (j = 0; j < perIt2->second.size(); ++j)
1226  {
1227  if (perIt2->second[j].id == perIt->first)
1228  {
1229  continue;
1230  }
1231 
1232  bool doAdd = true;
1233  for (k = 0; k < perIt->second.size(); ++k)
1234  {
1235  if (perIt2->second[j].id == perIt->second[k].id)
1236  {
1237  doAdd = false;
1238  break;
1239  }
1240  }
1241 
1242  if (doAdd)
1243  {
1244  perIt->second.push_back(perIt2->second[j]);
1245  }
1246  }
1247  }
1248  }
1249 
1250  // Do one final loop over periodic vertices to remove non-local
1251  // vertices from map.
1252  for (perIt = periodicVerts.begin();
1253  perIt != periodicVerts.end(); ++perIt)
1254  {
1255  if (locVerts.count(perIt->first) > 0)
1256  {
1257  m_periodicVerts.insert(*perIt);
1258  }
1259  }
1260  }
1261 
1262  bool DisContField2D::IsLeftAdjacentEdge(const int n, const int e)
1263  {
1264  set<int>::iterator it;
1266  m_traceMap->GetElmtToTrace()[n][e]->
1267  as<LocalRegions::Expansion1D>();
1268 
1269 
1270  bool fwd = true;
1271  if (traceEl->GetLeftAdjacentElementEdge () == -1 ||
1272  traceEl->GetRightAdjacentElementEdge() == -1)
1273  {
1274  // Boundary edge (1 connected element). Do nothing in
1275  // serial.
1276  it = m_boundaryEdges.find(traceEl->GetElmtId());
1277 
1278  // If the edge does not have a boundary condition set on
1279  // it, then assume it is a partition edge.
1280  if (it == m_boundaryEdges.end())
1281  {
1282  int traceGeomId = traceEl->GetGeom1D()->GetGlobalID();
1284  traceGeomId);
1285 
1286  if (pIt != m_periodicEdges.end() && !pIt->second[0].isLocal)
1287  {
1288  fwd = traceGeomId == min(traceGeomId,pIt->second[0].id);
1289  }
1290  else
1291  {
1292  int offset = m_trace->GetPhys_Offset(traceEl->GetElmtId());
1293 
1294  fwd = m_traceMap->
1295  GetTraceToUniversalMapUnique(offset) >= 0;
1296  }
1297  }
1298  }
1299  else if (traceEl->GetLeftAdjacentElementEdge () != -1 &&
1300  traceEl->GetRightAdjacentElementEdge() != -1)
1301  {
1302  // Non-boundary edge (2 connected elements).
1303  fwd = dynamic_cast<Nektar::StdRegions::StdExpansion*>
1304  (traceEl->GetLeftAdjacentElementExp().get()) ==
1305  (*m_exp)[n].get();
1306  }
1307  else
1308  {
1309  ASSERTL2(false, "Unconnected trace element!");
1310  }
1311 
1312  return fwd;
1313  }
1314 
1315  // Construct the two trace vectors of the inner and outer
1316  // trace solution from the field contained in m_phys, where
1317  // the Weak dirichlet boundary conditions are listed in the
1318  // outer part of the vecotr
1322  {
1323  v_GetFwdBwdTracePhys(m_phys, Fwd, Bwd);
1324  }
1325 
1326  /**
1327  * @brief This method extracts the "forward" and "backward" trace data
1328  * from the array @a field and puts the data into output vectors @a Fwd
1329  * and @a Bwd.
1330  *
1331  * We first define the convention which defines "forwards" and
1332  * "backwards". First an association is made between the edge of each
1333  * element and its corresponding edge in the trace space using the
1334  * mapping #m_traceMap. The element can either be left-adjacent or
1335  * right-adjacent to this trace edge (see
1336  * Expansion1D::GetLeftAdjacentElementExp). Boundary edges are always
1337  * left-adjacent since left-adjacency is populated first.
1338  *
1339  * If the element is left-adjacent we extract the edge trace data from
1340  * @a field into the forward trace space @a Fwd; otherwise, we place it
1341  * in the backwards trace space @a Bwd. In this way, we form a unique
1342  * set of trace normals since these are always extracted from
1343  * left-adjacent elements.
1344  *
1345  * @param field is a NekDouble array which contains the 2D data
1346  * from which we wish to extract the backward and
1347  * forward orientated trace/edge arrays.
1348  * @param Fwd The resulting forwards space.
1349  * @param Bwd The resulting backwards space.
1350  */
1352  const Array<OneD, const NekDouble> &field,
1355  {
1356  int cnt, n, e, npts, phys_offset;
1357 
1358  // Zero forward/backward vectors.
1359  Vmath::Zero(Fwd.num_elements(), Fwd, 1);
1360  Vmath::Zero(Bwd.num_elements(), Bwd, 1);
1361 
1362  // Basis definition on each element
1363  LibUtilities::BasisSharedPtr basis = (*m_exp)[0]->GetBasis(0);
1364  if (basis->GetBasisType() != LibUtilities::eGauss_Lagrange)
1365  {
1366 
1367  // blocked routine
1369  GetNLocTracePts());
1370 
1371  m_locTraceToTraceMap->LocTracesFromField(field, edgevals);
1372  m_locTraceToTraceMap->InterpLocEdgesToTrace(0, edgevals, Fwd);
1373 
1374  Array<OneD, NekDouble> invals = edgevals + m_locTraceToTraceMap->
1375  GetNFwdLocTracePts();
1376  m_locTraceToTraceMap->InterpLocEdgesToTrace(1, invals, Bwd);
1377  }
1378  else
1379  {
1380  // Loop over elements and collect forward expansion
1381  int nexp = GetExpSize();
1382  Array<OneD,NekDouble> e_tmp;
1384  boost::unordered_map<int,pair<int,int> >::iterator it3;
1386 
1388  &elmtToTrace = m_traceMap->GetElmtToTrace();
1389 
1390  for(cnt = n = 0; n < nexp; ++n)
1391  {
1392  exp2d = (*m_exp)[n]->as<LocalRegions::Expansion2D>();
1393  phys_offset = GetPhys_Offset(n);
1394 
1395  for(e = 0; e < exp2d->GetNedges(); ++e, ++cnt)
1396  {
1397  int offset = m_trace->GetPhys_Offset(
1398  elmtToTrace[n][e]->GetElmtId());
1399 
1400  if (m_leftAdjacentEdges[cnt])
1401  {
1402  exp2d->GetEdgePhysVals(e, elmtToTrace[n][e],
1403  field + phys_offset,
1404  e_tmp = Fwd + offset);
1405  }
1406  else
1407  {
1408  exp2d->GetEdgePhysVals(e, elmtToTrace[n][e],
1409  field + phys_offset,
1410  e_tmp = Bwd + offset);
1411  }
1412 
1413  }
1414  }
1415  }
1416 
1417  // Fill boundary conditions into missing elements
1418  int id1, id2 = 0;
1419 
1420  for (cnt = n = 0; n < m_bndCondExpansions.num_elements(); ++n)
1421  {
1422  if (m_bndConditions[n]->GetBoundaryConditionType() ==
1424  {
1425  for (e = 0; e < m_bndCondExpansions[n]->GetExpSize(); ++e)
1426  {
1427  npts = m_bndCondExpansions[n]->GetExp(e)->GetNumPoints(0);
1428  id1 = m_bndCondExpansions[n]->GetPhys_Offset(e);
1429  id2 = m_trace->GetPhys_Offset(m_traceMap->
1430  GetBndCondTraceToGlobalTraceMap(cnt+e));
1431  Vmath::Vcopy(npts,
1432  &(m_bndCondExpansions[n]->GetPhys())[id1], 1,
1433  &Bwd[id2], 1);
1434  }
1435 
1436  cnt += e;
1437  }
1438  else if (m_bndConditions[n]->GetBoundaryConditionType() ==
1440  m_bndConditions[n]->GetBoundaryConditionType() ==
1442  {
1443  for(e = 0; e < m_bndCondExpansions[n]->GetExpSize(); ++e)
1444  {
1445  npts = m_bndCondExpansions[n]->GetExp(e)->GetNumPoints(0);
1446  id1 = m_bndCondExpansions[n]->GetPhys_Offset(e);
1447  ASSERTL0((m_bndCondExpansions[n]->GetPhys())[id1]==0.0,
1448  "Method not set up for non-zero Neumann "
1449  "boundary condition");
1450  id2 = m_trace->GetPhys_Offset(
1451  m_traceMap->GetBndCondTraceToGlobalTraceMap(cnt+e));
1452  Vmath::Vcopy(npts, &Fwd[id2], 1, &Bwd[id2], 1);
1453  }
1454 
1455  cnt += e;
1456  }
1457  else if (m_bndConditions[n]->GetBoundaryConditionType() !=
1459  {
1460  ASSERTL0(false,
1461  "Method not set up for this boundary condition.");
1462  }
1463  }
1464 
1465  // Copy any periodic boundary conditions.
1466  for (n = 0; n < m_periodicFwdCopy.size(); ++n)
1467  {
1468  Bwd[m_periodicBwdCopy[n]] = Fwd[m_periodicFwdCopy[n]];
1469  }
1470 
1471  // Do parallel exchange for forwards/backwards spaces.
1472  m_traceMap->UniversalTraceAssemble(Fwd);
1473  m_traceMap->UniversalTraceAssemble(Bwd);
1474  }
1475 
1477  {
1478 
1479  }
1480 
1482  Array<OneD, NekDouble> &outarray)
1483  {
1484  ASSERTL1(m_physState == true,
1485  "Field must be in physical state to extract trace space.");
1486 
1487  v_ExtractTracePhys(m_phys, outarray);
1488  }
1489 
1490  /**
1491  * @brief This method extracts the trace (edges in 2D) from the field @a
1492  * inarray and puts the values in @a outarray.
1493  *
1494  * It assumes the field is C0 continuous so that it can overwrite the
1495  * edge data when visited by the two adjacent elements.
1496  *
1497  * @param inarray An array containing the 2D data from which we wish
1498  * to extract the edge data.
1499  * @param outarray The resulting edge information.
1500  */
1502  const Array<OneD, const NekDouble> &inarray,
1503  Array<OneD, NekDouble> &outarray)
1504  {
1505  // Loop over elemente and collect forward expansion
1506  int nexp = GetExpSize();
1507  int n, e, offset, phys_offset;
1508  Array<OneD,NekDouble> e_tmp;
1510  &elmtToTrace = m_traceMap->GetElmtToTrace();
1511 
1512  ASSERTL1(outarray.num_elements() >= m_trace->GetNpoints(),
1513  "input array is of insufficient length");
1514 
1515  // use m_trace tmp space in element to fill values
1516  for(n = 0; n < nexp; ++n)
1517  {
1518  phys_offset = GetPhys_Offset(n);
1519 
1520  for(e = 0; e < (*m_exp)[n]->GetNedges(); ++e)
1521  {
1522  offset = m_trace->GetPhys_Offset(
1523  elmtToTrace[n][e]->GetElmtId());
1524  (*m_exp)[n]->GetEdgePhysVals(e, elmtToTrace[n][e],
1525  inarray + phys_offset,
1526  e_tmp = outarray + offset);
1527  }
1528  }
1529  }
1530 
1532  const Array<OneD, const NekDouble> &Fx,
1533  const Array<OneD, const NekDouble> &Fy,
1534  Array<OneD, NekDouble> &outarray)
1535  {
1536  int e, n, offset, t_offset;
1537  Array<OneD, NekDouble> e_outarray;
1539  &elmtToTrace = m_traceMap->GetElmtToTrace();
1540 
1541  for(n = 0; n < GetExpSize(); ++n)
1542  {
1543  offset = GetCoeff_Offset(n);
1544  for(e = 0; e < (*m_exp)[n]->GetNedges(); ++e)
1545  {
1546  t_offset = GetTrace()->GetPhys_Offset(
1547  elmtToTrace[n][e]->GetElmtId());
1548 
1549  (*m_exp)[n]->AddEdgeNormBoundaryInt(
1550  e,elmtToTrace[n][e],
1551  Fx + t_offset,
1552  Fy + t_offset,
1553  e_outarray = outarray+offset);
1554  }
1555  }
1556  }
1557 
1558  /**
1559  * @brief Add trace contributions into elemental coefficient spaces.
1560  *
1561  * Given some quantity \f$ \vec{Fn} \f$, which conatins this
1562  * routine calculates the integral
1563  *
1564  * \f[
1565  * \int_{\Omega^e} \vec{Fn}, \mathrm{d}S
1566  * \f]
1567  *
1568  * and adds this to the coefficient space provided by outarray.
1569  *
1570  * @see Expansion2D::AddEdgeNormBoundaryInt
1571  *
1572  * @param Fn The trace quantities.
1573  * @param outarray Resulting 2D coefficient space.
1574  */
1576  const Array<OneD, const NekDouble> &Fn,
1577  Array<OneD, NekDouble> &outarray)
1578  {
1579  // Basis definition on each element
1580  LibUtilities::BasisSharedPtr basis = (*m_exp)[0]->GetBasis(0);
1581  if (basis->GetBasisType() != LibUtilities::eGauss_Lagrange)
1582  {
1583  Array<OneD, NekDouble> Fcoeffs(m_trace->GetNcoeffs());
1584  m_trace->IProductWRTBase(Fn, Fcoeffs);
1585 
1586  m_locTraceToTraceMap->AddTraceCoeffsToFieldCoeffs(Fcoeffs,
1587  outarray);
1588  }
1589  else
1590  {
1591  int e, n, offset, t_offset;
1592  Array<OneD, NekDouble> e_outarray;
1594  &elmtToTrace = m_traceMap->GetElmtToTrace();
1595 
1596  for(n = 0; n < GetExpSize(); ++n)
1597  {
1598  offset = GetCoeff_Offset(n);
1599  for(e = 0; e < (*m_exp)[n]->GetNedges(); ++e)
1600  {
1601  t_offset = GetTrace()->GetPhys_Offset(
1602  elmtToTrace[n][e]->GetElmtId());
1603  (*m_exp)[n]->AddEdgeNormBoundaryInt(
1604  e, elmtToTrace[n][e],
1605  Fn+t_offset,
1606  e_outarray = outarray+offset);
1607  }
1608  }
1609  }
1610  }
1611 
1612 
1613  /**
1614  * @brief Add trace contributions into elemental coefficient spaces.
1615  *
1616  * Given some quantity \f$ \vec{q} \f$, calculate the elemental integral
1617  *
1618  * \f[
1619  * \int_{\Omega^e} \vec{q}, \mathrm{d}S
1620  * \f]
1621  *
1622  * and adds this to the coefficient space provided by
1623  * outarray. The value of q is determined from the routine
1624  * IsLeftAdjacentEdge() which if true we use Fwd else we use
1625  * Bwd
1626  *
1627  * @see Expansion2D::AddEdgeNormBoundaryInt
1628  *
1629  * @param Fwd The trace quantities associated with left (fwd)
1630  * adjancent elmt.
1631  * @param Bwd The trace quantities associated with right (bwd)
1632  * adjacent elet.
1633  * @param outarray Resulting 2D coefficient space.
1634  */
1636  const Array<OneD, const NekDouble> &Fwd,
1637  const Array<OneD, const NekDouble> &Bwd,
1638  Array<OneD, NekDouble> &outarray)
1639  {
1640  int e,n,offset, t_offset;
1641  Array<OneD, NekDouble> e_outarray;
1643  &elmtToTrace = m_traceMap->GetElmtToTrace();
1644 
1645  for (n = 0; n < GetExpSize(); ++n)
1646  {
1647  offset = GetCoeff_Offset(n);
1648  for (e = 0; e < (*m_exp)[n]->GetNedges(); ++e)
1649  {
1650  t_offset = GetTrace()->GetPhys_Offset(
1651  elmtToTrace[n][e]->GetElmtId());
1652 
1653  // Evaluate upwind flux less local edge
1654  if (IsLeftAdjacentEdge(n, e))
1655  {
1656  (*m_exp)[n]->AddEdgeNormBoundaryInt(
1657  e, elmtToTrace[n][e], Fwd+t_offset,
1658  e_outarray = outarray+offset);
1659  }
1660  else
1661  {
1662  (*m_exp)[n]->AddEdgeNormBoundaryInt(
1663  e, elmtToTrace[n][e], Bwd+t_offset,
1664  e_outarray = outarray+offset);
1665  }
1666 
1667  }
1668  }
1669  }
1670 
1671  /**
1672  * @brief Set up a list of element IDs and edge IDs that link to the
1673  * boundary conditions.
1674  */
1676  Array<OneD, int> &ElmtID,
1677  Array<OneD, int> &EdgeID)
1678  {
1679  map<int, int> globalIdMap;
1680  int i,n;
1681  int cnt;
1682  int nbcs = 0;
1683 
1685  boost::dynamic_pointer_cast<SpatialDomains::MeshGraph2D>(
1686  m_graph);
1687 
1688  // Populate global ID map (takes global geometry ID to local
1689  // expansion list ID).
1690  for (i = 0; i < GetExpSize(); ++i)
1691  {
1692  globalIdMap[(*m_exp)[i]->GetGeom()->GetGlobalID()] = i;
1693  }
1694 
1695  // Determine number of boundary condition expansions.
1696  for(i = 0; i < m_bndConditions.num_elements(); ++i)
1697  {
1698  nbcs += m_bndCondExpansions[i]->GetExpSize();
1699  }
1700 
1701  // make sure arrays are of sufficient length
1702  if(ElmtID.num_elements() != nbcs)
1703  {
1704  ElmtID = Array<OneD, int>(nbcs);
1705  }
1706 
1707  if(EdgeID.num_elements() != nbcs)
1708  {
1709  EdgeID = Array<OneD, int>(nbcs);
1710  }
1711 
1713  for (cnt = n = 0; n < m_bndCondExpansions.num_elements(); ++n)
1714  {
1715  for (i = 0; i < m_bndCondExpansions[n]->GetExpSize();
1716  ++i, ++cnt)
1717  {
1718  exp1d = m_bndCondExpansions[n]->GetExp(i)->
1719  as<LocalRegions::Expansion1D>();
1720  // Use edge to element map from MeshGraph2D.
1722  graph2D->GetElementsFromEdge(exp1d->GetGeom1D());
1723 
1724  ElmtID[cnt] = globalIdMap[(*tmp)[0]->
1725  m_Element->GetGlobalID()];
1726  EdgeID[cnt] = (*tmp)[0]->m_EdgeIndx;
1727  }
1728  }
1729  }
1730 
1732  boost::shared_ptr<ExpList> &result)
1733  {
1734  int n, cnt, nq;
1735  int offsetOld, offsetNew;
1736  Array<OneD, NekDouble> tmp1, tmp2;
1737  std::vector<unsigned int> eIDs;
1738 
1739  Array<OneD, int> ElmtID,EdgeID;
1740  GetBoundaryToElmtMap(ElmtID,EdgeID);
1741 
1742  // Skip other boundary regions
1743  for (cnt = n = 0; n < i; ++n)
1744  {
1745  cnt += m_bndCondExpansions[n]->GetExpSize();
1746  }
1747 
1748  // Populate eIDs with information from BoundaryToElmtMap
1749  for (n = 0; n < m_bndCondExpansions[i]->GetExpSize(); ++n)
1750  {
1751  eIDs.push_back(ElmtID[cnt+n]);
1752  }
1753 
1754  // Create expansion list
1755  result =
1757 
1758  // Copy phys and coeffs to new explist
1759  for (n = 0; n < result->GetExpSize(); ++n)
1760  {
1761  nq = GetExp(ElmtID[cnt+n])->GetTotPoints();
1762  offsetOld = GetPhys_Offset(ElmtID[cnt+n]);
1763  offsetNew = result->GetPhys_Offset(n);
1764  Vmath::Vcopy(nq, tmp1 = GetPhys()+ offsetOld, 1,
1765  tmp2 = result->UpdatePhys()+ offsetNew, 1);
1766 
1767  nq = GetExp(ElmtID[cnt+n])->GetNcoeffs();
1768  offsetOld = GetCoeff_Offset(ElmtID[cnt+n]);
1769  offsetNew = result->GetCoeff_Offset(n);
1770  Vmath::Vcopy(nq, tmp1 = GetCoeffs()+ offsetOld, 1,
1771  tmp2 = result->UpdateCoeffs()+ offsetNew, 1);
1772  }
1773  }
1774 
1775  /**
1776  * @brief Reset this field, so that geometry information can be updated.
1777  */
1779  {
1780  ExpList::v_Reset();
1781 
1782  // Reset boundary condition expansions.
1783  for (int n = 0; n < m_bndCondExpansions.num_elements(); ++n)
1784  {
1785  m_bndCondExpansions[n]->Reset();
1786  }
1787  }
1788 
1789  /**
1790  * @brief Calculate the \f$ L^2 \f$ error of the \f$ Q_{\rm dir} \f$
1791  * derivative using the consistent DG evaluation of \f$ Q_{\rm dir} \f$.
1792  *
1793  * The solution provided is of the primative variation at the quadrature
1794  * points and the derivative is compared to the discrete derivative at
1795  * these points, which is likely to be undesirable unless using a much
1796  * higher number of quadrature points than the polynomial order used to
1797  * evaluate \f$ Q_{\rm dir} \f$.
1798  */
1800  const int dir,
1801  const Array<OneD, const NekDouble> &soln)
1802  {
1803  int i,e,ncoeff_edge;
1804  Array<OneD, const NekDouble> tmp_coeffs;
1805  Array<OneD, NekDouble> out_d(m_ncoeffs), out_tmp;
1806 
1808  &elmtToTrace = m_traceMap->GetElmtToTrace();
1809 
1810  StdRegions::Orientation edgedir;
1811 
1812  int eid,cnt;
1813  int LocBndCoeffs = m_traceMap->GetNumLocalBndCoeffs();
1814  Array<OneD, NekDouble> loc_lambda(LocBndCoeffs), edge_lambda;
1815  m_traceMap->GlobalToLocalBnd(m_trace->GetCoeffs(),loc_lambda);
1816 
1817  edge_lambda = loc_lambda;
1818 
1819  // Calculate Q using standard DG formulation.
1820  for(i = cnt = 0; i < GetExpSize(); ++i)
1821  {
1822  eid = m_offset_elmt_id[i];
1823 
1824  // Probably a better way of setting up lambda than this.
1825  // Note cannot use PutCoeffsInToElmts since lambda space
1826  // is mapped during the solve.
1827  int nEdges = (*m_exp)[i]->GetNedges();
1828  Array<OneD, Array<OneD, NekDouble> > edgeCoeffs(nEdges);
1829 
1830  for(e = 0; e < nEdges; ++e)
1831  {
1832  edgedir = (*m_exp)[eid]->GetEorient(e);
1833  ncoeff_edge = elmtToTrace[eid][e]->GetNcoeffs();
1834  edgeCoeffs[e] = Array<OneD, NekDouble>(ncoeff_edge);
1835  Vmath::Vcopy(ncoeff_edge, edge_lambda, 1, edgeCoeffs[e], 1);
1836  elmtToTrace[eid][e]->SetCoeffsToOrientation(
1837  edgedir, edgeCoeffs[e], edgeCoeffs[e]);
1838  edge_lambda = edge_lambda + ncoeff_edge;
1839  }
1840 
1841  (*m_exp)[eid]->DGDeriv(dir,
1842  tmp_coeffs=m_coeffs+m_coeff_offset[eid],
1843  elmtToTrace[eid],
1844  edgeCoeffs,
1845  out_tmp = out_d+cnt);
1846  cnt += (*m_exp)[eid]->GetNcoeffs();
1847  }
1848 
1849  BwdTrans(out_d,m_phys);
1850  Vmath::Vsub(m_npoints,m_phys,1,soln,1,m_phys,1);
1851  return L2(m_phys);
1852  }
1853 
1855  const Array<OneD, const NekDouble> &inarray,
1856  Array<OneD, NekDouble> &outarray,
1857  const FlagList &flags,
1858  const StdRegions::ConstFactorMap &factors,
1859  const StdRegions::VarCoeffMap &varcoeff,
1860  const Array<OneD, const NekDouble> &dirForcing)
1861  {
1862  int i,j,n,cnt,cnt1,nbndry;
1863  int nexp = GetExpSize();
1865 
1867  DNekVec F(m_ncoeffs,f,eWrapper);
1868  Array<OneD,NekDouble> e_f, e_l;
1869 
1870  //----------------------------------
1871  // Setup RHS Inner product
1872  //----------------------------------
1873  IProductWRTBase(inarray,f);
1874  Vmath::Neg(m_ncoeffs,f,1);
1875 
1876  //----------------------------------
1877  // Solve continuous flux System
1878  //----------------------------------
1879  int GloBndDofs = m_traceMap->GetNumGlobalBndCoeffs();
1880  int NumDirichlet = m_traceMap->GetNumLocalDirBndCoeffs();
1881  int e_ncoeffs,id;
1882 
1883  // Retrieve block matrix of U^e
1885  NullAssemblyMapSharedPtr,factors,varcoeff);
1886  const DNekScalBlkMatSharedPtr &HDGLamToU = GetBlockMatrix(
1887  HDGLamToUKey);
1888 
1889  // Retrieve global trace space storage, \Lambda, from trace
1890  // expansion
1891  Array<OneD,NekDouble> BndSol = m_trace->UpdateCoeffs();
1892 
1893  // Create trace space forcing, F
1894  Array<OneD,NekDouble> BndRhs(GloBndDofs,0.0);
1895 
1896  // Zero \Lambda
1897  Vmath::Zero(GloBndDofs,BndSol,1);
1898 
1899  // Retrieve number of local trace space coefficients N_{\lambda},
1900  // and set up local elemental trace solution \lambda^e.
1901  int LocBndCoeffs = m_traceMap->GetNumLocalBndCoeffs();
1902  Array<OneD, NekDouble> loc_lambda(LocBndCoeffs);
1903  DNekVec LocLambda(LocBndCoeffs,loc_lambda,eWrapper);
1904 
1905  //----------------------------------
1906  // Evaluate Trace Forcing vector F
1907  // Kirby et al, 2010, P23, Step 5.
1908  //----------------------------------
1909  // Loop over all expansions in the domain
1910  for(cnt = cnt1 = n = 0; n < nexp; ++n)
1911  {
1912  nbndry = (*m_exp)[m_offset_elmt_id[n]]->NumDGBndryCoeffs();
1913 
1914  e_ncoeffs = (*m_exp)[m_offset_elmt_id[n]]->GetNcoeffs();
1915  e_f = f + cnt;
1916  e_l = loc_lambda + cnt1;
1917 
1918  // Local trace space \lambda^e
1919  DNekVec Floc (nbndry, e_l, eWrapper);
1920  // Local forcing f^e
1921  DNekVec ElmtFce (e_ncoeffs, e_f, eWrapper);
1922  // Compute local (U^e)^{\top} f^e
1923  Floc = Transpose(*(HDGLamToU->GetBlock(n,n)))*ElmtFce;
1924 
1925  cnt += e_ncoeffs;
1926  cnt1 += nbndry;
1927  }
1928 
1929  // Assemble local \lambda_e into global \Lambda
1930  m_traceMap->AssembleBnd(loc_lambda,BndRhs);
1931 
1932  // Copy Dirichlet boundary conditions and weak forcing into trace
1933  // space
1934  cnt = 0;
1935  for(i = 0; i < m_bndCondExpansions.num_elements(); ++i)
1936  {
1937  if(m_bndConditions[i]->GetBoundaryConditionType() ==
1939  {
1940  for(j = 0; j < (m_bndCondExpansions[i])->GetNcoeffs(); ++j)
1941  {
1942  id = m_traceMap->GetBndCondCoeffsToGlobalCoeffsMap(cnt++);
1943  BndSol[id] = m_bndCondExpansions[i]->GetCoeffs()[j];
1944  }
1945  }
1946  else
1947  {
1948  //Add weak boundary condition to trace forcing
1949  for(j = 0; j < (m_bndCondExpansions[i])->GetNcoeffs(); ++j)
1950  {
1951  id = m_traceMap->GetBndCondCoeffsToGlobalCoeffsMap(cnt++);
1952  BndRhs[id] += m_bndCondExpansions[i]->GetCoeffs()[j];
1953  }
1954  }
1955  }
1956 
1957  //----------------------------------
1958  // Solve trace problem: \Lambda = K^{-1} F
1959  // K is the HybridDGHelmBndLam matrix.
1960  //----------------------------------
1961  if(GloBndDofs - NumDirichlet > 0)
1962  {
1964  m_traceMap,factors,varcoeff);
1966  LinSys->Solve(BndRhs,BndSol,m_traceMap);
1967  }
1968 
1969  //----------------------------------
1970  // Internal element solves
1971  //----------------------------------
1973  NullAssemblyMapSharedPtr,factors,varcoeff);
1974  const DNekScalBlkMatSharedPtr& InvHDGHelm = GetBlockMatrix(
1975  invHDGhelmkey);
1976  DNekVec out(m_ncoeffs,outarray,eWrapper);
1977  Vmath::Zero(m_ncoeffs,outarray,1);
1978 
1979  // get local trace solution from BndSol
1980  m_traceMap->GlobalToLocalBnd(BndSol,loc_lambda);
1981 
1982  // out = u_f + u_lam = (*InvHDGHelm)*f + (LamtoU)*Lam
1983  out = (*InvHDGHelm)*F + (*HDGLamToU)*LocLambda;
1984  }
1985 
1986 
1987  /**
1988  * @brief Calculates the result of the multiplication of a global matrix
1989  * of type specified by @a mkey with a vector given by @a inarray.
1990  *
1991  * @param mkey Key representing desired matrix multiplication.
1992  * @param inarray Input vector.
1993  * @param outarray Resulting multiplication.
1994  */
1996  const GlobalMatrixKey &gkey,
1997  const Array<OneD,const NekDouble> &inarray,
1998  Array<OneD, NekDouble> &outarray,
1999  CoeffState coeffstate)
2000  {
2001  int LocBndCoeffs = m_traceMap->GetNumLocalBndCoeffs();
2002  Array<OneD, NekDouble> loc_lambda(LocBndCoeffs);
2003  DNekVec LocLambda(LocBndCoeffs,loc_lambda,eWrapper);
2004  const DNekScalBlkMatSharedPtr& HDGHelm = GetBlockMatrix(gkey);
2005 
2006  m_traceMap->GlobalToLocalBnd(inarray, loc_lambda);
2007  LocLambda = (*HDGHelm) * LocLambda;
2008  m_traceMap->AssembleBnd(loc_lambda,outarray);
2009  }
2010 
2011  /**
2012  * @brief Search through the edge expansions and identify which ones
2013  * have Robin/Mixed type boundary conditions.
2014  *
2015  * If a Robin boundary is found then store the edge ID of the boundary
2016  * condition and the array of points of the physical space boundary
2017  * condition which are hold the boundary condition primitive variable
2018  * coefficient at the quatrature points
2019  *
2020  * @return A map containing the Robin boundary condition information
2021  * using a key of the element ID.
2022  */
2023  map<int, RobinBCInfoSharedPtr> DisContField2D::v_GetRobinBCInfo(void)
2024  {
2025  int i,cnt;
2026  map<int, RobinBCInfoSharedPtr> returnval;
2027  Array<OneD, int> ElmtID,EdgeID;
2028  GetBoundaryToElmtMap(ElmtID,EdgeID);
2029 
2030  for(cnt = i = 0; i < m_bndCondExpansions.num_elements(); ++i)
2031  {
2032  MultiRegions::ExpListSharedPtr locExpList;
2033 
2034  if(m_bndConditions[i]->GetBoundaryConditionType() ==
2036  {
2037  int e,elmtid;
2038  Array<OneD, NekDouble> Array_tmp;
2039 
2040  locExpList = m_bndCondExpansions[i];
2041 
2042  for(e = 0; e < locExpList->GetExpSize(); ++e)
2043  {
2046  EdgeID[cnt+e],
2047  Array_tmp = locExpList->GetPhys() +
2048  locExpList->GetPhys_Offset(e));
2049  elmtid = ElmtID[cnt+e];
2050  // make link list if necessary
2051  if(returnval.count(elmtid) != 0)
2052  {
2053  rInfo->next = returnval.find(elmtid)->second;
2054  }
2055  returnval[elmtid] = rInfo;
2056  }
2057  }
2058  cnt += m_bndCondExpansions[i]->GetExpSize();
2059  }
2060 
2061  return returnval;
2062  }
2063 
2064  /**
2065  * @brief Evaluate HDG post-processing to increase polynomial order of
2066  * solution.
2067  *
2068  * This function takes the solution (assumed to be one order lower) in
2069  * physical space, and postprocesses at the current polynomial order by
2070  * solving the system:
2071  *
2072  * \f[
2073  * \begin{aligned}
2074  * (\nabla w, \nabla u^*) &= (\nabla w, u), \\
2075  * \langle \nabla u^*, 1 \rangle &= \langle \nabla u, 1 \rangle
2076  * \end{aligned}
2077  * \f]
2078  *
2079  * where \f$ u \f$ corresponds with the current solution as stored
2080  * inside #m_coeffs.
2081  *
2082  * @param outarray The resulting field \f$ u^* \f$.
2083  */
2085  Array<OneD, NekDouble> &outarray)
2086  {
2087  int i,cnt,e,ncoeff_edge;
2088  Array<OneD, NekDouble> force, out_tmp, qrhs, qrhs1;
2090  &elmtToTrace = m_traceMap->GetElmtToTrace();
2091 
2092  StdRegions::Orientation edgedir;
2093 
2094  int eid,nq_elmt, nm_elmt;
2095  int LocBndCoeffs = m_traceMap->GetNumLocalBndCoeffs();
2096  Array<OneD, NekDouble> loc_lambda(LocBndCoeffs), edge_lambda;
2097  Array<OneD, NekDouble> tmp_coeffs;
2098  m_traceMap->GlobalToLocalBnd(m_trace->GetCoeffs(),loc_lambda);
2099 
2100  edge_lambda = loc_lambda;
2101 
2102  // Calculate Q using standard DG formulation.
2103  for(i = cnt = 0; i < GetExpSize(); ++i)
2104  {
2105  eid = m_offset_elmt_id[i];
2106 
2107  nq_elmt = (*m_exp)[eid]->GetTotPoints();
2108  nm_elmt = (*m_exp)[eid]->GetNcoeffs();
2109  qrhs = Array<OneD, NekDouble>(nq_elmt);
2110  qrhs1 = Array<OneD, NekDouble>(nq_elmt);
2111  force = Array<OneD, NekDouble>(2*nm_elmt);
2112  out_tmp = force + nm_elmt;
2114 
2115  int num_points0 = (*m_exp)[eid]->GetBasis(0)->GetNumPoints();
2116  int num_points1 = (*m_exp)[eid]->GetBasis(1)->GetNumPoints();
2117  int num_modes0 = (*m_exp)[eid]->GetBasis(0)->GetNumModes();
2118  int num_modes1 = (*m_exp)[eid]->GetBasis(1)->GetNumModes();
2119 
2120  // Probably a better way of setting up lambda than this. Note
2121  // cannot use PutCoeffsInToElmts since lambda space is mapped
2122  // during the solve.
2123  int nEdges = (*m_exp)[i]->GetNedges();
2124  Array<OneD, Array<OneD, NekDouble> > edgeCoeffs(nEdges);
2125 
2126  for(e = 0; e < (*m_exp)[eid]->GetNedges(); ++e)
2127  {
2128  edgedir = (*m_exp)[eid]->GetEorient(e);
2129  ncoeff_edge = elmtToTrace[eid][e]->GetNcoeffs();
2130  edgeCoeffs[e] = Array<OneD, NekDouble>(ncoeff_edge);
2131  Vmath::Vcopy(ncoeff_edge, edge_lambda, 1, edgeCoeffs[e], 1);
2132  elmtToTrace[eid][e]->SetCoeffsToOrientation(
2133  edgedir, edgeCoeffs[e], edgeCoeffs[e]);
2134  edge_lambda = edge_lambda + ncoeff_edge;
2135  }
2136 
2137  //creating orthogonal expansion (checking if we have quads or triangles)
2138  LibUtilities::ShapeType shape = (*m_exp)[eid]->DetShapeType();
2139  switch(shape)
2140  {
2142  {
2145  LibUtilities::BasisKey BkeyQ1(LibUtilities::eOrtho_A, num_modes0, PkeyQ1);
2146  LibUtilities::BasisKey BkeyQ2(LibUtilities::eOrtho_A, num_modes1, PkeyQ2);
2147  SpatialDomains::QuadGeomSharedPtr qGeom = boost::dynamic_pointer_cast<SpatialDomains::QuadGeom>((*m_exp)[eid]->GetGeom());
2148  ppExp = MemoryManager<LocalRegions::QuadExp>::AllocateSharedPtr(BkeyQ1, BkeyQ2, qGeom);
2149  }
2150  break;
2152  {
2155  LibUtilities::BasisKey BkeyT1(LibUtilities::eOrtho_A, num_modes0, PkeyT1);
2156  LibUtilities::BasisKey BkeyT2(LibUtilities::eOrtho_B, num_modes1, PkeyT2);
2157  SpatialDomains::TriGeomSharedPtr tGeom = boost::dynamic_pointer_cast<SpatialDomains::TriGeom>((*m_exp)[eid]->GetGeom());
2158  ppExp = MemoryManager<LocalRegions::TriExp>::AllocateSharedPtr(BkeyT1, BkeyT2, tGeom);
2159  }
2160  break;
2161  default:
2162  ASSERTL0(false, "Wrong shape type, HDG postprocessing is not implemented");
2163  };
2164 
2165 
2166  //DGDeriv
2167  // (d/dx w, d/dx q_0)
2168  (*m_exp)[eid]->DGDeriv(
2169  0,tmp_coeffs = m_coeffs + m_coeff_offset[eid],
2170  elmtToTrace[eid], edgeCoeffs, out_tmp);
2171  (*m_exp)[eid]->BwdTrans(out_tmp,qrhs);
2172  //(*m_exp)[eid]->IProductWRTDerivBase(0,qrhs,force);
2173  ppExp->IProductWRTDerivBase(0,qrhs,force);
2174 
2175 
2176  // + (d/dy w, d/dy q_1)
2177  (*m_exp)[eid]->DGDeriv(
2178  1,tmp_coeffs = m_coeffs + m_coeff_offset[eid],
2179  elmtToTrace[eid], edgeCoeffs, out_tmp);
2180 
2181  (*m_exp)[eid]->BwdTrans(out_tmp,qrhs);
2182  //(*m_exp)[eid]->IProductWRTDerivBase(1,qrhs,out_tmp);
2183  ppExp->IProductWRTDerivBase(1,qrhs,out_tmp);
2184 
2185  Vmath::Vadd(nm_elmt,force,1,out_tmp,1,force,1);
2186 
2187  // determine force[0] = (1,u)
2188  (*m_exp)[eid]->BwdTrans(
2189  tmp_coeffs = m_coeffs + m_coeff_offset[eid],qrhs);
2190  force[0] = (*m_exp)[eid]->Integral(qrhs);
2191 
2192  // multiply by inverse Laplacian matrix
2193  // get matrix inverse
2194  LocalRegions::MatrixKey lapkey(StdRegions::eInvLaplacianWithUnityMean, ppExp->DetShapeType(), *ppExp);
2195  DNekScalMatSharedPtr lapsys = ppExp->GetLocMatrix(lapkey);
2196 
2197  NekVector<NekDouble> in (nm_elmt,force,eWrapper);
2198  NekVector<NekDouble> out(nm_elmt);
2199 
2200  out = (*lapsys)*in;
2201 
2202  // Transforming back to modified basis
2203  Array<OneD, NekDouble> work(nq_elmt);
2204  ppExp->BwdTrans(out.GetPtr(), work);
2205  (*m_exp)[eid]->FwdTrans(work, tmp_coeffs = outarray + m_coeff_offset[eid]);
2206  }
2207  }
2208 
2209  /**
2210  * Evaluates the boundary condition expansions, \a bndCondExpansions,
2211  * given the information provided by \a bndConditions.
2212  * @param time The time at which the boundary conditions
2213  * should be evaluated.
2214  * @param bndCondExpansions List of boundary conditions.
2215  * @param bndConditions Information about the boundary conditions.
2216  *
2217  * This will only be undertaken for time dependent
2218  * boundary conditions unless time == 0.0 which is the
2219  * case when the method is called from the constructor.
2220  */
2222  const NekDouble time,
2223  const std::string varName,
2224  const NekDouble x2_in,
2225  const NekDouble x3_in)
2226  {
2227  int i;
2228  int npoints;
2229  int nbnd = m_bndCondExpansions.num_elements();
2230 
2231  MultiRegions::ExpListSharedPtr locExpList;
2232 
2233  for (i = 0; i < nbnd; ++i)
2234  {
2235  if (time == 0.0 ||
2236  m_bndConditions[i]->IsTimeDependent())
2237  {
2238  locExpList = m_bndCondExpansions[i];
2239  npoints = locExpList->GetNpoints();
2240  Array<OneD, NekDouble> x0(npoints, 0.0);
2241  Array<OneD, NekDouble> x1(npoints, 0.0);
2242  Array<OneD, NekDouble> x2(npoints, 0.0);
2243 
2244  // Homogeneous input case for x2.
2245  if (x2_in == NekConstants::kNekUnsetDouble)
2246  {
2247  locExpList->GetCoords(x0, x1, x2);
2248  }
2249  else
2250  {
2251  locExpList->GetCoords(x0, x1, x2);
2252  Vmath::Fill(npoints, x2_in, x2, 1);
2253  }
2254 
2255  if (m_bndConditions[i]->GetBoundaryConditionType()
2257  {
2258  string filebcs = boost::static_pointer_cast<
2260  m_bndConditions[i])->m_filename;
2261 
2262  if (filebcs != "")
2263  {
2264  ExtractFileBCs(filebcs, varName, locExpList);
2265  }
2266  else
2267  {
2268  LibUtilities::Equation condition =
2269  boost::static_pointer_cast<
2271  (m_bndConditions[i])->
2272  m_dirichletCondition;
2273 
2274  condition.Evaluate(x0, x1, x2, time,
2275  locExpList->UpdatePhys());
2276  }
2277 
2278  locExpList->FwdTrans_BndConstrained(
2279  locExpList->GetPhys(),
2280  locExpList->UpdateCoeffs());
2281  }
2282  else if (m_bndConditions[i]->GetBoundaryConditionType()
2284  {
2285  string filebcs = boost::static_pointer_cast<
2287  m_bndConditions[i])->m_filename;
2288 
2289  if (filebcs != "")
2290  {
2291  ExtractFileBCs(filebcs, varName, locExpList);
2292  }
2293  else
2294  {
2295  LibUtilities::Equation condition =
2296  boost::static_pointer_cast<
2298  (m_bndConditions[i])->
2299  m_neumannCondition;
2300  condition.Evaluate(x0, x1, x2, time,
2301  locExpList->UpdatePhys());
2302  }
2303 
2304  locExpList->IProductWRTBase(
2305  locExpList->GetPhys(),
2306  locExpList->UpdateCoeffs());
2307  }
2308  else if (m_bndConditions[i]->GetBoundaryConditionType()
2310  {
2311  string filebcs = boost::static_pointer_cast<
2313  (m_bndConditions[i])->m_filename;
2314 
2315  if (filebcs != "")
2316  {
2317  ExtractFileBCs(filebcs, varName, locExpList);
2318  }
2319  else
2320  {
2321  LibUtilities::Equation condition =
2322  boost::static_pointer_cast<
2324  (m_bndConditions[i])->
2325  m_robinFunction;
2326  condition.Evaluate(x0, x1, x2, time,
2327  locExpList->UpdatePhys());
2328  }
2329 
2330  LibUtilities::Equation coeff =
2331  boost::static_pointer_cast<
2333  m_bndConditions[i])->m_robinPrimitiveCoeff;
2334  locExpList->IProductWRTBase(
2335  locExpList->GetPhys(),
2336  locExpList->UpdateCoeffs());
2337 
2338  // put primitive coefficient into the physical
2339  // space storage
2340  coeff.Evaluate(x0, x1, x2, time,
2341  locExpList->UpdatePhys());
2342  }
2343  else
2344  {
2345  ASSERTL0(false, "This type of BC not implemented yet");
2346  }
2347  }
2348  else if (boost::iequals(m_bndConditions[i]->GetUserDefined(),
2349  "MovingBody"))
2350  {
2351  locExpList = m_bndCondExpansions[i];
2352  if (m_bndConditions[i]->GetBoundaryConditionType()
2354  {
2355  locExpList->FwdTrans_IterPerExp(
2356  locExpList->GetPhys(),
2357  locExpList->UpdateCoeffs());
2358  }
2359  else
2360  {
2361  ASSERTL0(false, "This type of BC not implemented yet");
2362  }
2363  }
2364  }
2365  }
2366  } // end of namespace
2367 } //end of namespace
GlobalSysSolnType GetGlobalSysSolnType() const
Return the associated solution type.
const DNekScalBlkMatSharedPtr & GetBlockMatrix(const GlobalMatrixKey &gkey)
Definition: ExpList.cpp:812
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
virtual void v_ExtractTracePhys(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
This method extracts the trace (edges in 2D) from the field inarray and puts the values in outarray...
#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
void FindPeriodicEdges(const SpatialDomains::BoundaryConditions &bcs, const std::string &variable)
Determine the periodic edges and vertices for the given graph.
virtual void v_AddTraceIntegral(const Array< OneD, const NekDouble > &Fx, const Array< OneD, const NekDouble > &Fy, Array< OneD, NekDouble > &outarray)
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
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
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
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
vector< int > m_periodicFwdCopy
A vector indicating degress of freedom which need to be copied from forwards to backwards space in ca...
void Fill(int n, const T alpha, T *x, const int incx)
Fill a vector with a constant value.
Definition: Vmath.cpp:46
boost::shared_ptr< RobinBCInfo > RobinBCInfoSharedPtr
boost::shared_ptr< QuadGeom > QuadGeomSharedPtr
Definition: QuadGeom.h:54
const boost::shared_ptr< LocalRegions::ExpansionVector > GetExp() const
This function returns the vector of elements in the expansion.
Definition: ExpList.h:1917
GlobalLinSysSharedPtr GetGlobalBndLinSys(const GlobalLinSysKey &mkey)
Lagrange Polynomials using the Gauss points .
Definition: BasisType.h:54
virtual void v_GetBndElmtExpansion(int i, boost::shared_ptr< ExpList > &result)
PeriodicMap m_periodicEdges
A map which identifies pairs of periodic edges.
void BwdTrans(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, CoeffState coeffstate=eLocal)
Definition: ExpList.h:1609
std::map< int, std::vector< unsigned int > > BndRegionOrdering
Definition: MeshPartition.h:54
std::map< ConstFactorType, NekDouble > ConstFactorMap
Definition: StdRegions.hpp:251
PeriodicMap m_periodicVerts
A map which identifies groups of periodic vertices.
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
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.
std::map< int, std::vector< unsigned int > > CompositeOrdering
Definition: MeshPartition.h:53
Array< OneD, NekDouble > m_coeffs
Concatenation of all local expansion coefficients.
Definition: ExpList.h:939
boost::shared_ptr< MeshGraph2D > MeshGraph2DSharedPtr
Definition: MeshGraph2D.h:238
int GetExpSize(void)
This function returns the number of elements in the expansion.
Definition: ExpList.h:1896
boost::shared_ptr< SessionReader > SessionReaderSharedPtr
Definition: MeshPartition.h:51
virtual map< int, RobinBCInfoSharedPtr > v_GetRobinBCInfo()
Search through the edge expansions and identify which ones have Robin/Mixed type boundary conditions...
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
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)
Principle Orthogonal Functions .
Definition: BasisType.h:47
bool SameTypeOfBoundaryConditions(const DisContField2D &In)
Array< OneD, int > m_coeff_offset
Offset of elemental data into the array m_coeffs.
Definition: ExpList.h:988
Base class for all multi-elemental spectral/hp expansions.
Definition: ExpList.h:101
boost::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition: Comm.h:53
DisContField2D()
Default constructor.
The base class for all shapes.
Definition: StdExpansion.h:69
boost::shared_ptr< ExpList > & GetTrace()
Definition: ExpList.h:2001
LocTraceToTraceMapSharedPtr m_locTraceToTraceMap
Array< OneD, MultiRegions::ExpListSharedPtr > m_bndCondExpansions
An object which contains the discretised boundary conditions.
boost::shared_ptr< LocalRegions::ExpansionVector > m_exp
The list of local expansions.
Definition: ExpList.h:977
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)
boost::shared_ptr< ExpList1D > ExpList1DSharedPtr
Shared pointer to an ExpList1D object.
Definition: ExpList1D.h:50
virtual ~DisContField2D()
Default destructor.
std::map< StdRegions::VarCoeffType, Array< OneD, NekDouble > > VarCoeffMap
Definition: StdRegions.hpp:226
boost::shared_ptr< SegGeom > SegGeomSharedPtr
Definition: Geometry2D.h:60
std::set< int > m_boundaryEdges
A set storing the global IDs of any boundary edges.
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:46
NekMatrix< InnerMatrixType, BlockMatrixTag > Transpose(NekMatrix< InnerMatrixType, BlockMatrixTag > &rhs)
SpatialDomains::MeshGraphSharedPtr m_graph
Mesh associated with this expansion list.
Definition: ExpList.h:913
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
boost::shared_ptr< Expansion > ExpansionSharedPtr
Definition: Expansion.h:68
Defines a list of flags.
std::map< int, BoundaryConditionMapShPtr > BoundaryConditionCollection
Definition: Conditions.h:215
Array< OneD, SpatialDomains::BoundaryConditionShPtr > m_bndConditions
An array which contains the information about the boundary condition on the different boundary region...
boost::shared_ptr< GeometryVector > Composite
Definition: MeshGraph.h:114
bool IsLeftAdjacentEdge(const int n, const int e)
virtual void v_Reset()
Reset this field, so that geometry information can be updated.
static const NekDouble kNekUnsetDouble
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
void SetUpDG(const std::string="DefaultVar")
Set up all DG member variables and maps.
boost::shared_ptr< Geometry2D > Geometry2DSharedPtr
Definition: Geometry2D.h:59
void Vsub(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Subtract vector z = x-y.
Definition: Vmath.cpp:329
boost::shared_ptr< ElementEdgeVector > ElementEdgeVectorSharedPtr
Definition: MeshGraph.h:134
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
2D geometry information
Definition: Geometry2D.h:65
#define ASSERTL2(condition, msg)
Assert Level 2 – Debugging which is used FULLDEBUG compilation mode. This level assert is designed t...
Definition: ErrorUtil.hpp:213
void IProductWRTBase(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, CoeffState coeffstate=eLocal)
Definition: ExpList.h:1559
Abstraction of a two-dimensional multi-elemental expansion which is merely a collection of local expa...
Definition: ExpList2D.h:60
int GetNcoeffs(void) const
Returns the total number of local degrees of freedom .
Definition: ExpList.h:1403
virtual void v_GetFwdBwdTracePhys(const Array< OneD, const NekDouble > &field, 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...
boost::shared_ptr< TriGeom > TriGeomSharedPtr
Definition: TriGeom.h:58
void EvaluateHDGPostProcessing(Array< OneD, NekDouble > &outarray)
Evaluate HDG post-processing to increase polynomial order of solution.
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
const BoundaryRegionCollection & GetBoundaryRegions(void) const
Definition: Conditions.h:227
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...
boost::shared_ptr< BoundaryConditionBase > BoundaryConditionShPtr
Definition: Conditions.h:208
boost::shared_ptr< Basis > BasisSharedPtr
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
void GenerateBoundaryConditionExpansion(const SpatialDomains::MeshGraphSharedPtr &graph2D, const SpatialDomains::BoundaryConditions &bcs, const std::string &variable, const bool DeclareCoeffPhysArrays=true)
This function discretises the boundary conditions by setting up a list of one-dimensional boundary ex...
virtual void v_GetBoundaryToElmtMap(Array< OneD, int > &ElmtID, Array< OneD, int > &EdgeID)
Set up a list of element IDs and edge IDs that link to the boundary conditions.
#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
boost::shared_ptr< Expansion1D > Expansion1DSharedPtr
Definition: Expansion1D.h:53
NekDouble L2(const Array< OneD, const NekDouble > &inarray, const Array< OneD, const NekDouble > &soln=NullNekDouble1DArray)
This function calculates the error with respect to soln of the global spectral/hp element approximat...
Definition: ExpList.h:477
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.cpp:1047
NekDouble L2_DGDeriv(const int dir, const Array< OneD, const NekDouble > &soln)
Calculate the error of the derivative using the consistent DG evaluation of .
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
boost::shared_ptr< Expansion2D > Expansion2DSharedPtr
Definition: Expansion1D.h:49