Nektar++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
AssemblyMapCG1D.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File AssemblyMapCG1D.cpp
4 //
5 // For more information, please see: http://www.nektar.info
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // License for the specific language governing rights and limitations under
14 // Permission is hereby granted, free of charge, to any person obtaining a
15 // copy of this software and associated documentation files (the "Software"),
16 // to deal in the Software without restriction, including without limitation
17 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 // and/or sell copies of the Software, and to permit persons to whom the
19 // Software is furnished to do so, subject to the following conditions:
20 //
21 // The above copyright notice and this permission notice shall be included
22 // in all copies or substantial portions of the Software.
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 // DEALINGS IN THE SOFTWARE.
31 //
32 // Description: C0-continuous assembly mappings specific to 1D
33 //
34 ///////////////////////////////////////////////////////////////////////////////
35 
37 #include <LocalRegions/SegExp.h>
38 
39 #include <boost/config.hpp>
40 #include <boost/graph/adjacency_list.hpp>
41 #include <boost/graph/cuthill_mckee_ordering.hpp>
42 #include <boost/graph/properties.hpp>
43 #include <boost/graph/bandwidth.hpp>
44 
45 namespace Nektar
46 {
47  namespace MultiRegions
48  {
49  /**
50  * @class AssemblyMapCG1D
51  * Mappings are created for three possible global solution types:
52  * - Direct full matrix
53  * - Direct static condensation
54  * - Direct multi-level static condensation
55  * In the latter case, mappings are created recursively for the
56  * different levels of static condensation.
57  *
58  * These mappings are used by GlobalLinSys to generate the global
59  * system.
60  */
61 
62  /**
63  *
64  */
67  const std::string variable):
68  AssemblyMapCG(pSession,variable)
69  {
70  }
71 
72 
73  /**
74  *
75  */
78  const int numLocalCoeffs,
79  const ExpList &locExp,
80  const Array<OneD, const ExpListSharedPtr>
81  &bndCondExp,
82  const Array<OneD, const SpatialDomains::BoundaryConditionShPtr>
83  &bndConditions,
84  const PeriodicMap &periodicVerts,
85  const std::string variable):
86  AssemblyMapCG(pSession,variable)
87  {
88  SetUp1DExpansionC0ContMap(numLocalCoeffs,
89  locExp,
90  bndCondExp,
91  bndConditions,
92  periodicVerts);
93 
96  }
97 
98 
99  /**
100  *
101  */
103  const LibUtilities::SessionReaderSharedPtr &pSession,
104  const int numLocalCoeffs,
105  const ExpList &locExp):
106  AssemblyMapCG(pSession)
107  {
108  SetUp1DExpansionC0ContMap(numLocalCoeffs, locExp);
111  }
112 
113 
114  /**
115  *
116  */
118  {
119  }
120 
121 
122  /**
123  * Construction of the local->global map is achieved in several stages.
124  * A mesh vertex renumbering is constructed as follows
125  * - Domain Dirichlet boundaries are numbered first.
126  * - Domain periodic boundaries are numbered next and given
127  * consistent global indices.
128  * - Remaining vertices are ordered last.
129  * This mesh vertex renumbering is then used to generate the first
130  * part of the local to global mapping of the degrees of freedom. The
131  * remainder of the map consists of the element-interior degrees of
132  * freedom. This leads to the block-diagonal submatrix as each
133  * element-interior mode is globally orthogonal to modes in all other
134  * elements.
135  *
136  * The boundary condition mapping is generated from the same vertex
137  * renumbering.
138  */
140  const int numLocalCoeffs,
141  const ExpList &locExp,
142  const Array<OneD, const MultiRegions::ExpListSharedPtr>
143  &bndCondExp,
144  const Array<OneD, const SpatialDomains::BoundaryConditionShPtr>
145  &bndConditions,
146  const PeriodicMap &periodicVerts)
147  {
148  int i,j;
149  int cnt = 0;
150  int meshVertId;
151  int meshVertId2;
152  int graphVertId = 0;
153  int globalId;
154 
155  const LocalRegions::ExpansionVector &locExpVector = *(locExp.GetExp());
156 
158 
159  int nbnd = bndCondExp.num_elements();
160  m_staticCondLevel = 0;
161  m_signChange = false;
162  m_numPatches = locExpVector.size();
163  m_numLocalCoeffs = numLocalCoeffs;
164  m_numLocalBndCoeffs = 2*locExpVector.size();
165  m_localToGlobalMap = Array<OneD, int>(m_numLocalCoeffs,-1);
166  m_localToGlobalBndMap = Array<OneD, int>(m_numLocalBndCoeffs,-1);
167  m_bndCondCoeffsToGlobalCoeffsMap = Array<OneD, int>(nbnd);
168  m_numLocalBndCoeffsPerPatch = Array<OneD, unsigned int>(m_numPatches);
169  m_numLocalIntCoeffsPerPatch = Array<OneD, unsigned int>(m_numPatches);
170  for(i = 0; i < m_numPatches; ++i)
171  {
172  m_numLocalBndCoeffsPerPatch[i] = (unsigned int) locExpVector[locExp.GetOffset_Elmt_Id(i)]->NumBndryCoeffs();
173  m_numLocalIntCoeffsPerPatch[i] = (unsigned int) locExpVector[locExp.GetOffset_Elmt_Id(i)]->GetNcoeffs() - locExpVector[locExp.GetOffset_Elmt_Id(i)]->NumBndryCoeffs();
174  }
175 
176  // The only unique identifiers of the vertices of the mesh
177  // are the vertex id (stored in their corresponding
178  // Geometry object). However, setting up a global
179  // numbering based on these id's will not lead to a
180  // suitable or optimal numbering. Mainly because: - we
181  // want the Dirichlet DOF's to be listed first - we want
182  // an optimal global numbering of the remaining DOF's
183  // (strategy still need to be defined but can for example
184  // be: minimum bandwith or minimum fill-in of the
185  // resulting global system matrix)
186  //
187  // That's why the vertices be rearranged. Currently, this
188  // is done in the following way: The vertices of the mesh
189  // are considered as vertices of a graph. (We then will
190  // use algorithms to reorder these graph-vertices -
191  // although not implemented yet in 1D).
192  //
193  // A container is used to store the graph vertex id's of
194  // the different mesh vertices. This is implemented as a
195  // STL map such that the graph vertex id can later be
196  // retrieved by the unique mesh vertex id's which serve as
197  // the key of the map.
198  map<int, int> vertReorderedGraphVertId;
199 
200  PeriodicMap::const_iterator pIt;
201 
202  // STEP 1: Order the Dirichlet vertices first
204  for(i = 0; i < nbnd; i++)
205  {
206  ASSERTL0(bndCondExp[i]->GetNumElmts() > 0,
207  "Boundary expansion contains no expansions.");
208  if(bndConditions[i]->GetBoundaryConditionType()==SpatialDomains::eDirichlet)
209  {
210  meshVertId = bndCondExp[i]->GetExp(0)->GetGeom()->GetVertex(0)->GetVid();
211  vertReorderedGraphVertId[meshVertId] = graphVertId++;
214  }
215  }
216 
217  // STEP 2: Order the periodic vertices next. This allows to give
218  // corresponding DOF's the same global ID
219  for(pIt = periodicVerts.begin(); pIt != periodicVerts.end(); pIt++)
220  {
221  meshVertId = pIt->first;
222  meshVertId2 = pIt->second[0].id;
223 
224  if (!pIt->second[0].isLocal)
225  {
226  if (vertReorderedGraphVertId.count(meshVertId) == 0)
227  {
228  vertReorderedGraphVertId[meshVertId] = graphVertId++;
229  }
230  }
231  else
232  {
233  if (vertReorderedGraphVertId.count(meshVertId) == 0 &&
234  vertReorderedGraphVertId.count(meshVertId2) == 0)
235  {
236  vertReorderedGraphVertId[meshVertId] = graphVertId;
237  vertReorderedGraphVertId[meshVertId2] = graphVertId++;
238  }
239  else if ((vertReorderedGraphVertId.count(meshVertId) == 0 &&
240  vertReorderedGraphVertId.count(meshVertId2) != 0) ||
241  (vertReorderedGraphVertId.count(meshVertId) != 0 &&
242  vertReorderedGraphVertId.count(meshVertId2) == 0))
243  {
244  ASSERTL0(false,
245  "Numbering error for periodic boundary conditions!");
246  }
247  }
248  }
249 
250  // STEP 3: List the other vertices
251  // STEP 4: Set up simple map based on vertex and edge id's
252  for(i = 0; i < locExpVector.size(); ++i)
253  {
254  cnt = locExp.GetCoeff_Offset(i);
255  if((locSegExp = locExpVector[i]->as<LocalRegions::SegExp>()))
256  {
257  for(j = 0; j < locSegExp->GetNverts(); ++j)
258  {
259  meshVertId = (locSegExp->GetGeom1D())->GetVid(j);
260  if(vertReorderedGraphVertId.count(meshVertId) == 0)
261  {
262  vertReorderedGraphVertId[meshVertId] = graphVertId++;
263  }
264 
265  m_localToGlobalMap[cnt+locSegExp->GetVertexMap(j)] =
266  vertReorderedGraphVertId[meshVertId];
267  }
268  }
269  else
270  {
271  ASSERTL0(false,"dynamic cast to a segment expansion failed");
272  }
273  }
274 
275  // Set up the mapping for the boundary conditions
276  for(i = 0; i < nbnd; i++)
277  {
278  meshVertId = bndCondExp[i]->GetExp(0)->GetGeom()->GetVertex(0)->GetVid();
279  m_bndCondCoeffsToGlobalCoeffsMap[i] = vertReorderedGraphVertId[meshVertId];
280  }
281 
282  // Setup interior mapping and the boundary map
283  globalId = graphVertId;
284  m_numGlobalBndCoeffs = globalId;
285 
286  cnt=0;
287  for(i = 0; i < m_numLocalCoeffs; ++i)
288  {
289  if(m_localToGlobalMap[i] == -1)
290  {
291  m_localToGlobalMap[i] = globalId++;
292  }
293  else
294  {
295  m_localToGlobalBndMap[cnt++]=m_localToGlobalMap[i];
296  }
297  }
298  m_numGlobalCoeffs = globalId;
299 
300  SetUpUniversalC0ContMap(locExp);
301 
302  m_hash = boost::hash_range(m_localToGlobalMap.begin(), m_localToGlobalMap.end());
303  // Add up hash values if parallel
304  int hash = m_hash;
305  m_comm->AllReduce(hash, LibUtilities::ReduceSum);
306  m_hash = hash;
307  }
308 
309 
310 
311 
312  } // namespace
313 } // namespace