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
44using namespace std;
45
46namespace Nektar
47{
48/**
49 * This is an vector extension of
50 * MultiRegions::AssemblyMapCG::SetUp2DExpansionC0ContMap related to the
51 * Linearised Navier Stokes problem
52 */
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
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
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
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;
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 {
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
CoupledLocalToGlobalC0ContMap(const LibUtilities::SessionReaderSharedPtr &pSession, const SpatialDomains::MeshGraphSharedPtr &graph, const SpatialDomains::BoundaryConditionsSharedPtr &boundaryConditions, const Array< OneD, MultiRegions::ExpListSharedPtr > &fields, const MultiRegions::ExpListSharedPtr &pressure, const size_t nz_loc, const bool CheeckForSingularSys=true)
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:367
bool m_signChange
Flag indicating if modes require sign reversal.
Definition: AssemblyMap.h:381
Array< OneD, int > m_localToLocalIntMap
Integer map of local boundary coeffs to local interior system numbering.
Definition: AssemblyMap.h:390
int m_numGlobalCoeffs
Total number of global coefficients.
Definition: AssemblyMap.h:378
Array< OneD, NekDouble > m_localToGlobalBndSign
Integer sign of local boundary coeffs to global space.
Definition: AssemblyMap.h:386
Array< OneD, unsigned int > m_numLocalBndCoeffsPerPatch
The number of bnd dofs per patch.
Definition: AssemblyMap.h:436
LibUtilities::SessionReaderSharedPtr m_session
Session object.
Definition: AssemblyMap.h:336
int m_numLocalBndCoeffs
Number of local boundary coefficients.
Definition: AssemblyMap.h:348
AssemblyMapSharedPtr m_nextLevelLocalToGlobalMap
Map from the patches of the previous level to the patches of the current level.
Definition: AssemblyMap.h:443
int m_staticCondLevel
The level of recursion in the case of multi-level static condensation.
Definition: AssemblyMap.h:432
int m_numLocalDirBndCoeffs
Number of Local Dirichlet Boundary Coefficients.
Definition: AssemblyMap.h:352
int m_numGlobalDirBndCoeffs
Number of Global Dirichlet Boundary Coefficients.
Definition: AssemblyMap.h:354
Array< OneD, unsigned int > m_numLocalIntCoeffsPerPatch
The number of int dofs per patch.
Definition: AssemblyMap.h:438
bool m_systemSingular
Flag indicating if the system is singular or not.
Definition: AssemblyMap.h:356
Array< OneD, int > m_localToGlobalBndMap
Integer map of local coeffs to global Boundary Dofs.
Definition: AssemblyMap.h:384
Array< OneD, int > m_localToLocalBndMap
Integer map of local boundary coeffs to local boundary system numbering.
Definition: AssemblyMap.h:388
int m_numPatches
The number of patches (~elements) in the current level.
Definition: AssemblyMap.h:434
int m_numGlobalBndCoeffs
Total number of global boundary coefficients.
Definition: AssemblyMap.h:350
Array< OneD, int > m_bndCondIDToGlobalTraceID
Integer map of bnd cond trace number to global trace number.
Definition: AssemblyMap.h:398
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:48
std::shared_ptr< Expansion1D > Expansion1DSharedPtr
Definition: Expansion1D.h:52
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:176
std::shared_ptr< Geometry1D > Geometry1DSharedPtr
Definition: Geometry.h:64
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:940
scalarT< T > abs(scalarT< T > in)
Definition: scalar.hpp:298