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