Nektar++
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 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 //
31 // Description: Wrapper class around the library
32 // LocalToGlobalC0ContMap class for use in the Couplied Linearised NS
33 // solver.
34 ///////////////////////////////////////////////////////////////////////////////
35 
38 #include <LocalRegions/SegExp.h>
42 
43 using namespace std;
44 
45 namespace Nektar
46 {
47  /**
48  * This is an vector extension of
49  * MultiRegions::AssemblyMapCG::SetUp2DExpansionC0ContMap related to the
50  * Linearised Navier Stokes problem
51  */
52  CoupledLocalToGlobalC0ContMap::CoupledLocalToGlobalC0ContMap(
55  const SpatialDomains::BoundaryConditionsSharedPtr &boundaryConditions,
58  const int nz_loc,
59  const bool CheckforSingularSys):
60  AssemblyMapCG(pSession)
61  {
62  int i,j,k,n;
63  int cnt = 0,offset=0;
64  int meshVertId;
65  int meshEdgeId;
66  int bndEdgeCnt;
67  int globalId;
68  int nEdgeCoeffs;
69  int nEdgeInteriorCoeffs;
70  int firstNonDirGraphVertId;
71  int nLocBndCondDofs = 0;
72  int nLocDirBndCondDofs = 0;
73  int nExtraDirichlet = 0;
77  StdRegions::Orientation edgeOrient;
78  Array<OneD, unsigned int> edgeInteriorMap;
79  Array<OneD, int> edgeInteriorSign;
80  int nvel = fields.size();
81 
82  const LocalRegions::ExpansionVector &locExpVector = *(fields[0]->GetExp());
83  int id, diff;
84  int nel = fields[0]->GetNumElmts();
85 
86  MultiRegions::PeriodicMap periodicVerts;
87  MultiRegions::PeriodicMap periodicEdges;
88  MultiRegions::PeriodicMap periodicFaces;
89  vector<map<int,int> > ReorderedGraphVertId(3);
91  int staticCondLevel = 0;
92 
93  if(CheckforSingularSys) //all singularity checking by setting flag to true
94  {
95  m_systemSingular = true;
96  }
97  else // Turn off singular checking by setting flag to false
98  {
99  m_systemSingular = false;
100  }
101 
102  /**
103  * STEP 1: Wrap boundary conditions vector in an array
104  * (since routine is set up for multiple fields) and call
105  * the graph re-odering subroutine to obtain the reordered
106  * values
107  */
108 
109  // Obtain any periodic information and allocate default mapping array
110  fields[0]->GetPeriodicEntities(periodicVerts,periodicEdges,periodicFaces);
111 
112 
113  const Array<OneD, const MultiRegions::ExpListSharedPtr> bndCondExp = fields[0]->GetBndCondExpansions();
114 
116  for(i = 0; i < nvel; ++i)
117  {
118  bndConditionsVec[i] = fields[i]->GetBndConditions();
119  }
120 
121  map<int,int> IsDirVertDof;
122  map<int,int> IsDirEdgeDof;
123 
125  for(j = 0; j < bndCondExp.size(); ++j)
126  {
127  map<int,int> BndExpVids;
128  // collect unique list of vertex ids for this expansion
129  for(k = 0; k < bndCondExp[j]->GetNumElmts(); ++k)
130  {
131  g = bndCondExp[j]->GetExp(k)->as<LocalRegions::Expansion1D>()
132  ->GetGeom1D();
133  BndExpVids[g->GetVid(0)] = g->GetVid(0);
134  BndExpVids[g->GetVid(1)] = g->GetVid(1);
135  }
136 
137  for(i = 0; i < nvel; ++i)
138  {
139  if(bndConditionsVec[i][j]->GetBoundaryConditionType()==SpatialDomains::eDirichlet)
140  {
141  // set number of Dirichlet conditions along edge
142  for(k = 0; k < bndCondExp[j]->GetNumElmts(); ++k)
143  {
144  IsDirEdgeDof[bndCondExp[j]->GetExp(k)
146  ->GetGeom1D()->GetGlobalID()] += 1;
147  }
148 
149 
150  // Set number of Dirichlet conditions at vertices
151  // with a clamp on its maximum value being nvel to
152  // handle corners between expansions
153  for(auto &mapIt : BndExpVids)
154  {
155  id = IsDirVertDof[mapIt.second]+1;
156  IsDirVertDof[mapIt.second] = (id > nvel)?nvel:id;
157  }
158  }
159  else
160  {
161  // Check to see that edge normals have non-zero
162  // component in this direction since otherwise
163  // also can be singular.
164  /// @TODO: Fix this so that we can extract normals from edges
165  for(k = 0; k < bndCondExp[j]->GetNumElmts(); ++k)
166  {
169  = bndCondExp[j]->GetExp(k)
171  locnorm = loc_exp->GetLeftAdjacentElementExp()->
172  GetTraceNormal(loc_exp->GetLeftAdjacentElementTrace());
173 
174  int ndir = locnorm.size();
175  if(i < ndir) // account for Fourier version where n can be larger then ndir
176  {
177  for(int l = 0; l < locnorm[0].size(); ++l)
178  {
179  if(fabs(locnorm[i][l]) > NekConstants::kNekZeroTol)
180  {
181  m_systemSingular = false;
182  break;
183  }
184  }
185  }
186  if(m_systemSingular == false)
187  {
188  break;
189  }
190  }
191  }
192  }
193  }
194 
195  Array<OneD, map<int,int> >Dofs(2);
196 
197  Array<OneD, int> AddMeanPressureToEdgeId(nel,-1);
198  int edgeId,vertId;
199 
200 
201  // special case of singular problem - need to fix one pressure
202  // dof to a dirichlet edge. Since we attached pressure dof to
203  // last velocity component of edge need to make sure this
204  // component is Dirichlet
205  if(m_systemSingular)
206  {
207  id = -1;
208  for(i = 0; i < bndConditionsVec[0].size(); ++i)
209  {
210  if(bndConditionsVec[nvel-1][i]->GetBoundaryConditionType() == SpatialDomains::eDirichlet)
211  {
212  id = bndCondExp[i]->GetExp(0)
213  ->as<LocalRegions::Expansion1D>()->GetGeom1D()
214  ->GetGlobalID();
215  break;
216  }
217  }
218 
219  ASSERTL0(id != -1," Did not find an edge to attach singular pressure degree of freedom");
220 
221  // determine element with this edge id. There may be a
222  // more direct way of getting element from spatialDomains
223  for(i = 0; i < nel; ++i)
224  {
225  for(j = 0; j < locExpVector[i]->GetNverts(); ++j)
226  {
227  edgeId = (locExpVector[i]->as<LocalRegions::Expansion2D>()
228  ->GetGeom2D())->GetEid(j);
229 
230  if(edgeId == id)
231  {
232  AddMeanPressureToEdgeId[i] = id;
233  break;
234  }
235  }
236 
237  if(AddMeanPressureToEdgeId[i] != -1)
238  {
239  break;
240  }
241  }
242  }
243 
244 
245  for(i = 0; i < nel; ++i)
246  {
247  for(j = 0; j < locExpVector[i]->GetNverts(); ++j)
248  {
249  vertId = (locExpVector[i]->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[i]->as<LocalRegions::Expansion2D>()
263  ->GetGeom2D())->GetEid(j);
264  if(Dofs[1].count(edgeId) == 0)
265  {
266  Dofs[1][edgeId] = nvel*(locExpVector[i]->
267  GetTraceNcoeffs(j)-2)*nz_loc;
268  }
269 
270  // Adjust for Dirichlet boundary conditions to give number to be solved
271  if(IsDirEdgeDof.count(edgeId) != 0)
272  {
273  Dofs[1][edgeId] -= IsDirEdgeDof[edgeId]*nz_loc*(locExpVector[i]->
274  GetTraceNcoeffs(j)-2);
275  }
276  }
277  }
278 
279  set<int> extraDirVerts, extraDirEdges;
280 
281  CreateGraph(*fields[0], bndCondExp, bndConditionsVec, false,
282  periodicVerts, periodicEdges, periodicFaces,
283  ReorderedGraphVertId, bottomUpGraph, extraDirVerts,
284  extraDirEdges, firstNonDirGraphVertId, nExtraDirichlet, 4);
285  /*
286  SetUp2DGraphC0ContMap(*fields[0],
287  bndCondExp,
288  bndConditionsVec,
289  periodicVerts, periodicEdges,
290  Dofs, ReorderedGraphVertId,
291  firstNonDirGraphVertId, nExtraDirichlet,
292  bottomUpGraph, extraDir, false, 4);
293  */
294 
295  /**
296  * STEP 2a: Set the mean pressure modes to edges depending on
297  * type of direct solver technique;
298  */
299 
300  // determine which edge to add mean pressure dof based on
301  // ensuring that at least one pressure dof from an internal
302  // patch is associated with its boundary system
303  if(m_session->MatchSolverInfoAsEnum("GlobalSysSoln", MultiRegions::eDirectMultiLevelStaticCond))
304  {
305 
306 
307  FindEdgeIdToAddMeanPressure(ReorderedGraphVertId,
308  nel, locExpVector,
309  edgeId, vertId, firstNonDirGraphVertId, IsDirEdgeDof,
310  bottomUpGraph,
311  AddMeanPressureToEdgeId);
312  }
313 
314  // Set unset elmts to non-Dirichlet edges.
315  // special case of singular problem - need to fix one
316  // pressure dof to a dirichlet edge
317  for(i = 0; i < nel; ++i)
318  {
319  for(j = 0; j < locExpVector[i]->GetNverts(); ++j)
320  {
321  edgeId = (locExpVector[i]->as<LocalRegions::Expansion2D>()
322  ->GetGeom2D())->GetEid(j);
323 
324  if(IsDirEdgeDof.count(edgeId) == 0) // interior edge
325  {
326  // setup AddMeanPressureToEdgeId to decide where to
327  // put pressure
328  if(AddMeanPressureToEdgeId[i] == -1)
329  {
330  AddMeanPressureToEdgeId[i] = edgeId;
331  }
332  }
333  }
334  ASSERTL0((AddMeanPressureToEdgeId[i] != -1),"Did not determine "
335  "an edge to attach mean pressure dof");
336  // Add the mean pressure degree of freedom to this edge
337  Dofs[1][AddMeanPressureToEdgeId[i]] += nz_loc;
338  }
339 
340  map<int,int> pressureEdgeOffset;
341 
342  /**
343  * STEP 2: Count out the number of Dirichlet vertices and edges first
344  */
345  for(i = 0; i < bndCondExp.size(); i++)
346  {
347  for(j = 0; j < bndCondExp[i]->GetNumElmts(); j++)
348  {
349  bndSegExp = bndCondExp[i]->GetExp(j)
350  ->as<LocalRegions::SegExp>();
351  for(k = 0; k < nvel; ++k)
352  {
353  if(bndConditionsVec[k][i]->GetBoundaryConditionType()==SpatialDomains::eDirichlet)
354  {
355  nLocDirBndCondDofs += bndSegExp->GetNcoeffs()*nz_loc;
356  }
357 
358  if (bndConditionsVec[k][i]->GetBoundaryConditionType()!=SpatialDomains::ePeriodic)
359  {
360  nLocBndCondDofs += bndSegExp->GetNcoeffs()*nz_loc;
361  }
362  }
363  }
364  }
365 
366  if(m_systemSingular)
367  {
368  m_numLocalDirBndCoeffs = nLocDirBndCondDofs+nExtraDirichlet+nz_loc;
369  }
370  else
371  {
372  m_numLocalDirBndCoeffs = nLocDirBndCondDofs+nExtraDirichlet;
373  }
374 
375  /**
376  * STEP 3: Set up an array which contains the offset information of
377  * the different graph vertices.
378  *
379  * This basically means to identify how many global degrees of
380  * freedom the individual graph vertices correspond. Obviously,
381  * the graph vertices corresponding to the mesh-vertices account
382  * for a single global DOF. However, the graph vertices
383  * corresponding to the element edges correspond to 2*(N-2) global DOF
384  * where N is equal to the number of boundary modes on this edge.
385  */
386  Array<OneD, int> graphVertOffset(nvel*nz_loc*(ReorderedGraphVertId[0].size() + ReorderedGraphVertId[1].size()),0);
387  graphVertOffset[0] = 0;
388 
389  m_signChange = false;
390 
391  for(i = 0; i < nel; ++i)
392  {
393  locExpansion = locExpVector[i]->as<LocalRegions::Expansion2D>();
394 
395  for(j = 0; j < locExpansion->GetNtraces(); ++j)
396  {
397  nEdgeCoeffs = locExpansion->GetTraceNcoeffs(j);
398  meshEdgeId = (locExpansion->GetGeom2D())->GetEid(j);
399  meshVertId = (locExpansion->GetGeom2D())->GetVid(j);
400 
401  for(k = 0; k < nvel*nz_loc; ++k)
402  {
403  graphVertOffset[ReorderedGraphVertId[0]
404  [meshVertId]*nvel*nz_loc+k] = 1;
405  graphVertOffset[ReorderedGraphVertId[1]
406  [meshEdgeId]*nvel*nz_loc+k] = (nEdgeCoeffs-2);
407  }
408 
409  bType = locExpansion->GetBasisType(0);
410  // need a sign vector for modal expansions if nEdgeCoeffs >=4
411  if( (nEdgeCoeffs >= 4)&&(bType == LibUtilities::eModified_A))
412  {
413  m_signChange = true;
414  }
415  }
416  }
417 
418  // Add mean pressure modes;
419  for(i = 0; i < nel; ++i)
420  {
421  graphVertOffset[(ReorderedGraphVertId[1][AddMeanPressureToEdgeId[i]]+1)*nvel*nz_loc-1] += nz_loc;
422  //graphVertOffset[(ReorderedGraphVertId[1][AddMeanPressureToEdgeId[i]])*nvel*nz_loc] += nz_loc;
423  }
424 
425  // Negate the vertices and edges with only a partial
426  // Dirichlet conditon. Essentially we check to see if an edge
427  // has a mixed Dirichlet with Neumann/Robin Condition and if
428  // so negate the offset associated with this vertex.
429 
430  map<int,int> DirVertChk;
431 
432  for(i = 0; i < bndConditionsVec[0].size(); ++i)
433  {
434  cnt = 0;
435  for(j = 0; j < nvel; ++j)
436  {
437  if(bndConditionsVec[j][i]->GetBoundaryConditionType() == SpatialDomains::eDirichlet)
438  {
439  cnt ++;
440  }
441  }
442 
443  // Case where partial Dirichlet boundary condition
444  if((cnt > 0)&&(cnt < nvel))
445  {
446  for(j = 0; j < nvel; ++j)
447  {
448  if(bndConditionsVec[j][i]->GetBoundaryConditionType() == SpatialDomains::eDirichlet)
449  {
450  //negate graph offsets which should be
451  //Dirichlet conditions
452  for(k = 0; k < bndCondExp[i]->GetNumElmts(); ++k)
453  {
454  // vertices with mix condition;
455  id = bndCondExp[i]->GetExp(k)
457  ->GetGeom1D()->GetVid(0);
458  if(DirVertChk.count(id*nvel+j) == 0)
459  {
460  DirVertChk[id*nvel+j] = 1;
461  for(n = 0; n < nz_loc; ++n)
462  {
463  graphVertOffset[ReorderedGraphVertId[0][id]*nvel*nz_loc+j*nz_loc + n] *= -1;
464  }
465  }
466 
467  id = bndCondExp[i]->GetExp(k)
469  ->GetGeom1D()->GetVid(1);
470  if(DirVertChk.count(id*nvel+j) == 0)
471  {
472  DirVertChk[id*nvel+j] = 1;
473  for(n = 0; n < nz_loc; ++n)
474  {
475  graphVertOffset[ReorderedGraphVertId[0][id]*nvel*nz_loc+j*nz_loc+n] *= -1;
476  }
477  }
478 
479  // edges with mixed id;
480  id = bndCondExp[i]->GetExp(k)
482  ->GetGeom1D()->GetGlobalID();
483  for(n = 0; n < nz_loc; ++n)
484  {
485  graphVertOffset[ReorderedGraphVertId[1][id]*nvel*nz_loc+j*nz_loc +n] *= -1;
486  }
487  }
488  }
489  }
490  }
491  }
492 
493 
494  cnt = 0;
495  // assemble accumulative list of full Dirichlet values.
496  for(i = 0; i < firstNonDirGraphVertId*nvel*nz_loc; ++i)
497  {
498  diff = abs(graphVertOffset[i]);
499  graphVertOffset[i] = cnt;
500  cnt += diff;
501  }
502 
503  // set Dirichlet values with negative values to Dirichlet value
504  for(i = firstNonDirGraphVertId*nvel*nz_loc; i < graphVertOffset.size(); ++i)
505  {
506  if(graphVertOffset[i] < 0)
507  {
508  diff = -graphVertOffset[i];
509  graphVertOffset[i] = -cnt;
510  cnt += diff;
511  }
512  }
513 
514  // Accumulate all interior degrees of freedom with positive values
516 
517  // offset values
518  for(i = firstNonDirGraphVertId*nvel*nz_loc; i < graphVertOffset.size(); ++i)
519  {
520  if(graphVertOffset[i] >= 0)
521  {
522  diff = graphVertOffset[i];
523  graphVertOffset[i] = cnt;
524  cnt += diff;
525  }
526  }
527 
528  // Finally set negative entries (corresponding to Dirichlet
529  // values ) to be positive
530  for(i = firstNonDirGraphVertId*nvel*nz_loc; i < graphVertOffset.size(); ++i)
531  {
532  if(graphVertOffset[i] < 0)
533  {
534  graphVertOffset[i] = -graphVertOffset[i];
535  }
536  }
537 
538 
539  // Allocate the proper amount of space for the class-data and fill
540  // information that is already known
541  cnt = 0;
543  m_numLocalCoeffs = 0;
544 
545  for(i = 0; i < nel; ++i)
546  {
547  m_numLocalBndCoeffs += nz_loc*(nvel*locExpVector[i]->NumBndryCoeffs() + 1);
548  // add these coeffs up separately since
549  // pressure->GetNcoeffs can include the coefficient in
550  // multiple planes.
551  m_numLocalCoeffs += (pressure->GetExp(i)->GetNcoeffs()-1)*nz_loc;
552  }
553 
555 
556 
559  m_bndCondIDToGlobalTraceID = Array<OneD, int>(nLocBndCondDofs,-1);
560 
561 
562  // Set default sign array.
565 
566  m_staticCondLevel = staticCondLevel;
567  m_numPatches = nel;
568 
571 
572  for(i = 0; i < nel; ++i)
573  {
574  m_numLocalBndCoeffsPerPatch[i] = (unsigned int) nz_loc*(nvel*locExpVector[i]->NumBndryCoeffs() + 1);
575  m_numLocalIntCoeffsPerPatch[i] = (unsigned int) nz_loc*(pressure->GetExp(i)->GetNcoeffs()-1);
576  }
577 
578  // Set up local to local bnd and local int maps
582 
583  int bndcnt = 0;
584  int intcnt = 0;
585  cnt = 0;
586  for(i = 0; i < nel; ++i)
587  {
588  for(j = 0; j < nz_loc*(nvel*locExpVector[i]->NumBndryCoeffs()); ++j)
589  {
590  m_localToLocalBndMap[bndcnt++] = cnt++;
591  }
592 
593  for(n = 0; n < nz_loc; ++n)
594  {
595  m_localToLocalBndMap[bndcnt++] = cnt++;
596  for(j = 1; j < pressure->GetExp(i)->GetNcoeffs(); ++j)
597  {
598  m_localToLocalIntMap[intcnt++] = cnt++;
599  }
600  }
601 
602  }
603 
604  /**
605  * STEP 4: Now, all ingredients are ready to set up the actual
606  * local to global mapping.
607  *
608  * The remainder of the map consists of the element-interior
609  * degrees of freedom. This leads to the block-diagonal submatrix
610  * as each element-interior mode is globally orthogonal to modes
611  * in all other elements.
612  */
613  cnt = 0;
614  int nv,velnbndry;
616 
617 
618  // Loop over all the elements in the domain in shuffled
619  // ordering (element type consistency)
620  for(i = 0; i < nel; ++i)
621  {
622  locExpansion = locExpVector[i]->as<LocalRegions::Expansion2D>();
623 
624  velnbndry = locExpansion->NumBndryCoeffs();
625 
626  // Require an inverse ordering of the bmap system to store
627  // local numbering system. Therefore get hold of elemental
628  // bmap and set up an inverse map
629  map<int,int> inv_bmap;
630  locExpansion->GetBoundaryMap(bmap);
631  for(j = 0; j < bmap.size(); ++j)
632  {
633  inv_bmap[bmap[j]] = j;
634  }
635 
636  // Loop over all edges (and vertices) of element i
637  for(j = 0; j < locExpansion->GetNtraces(); ++j)
638  {
639  nEdgeInteriorCoeffs = locExpansion->GetTraceNcoeffs(j)-2;
640  edgeOrient = (locExpansion->GetGeom())->GetEorient(j);
641  meshEdgeId = (locExpansion->GetGeom())->GetEid(j);
642  meshVertId = (locExpansion->GetGeom())->GetVid(j);
643 
644  auto pIt = periodicEdges.find(meshEdgeId);
645 
646  // See if this edge is periodic. If it is, then we map all
647  // edges to the one with lowest ID, and align all
648  // coefficients to this edge orientation.
649  if (pIt != periodicEdges.end())
650  {
651  pair<int, StdRegions::Orientation> idOrient =
653  meshEdgeId, edgeOrient, pIt->second);
654  edgeOrient = idOrient.second;
655  }
656 
657  locExpansion->GetTraceInteriorToElementMap(j,edgeInteriorMap,
658  edgeInteriorSign,edgeOrient);
659 
660  // Set the global DOF for vertex j of element i
661  for(nv = 0; nv < nvel*nz_loc; ++nv)
662  {
663  m_localToGlobalMap[cnt+nv*velnbndry+
664  inv_bmap[locExpansion->GetVertexMap(j)]]
665  = graphVertOffset[ReorderedGraphVertId[0]
666  [meshVertId]*nvel*nz_loc+ nv];
667 
668  // Set the global DOF's for the interior modes of edge j
669  for(k = 0; k < nEdgeInteriorCoeffs; ++k)
670  {
671  m_localToGlobalMap[cnt+nv*velnbndry+
672  inv_bmap[edgeInteriorMap[k]]] =
673  graphVertOffset[ReorderedGraphVertId[1]
674  [meshEdgeId]*nvel*nz_loc+nv]+k;
675  }
676  }
677 
678  // Fill the sign vector if required
679  if(m_signChange)
680  {
681  for(nv = 0; nv < nvel*nz_loc; ++nv)
682  {
683  for(k = 0; k < nEdgeInteriorCoeffs; ++k)
684  {
685  m_localToGlobalSign[cnt+nv*velnbndry +
686  inv_bmap[edgeInteriorMap[k]]]
687  = (NekDouble) edgeInteriorSign[k];
688  }
689  }
690  }
691  }
692 
693  // use difference between two edges of the
694  // AddMeanPressureEdgeId to det nEdgeInteriorCoeffs.
695  nEdgeInteriorCoeffs = graphVertOffset[(ReorderedGraphVertId[1][AddMeanPressureToEdgeId[i]])*nvel*nz_loc+1] - graphVertOffset[(ReorderedGraphVertId[1][AddMeanPressureToEdgeId[i]])*nvel*nz_loc];
696 
697  int psize = pressure->GetExp(i)->GetNcoeffs();
698  for(n = 0; n < nz_loc; ++n)
699  {
700  m_localToGlobalMap[cnt + nz_loc*nvel*velnbndry + n*psize] =
701  graphVertOffset[(ReorderedGraphVertId[1]
702  [AddMeanPressureToEdgeId[i]]+1)*nvel*nz_loc-1]+
703  nEdgeInteriorCoeffs +
704  pressureEdgeOffset[AddMeanPressureToEdgeId[i]];
705 
706  pressureEdgeOffset[AddMeanPressureToEdgeId[i]] += 1;
707  }
708 
709  cnt += (velnbndry*nvel+ psize)*nz_loc;
710  }
711 
712  // Set up the mapping for the boundary conditions
713  offset = cnt = 0;
714  for(nv = 0; nv < nvel; ++nv)
715  {
716  for(i = 0; i < bndCondExp.size(); i++)
717  {
718  if (bndConditionsVec[nv][i]->GetBoundaryConditionType()==
720  {
721  continue;
722  }
723 
724  for(n = 0; n < nz_loc; ++n)
725  {
726  int ncoeffcnt = 0;
727  for(j = 0; j < bndCondExp[i]->GetNumElmts(); j++)
728  {
729  bndSegExp = bndCondExp[i]->GetExp(j)
730  ->as<LocalRegions::SegExp>();
731 
732  cnt = offset + bndCondExp[i]->GetCoeff_Offset(j);
733  for(k = 0; k < 2; k++)
734  {
735  meshVertId = (bndSegExp->GetGeom1D())->GetVid(k);
737  bndSegExp->GetVertexMap(k)] =
738  graphVertOffset[ReorderedGraphVertId[0]
739  [meshVertId]*nvel*nz_loc+nv*nz_loc+n];
740  }
741 
742  meshEdgeId = (bndSegExp->GetGeom1D())->GetGlobalID();
743  bndEdgeCnt = 0;
744  nEdgeCoeffs = bndSegExp->GetNcoeffs();
745  for(k = 0; k < nEdgeCoeffs; k++)
746  {
747  if(m_bndCondIDToGlobalTraceID[cnt+k] == -1)
748  {
750  graphVertOffset[ReorderedGraphVertId[1]
751  [meshEdgeId]*nvel*nz_loc+nv*nz_loc+n]+bndEdgeCnt;
752  bndEdgeCnt++;
753  }
754  }
755  ncoeffcnt += nEdgeCoeffs;
756  }
757  // Note: Can not use bndCondExp[i]->GetNcoeffs()
758  // due to homogeneous extension not returning just
759  // the value per plane
760  offset += ncoeffcnt;
761  }
762  }
763  }
764 
765  globalId = Vmath::Vmax(m_numLocalCoeffs,&m_localToGlobalMap[0],1)+1;
766  m_numGlobalBndCoeffs = globalId;
767 
768  /**
769  * STEP 5: The boundary condition mapping is generated from the
770  * same vertex renumbering and fill in a unique interior map.
771  */
772  cnt=0;
773  for(i = 0; i < m_numLocalCoeffs; ++i)
774  {
775  if(m_localToGlobalMap[i] == -1)
776  {
777  m_localToGlobalMap[i] = globalId++;
778  }
779  else
780  {
781  if(m_signChange)
782  {
784  }
786  }
787  }
788  m_numGlobalCoeffs = globalId;
789 
790  // Set up the local to global map for the next level when using
791  // multi-level static condensation
792  if( m_session->MatchSolverInfoAsEnum("GlobalSysSoln", MultiRegions::eDirectMultiLevelStaticCond) )
793  {
794  if (m_staticCondLevel < (bottomUpGraph->GetNlevels()-1))
795  {
796  Array<OneD, int> vwgts_perm(
797  Dofs[0].size()+Dofs[1].size()-firstNonDirGraphVertId);
798  for(i = 0; i < locExpVector.size(); ++i)
799  {
800  locExpansion = locExpVector[i]->as<LocalRegions::Expansion2D>();
801  for(j = 0; j < locExpansion->GetNverts(); ++j)
802  {
803  meshEdgeId = (locExpansion->GetGeom2D())->GetEid(j);
804  meshVertId = (locExpansion->GetGeom2D())->GetVid(j);
805 
806  if(ReorderedGraphVertId[0][meshVertId] >=
807  firstNonDirGraphVertId)
808  {
809  vwgts_perm[ReorderedGraphVertId[0][meshVertId]-
810  firstNonDirGraphVertId] =
811  Dofs[0][meshVertId];
812  }
813 
814  if(ReorderedGraphVertId[1][meshEdgeId] >=
815  firstNonDirGraphVertId)
816  {
817  vwgts_perm[ReorderedGraphVertId[1][meshEdgeId]-
818  firstNonDirGraphVertId] =
819  Dofs[1][meshEdgeId];
820  }
821  }
822  }
823 
824  bottomUpGraph->ExpandGraphWithVertexWeights(vwgts_perm);
825 
827  AllocateSharedPtr(this,bottomUpGraph);
828  }
829  }
830  }
831 
832 
833 
834 void CoupledLocalToGlobalC0ContMap::FindEdgeIdToAddMeanPressure(vector<map<int,int> > &ReorderedGraphVertId,
835  int &nel, const LocalRegions::ExpansionVector &locExpVector,
836  int &edgeId, int &vertId, int &firstNonDirGraphVertId, map<int,int> &IsDirEdgeDof,
838  Array<OneD, int> &AddMeanPressureToEdgeId)
839 {
840 
841  int i,j,k;
842 
843  // Make list of homogeneous graph edges to elmt mappings
844  Array<TwoD, int> EdgeIdToElmts(ReorderedGraphVertId[1].size(),2,-1);
845  map<int,int> HomGraphEdgeIdToEdgeId;
846 
847  for(i = 0; i < nel; ++i)
848  {
849  for(j = 0; j < locExpVector[i]->GetNverts(); ++j)
850  {
851  edgeId = (locExpVector[i]->as<LocalRegions::Expansion2D>()
852  ->GetGeom2D())->GetEid(j);
853 
854  // note second condition stops us using mixed boundary condition
855  if((ReorderedGraphVertId[1][edgeId] >= firstNonDirGraphVertId)
856  && (IsDirEdgeDof.count(edgeId) == 0))
857  {
858  HomGraphEdgeIdToEdgeId[ReorderedGraphVertId[1][edgeId]-firstNonDirGraphVertId] = edgeId;
859 
860  if(EdgeIdToElmts[edgeId][0] == -1)
861  {
862  EdgeIdToElmts[edgeId][0] = i;
863  }
864  else
865  {
866  EdgeIdToElmts[edgeId][1] = i;
867  }
868  }
869  }
870  }
871 
872  // Start at second to last level and find edge on boundary
873  // to attach element
874  int nlevels = bottomUpGraph->GetNlevels();
875 
876  // determine a default edge to attach pressure modes to
877  // which is part of the inner solve;
878  int defedge = -1;
879 
880  vector<MultiRegions::SubGraphSharedPtr> bndgraphs = bottomUpGraph->GetInteriorBlocks(nlevels);
881  for(i = 0; i < bndgraphs.size(); ++i)
882  {
883  int GlobIdOffset = bndgraphs[i]->GetIdOffset();
884 
885  for(j = 0; j < bndgraphs[i]->GetNverts(); ++j)
886  {
887  // find edge in graph vert list
888  if(HomGraphEdgeIdToEdgeId.count(GlobIdOffset+j) != 0)
889  {
890  edgeId = HomGraphEdgeIdToEdgeId[GlobIdOffset+j];
891 
892  if(defedge == -1)
893  {
894  defedge = edgeId;
895  break;
896  }
897  }
898  }
899  if(defedge != -1)
900  {
901  break;
902  }
903  }
904 
905  for(int n = 1; n < nlevels; ++n)
906  {
907  // produce a map with a key that is the element id
908  // that contains which next level patch it belongs to
909  vector<MultiRegions::SubGraphSharedPtr> bndgraphs = bottomUpGraph->GetInteriorBlocks(n+1);
910 
911  // Fill next level graph of adjacent elements and their level
912  map<int,int> ElmtInBndry;
913 
914  for(i = 0; i < bndgraphs.size(); ++i)
915  {
916  int GlobIdOffset = bndgraphs[i]->GetIdOffset();
917 
918  for(j = 0; j < bndgraphs[i]->GetNverts(); ++j)
919  {
920  // find edge in graph vert list
921  if(HomGraphEdgeIdToEdgeId.count(GlobIdOffset+j) != 0)
922  {
923  edgeId = HomGraphEdgeIdToEdgeId[GlobIdOffset+j];
924 
925  if(EdgeIdToElmts[edgeId][0] != -1)
926  {
927  ElmtInBndry[EdgeIdToElmts[edgeId][0]] = i;
928  }
929  if(EdgeIdToElmts[edgeId][1] != -1)
930  {
931  ElmtInBndry[EdgeIdToElmts[edgeId][1]] = i;
932  }
933  }
934  }
935  }
936 
937  // Now search interior patches in this level for edges
938  // that share the same element as a boundary edge and
939  // assign this elmt that boundary edge
940  vector<MultiRegions::SubGraphSharedPtr> intgraphs = bottomUpGraph->GetInteriorBlocks(n);
941  for(i = 0; i < intgraphs.size(); ++i)
942  {
943  int GlobIdOffset = intgraphs[i]->GetIdOffset();
944  bool SetEdge = false;
945  int elmtid = 0;
946  for(j = 0; j < intgraphs[i]->GetNverts(); ++j)
947  {
948  // Check to see if graph vert is an edge
949  if(HomGraphEdgeIdToEdgeId.count(GlobIdOffset+j) != 0)
950  {
951  edgeId = HomGraphEdgeIdToEdgeId[GlobIdOffset+j];
952 
953  for(k = 0; k < 2; ++k)
954  {
955  // relevant edge id
956  elmtid = EdgeIdToElmts[edgeId][k];
957 
958  if(elmtid != -1)
959  {
960  auto mapIt = ElmtInBndry.find(elmtid);
961 
962  if(mapIt != ElmtInBndry.end())
963  {
964  // now find a edge in the next level boundary graph
965  int GlobIdOffset1 = bndgraphs[mapIt->second]->GetIdOffset();
966  for(int l = 0; l < bndgraphs[mapIt->second]->GetNverts(); ++l)
967  {
968  // find edge in graph vert list
969  if(HomGraphEdgeIdToEdgeId.count(GlobIdOffset1+l) != 0)
970  {
971  //June 2012: commenting this condition apparently
972  //solved the bug caused by the edge reordering procedure
973 
974  //if(AddMeanPressureToEdgeId[elmtid] == -1)
975  //{
976 
977  //AddMeanPressureToEdgeId[elmtid] = HomGraphEdgeIdToEdgeId[GlobIdOffset1+l];
978  AddMeanPressureToEdgeId[elmtid] = defedge;
979 
980  //}
981  SetEdge = true;
982  break;
983  }
984  }
985  }
986  }
987  }
988  }
989  }
990 
991 
992  // if we have failed to find matching edge in next
993  // level patch boundary then set last found elmt
994  // associated to this interior patch to the
995  // default edget value
996  if(SetEdge == false)
997  {
998  if(elmtid == -1) // find an elmtid in patch
999  {
1000  for(j = 0; j < intgraphs[i]->GetNverts(); ++j)
1001  {
1002  if(HomGraphEdgeIdToEdgeId.count(GlobIdOffset+j) != 0)
1003  {
1004  edgeId = HomGraphEdgeIdToEdgeId[GlobIdOffset+j];
1005  for(k = 0; k < 2; ++k)
1006  {
1007  // relevant edge id
1008  elmtid = EdgeIdToElmts[edgeId][k];
1009  if(elmtid != -1)
1010  {
1011  break;
1012  }
1013  }
1014  }
1015  if(elmtid != -1)
1016  {
1017  break;
1018  }
1019  }
1020  }
1021  if(AddMeanPressureToEdgeId[elmtid] == -1)
1022  {
1023  AddMeanPressureToEdgeId[elmtid] = defedge;
1024  }
1025  }
1026  }
1027  }
1028 
1029 }
1030 
1031 
1032 
1033 
1034 }
1035 
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
void FindEdgeIdToAddMeanPressure(std::vector< std::map< int, int > > &ReorderedGraphVertId, int &nel, const LocalRegions::ExpansionVector &locExpVector, int &edgeId, int &vertId, int &firstNonDirGraphVertId, std::map< int, int > &IsDirEdgeDof, MultiRegions::BottomUpSubStructuredGraphSharedPtr &bottomUpGraph, Array< OneD, int > &AddMeanPressureToEdgeId)
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
Constructs mappings for the C0 scalar continuous Galerkin formulation.
Definition: AssemblyMapCG.h:71
int CreateGraph(const ExpList &locExp, const BndCondExp &bndCondExp, const Array< OneD, const BndCond > &bndConditions, const bool checkIfSystemSingular, const PeriodicMap &periodicVerts, const PeriodicMap &periodicEdges, const PeriodicMap &periodicFaces, DofGraph &graph, BottomUpSubStructuredGraphSharedPtr &bottomUpGraph, std::set< int > &extraDirVerts, std::set< int > &extraDirEdges, int &firstNonDirGraphVertId, int &nExtraDirichlet, int mdswitch=1)
Array< OneD, NekDouble > m_localToGlobalSign
Integer sign of local coeffs to global space.
Array< OneD, int > m_localToGlobalMap
Integer map of local coeffs to global space.
int m_numLocalCoeffs
Total number of local coefficients.
Definition: AssemblyMap.h:357
bool m_signChange
Flag indicating if modes require sign reversal.
Definition: AssemblyMap.h:371
int m_numGlobalCoeffs
Total number of global coefficients.
Definition: AssemblyMap.h:368
Array< OneD, int > m_localToGlobalBndMap
Integer map of local coeffs to global Boundary Dofs.
Definition: AssemblyMap.h:374
Array< OneD, unsigned int > m_numLocalBndCoeffsPerPatch
The number of bnd dofs per patch.
Definition: AssemblyMap.h:425
LibUtilities::SessionReaderSharedPtr m_session
Session object.
Definition: AssemblyMap.h:329
int m_numLocalBndCoeffs
Number of local boundary coefficients.
Definition: AssemblyMap.h:338
AssemblyMapSharedPtr m_nextLevelLocalToGlobalMap
Map from the patches of the previous level to the patches of the current level.
Definition: AssemblyMap.h:432
int m_staticCondLevel
The level of recursion in the case of multi-level static condensation.
Definition: AssemblyMap.h:421
Array< OneD, NekDouble > m_localToGlobalBndSign
Integer sign of local boundary coeffs to global space.
Definition: AssemblyMap.h:376
Array< OneD, int > m_localToLocalIntMap
Integer map of local boundary coeffs to local interior system numbering.
Definition: AssemblyMap.h:380
int m_numLocalDirBndCoeffs
Number of Local Dirichlet Boundary Coefficients.
Definition: AssemblyMap.h:342
int m_numGlobalDirBndCoeffs
Number of Global Dirichlet Boundary Coefficients.
Definition: AssemblyMap.h:344
Array< OneD, unsigned int > m_numLocalIntCoeffsPerPatch
The number of int dofs per patch.
Definition: AssemblyMap.h:427
bool m_systemSingular
Flag indicating if the system is singular or not.
Definition: AssemblyMap.h:346
Array< OneD, int > m_localToLocalBndMap
Integer map of local boundary coeffs to local boundary system numbering.
Definition: AssemblyMap.h:378
int m_numPatches
The number of patches (~elements) in the current level.
Definition: AssemblyMap.h:423
Array< OneD, int > m_bndCondIDToGlobalTraceID
Integer map of bnd cond trace number to global trace number.
Definition: AssemblyMap.h:388
int m_numGlobalBndCoeffs
Total number of global boundary coefficients.
Definition: AssemblyMap.h:340
int GetNcoeffs(void) const
This function returns the total number of coefficients used in the expansion.
Definition: StdExpansion.h:124
int GetVertexMap(const int localVertexId, bool useCoeffPacking=false)
Definition: StdExpansion.h:697
int GetTraceNcoeffs(const int i) const
This function returns the number of expansion coefficients belonging to the i-th trace.
Definition: StdExpansion.h:265
std::shared_ptr< SessionReader > SessionReaderSharedPtr
@ eModified_A
Principle Modified Functions .
Definition: BasisType.h:48
std::shared_ptr< SegExp > SegExpSharedPtr
Definition: SegExp.h:272
std::shared_ptr< Expansion2D > Expansion2DSharedPtr
Definition: Expansion1D.h:47
std::vector< ExpansionSharedPtr > ExpansionVector
Definition: Expansion.h:70
std::shared_ptr< Expansion1D > Expansion1DSharedPtr
Definition: Expansion1D.h:51
std::shared_ptr< BottomUpSubStructuredGraph > BottomUpSubStructuredGraphSharedPtr
std::shared_ptr< ExpList > ExpListSharedPtr
Shared pointer to an ExpList object.
pair< int, StdRegions::Orientation > DeterminePeriodicEdgeOrientId(int meshEdgeId, StdRegions::Orientation edgeOrient, const vector< PeriodicEntity > &periodicEdges)
Determine orientation of an edge to its periodic equivalents, as well as the ID of the representative...
std::map< int, std::vector< PeriodicEntity > > PeriodicMap
static const NekDouble kNekZeroTol
std::shared_ptr< BoundaryConditions > BoundaryConditionsSharedPtr
Definition: Conditions.h:289
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition: MeshGraph.h:174
std::shared_ptr< Geometry1D > Geometry1DSharedPtr
Definition: Geometry.h:63
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:1
double NekDouble
T Vmax(int n, const T *x, const int incx)
Return the maximum element in x – called vmax to avoid conflict with max.
Definition: Vmath.cpp:892
scalarT< T > abs(scalarT< T > in)
Definition: scalar.hpp:272