Nektar++
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 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 //
31 // Description: Field definition for 2D domain with boundary conditions using
32 // LDG flux.
33 //
34 ///////////////////////////////////////////////////////////////////////////////
35 
36 #include <boost/core/ignore_unused.hpp>
37 
39 #include <LocalRegions/MatrixKey.h>
41 #include <LocalRegions/Expansion.h>
42 #include <LocalRegions/QuadExp.h>
43 #include <LocalRegions/TriExp.h>
47 
48 #include <boost/algorithm/string/predicate.hpp>
49 
50 using namespace std;
51 
52 namespace Nektar
53 {
54  namespace MultiRegions
55  {
56  /**
57  * @class DisContField2D
58  * Abstraction of a global discontinuous two-dimensional spectral/hp
59  * element expansion which approximates the solution of a set of
60  * partial differential equations.
61  */
62 
63  /**
64  * @brief Default constructor.
65  */
66  DisContField2D::DisContField2D(void)
67  : ExpList2D (),
68  m_bndCondExpansions(),
69  m_bndConditions (),
70  m_trace (NullExpListSharedPtr)
71  {
72  }
73 
75  const DisContField2D &In,
76  const bool DeclareCoeffPhysArrays)
77  : ExpList2D (In,DeclareCoeffPhysArrays),
89  {
90  if (In.m_trace)
91  {
93  *std::dynamic_pointer_cast<ExpList1D>(In.m_trace),
94  DeclareCoeffPhysArrays);
95  }
96  }
97 
98  /**
99  * @brief Constructs a global discontinuous field based on an input
100  * mesh with boundary conditions.
101  */
103  const LibUtilities::SessionReaderSharedPtr &pSession,
104  const SpatialDomains::MeshGraphSharedPtr &graph2D,
105  const std::string &variable,
106  const bool SetUpJustDG,
107  const bool DeclareCoeffPhysArrays,
108  const Collections::ImplementationType ImpType)
109  : ExpList2D(pSession, graph2D, DeclareCoeffPhysArrays, variable,
110  ImpType),
112  m_bndConditions(),
114  m_periodicVerts(),
115  m_periodicEdges(),
118  {
119 
120  if (variable.compare("DefaultVar") != 0) // do not set up BCs if default variable
121  {
123  GenerateBoundaryConditionExpansion(graph2D, bcs, variable,
124  DeclareCoeffPhysArrays);
125 
126  if (DeclareCoeffPhysArrays)
127  {
128  EvaluateBoundaryConditions(0.0, variable);
129  }
130 
131  // Find periodic edges for this variable.
132  FindPeriodicEdges(bcs, variable);
133  }
134 
135  if (SetUpJustDG)
136  {
137  SetUpDG(variable);
138  }
139  else
140  {
141  // Set element edges to point to Robin BC edges if required.
142  int i, cnt;
143  Array<OneD, int> ElmtID, EdgeID;
144  GetBoundaryToElmtMap(ElmtID, EdgeID);
145 
146  for(cnt = i = 0; i < m_bndCondExpansions.num_elements(); ++i)
147  {
149  int e;
150  locExpList = m_bndCondExpansions[i];
151 
152  for(e = 0; e < locExpList->GetExpSize(); ++e)
153  {
155  (*m_exp)[ElmtID[cnt+e]]->
156  as<LocalRegions::Expansion2D>();
158  locExpList->GetExp(e)->
159  as<LocalRegions::Expansion1D>();
161  locExpList->GetExp(e)->
162  as<LocalRegions::Expansion> ();
163 
164  exp2d->SetEdgeExp(EdgeID[cnt+e], exp1d);
165  exp1d->SetAdjacentElementExp(EdgeID[cnt+e], exp2d);
166  }
167  cnt += m_bndCondExpansions[i]->GetExpSize();
168  }
169 
170  if(m_session->DefinesSolverInfo("PROJECTION"))
171  {
172  std::string ProjectStr =
173  m_session->GetSolverInfo("PROJECTION");
174  if((ProjectStr == "MixedCGDG") ||
175  (ProjectStr == "Mixed_CG_Discontinuous"))
176  {
177  SetUpDG();
178  }
179  else
180  {
182  }
183  }
184  else
185  {
187  }
188  }
189  }
190 
191 
192  /*
193  * @brief Copy type constructor which declares new boundary conditions
194  * and re-uses mapping info and trace space if possible
195  */
197  const DisContField2D &In,
198  const SpatialDomains::MeshGraphSharedPtr &graph2D,
199  const std::string &variable,
200  const bool SetUpJustDG,
201  const bool DeclareCoeffPhysArrays):
202  ExpList2D(In,DeclareCoeffPhysArrays),
204  {
205  // Set up boundary conditions for this variable.
206  // Do not set up BCs if default variable
207  if(variable.compare("DefaultVar") != 0)
208  {
210  GenerateBoundaryConditionExpansion(graph2D, bcs, variable);
211 
212  if (DeclareCoeffPhysArrays)
213  {
214  EvaluateBoundaryConditions(0.0, variable);
215  }
216 
218  {
219  // Find periodic edges for this variable.
220  FindPeriodicEdges(bcs, variable);
221 
222  if(SetUpJustDG)
223  {
224  SetUpDG();
225  }
226  else
227  {
228  // set elmt edges to point to robin bc edges if required
229  int i, cnt = 0;
230  Array<OneD, int> ElmtID,EdgeID;
231  GetBoundaryToElmtMap(ElmtID,EdgeID);
232 
233  for (i = 0; i < m_bndCondExpansions.num_elements(); ++i)
234  {
236 
237  int e;
238  locExpList = m_bndCondExpansions[i];
239 
240  for(e = 0; e < locExpList->GetExpSize(); ++e)
241  {
243  = (*m_exp)[ElmtID[cnt+e]]->
244  as<LocalRegions::Expansion2D>();
246  = locExpList->GetExp(e)->
247  as<LocalRegions::Expansion1D>();
249  = locExpList->GetExp(e)->
250  as<LocalRegions::Expansion> ();
251 
252  exp2d->SetEdgeExp(EdgeID[cnt+e], exp1d);
253  exp1d->SetAdjacentElementExp(EdgeID[cnt+e],
254  exp2d);
255  }
256 
257  cnt += m_bndCondExpansions[i]->GetExpSize();
258  }
259 
260 
261  if (m_session->DefinesSolverInfo("PROJECTION"))
262  {
263  std::string ProjectStr =
264  m_session->GetSolverInfo("PROJECTION");
265 
266  if ((ProjectStr == "MixedCGDG") ||
267  (ProjectStr == "Mixed_CG_Discontinuous"))
268  {
269  SetUpDG();
270  }
271  else
272  {
274  }
275  }
276  else
277  {
279  }
280  }
281  }
282  else
283  {
284  if (SetUpJustDG)
285  {
287  m_trace = In.m_trace;
288  m_traceMap = In.m_traceMap;
296  }
297  else
298  {
300  m_trace = In.m_trace;
301  m_traceMap = In.m_traceMap;
309 
310  // set elmt edges to point to robin bc edges if required
311  int i, cnt = 0;
312  Array<OneD, int> ElmtID, EdgeID;
313  GetBoundaryToElmtMap(ElmtID, EdgeID);
314 
315  for (i = 0; i < m_bndCondExpansions.num_elements(); ++i)
316  {
318 
319  int e;
320  locExpList = m_bndCondExpansions[i];
321 
322  for (e = 0; e < locExpList->GetExpSize(); ++e)
323  {
325  = (*m_exp)[ElmtID[cnt+e]]->
326  as<LocalRegions::Expansion2D>();
328  = locExpList->GetExp(e)->
329  as<LocalRegions::Expansion1D>();
331  = locExpList->GetExp(e)->
332  as<LocalRegions::Expansion> ();
333 
334  exp2d->SetEdgeExp(EdgeID[cnt+e], exp1d);
335  exp1d->SetAdjacentElementExp(EdgeID[cnt+e],
336  exp2d);
337  }
338  cnt += m_bndCondExpansions[i]->GetExpSize();
339  }
340 
342  }
343  }
344  }
345  }
346 
347  /**
348  * @brief Default destructor.
349  */
351  {
352  }
353 
355  const GlobalLinSysKey &mkey)
356  {
358  "Routine currently only tested for HybridDGHelmholtz");
359  ASSERTL1(mkey.GetGlobalSysSolnType() ==
360  m_traceMap->GetGlobalSysSolnType(),
361  "The local to global map is not set up for the requested "
362  "solution type");
363 
364  GlobalLinSysSharedPtr glo_matrix;
365  auto matrixIter = m_globalBndMat->find(mkey);
366 
367  if(matrixIter == m_globalBndMat->end())
368  {
369  glo_matrix = GenGlobalBndLinSys(mkey,m_traceMap);
370  (*m_globalBndMat)[mkey] = glo_matrix;
371  }
372  else
373  {
374  glo_matrix = matrixIter->second;
375  }
376 
377  return glo_matrix;
378  }
379 
380  /**
381  * @brief Set up all DG member variables and maps.
382  */
383  void DisContField2D::SetUpDG(const std::string variable)
384  {
385  // Check for multiple calls
387  {
388  return;
389  }
390 
391  ExpList1DSharedPtr trace;
392 
393  // Set up matrix map
396 
397  // Set up trace space
401 
402  m_trace = std::dynamic_pointer_cast<ExpList>(trace);
404  AllocateSharedPtr(m_session, m_graph, trace, *this,
407  variable);
408 
409  if (m_session->DefinesCmdLineArgument("verbose"))
410  {
411  m_traceMap->PrintStats(std::cout, variable);
412  }
413 
415  &elmtToTrace = m_traceMap->GetElmtToTrace();
416 
417  // Scatter trace segments to 2D elements. For each element,
418  // we find the trace segment associated to each edge. The
419  // element then retains a pointer to the trace space segments,
420  // to ensure uniqueness of normals when retrieving from two
421  //adjoining elements which do not lie in a plane.
422  for (int i = 0; i < m_exp->size(); ++i)
423  {
424  for (int j = 0; j < (*m_exp)[i]->GetNedges(); ++j)
425  {
427  (*m_exp)[i]->as<LocalRegions::Expansion2D>();
429  elmtToTrace[i][j]->as<LocalRegions::Expansion1D>();
430  LocalRegions::ExpansionSharedPtr exp = elmtToTrace[i][j];;
431  exp2d->SetEdgeExp (j, exp1d);
432  exp1d->SetAdjacentElementExp(j, exp2d);
433  }
434  }
435 
436  // Set up physical normals
438 
439  // Set up information for parallel and periodic problems.
440  for (int i = 0; i < m_trace->GetExpSize(); ++i)
441  {
443  m_trace->GetExp(i)->as<LocalRegions::Expansion1D>();
444 
445  int offset = m_trace->GetPhys_Offset(i);
446  int traceGeomId = traceEl->GetGeom1D()->GetGlobalID();
447  auto pIt = m_periodicEdges.find(traceGeomId);
448 
449  if (pIt != m_periodicEdges.end() && !pIt->second[0].isLocal)
450  {
451  if (traceGeomId != min(pIt->second[0].id, traceGeomId))
452  {
453  traceEl->GetLeftAdjacentElementExp()->NegateEdgeNormal(
454  traceEl->GetLeftAdjacentElementEdge());
455  }
456  }
457  else if (m_traceMap->GetTraceToUniversalMapUnique(offset) < 0)
458  {
459  traceEl->GetLeftAdjacentElementExp()->NegateEdgeNormal(
460  traceEl->GetLeftAdjacentElementEdge());
461  }
462  }
463 
464  int cnt, n, e;
465 
466  // Identify boundary edges
467  for (cnt = 0, n = 0; n < m_bndCondExpansions.num_elements(); ++n)
468  {
469  if (m_bndConditions[n]->GetBoundaryConditionType() !=
471  {
472  for (e = 0; e < m_bndCondExpansions[n]->GetExpSize(); ++e)
473  {
474  m_boundaryEdges.insert(
475  m_traceMap->GetBndCondTraceToGlobalTraceMap(cnt+e));
476  }
477  cnt += m_bndCondExpansions[n]->GetExpSize();
478  }
479  }
480 
481  // Set up information for periodic boundary conditions.
482  std::unordered_map<int,pair<int,int> > perEdgeToExpMap;
483  for (cnt = n = 0; n < m_exp->size(); ++n)
484  {
485  for (e = 0; e < (*m_exp)[n]->GetNedges(); ++e, ++cnt)
486  {
487  auto it = m_periodicEdges.find(
488  (*m_exp)[n]->GetGeom()->GetEid(e));
489 
490  if (it != m_periodicEdges.end())
491  {
492  perEdgeToExpMap[it->first] = make_pair(n, e);
493  }
494  }
495  }
496 
497  // Set up left-adjacent edge list.
498  m_leftAdjacentEdges.resize(cnt);
499  cnt = 0;
500  for (int i = 0; i < m_exp->size(); ++i)
501  {
502  for (int j = 0; j < (*m_exp)[i]->GetNedges(); ++j, ++cnt)
503  {
505  }
506  }
507 
508  // Set up mapping to copy Fwd of periodic bcs to Bwd of other edge.
509  cnt = 0;
510  for (int n = 0; n < m_exp->size(); ++n)
511  {
512  for (int e = 0; e < (*m_exp)[n]->GetNedges(); ++e, ++cnt)
513  {
514  int edgeGeomId = (*m_exp)[n]->GetGeom()->GetEid(e);
515  int offset = m_trace->GetPhys_Offset(
516  elmtToTrace[n][e]->GetElmtId());
517 
518  // Check to see if this face is periodic.
519  auto it = m_periodicEdges.find(edgeGeomId);
520 
521  if (it != m_periodicEdges.end())
522  {
523  const PeriodicEntity &ent = it->second[0];
524  auto it2 = perEdgeToExpMap.find(ent.id);
525 
526  if (it2 == perEdgeToExpMap.end())
527  {
528  if (m_session->GetComm()->
529  GetRowComm()->GetSize() > 1 && !ent.isLocal)
530  {
531  continue;
532  }
533  else
534  {
535  ASSERTL1(false, "Periodic edge not found!");
536  }
537  }
538 
540  "Periodic edge in non-forward space?");
541 
542  int offset2 = m_trace->GetPhys_Offset(
543  elmtToTrace[it2->second.first][it2->second.second]->
544  GetElmtId());
545 
546  // Calculate relative orientations between edges to
547  // calculate copying map.
548  int nquad = elmtToTrace[n][e]->GetNumPoints(0);
549 
550  vector<int> tmpBwd(nquad);
551  vector<int> tmpFwd(nquad);
552 
553  if (ent.orient == StdRegions::eForwards)
554  {
555  for (int i = 0; i < nquad; ++i)
556  {
557  tmpBwd[i] = offset2 + i;
558  tmpFwd[i] = offset + i;
559  }
560  }
561  else
562  {
563  for (int i = 0; i < nquad; ++i)
564  {
565  tmpBwd[i] = offset2 + i;
566  tmpFwd[i] = offset + nquad - i - 1;
567  }
568  }
569 
570  for (int i = 0; i < nquad; ++i)
571  {
572  m_periodicFwdCopy.push_back(tmpFwd[i]);
573  m_periodicBwdCopy.push_back(tmpBwd[i]);
574  }
575  }
576  }
577  }
578 
580  AllocateSharedPtr(*this, m_trace, elmtToTrace,
582  }
583 
584  /**
585  * For each boundary region, checks that the types and number of
586  * boundary expansions in that region match.
587  * @param In ContField2D to compare with.
588  * @return True if boundary conditions match.
589  */
591  const DisContField2D &In)
592  {
593  int i;
594  bool returnval = true;
595 
596  for(i = 0; i < m_bndConditions.num_elements(); ++i)
597  {
598 
599  // check to see if boundary condition type is the same
600  // and there are the same number of boundary
601  // conditions in the boundary definition.
602  if((m_bndConditions[i]->GetBoundaryConditionType()
603  != In.m_bndConditions[i]->GetBoundaryConditionType())||
605  != In.m_bndCondExpansions[i]->GetExpSize()))
606  {
607  returnval = false;
608  break;
609  }
610  }
611 
612  // Compare with all other processes. Return true only if all
613  // processes report having the same boundary conditions.
614  int vSame = (returnval?1:0);
615  m_comm->GetRowComm()->AllReduce(vSame, LibUtilities::ReduceMin);
616 
617  return (vSame == 1);
618  }
619 
620  /**
621  * \brief This function discretises the boundary conditions by setting
622  * up a list of one-dimensional boundary expansions.
623  *
624  * According to their boundary region, the separate segmental boundary
625  * expansions are bundled together in an object of the class
626  * MultiRegions#ExpList1D.
627  *
628  * \param graph2D A mesh, containing information about the domain and
629  * the spectral/hp element expansion.
630  * \param bcs An entity containing information about the
631  * boundaries and boundary conditions.
632  * \param variable An optional parameter to indicate for which variable
633  * the boundary conditions should be discretised.
634  */
636  const SpatialDomains::MeshGraphSharedPtr &graph2D,
638  const std::string &variable,
639  const bool DeclareCoeffPhysArrays)
640  {
641  int cnt = 0;
645  bcs.GetBoundaryRegions();
647  bcs.GetBoundaryConditions();
648 
653 
654  for (auto &it : bregions)
655  {
656  bc = GetBoundaryCondition(bconditions, it.first, variable);
657 
659  ::AllocateSharedPtr(m_session, *(it.second), graph2D,
660  DeclareCoeffPhysArrays, variable,
661  bc->GetComm());
662 
663  m_bndCondExpansions[cnt] = locExpList;
664  m_bndConditions[cnt] = bc;
665 
666  std::string type = m_bndConditions[cnt]->GetUserDefined();
667 
668  // Set up normals on non-Dirichlet boundary conditions. Second
669  // two conditions ideally should be in local solver setup (when
670  // made into factory)
671  if(bc->GetBoundaryConditionType() != SpatialDomains::eDirichlet
672  || boost::iequals(type,"I") || boost::iequals(type,"CalcBC"))
673  {
675  }
676 
677  cnt++;
678  }
679  }
680 
681  /**
682  * @brief Determine the periodic edges and vertices for the given graph.
683  *
684  * Note that much of this routine is the same as the three-dimensional
685  * version, which therefore has much better documentation.
686  *
687  * @param bcs Information about the boundary conditions.
688  * @param variable Specifies the field.
689  *
690  * @see DisContField3D::FindPeriodicFaces
691  */
694  const std::string &variable)
695  {
697  = bcs.GetBoundaryRegions();
699  = bcs.GetBoundaryConditions();
700 
702  m_session->GetComm()->GetRowComm();
704  m_graph->GetCompositeOrdering();
706  m_graph->GetBndRegionOrdering();
708  m_graph->GetComposites();
709 
710  // Unique collection of pairs of periodic composites (i.e. if
711  // composites 1 and 2 are periodic then this map will contain either
712  // the pair (1,2) or (2,1) but not both).
713  map<int,int> perComps;
714  map<int,vector<int>> allVerts;
715  set<int> locVerts;
716  map<int, pair<int, StdRegions::Orientation>> allEdges;
717 
718  int region1ID, region2ID, i, j, k, cnt;
720 
721  // Set up a set of all local verts and edges.
722  for(i = 0; i < (*m_exp).size(); ++i)
723  {
724  for(j = 0; j < (*m_exp)[i]->GetNverts(); ++j)
725  {
726  int id = (*m_exp)[i]->GetGeom()->GetVid(j);
727  locVerts.insert(id);
728  }
729  }
730 
731  // Construct list of all periodic pairs local to this process.
732  for (auto &it : bregions)
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 = std::static_pointer_cast<
747  locBCond)->m_connectedBoundaryRegion;
748 
749  // From this identify composites. Note that in serial this will
750  // be an empty map.
751  int cId1, cId2;
752  if (vComm->GetSize() == 1)
753  {
754  cId1 = it.second->begin()->first;
755  cId2 = bregions.find(region2ID)->second->begin()->first;
756  }
757  else
758  {
759  cId1 = bndRegOrder.find(region1ID)->second[0];
760  cId2 = bndRegOrder.find(region2ID)->second[0];
761  }
762 
763  ASSERTL0(it.second->size() == 1,
764  "Boundary region "+boost::lexical_cast<string>(
765  region1ID)+" should only contain 1 composite.");
766 
767  // Construct set containing all periodic edges on this process
768  SpatialDomains::CompositeSharedPtr c = it.second->begin()->second;
769 
770  vector<unsigned int> tmpOrder;
771 
772  for (i = 0; i < c->m_geomVec.size(); ++i)
773  {
775  std::dynamic_pointer_cast<
776  SpatialDomains::SegGeom>(c->m_geomVec[i]);
777  ASSERTL0(segGeom, "Unable to cast to shared ptr");
778 
780  m_graph->GetElementsFromEdge(segGeom);
781  ASSERTL0(elmt->size() == 1,
782  "The periodic boundaries belong to "
783  "more than one element of the mesh");
784 
786  std::dynamic_pointer_cast<SpatialDomains::Geometry2D>(
787  elmt->at(0).first);
788 
789  allEdges[c->m_geomVec[i]->GetGlobalID()] =
790  make_pair(elmt->at(0).second,
791  geom->GetEorient(elmt->at(0).second));
792 
793  // In serial mesh partitioning will not have occurred so
794  // need to fill composite ordering map manually.
795  if (vComm->GetSize() == 1)
796  {
797  tmpOrder.push_back(c->m_geomVec[i]->GetGlobalID());
798  }
799 
800  vector<int> vertList(2);
801  vertList[0] = segGeom->GetVid(0);
802  vertList[1] = segGeom->GetVid(1);
803  allVerts[c->m_geomVec[i]->GetGlobalID()] = vertList;
804  }
805 
806  if (vComm->GetSize() == 1)
807  {
808  compOrder[it.second->begin()->first] = tmpOrder;
809  }
810 
811  // See if we already have either region1 or region2 stored in
812  // perComps map.
813  if (perComps.count(cId1) == 0)
814  {
815  if (perComps.count(cId2) == 0)
816  {
817  perComps[cId1] = cId2;
818  }
819  else
820  {
821  std::stringstream ss;
822  ss << "Boundary region " << cId2 << " should be "
823  << "periodic with " << perComps[cId2] << " but "
824  << "found " << cId1 << " instead!";
825  ASSERTL0(perComps[cId2] == cId1, ss.str());
826  }
827  }
828  else
829  {
830  std::stringstream ss;
831  ss << "Boundary region " << cId1 << " should be "
832  << "periodic with " << perComps[cId1] << " but "
833  << "found " << cId2 << " instead!";
834  ASSERTL0(perComps[cId1] == cId1, ss.str());
835  }
836  }
837 
838  // Process local edge list to obtain relative edge orientations.
839  int n = vComm->GetSize();
840  int p = vComm->GetRank();
841  int totEdges;
842  Array<OneD, int> edgecounts(n,0);
843  Array<OneD, int> edgeoffset(n,0);
844  Array<OneD, int> vertoffset(n,0);
845 
846  edgecounts[p] = allEdges.size();
847  vComm->AllReduce(edgecounts, LibUtilities::ReduceSum);
848 
849  edgeoffset[0] = 0;
850  for (i = 1; i < n; ++i)
851  {
852  edgeoffset[i] = edgeoffset[i-1] + edgecounts[i-1];
853  }
854 
855  totEdges = Vmath::Vsum(n, edgecounts, 1);
856  Array<OneD, int> edgeIds (totEdges, 0);
857  Array<OneD, int> edgeIdx (totEdges, 0);
858  Array<OneD, int> edgeOrient(totEdges, 0);
859  Array<OneD, int> edgeVerts (totEdges, 0);
860 
861  auto sIt = allEdges.begin();
862 
863  for (i = 0; sIt != allEdges.end(); ++sIt)
864  {
865  edgeIds [edgeoffset[p] + i ] = sIt->first;
866  edgeIdx [edgeoffset[p] + i ] = sIt->second.first;
867  edgeOrient[edgeoffset[p] + i ] = sIt->second.second;
868  edgeVerts [edgeoffset[p] + i++] = allVerts[sIt->first].size();
869  }
870 
871  vComm->AllReduce(edgeIds, LibUtilities::ReduceSum);
872  vComm->AllReduce(edgeIdx, LibUtilities::ReduceSum);
873  vComm->AllReduce(edgeOrient, LibUtilities::ReduceSum);
874  vComm->AllReduce(edgeVerts, LibUtilities::ReduceSum);
875 
876  // Calculate number of vertices on each processor.
877  Array<OneD, int> procVerts(n,0);
878  int nTotVerts;
879 
880  // Note if there are no periodic edges at all calling Vsum will
881  // cause a segfault.
882  if (totEdges > 0)
883  {
884  nTotVerts = Vmath::Vsum(totEdges, edgeVerts, 1);
885  }
886  else
887  {
888  nTotVerts = 0;
889  }
890 
891  for (i = 0; i < n; ++i)
892  {
893  if (edgecounts[i] > 0)
894  {
895  procVerts[i] = Vmath::Vsum(
896  edgecounts[i], edgeVerts + edgeoffset[i], 1);
897  }
898  else
899  {
900  procVerts[i] = 0;
901  }
902  }
903  vertoffset[0] = 0;
904 
905  for (i = 1; i < n; ++i)
906  {
907  vertoffset[i] = vertoffset[i-1] + procVerts[i-1];
908  }
909 
910  Array<OneD, int> vertIds(nTotVerts, 0);
911  for (i = 0, sIt = allEdges.begin(); sIt != allEdges.end(); ++sIt)
912  {
913  for (j = 0; j < allVerts[sIt->first].size(); ++j)
914  {
915  vertIds[vertoffset[p] + i++] = allVerts[sIt->first][j];
916  }
917  }
918 
919  vComm->AllReduce(vertIds, LibUtilities::ReduceSum);
920 
921  // For simplicity's sake create a map of edge id -> orientation.
922  map<int, StdRegions::Orientation> orientMap;
923  map<int, vector<int> > vertMap;
924 
925  for (cnt = i = 0; i < totEdges; ++i)
926  {
927  ASSERTL0(orientMap.count(edgeIds[i]) == 0,
928  "Already found edge in orientation map!");
929 
930  // Work out relative orientations. To avoid having to exchange
931  // vertex locations, we figure out if the edges are backwards or
932  // forwards orientated with respect to a forwards orientation
933  // that is CCW. Since our local geometries are
934  // forwards-orientated with respect to the Cartesian axes, we
935  // need to invert the orientation for the top and left edges of
936  // a quad and the left edge of a triangle.
938  (StdRegions::Orientation)edgeOrient[i];
939 
940  if (edgeIdx[i] > 1)
941  {
942  o = o == StdRegions::eForwards ?
944  }
945 
946  orientMap[edgeIds[i]] = o;
947 
948  vector<int> verts(edgeVerts[i]);
949 
950  for (j = 0; j < edgeVerts[i]; ++j)
951  {
952  verts[j] = vertIds[cnt++];
953  }
954  vertMap[edgeIds[i]] = verts;
955  }
956 
957  // Go through list of composites and figure out which edges are
958  // parallel from original ordering in session file. This includes
959  // composites which are not necessarily on this process.
960  map<int,int> allCompPairs;
961 
962  // Store temporary map of periodic vertices which will hold all
963  // periodic vertices on the entire mesh so that doubly periodic
964  // vertices can be counted properly across partitions. Local
965  // vertices are copied into m_periodicVerts at the end of the
966  // function.
967  PeriodicMap periodicVerts;
968 
969  for (auto &cIt : perComps)
970  {
972  const int id1 = cIt.first;
973  const int id2 = cIt.second;
974  std::string id1s = boost::lexical_cast<string>(id1);
975  std::string id2s = boost::lexical_cast<string>(id2);
976 
977  if (compMap.count(id1) > 0)
978  {
979  c[0] = compMap[id1];
980  }
981 
982  if (compMap.count(id2) > 0)
983  {
984  c[1] = compMap[id2];
985  }
986 
987  ASSERTL0(c[0] || c[1],
988  "Both composites not found on this process!");
989 
990  // Loop over composite ordering to construct list of all
991  // periodic edges regardless of whether they are on this
992  // process.
993  map<int,int> compPairs;
994 
995  ASSERTL0(compOrder.count(id1) > 0,
996  "Unable to find composite "+id1s+" in order map.");
997  ASSERTL0(compOrder.count(id2) > 0,
998  "Unable to find composite "+id2s+" in order map.");
999  ASSERTL0(compOrder[id1].size() == compOrder[id2].size(),
1000  "Periodic composites "+id1s+" and "+id2s+
1001  " should have the same number of elements.");
1002  ASSERTL0(compOrder[id1].size() > 0,
1003  "Periodic composites "+id1s+" and "+id2s+
1004  " are empty!");
1005 
1006  // TODO: Add more checks.
1007  for (i = 0; i < compOrder[id1].size(); ++i)
1008  {
1009  int eId1 = compOrder[id1][i];
1010  int eId2 = compOrder[id2][i];
1011 
1012  ASSERTL0(compPairs.count(eId1) == 0,
1013  "Already paired.");
1014 
1015  if (compPairs.count(eId2) != 0)
1016  {
1017  ASSERTL0(compPairs[eId2] == eId1, "Pairing incorrect");
1018  }
1019  compPairs[eId1] = eId2;
1020  }
1021 
1022  // Construct set of all edges that we have locally on this
1023  // processor.
1024  set<int> locEdges;
1025  for (i = 0; i < 2; ++i)
1026  {
1027  if (!c[i])
1028  {
1029  continue;
1030  }
1031 
1032  if (c[i]->m_geomVec.size() > 0)
1033  {
1034  for (j = 0; j < c[i]->m_geomVec.size(); ++j)
1035  {
1036  locEdges.insert(c[i]->m_geomVec[j]->GetGlobalID());
1037  }
1038  }
1039  }
1040 
1041  // Loop over all edges in the geometry composite.
1042  for (auto &pIt : compPairs)
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  if (o == StdRegions::eForwards)
1089  {
1090  tmpMap[perVerts1[0]] = make_pair(
1091  perVerts2[0], locVerts.count(perVerts2[0]) > 0);
1092  tmpMap[perVerts1[1]] = make_pair(
1093  perVerts2[1], locVerts.count(perVerts2[1]) > 0);
1094  }
1095  else
1096  {
1097  tmpMap[perVerts1[0]] = make_pair(
1098  perVerts2[1], locVerts.count(perVerts2[1]) > 0);
1099  tmpMap[perVerts1[1]] = make_pair(
1100  perVerts2[0], locVerts.count(perVerts2[0]) > 0);
1101  }
1102 
1103  for (auto &mIt : tmpMap)
1104  {
1105  // See if this vertex has been recorded already.
1106  PeriodicEntity ent2(mIt.second.first,
1108  mIt.second.second);
1109  auto perIt = periodicVerts.find(mIt.first);
1110 
1111  if (perIt == periodicVerts.end())
1112  {
1113  periodicVerts[mIt.first].push_back(ent2);
1114  perIt = periodicVerts.find(mIt.first);
1115  }
1116  else
1117  {
1118  bool doAdd = true;
1119  for (j = 0; j < perIt->second.size(); ++j)
1120  {
1121  if (perIt->second[j].id == mIt.second.first)
1122  {
1123  doAdd = false;
1124  break;
1125  }
1126  }
1127 
1128  if (doAdd)
1129  {
1130  perIt->second.push_back(ent2);
1131  }
1132  }
1133  }
1134  }
1135  }
1136  }
1137 
1138  Array<OneD, int> pairSizes(n, 0);
1139  pairSizes[p] = allCompPairs.size();
1140  vComm->AllReduce(pairSizes, LibUtilities::ReduceSum);
1141 
1142  int totPairSizes = Vmath::Vsum(n, pairSizes, 1);
1143 
1144  Array<OneD, int> pairOffsets(n, 0);
1145  pairOffsets[0] = 0;
1146 
1147  for (i = 1; i < n; ++i)
1148  {
1149  pairOffsets[i] = pairOffsets[i-1] + pairSizes[i-1];
1150  }
1151 
1152  Array<OneD, int> first (totPairSizes, 0);
1153  Array<OneD, int> second(totPairSizes, 0);
1154 
1155  cnt = pairOffsets[p];
1156 
1157  for (auto &pIt : allCompPairs)
1158  {
1159  first [cnt ] = pIt.first;
1160  second[cnt++] = pIt.second;
1161  }
1162 
1163  vComm->AllReduce(first, LibUtilities::ReduceSum);
1164  vComm->AllReduce(second, LibUtilities::ReduceSum);
1165 
1166  allCompPairs.clear();
1167 
1168  for(cnt = 0; cnt < totPairSizes; ++cnt)
1169  {
1170  allCompPairs[first[cnt]] = second[cnt];
1171  }
1172 
1173  // Search for periodic vertices and edges which are not in
1174  // a periodic composite but lie in this process. First, loop
1175  // over all information we have from other processors.
1176  for (cnt = i = 0; i < totEdges; ++i)
1177  {
1178  int edgeId = edgeIds[i];
1179 
1180  ASSERTL0(allCompPairs.count(edgeId) > 0,
1181  "Unable to find matching periodic edge.");
1182 
1183  int perEdgeId = allCompPairs[edgeId];
1184 
1185  for (j = 0; j < edgeVerts[i]; ++j, ++cnt)
1186  {
1187  int vId = vertIds[cnt];
1188 
1189  auto perId = periodicVerts.find(vId);
1190 
1191  if (perId == periodicVerts.end())
1192  {
1193  // This vertex is not included in the map. Figure
1194  // out which vertex it is supposed to be periodic
1195  // with. perEdgeId is the edge ID which is periodic with
1196  // edgeId. The logic is much the same as the loop above.
1197  int perVertexId =
1198  orientMap[edgeId] == orientMap[perEdgeId] ?
1199  vertMap[perEdgeId][(j+1)%2] : vertMap[perEdgeId][j];
1200 
1201  PeriodicEntity ent(perVertexId,
1203  locVerts.count(perVertexId) > 0);
1204 
1205  periodicVerts[vId].push_back(ent);
1206  }
1207  }
1208  }
1209 
1210  // Loop over all periodic vertices to complete connectivity
1211  // information.
1212  for (auto &perIt : periodicVerts)
1213  {
1214  // Loop over associated vertices.
1215  for (i = 0; i < perIt.second.size(); ++i)
1216  {
1217  auto perIt2 = periodicVerts.find(perIt.second[i].id);
1218  ASSERTL0(perIt2 != periodicVerts.end(),
1219  "Couldn't find periodic vertex.");
1220 
1221  for (j = 0; j < perIt2->second.size(); ++j)
1222  {
1223  if (perIt2->second[j].id == perIt.first)
1224  {
1225  continue;
1226  }
1227 
1228  bool doAdd = true;
1229  for (k = 0; k < perIt.second.size(); ++k)
1230  {
1231  if (perIt2->second[j].id == perIt.second[k].id)
1232  {
1233  doAdd = false;
1234  break;
1235  }
1236  }
1237 
1238  if (doAdd)
1239  {
1240  perIt.second.push_back(perIt2->second[j]);
1241  }
1242  }
1243  }
1244  }
1245 
1246  // Do one final loop over periodic vertices to remove non-local
1247  // vertices from map.
1248  for (auto &perIt : periodicVerts)
1249  {
1250  if (locVerts.count(perIt.first) > 0)
1251  {
1252  m_periodicVerts.insert(perIt);
1253  }
1254  }
1255  }
1256 
1257  bool DisContField2D::IsLeftAdjacentEdge(const int n, const int e)
1258  {
1260  m_traceMap->GetElmtToTrace()[n][e]->
1261  as<LocalRegions::Expansion1D>();
1262 
1263 
1264  bool fwd = true;
1265  if (traceEl->GetLeftAdjacentElementEdge () == -1 ||
1266  traceEl->GetRightAdjacentElementEdge() == -1)
1267  {
1268  // Boundary edge (1 connected element). Do nothing in
1269  // serial.
1270  auto it = m_boundaryEdges.find(traceEl->GetElmtId());
1271 
1272  // If the edge does not have a boundary condition set on
1273  // it, then assume it is a partition edge.
1274  if (it == m_boundaryEdges.end())
1275  {
1276  int traceGeomId = traceEl->GetGeom1D()->GetGlobalID();
1277  auto pIt = m_periodicEdges.find(traceGeomId);
1278 
1279  if (pIt != m_periodicEdges.end() && !pIt->second[0].isLocal)
1280  {
1281  fwd = traceGeomId == min(traceGeomId,pIt->second[0].id);
1282  }
1283  else
1284  {
1285  int offset = m_trace->GetPhys_Offset(traceEl->GetElmtId());
1286 
1287  fwd = m_traceMap->
1288  GetTraceToUniversalMapUnique(offset) >= 0;
1289  }
1290  }
1291  }
1292  else if ( traceEl->GetLeftAdjacentElementEdge () != -1 &&
1293  traceEl->GetRightAdjacentElementEdge() != -1 )
1294  {
1295  // Non-boundary edge (2 connected elements).
1296  fwd = ( traceEl->GetLeftAdjacentElementExp().get() == (*m_exp)[n].get() );
1297  }
1298  else
1299  {
1300  ASSERTL2( false, "Unconnected trace element!" );
1301  }
1302 
1303  return fwd;
1304  }
1305 
1306  // Construct the two trace vectors of the inner and outer
1307  // trace solution from the field contained in m_phys, where
1308  // the Weak dirichlet boundary conditions are listed in the
1309  // outer part of the vecotr
1313  {
1314  v_GetFwdBwdTracePhys(m_phys, Fwd, Bwd);
1315  }
1316 
1317  /**
1318  * @brief This method extracts the "forward" and "backward" trace data
1319  * from the array @a field and puts the data into output vectors @a Fwd
1320  * and @a Bwd.
1321  *
1322  * We first define the convention which defines "forwards" and
1323  * "backwards". First an association is made between the edge of each
1324  * element and its corresponding edge in the trace space using the
1325  * mapping #m_traceMap. The element can either be left-adjacent or
1326  * right-adjacent to this trace edge (see
1327  * Expansion1D::GetLeftAdjacentElementExp). Boundary edges are always
1328  * left-adjacent since left-adjacency is populated first.
1329  *
1330  * If the element is left-adjacent we extract the edge trace data from
1331  * @a field into the forward trace space @a Fwd; otherwise, we place it
1332  * in the backwards trace space @a Bwd. In this way, we form a unique
1333  * set of trace normals since these are always extracted from
1334  * left-adjacent elements.
1335  *
1336  * @param field is a NekDouble array which contains the 2D data
1337  * from which we wish to extract the backward and
1338  * forward orientated trace/edge arrays.
1339  * @param Fwd The resulting forwards space.
1340  * @param Bwd The resulting backwards space.
1341  */
1343  const Array<OneD, const NekDouble> &field,
1346  {
1347  int cnt, n, e, npts, phys_offset;
1348 
1349  // Zero forward/backward vectors.
1350  Vmath::Zero(Fwd.num_elements(), Fwd, 1);
1351  Vmath::Zero(Bwd.num_elements(), Bwd, 1);
1352 
1353  // Basis definition on each element
1354  LibUtilities::BasisSharedPtr basis = (*m_exp)[0]->GetBasis(0);
1355  if (basis->GetBasisType() != LibUtilities::eGauss_Lagrange)
1356  {
1357 
1358  // blocked routine
1360  GetNLocTracePts());
1361 
1362  m_locTraceToTraceMap->LocTracesFromField(field, edgevals);
1363  m_locTraceToTraceMap->InterpLocEdgesToTrace(0, edgevals, Fwd);
1364 
1365  Array<OneD, NekDouble> invals = edgevals + m_locTraceToTraceMap->
1366  GetNFwdLocTracePts();
1367  m_locTraceToTraceMap->InterpLocEdgesToTrace(1, invals, Bwd);
1368  }
1369  else
1370  {
1371  // Loop over elements and collect forward expansion
1372  int nexp = GetExpSize();
1373  Array<OneD,NekDouble> e_tmp;
1375 
1377  &elmtToTrace = m_traceMap->GetElmtToTrace();
1378 
1379  for(cnt = n = 0; n < nexp; ++n)
1380  {
1381  exp2d = (*m_exp)[n]->as<LocalRegions::Expansion2D>();
1382  phys_offset = GetPhys_Offset(n);
1383 
1384  for(e = 0; e < exp2d->GetNedges(); ++e, ++cnt)
1385  {
1386  int offset = m_trace->GetPhys_Offset(
1387  elmtToTrace[n][e]->GetElmtId());
1388 
1389  if (m_leftAdjacentEdges[cnt])
1390  {
1391  exp2d->GetEdgePhysVals(e, elmtToTrace[n][e],
1392  field + phys_offset,
1393  e_tmp = Fwd + offset);
1394  }
1395  else
1396  {
1397  exp2d->GetEdgePhysVals(e, elmtToTrace[n][e],
1398  field + phys_offset,
1399  e_tmp = Bwd + offset);
1400  }
1401 
1402  }
1403  }
1404  }
1405 
1406  // Fill boundary conditions into missing elements
1407  int id1, id2 = 0;
1408 
1409  for (cnt = n = 0; n < m_bndCondExpansions.num_elements(); ++n)
1410  {
1411  if (m_bndConditions[n]->GetBoundaryConditionType() ==
1413  {
1414  for (e = 0; e < m_bndCondExpansions[n]->GetExpSize(); ++e)
1415  {
1416  npts = m_bndCondExpansions[n]->GetExp(e)->GetNumPoints(0);
1417  id1 = m_bndCondExpansions[n]->GetPhys_Offset(e);
1418  id2 = m_trace->GetPhys_Offset(m_traceMap->
1419  GetBndCondTraceToGlobalTraceMap(cnt+e));
1420  Vmath::Vcopy(npts,
1421  &(m_bndCondExpansions[n]->GetPhys())[id1], 1,
1422  &Bwd[id2], 1);
1423  }
1424 
1425  cnt += e;
1426  }
1427  else if (m_bndConditions[n]->GetBoundaryConditionType() ==
1429  m_bndConditions[n]->GetBoundaryConditionType() ==
1431  {
1432  for(e = 0; e < m_bndCondExpansions[n]->GetExpSize(); ++e)
1433  {
1434  npts = m_bndCondExpansions[n]->GetExp(e)->GetNumPoints(0);
1435  id1 = m_bndCondExpansions[n]->GetPhys_Offset(e);
1436  ASSERTL0((m_bndCondExpansions[n]->GetPhys())[id1]==0.0,
1437  "Method not set up for non-zero Neumann "
1438  "boundary condition");
1439  id2 = m_trace->GetPhys_Offset(
1440  m_traceMap->GetBndCondTraceToGlobalTraceMap(cnt+e));
1441  Vmath::Vcopy(npts, &Fwd[id2], 1, &Bwd[id2], 1);
1442  }
1443 
1444  cnt += e;
1445  }
1446  else if (m_bndConditions[n]->GetBoundaryConditionType() !=
1448  {
1449  ASSERTL0(false,
1450  "Method not set up for this boundary condition.");
1451  }
1452  }
1453 
1454  // Copy any periodic boundary conditions.
1455  for (n = 0; n < m_periodicFwdCopy.size(); ++n)
1456  {
1457  Bwd[m_periodicBwdCopy[n]] = Fwd[m_periodicFwdCopy[n]];
1458  }
1459 
1460  // Do parallel exchange for forwards/backwards spaces.
1461  m_traceMap->UniversalTraceAssemble(Fwd);
1462  m_traceMap->UniversalTraceAssemble(Bwd);
1463  }
1464 
1465 
1467  Array<OneD, NekDouble> &outarray)
1468  {
1469  ASSERTL1(m_physState == true,
1470  "Field must be in physical state to extract trace space.");
1471 
1472  v_ExtractTracePhys(m_phys, outarray);
1473  }
1474 
1475  /**
1476  * @brief This method extracts the trace (edges in 2D) from the field @a
1477  * inarray and puts the values in @a outarray.
1478  *
1479  * It assumes the field is C0 continuous so that it can overwrite the
1480  * edge data when visited by the two adjacent elements.
1481  *
1482  * @param inarray An array containing the 2D data from which we wish
1483  * to extract the edge data.
1484  * @param outarray The resulting edge information.
1485  */
1487  const Array<OneD, const NekDouble> &inarray,
1488  Array<OneD, NekDouble> &outarray)
1489  {
1490  LibUtilities::BasisSharedPtr basis = (*m_exp)[0]->GetBasis(0);
1491  if (basis->GetBasisType() != LibUtilities::eGauss_Lagrange)
1492  {
1493  Vmath::Zero(outarray.num_elements(), outarray, 1);
1494 
1495  Array<OneD, NekDouble> tracevals(
1496  m_locTraceToTraceMap->GetNFwdLocTracePts());
1497  m_locTraceToTraceMap->FwdLocTracesFromField(inarray,tracevals);
1499  InterpLocEdgesToTrace(0,tracevals,outarray);
1500  m_traceMap->UniversalTraceAssemble(outarray);
1501  }
1502  else
1503  {
1504  // Loop over elemente and collect forward expansion
1505  int nexp = GetExpSize();
1506  int n, e, offset, phys_offset;
1507  Array<OneD,NekDouble> e_tmp;
1509  &elmtToTrace = m_traceMap->GetElmtToTrace();
1510 
1511  ASSERTL1(outarray.num_elements() >= m_trace->GetNpoints(),
1512  "input array is of insufficient length");
1513 
1514  // use m_trace tmp space in element to fill values
1515  for(n = 0; n < nexp; ++n)
1516  {
1517  phys_offset = GetPhys_Offset(n);
1518 
1519  for(e = 0; e < (*m_exp)[n]->GetNedges(); ++e)
1520  {
1521  offset = m_trace->GetPhys_Offset(
1522  elmtToTrace[n][e]->GetElmtId());
1523  (*m_exp)[n]->GetEdgePhysVals(e, elmtToTrace[n][e],
1524  inarray + phys_offset,
1525  e_tmp = outarray + offset);
1526  }
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  if (m_BCtoElmMap.num_elements() == 0)
1680  {
1681  map<int, int> globalIdMap;
1682  int i,n;
1683  int cnt;
1684  int nbcs = 0;
1685 
1686  // Populate global ID map (takes global geometry ID to local
1687  // expansion list ID).
1688  for (i = 0; i < GetExpSize(); ++i)
1689  {
1690  globalIdMap[(*m_exp)[i]->GetGeom()->GetGlobalID()] = i;
1691  }
1692 
1693  // Determine number of boundary condition expansions.
1694  for(i = 0; i < m_bndConditions.num_elements(); ++i)
1695  {
1696  nbcs += m_bndCondExpansions[i]->GetExpSize();
1697  }
1698 
1699  // Initialize arrays
1702 
1704  for (cnt = n = 0; n < m_bndCondExpansions.num_elements(); ++n)
1705  {
1706  for (i = 0; i < m_bndCondExpansions[n]->GetExpSize();
1707  ++i, ++cnt)
1708  {
1709  exp1d = m_bndCondExpansions[n]->GetExp(i)->
1710  as<LocalRegions::Expansion1D>();
1711  // Use edge to element map from MeshGraph.
1713  m_graph->GetElementsFromEdge(exp1d->GetGeom1D());
1714 
1715  m_BCtoElmMap[cnt] = globalIdMap[
1716  (*tmp)[0].first->GetGlobalID()];
1717  m_BCtoEdgMap[cnt] = (*tmp)[0].second;
1718  }
1719  }
1720  }
1721  ElmtID = m_BCtoElmMap;
1722  EdgeID = m_BCtoEdgMap;
1723  }
1724 
1726  std::shared_ptr<ExpList> &result,
1727  const bool DeclareCoeffPhysArrays)
1728  {
1729  int n, cnt, nq;
1730  int offsetOld, offsetNew;
1731  std::vector<unsigned int> eIDs;
1732 
1733  Array<OneD, int> ElmtID,EdgeID;
1734  GetBoundaryToElmtMap(ElmtID,EdgeID);
1735 
1736  // Skip other boundary regions
1737  for (cnt = n = 0; n < i; ++n)
1738  {
1739  cnt += m_bndCondExpansions[n]->GetExpSize();
1740  }
1741 
1742  // Populate eIDs with information from BoundaryToElmtMap
1743  for (n = 0; n < m_bndCondExpansions[i]->GetExpSize(); ++n)
1744  {
1745  eIDs.push_back(ElmtID[cnt+n]);
1746  }
1747 
1748  // Create expansion list
1749  result =
1751  (*this, eIDs, DeclareCoeffPhysArrays);
1752 
1753  // Copy phys and coeffs to new explist
1754  if( DeclareCoeffPhysArrays)
1755  {
1756  Array<OneD, NekDouble> tmp1, tmp2;
1757  for (n = 0; n < result->GetExpSize(); ++n)
1758  {
1759  nq = GetExp(ElmtID[cnt+n])->GetTotPoints();
1760  offsetOld = GetPhys_Offset(ElmtID[cnt+n]);
1761  offsetNew = result->GetPhys_Offset(n);
1762  Vmath::Vcopy(nq, tmp1 = GetPhys()+ offsetOld, 1,
1763  tmp2 = result->UpdatePhys()+ offsetNew, 1);
1764 
1765  nq = GetExp(ElmtID[cnt+n])->GetNcoeffs();
1766  offsetOld = GetCoeff_Offset(ElmtID[cnt+n]);
1767  offsetNew = result->GetCoeff_Offset(n);
1768  Vmath::Vcopy(nq, tmp1 = GetCoeffs()+ offsetOld, 1,
1769  tmp2 = result->UpdateCoeffs()+ offsetNew, 1);
1770  }
1771  }
1772  }
1773 
1774  /**
1775  * @brief Reset this field, so that geometry information can be updated.
1776  */
1778  {
1779  ExpList::v_Reset();
1780 
1781  // Reset boundary condition expansions.
1782  for (int n = 0; n < m_bndCondExpansions.num_elements(); ++n)
1783  {
1784  m_bndCondExpansions[n]->Reset();
1785  }
1786  }
1787 
1788  /**
1789  * @brief Calculate the \f$ L^2 \f$ error of the \f$ Q_{\rm dir} \f$
1790  * derivative using the consistent DG evaluation of \f$ Q_{\rm dir} \f$.
1791  *
1792  * The solution provided is of the primative variation at the quadrature
1793  * points and the derivative is compared to the discrete derivative at
1794  * these points, which is likely to be undesirable unless using a much
1795  * higher number of quadrature points than the polynomial order used to
1796  * evaluate \f$ Q_{\rm dir} \f$.
1797  */
1799  const int dir,
1800  const Array<OneD, const NekDouble> &soln)
1801  {
1802  int i,e,ncoeff_edge;
1803  Array<OneD, const NekDouble> tmp_coeffs;
1804  Array<OneD, NekDouble> out_d(m_ncoeffs), out_tmp;
1805 
1807  &elmtToTrace = m_traceMap->GetElmtToTrace();
1808 
1809  StdRegions::Orientation edgedir;
1810 
1811  int cnt;
1812  int LocBndCoeffs = m_traceMap->GetNumLocalBndCoeffs();
1813  Array<OneD, NekDouble> loc_lambda(LocBndCoeffs), edge_lambda;
1814  m_traceMap->GlobalToLocalBnd(m_trace->GetCoeffs(),loc_lambda);
1815 
1816  edge_lambda = loc_lambda;
1817 
1818  // Calculate Q using standard DG formulation.
1819  for(i = cnt = 0; i < GetExpSize(); ++i)
1820  {
1821  // Probably a better way of setting up lambda than this.
1822  // Note cannot use PutCoeffsInToElmts since lambda space
1823  // is mapped during the solve.
1824  int nEdges = (*m_exp)[i]->GetNedges();
1825  Array<OneD, Array<OneD, NekDouble> > edgeCoeffs(nEdges);
1826 
1827  for(e = 0; e < nEdges; ++e)
1828  {
1829  edgedir = (*m_exp)[i]->GetEorient(e);
1830  ncoeff_edge = elmtToTrace[i][e]->GetNcoeffs();
1831  edgeCoeffs[e] = Array<OneD, NekDouble>(ncoeff_edge);
1832  Vmath::Vcopy(ncoeff_edge, edge_lambda, 1, edgeCoeffs[e], 1);
1833  elmtToTrace[i][e]->SetCoeffsToOrientation(
1834  edgedir, edgeCoeffs[e], edgeCoeffs[e]);
1835  edge_lambda = edge_lambda + ncoeff_edge;
1836  }
1837 
1838  (*m_exp)[i]->DGDeriv(dir,
1839  tmp_coeffs=m_coeffs+m_coeff_offset[i],
1840  elmtToTrace[i],
1841  edgeCoeffs,
1842  out_tmp = out_d+cnt);
1843  cnt += (*m_exp)[i]->GetNcoeffs();
1844  }
1845 
1846  BwdTrans(out_d,m_phys);
1847  Vmath::Vsub(m_npoints,m_phys,1,soln,1,m_phys,1);
1848  return L2(m_phys);
1849  }
1850 
1852  const Array<OneD, const NekDouble> &inarray,
1853  Array<OneD, NekDouble> &outarray,
1854  const FlagList &flags,
1855  const StdRegions::ConstFactorMap &factors,
1856  const StdRegions::VarCoeffMap &varcoeff,
1857  const MultiRegions::VarFactorsMap &varfactors,
1858  const Array<OneD, const NekDouble> &dirForcing,
1859  const bool PhysSpaceForcing)
1860 
1861  {
1862  boost::ignore_unused(flags, varfactors, dirForcing);
1863  int i,j,n,cnt,cnt1,nbndry;
1864  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  if(PhysSpaceForcing)
1874  {
1875  IProductWRTBase(inarray,f);
1876  Vmath::Neg(m_ncoeffs,f,1);
1877  }
1878  else
1879  {
1880  Vmath::Smul(m_ncoeffs,-1.0,inarray,1,f,1);
1881  }
1882 
1883  //----------------------------------
1884  // Solve continuous flux System
1885  //----------------------------------
1886  int GloBndDofs = m_traceMap->GetNumGlobalBndCoeffs();
1887  int NumDirichlet = m_traceMap->GetNumLocalDirBndCoeffs();
1888  int e_ncoeffs,id;
1889 
1890  // Retrieve block matrix of U^e
1892  NullAssemblyMapSharedPtr,factors,varcoeff);
1893  const DNekScalBlkMatSharedPtr &HDGLamToU = GetBlockMatrix(
1894  HDGLamToUKey);
1895 
1896  // Retrieve global trace space storage, \Lambda, from trace
1897  // expansion
1898  Array<OneD,NekDouble> BndSol = m_trace->UpdateCoeffs();
1899 
1900  // Create trace space forcing, F
1901  Array<OneD,NekDouble> BndRhs(GloBndDofs,0.0);
1902 
1903  // Zero \Lambda
1904  Vmath::Zero(GloBndDofs,BndSol,1);
1905 
1906  // Retrieve number of local trace space coefficients N_{\lambda},
1907  // and set up local elemental trace solution \lambda^e.
1908  int LocBndCoeffs = m_traceMap->GetNumLocalBndCoeffs();
1909  Array<OneD, NekDouble> loc_lambda(LocBndCoeffs);
1910  DNekVec LocLambda(LocBndCoeffs,loc_lambda,eWrapper);
1911 
1912  //----------------------------------
1913  // Evaluate Trace Forcing vector F
1914  // Kirby et al, 2010, P23, Step 5.
1915  //----------------------------------
1916  // Loop over all expansions in the domain
1917  for(cnt = cnt1 = n = 0; n < nexp; ++n)
1918  {
1919  nbndry = (*m_exp)[n]->NumDGBndryCoeffs();
1920 
1921  e_ncoeffs = (*m_exp)[n]->GetNcoeffs();
1922  e_f = f + cnt;
1923  e_l = loc_lambda + cnt1;
1924 
1925  // Local trace space \lambda^e
1926  DNekVec Floc (nbndry, e_l, eWrapper);
1927  // Local forcing f^e
1928  DNekVec ElmtFce (e_ncoeffs, e_f, eWrapper);
1929  // Compute local (U^e)^{\top} f^e
1930  Floc = Transpose(*(HDGLamToU->GetBlock(n,n)))*ElmtFce;
1931 
1932  cnt += e_ncoeffs;
1933  cnt1 += nbndry;
1934  }
1935 
1936  // Assemble local \lambda_e into global \Lambda
1937  m_traceMap->AssembleBnd(loc_lambda,BndRhs);
1938 
1939  // Copy Dirichlet boundary conditions and weak forcing into trace
1940  // space
1941  cnt = 0;
1942  for(i = 0; i < m_bndCondExpansions.num_elements(); ++i)
1943  {
1944  if(m_bndConditions[i]->GetBoundaryConditionType() ==
1946  {
1947  for(j = 0; j < (m_bndCondExpansions[i])->GetNcoeffs(); ++j)
1948  {
1949  id = m_traceMap->GetBndCondCoeffsToGlobalCoeffsMap(cnt++);
1950  BndSol[id] = m_bndCondExpansions[i]->GetCoeffs()[j];
1951  }
1952  }
1953  else if (m_bndConditions[i]->GetBoundaryConditionType() ==
1955  m_bndConditions[i]->GetBoundaryConditionType() ==
1957  {
1958  //Add weak boundary condition to trace forcing
1959  for(j = 0; j < (m_bndCondExpansions[i])->GetNcoeffs(); ++j)
1960  {
1961  id = m_traceMap->GetBndCondCoeffsToGlobalCoeffsMap(cnt++);
1962  BndRhs[id] += m_bndCondExpansions[i]->GetCoeffs()[j];
1963  }
1964  }
1965  else if (m_bndConditions[i]->GetBoundaryConditionType() ==
1967  {
1968  ASSERTL0(false, "HDG implementation does not support "
1969  "periodic boundary conditions at present.");
1970  }
1971  }
1972 
1973  //----------------------------------
1974  // Solve trace problem: \Lambda = K^{-1} F
1975  // K is the HybridDGHelmBndLam matrix.
1976  //----------------------------------
1977  if(GloBndDofs - NumDirichlet > 0)
1978  {
1980  m_traceMap,factors,varcoeff);
1982  LinSys->Solve(BndRhs,BndSol,m_traceMap);
1983  }
1984 
1985  //----------------------------------
1986  // Internal element solves
1987  //----------------------------------
1989  NullAssemblyMapSharedPtr,factors,varcoeff);
1990  const DNekScalBlkMatSharedPtr& InvHDGHelm = GetBlockMatrix(
1991  invHDGhelmkey);
1992  DNekVec out(m_ncoeffs,outarray,eWrapper);
1993  Vmath::Zero(m_ncoeffs,outarray,1);
1994 
1995  // get local trace solution from BndSol
1996  m_traceMap->GlobalToLocalBnd(BndSol,loc_lambda);
1997 
1998  // out = u_f + u_lam = (*InvHDGHelm)*f + (LamtoU)*Lam
1999  out = (*InvHDGHelm)*F + (*HDGLamToU)*LocLambda;
2000  }
2001 
2002 
2003  /**
2004  * @brief Calculates the result of the multiplication of a global matrix
2005  * of type specified by @a mkey with a vector given by @a inarray.
2006  *
2007  * @param mkey Key representing desired matrix multiplication.
2008  * @param inarray Input vector.
2009  * @param outarray Resulting multiplication.
2010  */
2012  const GlobalMatrixKey &gkey,
2013  const Array<OneD,const NekDouble> &inarray,
2014  Array<OneD, NekDouble> &outarray,
2015  CoeffState coeffstate)
2016  {
2017  boost::ignore_unused(coeffstate);
2018 
2019  int LocBndCoeffs = m_traceMap->GetNumLocalBndCoeffs();
2020  Array<OneD, NekDouble> loc_lambda(LocBndCoeffs);
2021  DNekVec LocLambda(LocBndCoeffs,loc_lambda,eWrapper);
2022  const DNekScalBlkMatSharedPtr& HDGHelm = GetBlockMatrix(gkey);
2023 
2024  m_traceMap->GlobalToLocalBnd(inarray, loc_lambda);
2025  LocLambda = (*HDGHelm) * LocLambda;
2026  m_traceMap->AssembleBnd(loc_lambda,outarray);
2027  }
2028 
2029  /**
2030  * @brief Search through the edge expansions and identify which ones
2031  * have Robin/Mixed type boundary conditions.
2032  *
2033  * If a Robin boundary is found then store the edge ID of the boundary
2034  * condition and the array of points of the physical space boundary
2035  * condition which are hold the boundary condition primitive variable
2036  * coefficient at the quatrature points
2037  *
2038  * @return A map containing the Robin boundary condition information
2039  * using a key of the element ID.
2040  */
2041  map<int, RobinBCInfoSharedPtr> DisContField2D::v_GetRobinBCInfo(void)
2042  {
2043  int i,cnt;
2044  map<int, RobinBCInfoSharedPtr> returnval;
2045  Array<OneD, int> ElmtID,EdgeID;
2046  GetBoundaryToElmtMap(ElmtID,EdgeID);
2047 
2048  for(cnt = i = 0; i < m_bndCondExpansions.num_elements(); ++i)
2049  {
2050  MultiRegions::ExpListSharedPtr locExpList;
2051 
2052  if(m_bndConditions[i]->GetBoundaryConditionType() ==
2054  {
2055  int e,elmtid;
2056  Array<OneD, NekDouble> Array_tmp;
2057 
2058  locExpList = m_bndCondExpansions[i];
2059 
2060  int npoints = locExpList->GetNpoints();
2061  Array<OneD, NekDouble> x0(npoints, 0.0);
2062  Array<OneD, NekDouble> x1(npoints, 0.0);
2063  Array<OneD, NekDouble> x2(npoints, 0.0);
2064  Array<OneD, NekDouble> coeffphys(npoints);
2065 
2066  locExpList->GetCoords(x0, x1, x2);
2067 
2068  LibUtilities::Equation coeffeqn =
2069  std::static_pointer_cast<
2071  (m_bndConditions[i])->m_robinPrimitiveCoeff;
2072 
2073  // evalaute coefficient
2074  coeffeqn.Evaluate(x0, x1, x2, 0.0, coeffphys);
2075 
2076  for(e = 0; e < locExpList->GetExpSize(); ++e)
2077  {
2078  RobinBCInfoSharedPtr rInfo =
2081  EdgeID[cnt+e],
2082  Array_tmp = coeffphys +
2083  locExpList->GetPhys_Offset(e));
2084 
2085  elmtid = ElmtID[cnt+e];
2086  // make link list if necessary
2087  if(returnval.count(elmtid) != 0)
2088  {
2089  rInfo->next = returnval.find(elmtid)->second;
2090  }
2091  returnval[elmtid] = rInfo;
2092  }
2093  }
2094  cnt += m_bndCondExpansions[i]->GetExpSize();
2095  }
2096 
2097  return returnval;
2098  }
2099 
2100  /**
2101  * @brief Evaluate HDG post-processing to increase polynomial order of
2102  * solution.
2103  *
2104  * This function takes the solution (assumed to be one order lower) in
2105  * physical space, and postprocesses at the current polynomial order by
2106  * solving the system:
2107  *
2108  * \f[
2109  * \begin{aligned}
2110  * (\nabla w, \nabla u^*) &= (\nabla w, u), \\
2111  * \langle \nabla u^*, 1 \rangle &= \langle \nabla u, 1 \rangle
2112  * \end{aligned}
2113  * \f]
2114  *
2115  * where \f$ u \f$ corresponds with the current solution as stored
2116  * inside #m_coeffs.
2117  *
2118  * @param outarray The resulting field \f$ u^* \f$.
2119  */
2121  Array<OneD, NekDouble> &outarray)
2122  {
2123  int i,cnt,e,ncoeff_edge;
2124  Array<OneD, NekDouble> force, out_tmp, qrhs, qrhs1;
2126  &elmtToTrace = m_traceMap->GetElmtToTrace();
2127 
2128  StdRegions::Orientation edgedir;
2129 
2130  int nq_elmt, nm_elmt;
2131  int LocBndCoeffs = m_traceMap->GetNumLocalBndCoeffs();
2132  Array<OneD, NekDouble> loc_lambda(LocBndCoeffs), edge_lambda;
2133  Array<OneD, NekDouble> tmp_coeffs;
2134  m_traceMap->GlobalToLocalBnd(m_trace->GetCoeffs(),loc_lambda);
2135 
2136  edge_lambda = loc_lambda;
2137 
2138  // Calculate Q using standard DG formulation.
2139  for(i = cnt = 0; i < GetExpSize(); ++i)
2140  {
2141  nq_elmt = (*m_exp)[i]->GetTotPoints();
2142  nm_elmt = (*m_exp)[i]->GetNcoeffs();
2143  qrhs = Array<OneD, NekDouble>(nq_elmt);
2144  qrhs1 = Array<OneD, NekDouble>(nq_elmt);
2145  force = Array<OneD, NekDouble>(2*nm_elmt);
2146  out_tmp = force + nm_elmt;
2148 
2149  int num_points0 = (*m_exp)[i]->GetBasis(0)->GetNumPoints();
2150  int num_points1 = (*m_exp)[i]->GetBasis(1)->GetNumPoints();
2151  int num_modes0 = (*m_exp)[i]->GetBasis(0)->GetNumModes();
2152  int num_modes1 = (*m_exp)[i]->GetBasis(1)->GetNumModes();
2153 
2154  // Probably a better way of setting up lambda than this. Note
2155  // cannot use PutCoeffsInToElmts since lambda space is mapped
2156  // during the solve.
2157  int nEdges = (*m_exp)[i]->GetNedges();
2158  Array<OneD, Array<OneD, NekDouble> > edgeCoeffs(nEdges);
2159 
2160  for(e = 0; e < (*m_exp)[i]->GetNedges(); ++e)
2161  {
2162  edgedir = (*m_exp)[i]->GetEorient(e);
2163  ncoeff_edge = elmtToTrace[i][e]->GetNcoeffs();
2164  edgeCoeffs[e] = Array<OneD, NekDouble>(ncoeff_edge);
2165  Vmath::Vcopy(ncoeff_edge, edge_lambda, 1, edgeCoeffs[e], 1);
2166  elmtToTrace[i][e]->SetCoeffsToOrientation(
2167  edgedir, edgeCoeffs[e], edgeCoeffs[e]);
2168  edge_lambda = edge_lambda + ncoeff_edge;
2169  }
2170 
2171  //creating orthogonal expansion (checking if we have quads or triangles)
2172  LibUtilities::ShapeType shape = (*m_exp)[i]->DetShapeType();
2173  switch(shape)
2174  {
2176  {
2179  LibUtilities::BasisKey BkeyQ1(LibUtilities::eOrtho_A, num_modes0, PkeyQ1);
2180  LibUtilities::BasisKey BkeyQ2(LibUtilities::eOrtho_A, num_modes1, PkeyQ2);
2181  SpatialDomains::QuadGeomSharedPtr qGeom = std::dynamic_pointer_cast<SpatialDomains::QuadGeom>((*m_exp)[i]->GetGeom());
2182  ppExp = MemoryManager<LocalRegions::QuadExp>::AllocateSharedPtr(BkeyQ1, BkeyQ2, qGeom);
2183  }
2184  break;
2186  {
2189  LibUtilities::BasisKey BkeyT1(LibUtilities::eOrtho_A, num_modes0, PkeyT1);
2190  LibUtilities::BasisKey BkeyT2(LibUtilities::eOrtho_B, num_modes1, PkeyT2);
2191  SpatialDomains::TriGeomSharedPtr tGeom = std::dynamic_pointer_cast<SpatialDomains::TriGeom>((*m_exp)[i]->GetGeom());
2192  ppExp = MemoryManager<LocalRegions::TriExp>::AllocateSharedPtr(BkeyT1, BkeyT2, tGeom);
2193  }
2194  break;
2195  default:
2196  ASSERTL0(false, "Wrong shape type, HDG postprocessing is not implemented");
2197  };
2198 
2199 
2200  //DGDeriv
2201  // (d/dx w, d/dx q_0)
2202  (*m_exp)[i]->DGDeriv(
2203  0,tmp_coeffs = m_coeffs + m_coeff_offset[i],
2204  elmtToTrace[i], edgeCoeffs, out_tmp);
2205  (*m_exp)[i]->BwdTrans(out_tmp,qrhs);
2206  //(*m_exp)[i]->IProductWRTDerivBase(0,qrhs,force);
2207  ppExp->IProductWRTDerivBase(0,qrhs,force);
2208 
2209 
2210  // + (d/dy w, d/dy q_1)
2211  (*m_exp)[i]->DGDeriv(
2212  1,tmp_coeffs = m_coeffs + m_coeff_offset[i],
2213  elmtToTrace[i], edgeCoeffs, out_tmp);
2214 
2215  (*m_exp)[i]->BwdTrans(out_tmp,qrhs);
2216  //(*m_exp)[i]->IProductWRTDerivBase(1,qrhs,out_tmp);
2217  ppExp->IProductWRTDerivBase(1,qrhs,out_tmp);
2218 
2219  Vmath::Vadd(nm_elmt,force,1,out_tmp,1,force,1);
2220 
2221  // determine force[0] = (1,u)
2222  (*m_exp)[i]->BwdTrans(
2223  tmp_coeffs = m_coeffs + m_coeff_offset[i],qrhs);
2224  force[0] = (*m_exp)[i]->Integral(qrhs);
2225 
2226  // multiply by inverse Laplacian matrix
2227  // get matrix inverse
2228  LocalRegions::MatrixKey lapkey(StdRegions::eInvLaplacianWithUnityMean, ppExp->DetShapeType(), *ppExp);
2229  DNekScalMatSharedPtr lapsys = ppExp->GetLocMatrix(lapkey);
2230 
2231  NekVector<NekDouble> in (nm_elmt,force,eWrapper);
2232  NekVector<NekDouble> out(nm_elmt);
2233 
2234  out = (*lapsys)*in;
2235 
2236  // Transforming back to modified basis
2237  Array<OneD, NekDouble> work(nq_elmt);
2238  ppExp->BwdTrans(out.GetPtr(), work);
2239  (*m_exp)[i]->FwdTrans(work, tmp_coeffs = outarray + m_coeff_offset[i]);
2240  }
2241  }
2242 
2243  /**
2244  * Evaluates the boundary condition expansions, \a bndCondExpansions,
2245  * given the information provided by \a bndConditions.
2246  * @param time The time at which the boundary conditions
2247  * should be evaluated.
2248  * @param bndCondExpansions List of boundary conditions.
2249  * @param bndConditions Information about the boundary conditions.
2250  *
2251  * This will only be undertaken for time dependent
2252  * boundary conditions unless time == 0.0 which is the
2253  * case when the method is called from the constructor.
2254  */
2256  const NekDouble time,
2257  const std::string varName,
2258  const NekDouble x2_in,
2259  const NekDouble x3_in)
2260  {
2261  boost::ignore_unused(x3_in);
2262 
2263  int i;
2264  int npoints;
2265  int nbnd = m_bndCondExpansions.num_elements();
2266 
2267  MultiRegions::ExpListSharedPtr locExpList;
2268 
2269  for (i = 0; i < nbnd; ++i)
2270  {
2271  if (time == 0.0 ||
2272  m_bndConditions[i]->IsTimeDependent())
2273  {
2274  locExpList = m_bndCondExpansions[i];
2275  npoints = locExpList->GetNpoints();
2276  Array<OneD, NekDouble> x0(npoints, 0.0);
2277  Array<OneD, NekDouble> x1(npoints, 0.0);
2278  Array<OneD, NekDouble> x2(npoints, 0.0);
2279 
2280  // Homogeneous input case for x2.
2281  if (x2_in == NekConstants::kNekUnsetDouble)
2282  {
2283  locExpList->GetCoords(x0, x1, x2);
2284  }
2285  else
2286  {
2287  locExpList->GetCoords(x0, x1, x2);
2288  Vmath::Fill(npoints, x2_in, x2, 1);
2289  }
2290 
2291  if (m_bndConditions[i]->GetBoundaryConditionType()
2293  {
2295  = std::static_pointer_cast<
2297  m_bndConditions[i]);
2298  string filebcs = bcPtr->m_filename;
2299 
2300  if (filebcs != "")
2301  {
2302  ExtractFileBCs(filebcs, bcPtr->GetComm(), varName, locExpList);
2303  }
2304  else
2305  {
2306  LibUtilities::Equation condition =
2307  std::static_pointer_cast<
2309  (m_bndConditions[i])->
2310  m_dirichletCondition;
2311 
2312  condition.Evaluate(x0, x1, x2, time,
2313  locExpList->UpdatePhys());
2314  }
2315 
2316  locExpList->FwdTrans_BndConstrained(
2317  locExpList->GetPhys(),
2318  locExpList->UpdateCoeffs());
2319  }
2320  else if (m_bndConditions[i]->GetBoundaryConditionType()
2322  {
2323  SpatialDomains::NeumannBCShPtr bcPtr = std::static_pointer_cast<
2325  m_bndConditions[i]);
2326  string filebcs = bcPtr->m_filename;
2327  if (filebcs != "")
2328  {
2329  ExtractFileBCs(filebcs, bcPtr->GetComm(), varName, locExpList);
2330  }
2331  else
2332  {
2333  LibUtilities::Equation condition =
2334  std::static_pointer_cast<
2336  (m_bndConditions[i])->
2337  m_neumannCondition;
2338  condition.Evaluate(x0, x1, x2, time,
2339  locExpList->UpdatePhys());
2340  }
2341 
2342  locExpList->IProductWRTBase(
2343  locExpList->GetPhys(),
2344  locExpList->UpdateCoeffs());
2345  }
2346  else if (m_bndConditions[i]->GetBoundaryConditionType()
2348  {
2349  SpatialDomains::RobinBCShPtr bcPtr = std::static_pointer_cast<
2351  (m_bndConditions[i]);
2352  string filebcs = bcPtr->m_filename;
2353 
2354  if (filebcs != "")
2355  {
2356  ExtractFileBCs(filebcs, bcPtr->GetComm(), varName, locExpList);
2357  }
2358  else
2359  {
2360  LibUtilities::Equation condition =
2361  std::static_pointer_cast<
2363  (m_bndConditions[i])->
2364  m_robinFunction;
2365  condition.Evaluate(x0, x1, x2, time,
2366  locExpList->UpdatePhys());
2367  }
2368 
2369  locExpList->IProductWRTBase(
2370  locExpList->GetPhys(),
2371  locExpList->UpdateCoeffs());
2372  }
2373  else if (m_bndConditions[i]->GetBoundaryConditionType()
2375  {
2376  continue;
2377  }
2378  else
2379  {
2380  ASSERTL0(false, "This type of BC not implemented yet");
2381  }
2382  }
2383  }
2384  }
2385  } // end of namespace
2386 } //end of namespace
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:2161
const DNekScalBlkMatSharedPtr & GetBlockMatrix(const GlobalMatrixKey &gkey)
Definition: ExpList.cpp:1004
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:216
virtual void v_Reset()
Reset geometry information, metrics, matrix managers and geometry information.
Definition: ExpList.cpp:1583
std::shared_ptr< RobinBCInfo > RobinBCInfoSharedPtr
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition: MeshGraph.h:163
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 id
Geometry ID of entity.
std::shared_ptr< Geometry2D > Geometry2DSharedPtr
Definition: Geometry.h:65
static ExpListSharedPtr NullExpListSharedPtr
Definition: ExpList.h:1550
std::shared_ptr< LocalRegions::ExpansionVector > m_exp
The list of local expansions.
Definition: ExpList.h:1090
void EvaluateBoundaryConditions(const NekDouble time=0.0, const std::string varName="", const NekDouble=NekConstants::kNekUnsetDouble, const NekDouble=NekConstants::kNekUnsetDouble)
Definition: ExpList.h:2356
std::shared_ptr< ExpList > ExpListSharedPtr
Shared pointer to an ExpList object.
std::shared_ptr< DNekScalMat > DNekScalMatSharedPtr
std::shared_ptr< std::vector< std::pair< GeometrySharedPtr, int > > > GeometryLinkSharedPtr
Definition: MeshGraph.h:159
std::vector< int > m_periodicFwdCopy
A vector indicating degress of freedom which need to be copied from forwards to backwards space in ca...
std::shared_ptr< DNekScalBlkMat > DNekScalBlkMatSharedPtr
Definition: NekTypeDefs.hpp:73
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 MultiRegions::VarFactorsMap &varfactors, const Array< OneD, const NekDouble > &dirForcing, const bool PhysSpaceForcing)
void Fill(int n, const T alpha, T *x, const int incx)
Fill a vector with a constant value.
Definition: Vmath.cpp:45
const BoundaryConditionCollection & GetBoundaryConditions(void) const
Definition: Conditions.h:248
const Array< OneD, const NekDouble > & GetCoeffs() const
This function returns (a reference to) the array (implemented as m_coeffs) containing all local expa...
Definition: ExpList.h:2062
std::shared_ptr< QuadGeom > QuadGeomSharedPtr
Definition: HexGeom.h:46
std::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition: Comm.h:53
GlobalLinSysSharedPtr GetGlobalBndLinSys(const GlobalLinSysKey &mkey)
Lagrange Polynomials using the Gauss points .
Definition: BasisType.h:55
std::shared_ptr< GlobalLinSys > GlobalLinSysSharedPtr
Pointer to a GlobalLinSys object.
Definition: GlobalLinSys.h:50
STL namespace.
std::shared_ptr< NeumannBoundaryCondition > NeumannBCShPtr
Definition: Conditions.h:221
std::map< int, CompositeSharedPtr > CompositeMap
Definition: MeshGraph.h:137
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:1775
std::map< ConstFactorType, NekDouble > ConstFactorMap
Definition: StdRegions.hpp:294
PeriodicMap m_periodicVerts
A map which identifies groups of periodic vertices.
void GetBoundaryToElmtMap(Array< OneD, int > &ElmtID, Array< OneD, int > &EdgeID)
Definition: ExpList.h:2409
Array< OneD, NekDouble > m_phys
The global expansion evaluated at the quadrature points.
Definition: ExpList.h:1069
std::shared_ptr< Composite > CompositeSharedPtr
Definition: MeshGraph.h:136
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::shared_ptr< Basis > BasisSharedPtr
Array< OneD, NekDouble > m_coeffs
Concatenation of all local expansion coefficients.
Definition: ExpList.h:1052
int GetExpSize(void)
This function returns the number of elements in the expansion.
Definition: ExpList.h:2170
const std::shared_ptr< LocalRegions::ExpansionVector > GetExp() const
This function returns the vector of elements in the expansion.
Definition: ExpList.h:2191
virtual std::map< int, RobinBCInfoSharedPtr > v_GetRobinBCInfo()
Search through the edge expansions and identify which ones have Robin/Mixed type boundary conditions...
std::shared_ptr< GlobalLinSys > GenGlobalBndLinSys(const GlobalLinSysKey &mkey, const AssemblyMapSharedPtr &locToGloMap)
Generate a GlobalLinSys from information provided by the key "mkey" and the mapping provided in LocTo...
Definition: ExpList.cpp:1381
Gauss Radau pinned at x=-1, .
Definition: PointsType.h:58
std::shared_ptr< RobinBoundaryCondition > RobinBCShPtr
Definition: Conditions.h:222
Principle Orthogonal Functions .
Definition: BasisType.h:46
bool SameTypeOfBoundaryConditions(const DisContField2D &In)
Array< OneD, int > m_coeff_offset
Offset of elemental data into the array m_coeffs.
Definition: ExpList.h:1101
Base class for all multi-elemental spectral/hp expansions.
Definition: ExpList.h:103
std::shared_ptr< TriGeom > TriGeomSharedPtr
Definition: TriGeom.h:58
DisContField2D()
Default constructor.
LocTraceToTraceMapSharedPtr m_locTraceToTraceMap
Array< OneD, MultiRegions::ExpListSharedPtr > m_bndCondExpansions
An object which contains the discretised boundary conditions.
void Smul(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Scalar multiply y = alpha*y.
Definition: Vmath.cpp:216
StdRegions::MatrixType GetMatrixType() const
Return the matrix type.
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)
virtual ~DisContField2D()
Default destructor.
std::map< StdRegions::VarCoeffType, Array< OneD, NekDouble > > VarCoeffMap
Definition: StdRegions.hpp:264
int GetNcoeffs(void) const
Returns the total number of local degrees of freedom .
Definition: ExpList.h:1558
std::set< int > m_boundaryEdges
A set storing the global IDs of any boundary edges.
std::map< int, std::vector< unsigned int > > CompositeOrdering
Definition: MeshGraph.h:108
bool m_physState
The state of the array m_phys.
Definition: ExpList.h:1078
int m_ncoeffs
The total number of local degrees of freedom. m_ncoeffs .
Definition: ExpList.h:1030
std::map< int, BoundaryRegionShPtr > BoundaryRegionCollection
Definition: Conditions.h:217
bool isLocal
Flag specifying if this entity is local to this partition.
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
StdRegions::Orientation orient
Orientation of entity within higher dimensional entity.
Principle Orthogonal Functions .
Definition: BasisType.h:45
NekMatrix< InnerMatrixType, BlockMatrixTag > Transpose(NekMatrix< InnerMatrixType, BlockMatrixTag > &rhs)
SpatialDomains::MeshGraphSharedPtr m_graph
Mesh associated with this expansion list.
Definition: ExpList.h:1026
LibUtilities::SessionReaderSharedPtr m_session
Session.
Definition: ExpList.h:1023
Defines a specification for a set of points.
Definition: Points.h:59
void Neg(int n, T *x, const int incx)
Negate x = -x.
Definition: Vmath.cpp:399
NekDouble Evaluate() const
Definition: Equation.cpp:95
double NekDouble
Defines a list of flags.
std::map< int, BoundaryConditionMapShPtr > BoundaryConditionCollection
Definition: Conditions.h:226
Array< OneD, SpatialDomains::BoundaryConditionShPtr > m_bndConditions
An array which contains the information about the boundary condition on the different boundary region...
void ExtractFileBCs(const std::string &fileName, LibUtilities::CommSharedPtr comm, const std::string &varName, const std::shared_ptr< ExpList > locExpList)
Definition: ExpList.cpp:2095
bool IsLeftAdjacentEdge(const int n, const int e)
std::map< int, std::vector< PeriodicEntity > > PeriodicMap
virtual void v_Reset()
Reset this field, so that geometry information can be updated.
static const NekDouble kNekUnsetDouble
Describe a linear system.
std::shared_ptr< BoundaryConditionBase > BoundaryConditionShPtr
Definition: Conditions.h:219
Describes a matrix with ordering defined by a local to global map.
void SetUpDG(const std::string="DefaultVar")
Set up all DG member variables and maps.
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:346
std::shared_ptr< Expansion > ExpansionSharedPtr
Definition: Expansion.h:65
LibUtilities::CommSharedPtr m_comm
Communicator.
Definition: ExpList.h:1020
static AssemblyMapSharedPtr NullAssemblyMapSharedPtr
Definition: AssemblyMap.h:54
2D geometry information
Definition: Geometry2D.h:68
virtual void v_GetBndElmtExpansion(int i, std::shared_ptr< ExpList > &result, const bool DeclareCoeffPhysArrays)
std::shared_ptr< Expansion2D > Expansion2DSharedPtr
Definition: Expansion1D.h:47
#define ASSERTL2(condition, msg)
Assert Level 2 – Debugging which is used FULLDEBUG compilation mode. This level assert is designed t...
Definition: ErrorUtil.hpp:274
void IProductWRTBase(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, CoeffState coeffstate=eLocal)
Definition: ExpList.h:1714
std::shared_ptr< DirichletBoundaryCondition > DirichletBCShPtr
Definition: Conditions.h:220
Abstraction of a two-dimensional multi-elemental expansion which is merely a collection of local expa...
Definition: ExpList2D.h:57
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...
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:3261
GlobalSysSolnType GetGlobalSysSolnType() const
Return the associated solution type.
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...
std::map< int, std::vector< unsigned int > > BndRegionOrdering
Definition: MeshGraph.h:109
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:2200
T Vsum(int n, const T *x, const int incx)
Subtract return sum(x)
Definition: Vmath.cpp:740
void Zero(int n, T *x, const int incx)
Zero vector.
Definition: Vmath.cpp:376
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:250
std::shared_ptr< SegGeom > SegGeomSharedPtr
Definition: Geometry2D.h:62
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:2208
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:548
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.cpp:1064
NekDouble L2_DGDeriv(const int dir, const Array< OneD, const NekDouble > &soln)
Calculate the error of the derivative using the consistent DG evaluation of .
std::shared_ptr< ExpList1D > ExpList1DSharedPtr
Shared pointer to an ExpList1D object.
Definition: ExpList1D.h:49
std::shared_ptr< Expansion1D > Expansion1DSharedPtr
Definition: Expansion1D.h:51
Describes the specification for a Basis.
Definition: Basis.h:49
std::shared_ptr< SessionReader > SessionReaderSharedPtr
const BoundaryRegionCollection & GetBoundaryRegions(void) const
Definition: Conditions.h:238
Array< OneD, DataType > & GetPtr()
Definition: NekVector.cpp:227
1D Gauss-Lobatto-Legendre quadrature points
Definition: PointsType.h:51
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:302
std::shared_ptr< ExpList > & GetTrace()
Definition: ExpList.h:2267
std::map< StdRegions::ConstFactorType, Array< OneD, NekDouble > > VarFactorsMap