Nektar++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
CoupledLocalToGlobalC0ContMap.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File CoupledLcoalToGlobalC0ContMap.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: Wrapper class around the library
33 // LocalToGlobalC0ContMap class for use in the Couplied Linearised NS
34 // solver.
35 ///////////////////////////////////////////////////////////////////////////////
38 #include <LocalRegions/SegExp.h>
42 
43 namespace Nektar
44 {
45  /**
46  * This is an vector extension of
47  * MultiRegion::LocalToGlobalC0BaseMap::SetUp2DExpansionC0ContMap
48  * related to the Linearised Navier Stokes problem
49  */
53  const SpatialDomains::BoundaryConditionsSharedPtr &boundaryConditions,
54  const Array<OneD, MultiRegions::ExpListSharedPtr> &fields,
55  const MultiRegions::ExpListSharedPtr &pressure,
56  const int nz_loc,
57  const bool CheckforSingularSys):
58  AssemblyMapCG2D(pSession)
59  {
60 
61  int i,j,k,n;
62  int cnt = 0,offset=0;
63  int meshVertId;
64  int meshEdgeId;
65  int bndEdgeCnt;
66  int globalId;
67  int nEdgeCoeffs;
68  int nEdgeInteriorCoeffs;
69  int firstNonDirGraphVertId;
70  int nLocBndCondDofs = 0;
71  int nLocDirBndCondDofs = 0;
72  int nExtraDirichlet = 0;
76  StdRegions::Orientation edgeOrient;
77  Array<OneD, unsigned int> edgeInteriorMap;
78  Array<OneD, int> edgeInteriorSign;
79  int nvel = fields.num_elements();
80 
81  const LocalRegions::ExpansionVector &locExpVector = *(fields[0]->GetExp());
82  int eid, id, diff;
83  int nel = fields[0]->GetNumElmts();
84 
85  MultiRegions::PeriodicMap periodicVerts;
86  MultiRegions::PeriodicMap periodicEdges;
87  Array<OneD, map<int,int> > ReorderedGraphVertId(2);
89  int staticCondLevel = 0;
90 
91  if(CheckforSingularSys) //all singularity checking by setting flag to true
92  {
93  m_systemSingular = true;
94  }
95  else // Turn off singular checking by setting flag to false
96  {
97  m_systemSingular = false;
98  }
99 
100  /**
101  * STEP 1: Wrap boundary conditions vector in an array
102  * (since routine is set up for multiple fields) and call
103  * the graph re-odering subroutine to obtain the reordered
104  * values
105  */
106 
107  // Obtain any periodic information and allocate default mapping array
108  fields[0]->GetPeriodicEntities(periodicVerts,periodicEdges);
109 
110 
111  const Array<OneD, const MultiRegions::ExpListSharedPtr> bndCondExp = fields[0]->GetBndCondExpansions();
112 
113  Array<OneD, Array<OneD, const SpatialDomains::BoundaryConditionShPtr> > bndConditionsVec(nvel);
114  for(i = 0; i < nvel; ++i)
115  {
116  bndConditionsVec[i] = fields[i]->GetBndConditions();
117  }
118 
119  map<int,int> IsDirVertDof;
120  map<int,int> IsDirEdgeDof;
122 
124  for(j = 0; j < bndCondExp.num_elements(); ++j)
125  {
126  map<int,int> BndExpVids;
127  // collect unique list of vertex ids for this expansion
128  for(k = 0; k < bndCondExp[j]->GetNumElmts(); ++k)
129  {
130  g = bndCondExp[j]->GetExp(k)->as<LocalRegions::Expansion1D>()
131  ->GetGeom1D();
132  BndExpVids[g->GetVid(0)] = g->GetVid(0);
133  BndExpVids[g->GetVid(1)] = g->GetVid(1);
134  }
135 
136  for(i = 0; i < nvel; ++i)
137  {
138  if(bndConditionsVec[i][j]->GetBoundaryConditionType()==SpatialDomains::eDirichlet)
139  {
140  // set number of Dirichlet conditions along edge
141  for(k = 0; k < bndCondExp[j]->GetNumElmts(); ++k)
142  {
143  IsDirEdgeDof[bndCondExp[j]->GetExp(k)
145  ->GetGeom1D()->GetEid()] += 1;
146  }
147 
148 
149  // Set number of Dirichlet conditions at vertices
150  // with a clamp on its maximum value being nvel to
151  // handle corners between expansions
152  for(mapIt = BndExpVids.begin(); mapIt != BndExpVids.end(); mapIt++)
153  {
154  id = IsDirVertDof[mapIt->second]+1;
155  IsDirVertDof[mapIt->second] = (id > nvel)?nvel:id;
156  }
157  }
158  else
159  {
160  // Check to see that edge normals have non-zero
161  // component in this direction since otherwise
162  // also can be singular.
163  /// @TODO: Fix this so that we can extract normals from edges
164  for(k = 0; k < bndCondExp[j]->GetNumElmts(); ++k)
165  {
166  Array<OneD,Array<OneD,NekDouble> > locnorm;
168  = bndCondExp[j]->GetExp(k)
170  locnorm = loc_exp->GetLeftAdjacentElementExp()->GetEdgeNormal(loc_exp->GetLeftAdjacentElementEdge());
171  //locnorm = bndCondExp[j]->GetExp(k)->Get GetMetricInfo()->GetNormal();
172 
173  int ndir = locnorm.num_elements();
174  if(i < ndir) // account for Fourier version where n can be larger then ndir
175  {
176  for(int l = 0; l < locnorm[0].num_elements(); ++l)
177  {
178  if(fabs(locnorm[i][l]) > NekConstants::kNekZeroTol)
179  {
180  m_systemSingular = false;
181  break;
182  }
183  }
184  }
185  if(m_systemSingular == false)
186  {
187  break;
188  }
189  }
190  }
191  }
192  }
193 
194  Array<OneD, map<int,int> >Dofs(2);
195 
196  Array<OneD, int> AddMeanPressureToEdgeId(nel,-1);
197  int edgeId,vertId;
198 
199 
200  // special case of singular problem - need to fix one pressure
201  // dof to a dirichlet edge. Since we attached pressure dof to
202  // last velocity component of edge need to make sure this
203  // component is Dirichlet
204  if(m_systemSingular)
205  {
206  id = -1;
207  for(i = 0; i < bndConditionsVec[0].num_elements(); ++i)
208  {
209  if(bndConditionsVec[nvel-1][i]->GetBoundaryConditionType() == SpatialDomains::eDirichlet)
210  {
211  id = bndCondExp[i]->GetExp(0)
212  ->as<LocalRegions::Expansion1D>()->GetGeom1D()
213  ->GetEid();
214  break;
215  }
216  }
217 
218  ASSERTL0(id != -1," Did not find an edge to attach singular pressure degree of freedom");
219 
220  // determine element with this edge id. There may be a
221  // more direct way of getting element from spatialDomains
222  for(i = 0; i < nel; ++i)
223  {
224  for(j = 0; j < locExpVector[i]->GetNverts(); ++j)
225  {
226  edgeId = (locExpVector[i]->as<LocalRegions::Expansion2D>()
227  ->GetGeom2D())->GetEid(j);
228 
229  if(edgeId == id)
230  {
231  AddMeanPressureToEdgeId[i] = id;
232  break;
233  }
234  }
235 
236  if(AddMeanPressureToEdgeId[i] != -1)
237  {
238  break;
239  }
240  }
241  }
242 
243 
244  for(i = 0; i < nel; ++i)
245  {
246  eid = fields[0]->GetOffset_Elmt_Id(i);
247  for(j = 0; j < locExpVector[eid]->GetNverts(); ++j)
248  {
249  vertId = (locExpVector[eid]->as<LocalRegions::Expansion2D>()
250  ->GetGeom2D())->GetVid(j);
251  if(Dofs[0].count(vertId) == 0)
252  {
253  Dofs[0][vertId] = nvel*nz_loc;
254 
255  // Adjust for a Dirichlet boundary condition to give number to be solved
256  if(IsDirVertDof.count(vertId) != 0)
257  {
258  Dofs[0][vertId] -= IsDirVertDof[vertId]*nz_loc;
259  }
260  }
261 
262  edgeId = (locExpVector[eid]->as<LocalRegions::Expansion2D>()
263  ->GetGeom2D())->GetEid(j);
264  if(Dofs[1].count(edgeId) == 0)
265  {
266  Dofs[1][edgeId] = nvel*(locExpVector[eid]->GetEdgeNcoeffs(j)-2)*nz_loc;
267  }
268 
269  // Adjust for Dirichlet boundary conditions to give number to be solved
270  if(IsDirEdgeDof.count(edgeId) != 0)
271  {
272  Dofs[1][edgeId] -= IsDirEdgeDof[edgeId]*nz_loc*(locExpVector[eid]->GetEdgeNcoeffs(j)-2);
273  }
274  }
275  }
276 
277  set<int> extraDir;
278  SetUp2DGraphC0ContMap(*fields[0],
279  bndCondExp,
280  bndConditionsVec,
281  periodicVerts, periodicEdges,
282  Dofs, ReorderedGraphVertId,
283  firstNonDirGraphVertId, nExtraDirichlet,
284  bottomUpGraph, extraDir, false, 4);
285 
286  /**
287  * STEP 2a: Set the mean pressure modes to edges depending on
288  * type of direct solver technique;
289  */
290 
291  // determine which edge to add mean pressure dof based on
292  // ensuring that at least one pressure dof from an internal
293  // patch is associated with its boundary system
294  if(m_session->MatchSolverInfoAsEnum("GlobalSysSoln", MultiRegions::eDirectMultiLevelStaticCond))
295  {
296 
297 
298  FindEdgeIdToAddMeanPressure(ReorderedGraphVertId,
299  nel, locExpVector,
300  edgeId, vertId, firstNonDirGraphVertId, IsDirEdgeDof,
301  bottomUpGraph,
302  AddMeanPressureToEdgeId);
303  }
304 
305  // Set unset elmts to non-Dirichlet edges.
306  // special case of singular problem - need to fix one
307  // pressure dof to a dirichlet edge
308  for(i = 0; i < nel; ++i)
309  {
310  eid = fields[0]->GetOffset_Elmt_Id(i);
311  for(j = 0; j < locExpVector[eid]->GetNverts(); ++j)
312  {
313  edgeId = (locExpVector[eid]->as<LocalRegions::Expansion2D>()
314  ->GetGeom2D())->GetEid(j);
315 
316  if(IsDirEdgeDof.count(edgeId) == 0) // interior edge
317  {
318  // setup AddMeanPressureToEdgeId to decide where to
319  // put pressure
320  if(AddMeanPressureToEdgeId[eid] == -1)
321  {
322  AddMeanPressureToEdgeId[eid] = edgeId;
323  }
324  }
325  }
326  ASSERTL0((AddMeanPressureToEdgeId[eid] != -1),"Did not determine "
327  "an edge to attach mean pressure dof");
328  // Add the mean pressure degree of freedom to this edge
329  Dofs[1][AddMeanPressureToEdgeId[eid]] += nz_loc;
330  }
331 
332  map<int,int> pressureEdgeOffset;
333 
334  /**
335  * STEP 2: Count out the number of Dirichlet vertices and edges first
336  */
337  for(i = 0; i < bndCondExp.num_elements(); i++)
338  {
339  for(j = 0; j < bndCondExp[i]->GetNumElmts(); j++)
340  {
341  bndSegExp = bndCondExp[i]->GetExp(j)
342  ->as<LocalRegions::SegExp>();
343  for(k = 0; k < nvel; ++k)
344  {
345  if(bndConditionsVec[k][i]->GetBoundaryConditionType()==SpatialDomains::eDirichlet)
346  {
347  nLocDirBndCondDofs += bndSegExp->GetNcoeffs()*nz_loc;
348  }
349  nLocBndCondDofs += bndSegExp->GetNcoeffs()*nz_loc;
350  }
351  }
352  }
353 
354  if(m_systemSingular)
355  {
356  m_numLocalDirBndCoeffs = nLocDirBndCondDofs+nExtraDirichlet+nz_loc;
357  }
358  else
359  {
360  m_numLocalDirBndCoeffs = nLocDirBndCondDofs+nExtraDirichlet;
361  }
362 
363  /**
364  * STEP 3: Set up an array which contains the offset information of
365  * the different graph vertices.
366  *
367  * This basically means to identify how many global degrees of
368  * freedom the individual graph vertices correspond. Obviously,
369  * the graph vertices corresponding to the mesh-vertices account
370  * for a single global DOF. However, the graph vertices
371  * corresponding to the element edges correspond to 2*(N-2) global DOF
372  * where N is equal to the number of boundary modes on this edge.
373  */
374  Array<OneD, int> graphVertOffset(nvel*nz_loc*(ReorderedGraphVertId[0].size() + ReorderedGraphVertId[1].size()),0);
375  graphVertOffset[0] = 0;
376 
377  m_signChange = false;
378 
379  for(i = 0; i < nel; ++i)
380  {
381  eid = fields[0]->GetOffset_Elmt_Id(i);
382  locExpansion = locExpVector[eid]->as<StdRegions::StdExpansion2D>();
383 
384  for(j = 0; j < locExpansion->GetNedges(); ++j)
385  {
386  nEdgeCoeffs = locExpansion->GetEdgeNcoeffs(j);
387  meshEdgeId = (locExpansion->as<LocalRegions::Expansion2D>()
388  ->GetGeom2D())->GetEid(j);
389  meshVertId = (locExpansion->as<LocalRegions::Expansion2D>()
390  ->GetGeom2D())->GetVid(j);
391 
392  for(k = 0; k < nvel*nz_loc; ++k)
393  {
394  graphVertOffset[ReorderedGraphVertId[0][meshVertId]*nvel*nz_loc+k] = 1;
395  graphVertOffset[ReorderedGraphVertId[1][meshEdgeId]*nvel*nz_loc+k] = (nEdgeCoeffs-2);
396  }
397 
398  bType = locExpansion->GetEdgeBasisType(j);
399  // need a sign vector for modal expansions if nEdgeCoeffs >=4
400  if( (nEdgeCoeffs >= 4)&&
401  ( (bType == LibUtilities::eModified_A)||
402  (bType == LibUtilities::eModified_B) ) )
403  {
404  m_signChange = true;
405  }
406  }
407  }
408 
409  // Add mean pressure modes;
410  for(i = 0; i < nel; ++i)
411  {
412  graphVertOffset[(ReorderedGraphVertId[1][AddMeanPressureToEdgeId[i]]+1)*nvel*nz_loc-1] += nz_loc;
413  //graphVertOffset[(ReorderedGraphVertId[1][AddMeanPressureToEdgeId[i]])*nvel*nz_loc] += nz_loc;
414  }
415 
416  // Negate the vertices and edges with only a partial
417  // Dirichlet conditon. Essentially we check to see if an edge
418  // has a mixed Dirichlet with Neumann/Robin Condition and if
419  // so negate the offset associated with this vertex.
420 
421  map<int,int> DirVertChk;
422 
423  for(i = 0; i < bndConditionsVec[0].num_elements(); ++i)
424  {
425  cnt = 0;
426  for(j = 0; j < nvel; ++j)
427  {
428  if(bndConditionsVec[j][i]->GetBoundaryConditionType() == SpatialDomains::eDirichlet)
429  {
430  cnt ++;
431  }
432  }
433 
434  // Case where partial Dirichlet boundary condition
435  if((cnt > 0)&&(cnt < nvel))
436  {
437  for(j = 0; j < nvel; ++j)
438  {
439  if(bndConditionsVec[j][i]->GetBoundaryConditionType() == SpatialDomains::eDirichlet)
440  {
441  //negate graph offsets which should be
442  //Dirichlet conditions
443  for(k = 0; k < bndCondExp[i]->GetNumElmts(); ++k)
444  {
445  // vertices with mix condition;
446  id = bndCondExp[i]->GetExp(k)
448  ->GetGeom1D()->GetVid(0);
449  if(DirVertChk.count(id*nvel+j) == 0)
450  {
451  DirVertChk[id*nvel+j] = 1;
452  for(n = 0; n < nz_loc; ++n)
453  {
454  graphVertOffset[ReorderedGraphVertId[0][id]*nvel*nz_loc+j*nz_loc + n] *= -1;
455  }
456  }
457 
458  id = bndCondExp[i]->GetExp(k)
460  ->GetGeom1D()->GetVid(1);
461  if(DirVertChk.count(id*nvel+j) == 0)
462  {
463  DirVertChk[id*nvel+j] = 1;
464  for(n = 0; n < nz_loc; ++n)
465  {
466  graphVertOffset[ReorderedGraphVertId[0][id]*nvel*nz_loc+j*nz_loc+n] *= -1;
467  }
468  }
469 
470  // edges with mixed id;
471  id = bndCondExp[i]->GetExp(k)
473  ->GetGeom1D()->GetEid();
474  for(n = 0; n < nz_loc; ++n)
475  {
476  graphVertOffset[ReorderedGraphVertId[1][id]*nvel*nz_loc+j*nz_loc +n] *= -1;
477  }
478  }
479  }
480  }
481  }
482  }
483 
484 
485  cnt = 0;
486  // assemble accumulative list of full Dirichlet values.
487  for(i = 0; i < firstNonDirGraphVertId*nvel*nz_loc; ++i)
488  {
489  diff = abs(graphVertOffset[i]);
490  graphVertOffset[i] = cnt;
491  cnt += diff;
492  }
493 
494  // set Dirichlet values with negative values to Dirichlet value
495  for(i = firstNonDirGraphVertId*nvel*nz_loc; i < graphVertOffset.num_elements(); ++i)
496  {
497  if(graphVertOffset[i] < 0)
498  {
499  diff = -graphVertOffset[i];
500  graphVertOffset[i] = -cnt;
501  cnt += diff;
502  }
503  }
504 
505  // Accumulate all interior degrees of freedom with positive values
507 
508  // offset values
509  for(i = firstNonDirGraphVertId*nvel*nz_loc; i < graphVertOffset.num_elements(); ++i)
510  {
511  if(graphVertOffset[i] >= 0)
512  {
513  diff = graphVertOffset[i];
514  graphVertOffset[i] = cnt;
515  cnt += diff;
516  }
517  }
518 
519  // Finally set negative entries (corresponding to Dirichlet
520  // values ) to be positive
521  for(i = firstNonDirGraphVertId*nvel*nz_loc; i < graphVertOffset.num_elements(); ++i)
522  {
523  if(graphVertOffset[i] < 0)
524  {
525  graphVertOffset[i] = -graphVertOffset[i];
526  }
527  }
528 
529 
530  // Allocate the proper amount of space for the class-data and fill
531  // information that is already known
532  cnt = 0;
534  m_numLocalCoeffs = 0;
535 
536  for(i = 0; i < nel; ++i)
537  {
538  m_numLocalBndCoeffs += nz_loc*(nvel*locExpVector[i]->NumBndryCoeffs() + 1);
539  // add these coeffs up separately since
540  // pressure->GetNcoeffs can include the coefficient in
541  // multiple planes.
542  m_numLocalCoeffs += (pressure->GetExp(i)->GetNcoeffs()-1)*nz_loc;
543  }
544 
546 
547 
548  m_localToGlobalMap = Array<OneD, int>(m_numLocalCoeffs,-1);
549  m_localToGlobalBndMap = Array<OneD, int>(m_numLocalBndCoeffs,-1);
550  m_bndCondCoeffsToGlobalCoeffsMap = Array<OneD, int>(nLocBndCondDofs,-1);
551 
552 
553  // Set default sign array.
554  m_localToGlobalSign = Array<OneD, NekDouble>(m_numLocalCoeffs,1.0);
555  m_localToGlobalBndSign = Array<OneD, NekDouble>(m_numLocalBndCoeffs,1.0);
556 
557  m_staticCondLevel = staticCondLevel;
558  m_numPatches = nel;
559 
560  m_numLocalBndCoeffsPerPatch = Array<OneD, unsigned int>(nel);
561  m_numLocalIntCoeffsPerPatch = Array<OneD, unsigned int>(nel);
562 
563  for(i = 0; i < nel; ++i)
564  {
565  m_numLocalBndCoeffsPerPatch[i] = (unsigned int) nz_loc*(nvel*locExpVector[fields[0]->GetOffset_Elmt_Id(i)]->NumBndryCoeffs() + 1);
566  m_numLocalIntCoeffsPerPatch[i] = (unsigned int) nz_loc*(pressure->GetExp(eid)->GetNcoeffs()-1);
567  }
568 
569  /**
570  * STEP 4: Now, all ingredients are ready to set up the actual
571  * local to global mapping.
572  *
573  * The remainder of the map consists of the element-interior
574  * degrees of freedom. This leads to the block-diagonal submatrix
575  * as each element-interior mode is globally orthogonal to modes
576  * in all other elements.
577  */
578  cnt = 0;
579  int nv,velnbndry;
580  Array<OneD, unsigned int> bmap;
581 
582 
583  // Loop over all the elements in the domain in shuffled
584  // ordering (element type consistency)
585  for(i = 0; i < nel; ++i)
586  {
587  eid = fields[0]->GetOffset_Elmt_Id(i);
588  locExpansion = locExpVector[eid]->as<StdRegions::StdExpansion2D>();
589 
590  velnbndry = locExpansion->NumBndryCoeffs();
591 
592  // require an inverse ordering of the bmap system to store
593  // local numbering system which takes matrix these
594  // matrices. Therefore get hold of elemental bmap and set
595  // up an inverse map
596  map<int,int> inv_bmap;
597  locExpansion->GetBoundaryMap(bmap);
598  for(j = 0; j < bmap.num_elements(); ++j)
599  {
600  inv_bmap[bmap[j]] = j;
601  }
602 
603  // Loop over all edges (and vertices) of element i
604  for(j = 0; j < locExpansion->GetNedges(); ++j)
605  {
606  nEdgeInteriorCoeffs = locExpansion->GetEdgeNcoeffs(j)-2;
607  edgeOrient = (locExpansion->as<LocalRegions::Expansion2D>()
608  ->GetGeom2D())->GetEorient(j);
609  meshEdgeId = (locExpansion->as<LocalRegions::Expansion2D>()
610  ->GetGeom2D())->GetEid(j);
611  meshVertId = (locExpansion->as<LocalRegions::Expansion2D>()
612  ->GetGeom2D())->GetVid(j);
613 
614  locExpansion->GetEdgeInteriorMap(j,edgeOrient,edgeInteriorMap,edgeInteriorSign);
615  // Set the global DOF for vertex j of element i
616 
617  for(nv = 0; nv < nvel*nz_loc; ++nv)
618  {
619  m_localToGlobalMap[cnt+nv*velnbndry+inv_bmap[locExpansion->GetVertexMap(j)]] = graphVertOffset[ReorderedGraphVertId[0][meshVertId]*nvel*nz_loc+ nv];
620  // Set the global DOF's for the interior modes of edge j
621  for(k = 0; k < nEdgeInteriorCoeffs; ++k)
622  {
623  m_localToGlobalMap[cnt+nv*velnbndry+inv_bmap[edgeInteriorMap[k]]] = graphVertOffset[ReorderedGraphVertId[1][meshEdgeId]*nvel*nz_loc+nv]+k;
624  }
625  }
626 
627  // Fill the sign vector if required
628  if(m_signChange)
629  {
630  for(nv = 0; nv < nvel*nz_loc; ++nv)
631  {
632  for(k = 0; k < nEdgeInteriorCoeffs; ++k)
633  {
634  m_localToGlobalSign[cnt+nv*velnbndry + inv_bmap[edgeInteriorMap[k]]] = (NekDouble) edgeInteriorSign[k];
635  }
636  }
637  }
638  }
639 
640  // use difference between two edges of the AddMeanPressureEdgeId to det nEdgeInteriorCoeffs.
641  nEdgeInteriorCoeffs = graphVertOffset[(ReorderedGraphVertId[1][AddMeanPressureToEdgeId[eid]])*nvel*nz_loc+1] - graphVertOffset[(ReorderedGraphVertId[1][AddMeanPressureToEdgeId[eid]])*nvel*nz_loc];
642 
643  int psize = pressure->GetExp(eid)->GetNcoeffs();
644  for(n = 0; n < nz_loc; ++n)
645  {
646  m_localToGlobalMap[cnt + nz_loc*nvel*velnbndry + n*psize] = graphVertOffset[(ReorderedGraphVertId[1][AddMeanPressureToEdgeId[eid]]+1)*nvel*nz_loc-1]+nEdgeInteriorCoeffs + pressureEdgeOffset[AddMeanPressureToEdgeId[eid]];
647 
648  pressureEdgeOffset[AddMeanPressureToEdgeId[eid]] += 1;
649  }
650 
651  cnt += (velnbndry*nvel+ psize)*nz_loc;
652  }
653 
654  // Set up the mapping for the boundary conditions
655  offset = cnt = 0;
656  for(nv = 0; nv < nvel; ++nv)
657  {
658  for(i = 0; i < bndCondExp.num_elements(); i++)
659  {
660  for(n = 0; n < nz_loc; ++n)
661  {
662  int ncoeffcnt = 0;
663  for(j = 0; j < bndCondExp[i]->GetNumElmts(); j++)
664  {
665  bndSegExp = bndCondExp[i]->GetExp(j)
666  ->as<LocalRegions::SegExp>();
667 
668  cnt = offset + bndCondExp[i]->GetCoeff_Offset(j);
669  for(k = 0; k < 2; k++)
670  {
671  meshVertId = (bndSegExp->GetGeom1D())->GetVid(k);
672  m_bndCondCoeffsToGlobalCoeffsMap[cnt+bndSegExp->GetVertexMap(k)] = graphVertOffset[ReorderedGraphVertId[0][meshVertId]*nvel*nz_loc+nv*nz_loc+n];
673  }
674 
675  meshEdgeId = (bndSegExp->GetGeom1D())->GetEid();
676  bndEdgeCnt = 0;
677  nEdgeCoeffs = bndSegExp->GetNcoeffs();
678  for(k = 0; k < nEdgeCoeffs; k++)
679  {
680  if(m_bndCondCoeffsToGlobalCoeffsMap[cnt+k] == -1)
681  {
682  m_bndCondCoeffsToGlobalCoeffsMap[cnt+k] =
683  graphVertOffset[ReorderedGraphVertId[1][meshEdgeId]*nvel*nz_loc+nv*nz_loc+n]+bndEdgeCnt;
684  bndEdgeCnt++;
685  }
686  }
687  ncoeffcnt += nEdgeCoeffs;
688  }
689  // Note: Can not use bndCondExp[i]->GetNcoeffs()
690  // due to homogeneous extension not returning just
691  // the value per plane
692  offset += ncoeffcnt;
693  }
694  }
695  }
696 
697  globalId = Vmath::Vmax(m_numLocalCoeffs,&m_localToGlobalMap[0],1)+1;
698  m_numGlobalBndCoeffs = globalId;
699 
700  /**
701  * STEP 5: The boundary condition mapping is generated from the
702  * same vertex renumbering and fill in a unique interior map.
703  */
704  cnt=0;
705  for(i = 0; i < m_numLocalCoeffs; ++i)
706  {
707  if(m_localToGlobalMap[i] == -1)
708  {
709  m_localToGlobalMap[i] = globalId++;
710  }
711  else
712  {
713  if(m_signChange)
714  {
715  m_localToGlobalBndSign[cnt]=m_localToGlobalSign[i];
716  }
717  m_localToGlobalBndMap[cnt++]=m_localToGlobalMap[i];
718  }
719  }
720  m_numGlobalCoeffs = globalId;
721 
722  // Set up the local to global map for the next level when using
723  // multi-level static condensation
724  if( m_session->MatchSolverInfoAsEnum("GlobalSysSoln", MultiRegions::eDirectMultiLevelStaticCond) )
725  {
726  if (m_staticCondLevel < (bottomUpGraph->GetNlevels()-1))
727  {
728  Array<OneD, int> vwgts_perm(
729  Dofs[0].size()+Dofs[1].size()-firstNonDirGraphVertId);
730  for(i = 0; i < locExpVector.size(); ++i)
731  {
732  int eid = fields[0]->GetOffset_Elmt_Id(i);
733  locExpansion = locExpVector[eid]
735  for(j = 0; j < locExpansion->GetNverts(); ++j)
736  {
737  meshEdgeId = (locExpansion
739  ->GetGeom2D())->GetEid(j);
740  meshVertId = (locExpansion
742  ->GetGeom2D())->GetVid(j);
743 
744  if(ReorderedGraphVertId[0][meshVertId] >=
745  firstNonDirGraphVertId)
746  {
747  vwgts_perm[ReorderedGraphVertId[0][meshVertId]-
748  firstNonDirGraphVertId] =
749  Dofs[0][meshVertId];
750  }
751 
752  if(ReorderedGraphVertId[1][meshEdgeId] >=
753  firstNonDirGraphVertId)
754  {
755  vwgts_perm[ReorderedGraphVertId[1][meshEdgeId]-
756  firstNonDirGraphVertId] =
757  Dofs[1][meshEdgeId];
758  }
759  }
760  }
761 
762  bottomUpGraph->ExpandGraphWithVertexWeights(vwgts_perm);
763 
765  AllocateSharedPtr(this,bottomUpGraph);
766  }
767  }
768  }
769 }
770 
771 
772 void CoupledLocalToGlobalC0ContMap::FindEdgeIdToAddMeanPressure(Array<OneD, map<int,int> > &ReorderedGraphVertId,
773  int &nel, const LocalRegions::ExpansionVector &locExpVector,
774  int &edgeId, int &vertId, int &firstNonDirGraphVertId, map<int,int> &IsDirEdgeDof,
776  Array<OneD, int> &AddMeanPressureToEdgeId)
777 {
778 
779  int i,j,k;
780 
781  // Make list of homogeneous graph edges to elmt mappings
782  Array<TwoD, int> EdgeIdToElmts(ReorderedGraphVertId[1].size(),2,-1);
783  map<int,int> HomGraphEdgeIdToEdgeId;
784 
785  for(i = 0; i < nel; ++i)
786  {
787  for(j = 0; j < locExpVector[i]->GetNverts(); ++j)
788  {
789  edgeId = (locExpVector[i]->as<LocalRegions::Expansion2D>()
790  ->GetGeom2D())->GetEid(j);
791 
792  // note second condition stops us using mixed boundary condition
793  if((ReorderedGraphVertId[1][edgeId] >= firstNonDirGraphVertId)
794  && (IsDirEdgeDof.count(edgeId) == 0))
795  {
796  HomGraphEdgeIdToEdgeId[ReorderedGraphVertId[1][edgeId]-firstNonDirGraphVertId] = edgeId;
797 
798  if(EdgeIdToElmts[edgeId][0] == -1)
799  {
800  EdgeIdToElmts[edgeId][0] = i;
801  }
802  else
803  {
804  EdgeIdToElmts[edgeId][1] = i;
805  }
806  }
807  }
808  }
809 
810 
812 
813  // Start at second to last level and find edge on boundary
814  // to attach element
815  int nlevels = bottomUpGraph->GetNlevels();
816 
817  // determine a default edge to attach pressure modes to
818  // which is part of the inner solve;
819  int defedge = -1;
820 
821  vector<MultiRegions::SubGraphSharedPtr> bndgraphs = bottomUpGraph->GetInteriorBlocks(nlevels);
822  for(i = 0; i < bndgraphs.size(); ++i)
823  {
824  int GlobIdOffset = bndgraphs[i]->GetIdOffset();
825 
826  for(j = 0; j < bndgraphs[i]->GetNverts(); ++j)
827  {
828  // find edge in graph vert list
829  if(HomGraphEdgeIdToEdgeId.count(GlobIdOffset+j) != 0)
830  {
831  edgeId = HomGraphEdgeIdToEdgeId[GlobIdOffset+j];
832 
833  if(defedge == -1)
834  {
835  defedge = edgeId;
836  break;
837  }
838  }
839  }
840  if(defedge != -1)
841  {
842  break;
843  }
844  }
845 
846  for(int n = 1; n < nlevels; ++n)
847  {
848  // produce a map with a key that is the element id
849  // that contains which next level patch it belongs to
850  vector<MultiRegions::SubGraphSharedPtr> bndgraphs = bottomUpGraph->GetInteriorBlocks(n+1);
851 
852  // Fill next level graph of adjacent elements and their level
853  map<int,int> ElmtInBndry;
854 
855  for(i = 0; i < bndgraphs.size(); ++i)
856  {
857  int GlobIdOffset = bndgraphs[i]->GetIdOffset();
858 
859  for(j = 0; j < bndgraphs[i]->GetNverts(); ++j)
860  {
861  // find edge in graph vert list
862  if(HomGraphEdgeIdToEdgeId.count(GlobIdOffset+j) != 0)
863  {
864  edgeId = HomGraphEdgeIdToEdgeId[GlobIdOffset+j];
865 
866  if(EdgeIdToElmts[edgeId][0] != -1)
867  {
868  ElmtInBndry[EdgeIdToElmts[edgeId][0]] = i;
869  }
870  if(EdgeIdToElmts[edgeId][1] != -1)
871  {
872  ElmtInBndry[EdgeIdToElmts[edgeId][1]] = i;
873  }
874  }
875  }
876  }
877 
878  // Now search interior patches in this level for edges
879  // that share the same element as a boundary edge and
880  // assign this elmt that boundary edge
881  vector<MultiRegions::SubGraphSharedPtr> intgraphs = bottomUpGraph->GetInteriorBlocks(n);
882  for(i = 0; i < intgraphs.size(); ++i)
883  {
884  int GlobIdOffset = intgraphs[i]->GetIdOffset();
885  bool SetEdge = false;
886  int elmtid;
887  for(j = 0; j < intgraphs[i]->GetNverts(); ++j)
888  {
889  // Check to see if graph vert is an edge
890  if(HomGraphEdgeIdToEdgeId.count(GlobIdOffset+j) != 0)
891  {
892  edgeId = HomGraphEdgeIdToEdgeId[GlobIdOffset+j];
893 
894  for(k = 0; k < 2; ++k)
895  {
896  // relevant edge id
897  elmtid = EdgeIdToElmts[edgeId][k];
898 
899  if(elmtid != -1)
900  {
901  mapIt = ElmtInBndry.find(elmtid);
902 
903  if(mapIt != ElmtInBndry.end())
904  {
905  // now find a edge in the next level boundary graph
906  int GlobIdOffset1 = bndgraphs[mapIt->second]->GetIdOffset();
907  for(int l = 0; l < bndgraphs[mapIt->second]->GetNverts(); ++l)
908  {
909  // find edge in graph vert list
910  if(HomGraphEdgeIdToEdgeId.count(GlobIdOffset1+l) != 0)
911  {
912  //June 2012: commenting this condition apparently
913  //solved the bug caused by the edge reordering procedure
914 
915  //if(AddMeanPressureToEdgeId[elmtid] == -1)
916  //{
917 
918  //AddMeanPressureToEdgeId[elmtid] = HomGraphEdgeIdToEdgeId[GlobIdOffset1+l];
919  AddMeanPressureToEdgeId[elmtid] = defedge;
920 
921  //}
922  SetEdge = true;
923  break;
924  }
925  }
926  }
927  }
928  }
929  }
930  }
931 
932 
933  // if we have failed to find matching edge in next
934  // level patch boundary then set last found elmt
935  // associated to this interior patch to the
936  // default edget value
937  if(SetEdge == false)
938  {
939  if(elmtid == -1) // find an elmtid in patch
940  {
941  for(j = 0; j < intgraphs[i]->GetNverts(); ++j)
942  {
943  if(HomGraphEdgeIdToEdgeId.count(GlobIdOffset+j) != 0)
944  {
945  edgeId = HomGraphEdgeIdToEdgeId[GlobIdOffset+j];
946  for(k = 0; k < 2; ++k)
947  {
948  // relevant edge id
949  elmtid = EdgeIdToElmts[edgeId][k];
950  if(elmtid != -1)
951  {
952  break;
953  }
954  }
955  }
956  if(elmtid != -1)
957  {
958  break;
959  }
960  }
961  }
962  if(AddMeanPressureToEdgeId[elmtid] == -1)
963  {
964  AddMeanPressureToEdgeId[elmtid] = defedge;
965  }
966  }
967  }
968  }
969 
970 }
971 
972 
973 
974 
975 
976