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