Nektar++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
PreconditionerLowEnergy.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File Preconditioner.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: Preconditioner definition
33 //
34 ///////////////////////////////////////////////////////////////////////////////
35 
41 #include <LocalRegions/MatrixKey.h>
42 #include <math.h>
43 
44 namespace Nektar
45 {
46  namespace MultiRegions
47  {
48  /**
49  * Registers the class with the Factory.
50  */
53  "LowEnergyBlock",
55  "LowEnergy Preconditioning");
56 
57  /**
58  * @class PreconditionerLowEnergy
59  *
60  * This class implements low energy preconditioning for the conjugate
61  * gradient matrix solver.
62  */
63 
65  const boost::shared_ptr<GlobalLinSys> &plinsys,
66  const AssemblyMapSharedPtr &pLocToGloMap)
67  : Preconditioner(plinsys, pLocToGloMap),
68  m_linsys(plinsys),
69  m_locToGloMap(pLocToGloMap)
70  {
71  }
72 
74  {
75  GlobalSysSolnType solvertype=m_locToGloMap->GetGlobalSysSolnType();
76  ASSERTL0(solvertype == eIterativeStaticCond ||
77  solvertype == ePETScStaticCond, "Solver type not valid");
78 
79  boost::shared_ptr<MultiRegions::ExpList>
80  expList=((m_linsys.lock())->GetLocMat()).lock();
81 
83 
84  locExpansion = expList->GetExp(0);
85 
86  int nDim = locExpansion->GetShapeDimension();
87 
88  ASSERTL0(nDim==3,
89  "Preconditioner type only valid in 3D");
90 
91  //Sets up reference element and builds transformation matrix
93 
94  //Set up block transformation matrix
96 
97  //Sets up multiplicity map for transformation from global to local
99  }
100 
101 
102  /**
103  * \brief Construct the low energy preconditioner from
104  * \f$\mathbf{S}_{2}\f$
105  *
106  * \f[\mathbf{M}^{-1}=\left[\begin{array}{ccc}
107  * Diag[(\mathbf{S_{2}})_{vv}] & & \\ & (\mathbf{S}_{2})_{eb} & \\ & &
108  * (\mathbf{S}_{2})_{fb} \end{array}\right] \f]
109  *
110  * where \f$\mathbf{R}\f$ is the transformation matrix and
111  * \f$\mathbf{S}_{2}\f$ the Schur complement of the modified basis,
112  * given by
113  *
114  * \f[\mathbf{S}_{2}=\mathbf{R}\mathbf{S}_{1}\mathbf{R}^{T}\f]
115  *
116  * where \f$\mathbf{S}_{1}\f$ is the local schur complement matrix for
117  * each element.
118  */
120  {
121  boost::shared_ptr<MultiRegions::ExpList>
122  expList=((m_linsys.lock())->GetLocMat()).lock();
124  GlobalLinSysKey m_linSysKey=(m_linsys.lock())->GetKey();
125  StdRegions::VarCoeffMap vVarCoeffMap;
126  int i, j, k;
127  int nVerts, nEdges,nFaces;
128  int eid, fid, n, cnt, nedgemodes, nfacemodes;
129  NekDouble zero = 0.0;
130 
131  int vMap1, vMap2, sign1, sign2;
132  int m, v, eMap1, eMap2, fMap1, fMap2;
133  int offset, globalrow, globalcol, nCoeffs;
134 
135  // Periodic information
136  PeriodicMap periodicVerts;
137  PeriodicMap periodicEdges;
138  PeriodicMap periodicFaces;
139  expList->GetPeriodicEntities(periodicVerts,periodicEdges,periodicFaces);
140 
141  //matrix storage
142  MatrixStorage storage = eFULL;
143  MatrixStorage vertstorage = eDIAGONAL;
144  MatrixStorage blkmatStorage = eDIAGONAL;
145 
146  //local element static condensed matrices
147  DNekScalBlkMatSharedPtr loc_mat;
148  DNekScalMatSharedPtr bnd_mat;
149 
150  DNekMatSharedPtr pRS;
151  DNekMatSharedPtr pRSRT;
152 
153  //Transformation matrices
154  DNekMat R;
155  DNekMat RT;
156  DNekMat RS;
157  DNekMat RSRT;
158 
159  int nDirBnd = m_locToGloMap->GetNumGlobalDirBndCoeffs();
160  int nNonDirVerts = m_locToGloMap->GetNumNonDirVertexModes();
161 
162  //Vertex, edge and face preconditioner matrices
164  AllocateSharedPtr(nNonDirVerts,nNonDirVerts,zero,vertstorage);
165 
166  Array<OneD, NekDouble> vertArray(nNonDirVerts,0.0);
167  Array<OneD, long> VertBlockToUniversalMap(nNonDirVerts,-1);
168 
169  //maps for different element types
170  map<LibUtilities::ShapeType,DNekScalMatSharedPtr> transmatrixmap;
171  map<LibUtilities::ShapeType,DNekScalMatSharedPtr> transposedtransmatrixmap;
172 
173  //Transformation matrix
174  transmatrixmap[LibUtilities::eTetrahedron]= m_Rtet;
175  transmatrixmap[LibUtilities::ePrism] = m_Rprism;
176  transmatrixmap[LibUtilities::eHexahedron] = m_Rhex;
177 
178  //Transposed transformation matrix
179  transposedtransmatrixmap[LibUtilities::eTetrahedron]= m_RTtet;
180  transposedtransmatrixmap[LibUtilities::ePrism] = m_RTprism;
181  transposedtransmatrixmap[LibUtilities::eHexahedron] = m_RThex;
182 
183  int n_exp = expList->GetNumElmts();
184  int nNonDirEdgeIDs=m_locToGloMap->GetNumNonDirEdges();
185  int nNonDirFaceIDs=m_locToGloMap->GetNumNonDirFaces();
186 
187  //set the number of blocks in the matrix
188  int numBlks = 1+nNonDirEdgeIDs+nNonDirFaceIDs;
189  Array<OneD,unsigned int> n_blks(numBlks);
190  for(i = 0; i < numBlks; ++i)
191  {
192  n_blks[i] = 0;
193  }
194  n_blks[0]=nNonDirVerts;
195 
196  set<int> edgeDirMap;
197  set<int> faceDirMap;
198  map<int,int> uniqueEdgeMap;
199  map<int,int> uniqueFaceMap;
200 
201  //this should be of size total number of local edges
202  Array<OneD, int> edgemodeoffset(nNonDirEdgeIDs,0);
203  Array<OneD, int> facemodeoffset(nNonDirFaceIDs,0);
204 
205  Array<OneD, int> edgeglobaloffset(nNonDirEdgeIDs,0);
206  Array<OneD, int> faceglobaloffset(nNonDirFaceIDs,0);
207 
208  const Array<OneD, const ExpListSharedPtr>& bndCondExp = expList->GetBndCondExpansions();
210  const Array<OneD, const SpatialDomains::BoundaryConditionShPtr>& bndConditions = expList->GetBndConditions();
211 
212  int meshVertId;
213  int meshEdgeId;
214  int meshFaceId;
215 
216  const Array<OneD, const int> &extradiredges
217  = m_locToGloMap->GetExtraDirEdges();
218  for(i=0; i<extradiredges.num_elements(); ++i)
219  {
220  meshEdgeId=extradiredges[i];
221  edgeDirMap.insert(meshEdgeId);
222  }
223 
224  //Determine which boundary edges and faces have dirichlet values
225  for(i = 0; i < bndCondExp.num_elements(); i++)
226  {
227  cnt = 0;
228  for(j = 0; j < bndCondExp[i]->GetNumElmts(); j++)
229  {
230  bndCondFaceExp = boost::dynamic_pointer_cast<
231  StdRegions::StdExpansion2D>(bndCondExp[i]->GetExp(j));
232  if (bndConditions[i]->GetBoundaryConditionType() ==
234  {
235  for(k = 0; k < bndCondFaceExp->GetNedges(); k++)
236  {
237  meshEdgeId = bndCondFaceExp->as<LocalRegions::Expansion2D>()->GetGeom2D()->GetEid(k);
238  if(edgeDirMap.count(meshEdgeId) == 0)
239  {
240  edgeDirMap.insert(meshEdgeId);
241  }
242  }
243  meshFaceId = bndCondFaceExp->as<LocalRegions::Expansion2D>()->GetGeom2D()->GetFid();
244  faceDirMap.insert(meshFaceId);
245  }
246  }
247  }
248 
249  int dof=0;
250  int maxFaceDof=0;
251  int maxEdgeDof=0;
252  int nlocalNonDirEdges=0;
253  int nlocalNonDirFaces=0;
254 
255  int edgematrixlocation=0;
256  int ntotaledgeentries=0;
257 
258  map<int,int> EdgeSize;
259  map<int,int> FaceSize;
260 
261  /// - Count edges, face and add up edges and face sizes
262  for(n = 0; n < n_exp; ++n)
263  {
264  eid = expList->GetOffset_Elmt_Id(n);
265  locExpansion = expList->GetExp(eid);
266 
267  nEdges = locExpansion->GetNedges();
268  for(j = 0; j < nEdges; ++j)
269  {
270  int nEdgeInteriorCoeffs = locExpansion->GetEdgeNcoeffs(j) - 2;
271  meshEdgeId = locExpansion->as<LocalRegions::Expansion3D>()->GetGeom3D()->GetEid(j);
272  EdgeSize[meshEdgeId] = nEdgeInteriorCoeffs;
273  }
274 
275  nFaces = locExpansion->GetNfaces();
276  for(j = 0; j < nFaces; ++j)
277  {
278  int nFaceInteriorCoeffs = locExpansion->GetFaceIntNcoeffs(j);
279  meshFaceId = locExpansion->as<LocalRegions::Expansion3D>()->GetGeom3D()->GetFid(j);
280  FaceSize[meshFaceId] = nFaceInteriorCoeffs;
281  }
282  }
283 
284  m_comm = expList->GetComm();
285 
286  // Loop over all the elements in the domain and compute max edge
287  // DOF and set up unique ordering.
288 
289  // First do periodic edges
290  PeriodicMap::const_iterator pIt;
291  for (pIt = periodicEdges.begin(); pIt != periodicEdges.end(); ++pIt)
292  {
293  meshEdgeId = pIt->first;
294 
295  if(edgeDirMap.count(meshEdgeId)==0)
296  {
297  dof = EdgeSize[meshEdgeId];
298  if(uniqueEdgeMap.count(meshEdgeId)==0 && dof > 0)
299  {
300  bool SetUpNewEdge = true;
301 
302 
303  for (i = 0; i < pIt->second.size(); ++i)
304  {
305  if (!pIt->second[i].isLocal)
306  {
307  continue;
308  }
309 
310  int meshEdgeId2 = pIt->second[i].id;
311 
312  if(edgeDirMap.count(meshEdgeId2)==0)
313  {
314  if(uniqueEdgeMap.count(meshEdgeId2)!=0)
315  {
316  // set unique map to same location
317  uniqueEdgeMap[meshEdgeId] =
318  uniqueEdgeMap[meshEdgeId2];
319  SetUpNewEdge = false;
320  }
321  }
322  else
323  {
324  edgeDirMap.insert(meshEdgeId);
325  SetUpNewEdge = false;
326  }
327  }
328 
329  if(SetUpNewEdge)
330  {
331  uniqueEdgeMap[meshEdgeId]=edgematrixlocation;
332 
333  edgeglobaloffset[edgematrixlocation]+=ntotaledgeentries;
334 
335  edgemodeoffset[edgematrixlocation]=dof*dof;
336 
337  ntotaledgeentries+=dof*dof;
338 
339  n_blks[1+edgematrixlocation++]=dof;
340 
341  }
342  }
343  }
344  }
345 
346 
347  for(cnt=n=0; n < n_exp; ++n)
348  {
349  eid = expList->GetOffset_Elmt_Id(n);
350  locExpansion = expList->GetExp(eid);
351 
352  for (j = 0; j < locExpansion->GetNedges(); ++j)
353  {
354  meshEdgeId = locExpansion->as<LocalRegions::Expansion3D>()->GetGeom3D()->GetEid(j);
355  dof = EdgeSize[meshEdgeId];
356  maxEdgeDof = (dof > maxEdgeDof ? dof : maxEdgeDof);
357 
358  if(edgeDirMap.count(meshEdgeId)==0)
359  {
360  if(uniqueEdgeMap.count(meshEdgeId)==0 && dof > 0)
361 
362  {
363  uniqueEdgeMap[meshEdgeId]=edgematrixlocation;
364 
365  edgeglobaloffset[edgematrixlocation]+=ntotaledgeentries;
366 
367  edgemodeoffset[edgematrixlocation]=dof*dof;
368 
369  ntotaledgeentries+=dof*dof;
370 
371  n_blks[1+edgematrixlocation++]=dof;
372 
373  }
374  nlocalNonDirEdges+=dof*dof;
375  }
376  }
377  }
378 
379  int facematrixlocation=0;
380  int ntotalfaceentries=0;
381 
382  // Loop over all the elements in the domain and compute max face
383  // DOF. Reduce across all processes to get universal maximum.
384  // - Periodic faces
385  for (pIt = periodicFaces.begin(); pIt != periodicFaces.end(); ++pIt)
386  {
387  meshFaceId = pIt->first;
388 
389  if(faceDirMap.count(meshFaceId)==0)
390  {
391  dof = FaceSize[meshFaceId];
392 
393  if(uniqueFaceMap.count(meshFaceId) == 0 && dof > 0)
394  {
395  bool SetUpNewFace = true;
396 
397  if(pIt->second[0].isLocal)
398  {
399  int meshFaceId2 = pIt->second[0].id;
400 
401  if(faceDirMap.count(meshFaceId2)==0)
402  {
403  if(uniqueFaceMap.count(meshFaceId2)!=0)
404  {
405  // set unique map to same location
406  uniqueFaceMap[meshFaceId] =
407  uniqueFaceMap[meshFaceId2];
408  SetUpNewFace = false;
409  }
410  }
411  else // set face to be a Dirichlet face
412  {
413  faceDirMap.insert(meshFaceId);
414  SetUpNewFace = false;
415  }
416  }
417 
418  if(SetUpNewFace)
419  {
420  uniqueFaceMap[meshFaceId]=facematrixlocation;
421 
422  facemodeoffset[facematrixlocation]=dof*dof;
423 
424  faceglobaloffset[facematrixlocation]+=ntotalfaceentries;
425 
426  ntotalfaceentries+=dof*dof;
427 
428  n_blks[1+nNonDirEdgeIDs+facematrixlocation++]=dof;
429  }
430  }
431  }
432  }
433 
434 
435  for(cnt=n=0; n < n_exp; ++n)
436  {
437  eid = expList->GetOffset_Elmt_Id(n);
438 
439  locExpansion = expList->GetExp(eid);
440 
441  for (j = 0; j < locExpansion->GetNfaces(); ++j)
442  {
443  meshFaceId = locExpansion->as<LocalRegions::Expansion3D>()->GetGeom3D()->GetFid(j);
444 
445  dof = FaceSize[meshFaceId];
446  maxFaceDof = (dof > maxFaceDof ? dof : maxFaceDof);
447 
448 
449  if(faceDirMap.count(meshFaceId)==0)
450  {
451  if(uniqueFaceMap.count(meshFaceId)==0 && dof > 0)
452  {
453  uniqueFaceMap[meshFaceId]=facematrixlocation;
454 
455  facemodeoffset[facematrixlocation]=dof*dof;
456 
457  faceglobaloffset[facematrixlocation]+=ntotalfaceentries;
458 
459  ntotalfaceentries+=dof*dof;
460 
461  n_blks[1+nNonDirEdgeIDs+facematrixlocation++]=dof;
462 
463  }
464  nlocalNonDirFaces+=dof*dof;
465  }
466  }
467  }
468 
469  m_comm->AllReduce(maxEdgeDof, LibUtilities::ReduceMax);
470  m_comm->AllReduce(maxFaceDof, LibUtilities::ReduceMax);
471 
472  //Allocate arrays for block to universal map (number of expansions * p^2)
473  Array<OneD, long> EdgeBlockToUniversalMap(ntotaledgeentries,-1);
474  Array<OneD, long> FaceBlockToUniversalMap(ntotalfaceentries,-1);
475 
476  Array<OneD, int> localEdgeToGlobalMatrixMap(nlocalNonDirEdges,-1);
477  Array<OneD, int> localFaceToGlobalMatrixMap(nlocalNonDirFaces,-1);
478 
479  //Allocate arrays to store matrices (number of expansions * p^2)
480  Array<OneD, NekDouble> EdgeBlockArray(nlocalNonDirEdges,-1);
481  Array<OneD, NekDouble> FaceBlockArray(nlocalNonDirFaces,-1);
482 
483  int edgematrixoffset=0;
484  int facematrixoffset=0;
485  int vGlobal;
486 
487  for(n=0; n < n_exp; ++n)
488  {
489  eid = expList->GetOffset_Elmt_Id(n);
490 
491  locExpansion = expList->GetExp(eid);
492 
493  //loop over the edges of the expansion
494  for(j = 0; j < locExpansion->GetNedges(); ++j)
495  {
496  //get mesh edge id
497  meshEdgeId = locExpansion->as<LocalRegions::Expansion3D>()->GetGeom3D()->GetEid(j);
498 
499  nedgemodes=locExpansion->GetEdgeNcoeffs(j)-2;
500 
501  if(edgeDirMap.count(meshEdgeId)==0)
502  {
503  // Determine the Global edge offset
504  int edgeOffset = edgeglobaloffset[uniqueEdgeMap[meshEdgeId]];
505 
506  // Determine a universal map offset
507  int uniOffset = meshEdgeId;
508  pIt = periodicEdges.find(meshEdgeId);
509  if (pIt != periodicEdges.end())
510  {
511  for (int l = 0; l < pIt->second.size(); ++l)
512  {
513  uniOffset = min(uniOffset, pIt->second[l].id);
514  }
515  }
516  uniOffset = uniOffset *maxEdgeDof*maxEdgeDof;
517 
518  for(k=0; k<nedgemodes*nedgemodes; ++k)
519  {
520  vGlobal=edgeOffset+k;
521  localEdgeToGlobalMatrixMap[edgematrixoffset+k]=vGlobal;
522  EdgeBlockToUniversalMap[vGlobal] = uniOffset + k + 1;
523  }
524  edgematrixoffset+=nedgemodes*nedgemodes;
525  }
526  }
527 
528  Array<OneD, unsigned int> faceInteriorMap;
529  Array<OneD, int> faceInteriorSign;
530  //loop over the faces of the expansion
531  for(j = 0; j < locExpansion->GetNfaces(); ++j)
532  {
533  //get mesh face id
534  meshFaceId = locExpansion->as<LocalRegions::Expansion3D>()->GetGeom3D()->GetFid(j);
535 
536  nfacemodes = locExpansion->GetFaceIntNcoeffs(j);
537 
538  //Check if face has dirichlet values
539  if(faceDirMap.count(meshFaceId)==0)
540  {
541  // Determine the Global edge offset
542  int faceOffset = faceglobaloffset[uniqueFaceMap[meshFaceId]];
543 
544  // Determine a universal map offset
545  int uniOffset = meshFaceId;
546  // use minimum face edge when periodic
547  pIt = periodicFaces.find(meshFaceId);
548  if (pIt != periodicFaces.end())
549  {
550  uniOffset = min(uniOffset, pIt->second[0].id);
551  }
552  uniOffset = uniOffset * maxFaceDof * maxFaceDof;
553 
554  for(k=0; k<nfacemodes*nfacemodes; ++k)
555  {
556  vGlobal=faceOffset+k;
557 
558  localFaceToGlobalMatrixMap[facematrixoffset+k]
559  = vGlobal;
560 
561  FaceBlockToUniversalMap[vGlobal] = uniOffset + k + 1;
562  }
563  facematrixoffset+=nfacemodes*nfacemodes;
564  }
565  }
566  }
567 
568  edgematrixoffset=0;
569  facematrixoffset=0;
570 
572  ::AllocateSharedPtr(n_blks, n_blks, blkmatStorage);
573 
574  const Array<OneD,const unsigned int>& nbdry_size
575  = m_locToGloMap->GetNumLocalBndCoeffsPerPatch();
576 
577  //Variants of R matrices required for low energy preconditioning
579  ::AllocateSharedPtr(nbdry_size, nbdry_size , blkmatStorage);
581  ::AllocateSharedPtr(nbdry_size, nbdry_size , blkmatStorage);
582 
583  //Here we loop over the expansion and build the block low energy
584  //preconditioner as well as the block versions of the transformation
585  //matrices.
586  for(cnt=n=0; n < n_exp; ++n)
587  {
588  eid = expList->GetOffset_Elmt_Id(n);
589 
590  locExpansion = expList->GetExp(eid);
591  nCoeffs=locExpansion->NumBndryCoeffs();
592  LibUtilities::ShapeType eType=locExpansion->DetShapeType();
593 
594  //Get correct transformation matrix for element type
595  R=(*(transmatrixmap[eType]));
596  RT=(*(transposedtransmatrixmap[eType]));
597 
599  (nCoeffs, nCoeffs, zero, storage);
600  RS = (*pRS);
601 
603  (nCoeffs, nCoeffs, zero, storage);
604  RSRT = (*pRSRT);
605 
606  nVerts=locExpansion->GetGeom()->GetNumVerts();
607  nEdges=locExpansion->GetGeom()->GetNumEdges();
608  nFaces=locExpansion->GetGeom()->GetNumFaces();
609 
610  //Get statically condensed matrix
611  loc_mat = (m_linsys.lock())->GetStaticCondBlock(n);
612 
613  //Extract boundary block (elemental S1)
614  bnd_mat=loc_mat->GetBlock(0,0);
615 
616  //offset by number of rows
617  offset = bnd_mat->GetRows();
618 
619  DNekScalMat &S=(*bnd_mat);
620 
621  //Calculate S*trans(R) (note R is already transposed)
622  RS=R*S;
623 
624  //Calculate R*S*trans(R)
625  RSRT=RS*RT;
626 
627  //loop over vertices of the element and return the vertex map
628  //for each vertex
629  for (v=0; v<nVerts; ++v)
630  {
631  vMap1=locExpansion->GetVertexMap(v);
632 
633  //Get vertex map
634  globalrow = m_locToGloMap->
635  GetLocalToGlobalBndMap(cnt+vMap1)-nDirBnd;
636 
637  if(globalrow >= 0)
638  {
639  for (m=0; m<nVerts; ++m)
640  {
641  vMap2=locExpansion->GetVertexMap(m);
642 
643  //global matrix location (without offset due to
644  //dirichlet values)
645  globalcol = m_locToGloMap->
646  GetLocalToGlobalBndMap(cnt+vMap2)-nDirBnd;
647 
648  //offset for dirichlet conditions
649  if (globalcol == globalrow)
650  {
651  //modal connectivity between elements
652  sign1 = m_locToGloMap->
653  GetLocalToGlobalBndSign(cnt + vMap1);
654  sign2 = m_locToGloMap->
655  GetLocalToGlobalBndSign(cnt + vMap2);
656 
657  vertArray[globalrow]
658  += sign1*sign2*RSRT(vMap1,vMap2);
659 
660 
661  meshVertId = locExpansion->as<LocalRegions::Expansion3D>()->GetGeom3D()->GetVid(v);
662 
663  pIt = periodicVerts.find(meshVertId);
664  if (pIt != periodicVerts.end())
665  {
666  for (k = 0; k < pIt->second.size(); ++k)
667  {
668  meshVertId = min(meshVertId, pIt->second[k].id);
669  }
670  }
671 
672  VertBlockToUniversalMap[globalrow]
673  = meshVertId + 1;
674  }
675  }
676  }
677  }
678 
679  //loop over edges of the element and return the edge map
680  for (eid=0; eid<nEdges; ++eid)
681  {
682  nedgemodes=locExpansion->GetEdgeNcoeffs(eid)-2;
683 
684  DNekMatSharedPtr m_locMat =
686  (nedgemodes,nedgemodes,zero,storage);
687 
688  meshEdgeId = locExpansion->as<LocalRegions::Expansion3D>()->GetGeom3D()->GetEid(eid);
689  Array<OneD, unsigned int> edgemodearray = locExpansion->GetEdgeInverseBoundaryMap(eid);
690 
691  if(edgeDirMap.count(meshEdgeId)==0)
692  {
693  for (v=0; v<nedgemodes; ++v)
694  {
695  eMap1=edgemodearray[v];
696 
697  for (m=0; m<nedgemodes; ++m)
698  {
699  eMap2=edgemodearray[m];
700 
701  //modal connectivity between elements
702  sign1 = m_locToGloMap->
703  GetLocalToGlobalBndSign(cnt + eMap1);
704  sign2 = m_locToGloMap->
705  GetLocalToGlobalBndSign(cnt + eMap2);
706 
707  NekDouble globalEdgeValue = sign1*sign2*RSRT(eMap1,eMap2);
708 
709  EdgeBlockArray[edgematrixoffset+v*nedgemodes+m]=globalEdgeValue;
710  }
711  }
712  edgematrixoffset+=nedgemodes*nedgemodes;
713  }
714  }
715 
716  //loop over faces of the element and return the face map
717  for (fid=0; fid<nFaces; ++fid)
718  {
719  nfacemodes = locExpansion->GetFaceIntNcoeffs(fid);
720 
721  DNekMatSharedPtr m_locMat =
723  (nfacemodes,nfacemodes,zero,storage);
724 
725  meshFaceId = locExpansion->as<LocalRegions::Expansion3D>()->GetGeom3D()->GetFid(fid);
726 
727  if(faceDirMap.count(meshFaceId)==0)
728  {
729  Array<OneD, unsigned int> facemodearray;
730  StdRegions::Orientation faceOrient = locExpansion->GetForient(fid);
731 
732  pIt = periodicFaces.find(meshFaceId);
733  if (pIt != periodicFaces.end())
734  {
735  if(meshFaceId == min(meshFaceId, pIt->second[0].id))
736  {
737  facemodearray = locExpansion->GetFaceInverseBoundaryMap(fid,faceOrient);
738  faceOrient = DeterminePeriodicFaceOrient(faceOrient,pIt->second[0].orient);
739  }
740  }
741 
742  facemodearray = locExpansion->GetFaceInverseBoundaryMap(fid,faceOrient);
743 
744 
745  for (v=0; v<nfacemodes; ++v)
746  {
747  fMap1=facemodearray[v];
748 
749  for (m=0; m<nfacemodes; ++m)
750  {
751  fMap2=facemodearray[m];
752 
753  //modal connectivity between elements
754  sign1 = m_locToGloMap->
755  GetLocalToGlobalBndSign(cnt + fMap1);
756  sign2 = m_locToGloMap->
757  GetLocalToGlobalBndSign(cnt + fMap2);
758 
759  // Get the face-face value from the low energy matrix (S2)
760  NekDouble globalFaceValue = sign1*sign2*RSRT(fMap1,fMap2);
761 
762  //local face value to global face value
763  FaceBlockArray[facematrixoffset+v*nfacemodes+m]=globalFaceValue;
764  }
765  }
766  facematrixoffset+=nfacemodes*nfacemodes;
767  }
768  }
769 
770  //offset for the expansion
771  cnt+=offset;
772 
773  //Here we build the block matrices for R and RT
774  m_RBlk->SetBlock(n,n, transmatrixmap[eType]);
775  m_RTBlk->SetBlock(n,n, transposedtransmatrixmap[eType]);
776  }
777 
778  if(nNonDirVerts!=0)
779  {
780  //Exchange vertex data over different processes
781  Gs::gs_data *tmp = Gs::Init(VertBlockToUniversalMap, m_comm);
782  Gs::Gather(vertArray, Gs::gs_add, tmp);
783 
784  }
785 
786  Array<OneD, NekDouble> GlobalEdgeBlock(ntotaledgeentries,0.0);
787  if(ntotaledgeentries)
788  {
789  //Assemble edge matrices of each process
790  Vmath::Assmb(EdgeBlockArray.num_elements(),
791  EdgeBlockArray,
792  localEdgeToGlobalMatrixMap,
793  GlobalEdgeBlock);
794  }
795 
796  //Exchange edge data over different processes
797  Gs::gs_data *tmp1 = Gs::Init(EdgeBlockToUniversalMap, m_comm);
798  Gs::Gather(GlobalEdgeBlock, Gs::gs_add, tmp1);
799 
800  Array<OneD, NekDouble> GlobalFaceBlock(ntotalfaceentries,0.0);
801  if(ntotalfaceentries)
802  {
803  //Assemble face matrices of each process
804  Vmath::Assmb(FaceBlockArray.num_elements(),
805  FaceBlockArray,
806  localFaceToGlobalMatrixMap,
807  GlobalFaceBlock);
808  }
809 
810  //Exchange face data over different processes
811  Gs::gs_data *tmp2 = Gs::Init(FaceBlockToUniversalMap, m_comm);
812  Gs::Gather(GlobalFaceBlock, Gs::gs_add, tmp2);
813 
814  // Populate vertex block
815  for (int i = 0; i < nNonDirVerts; ++i)
816  {
817  VertBlk->SetValue(i,i,1.0/vertArray[i]);
818  }
819 
820  //Set the first block to be the diagonal of the vertex space
821  m_BlkMat->SetBlock(0,0, VertBlk);
822 
823  offset=0;
824  //Build the edge matrices from the vector
825  DNekMatSharedPtr gmat;
826  for(int loc=0; loc<nNonDirEdgeIDs; ++loc)
827  {
828  nedgemodes = n_blks[1+loc];
830  (nedgemodes,nedgemodes,zero,storage);
831 
832  for (v=0; v<nedgemodes; ++v)
833  {
834  for (m=0; m<nedgemodes; ++m)
835  {
836  NekDouble EdgeValue = GlobalEdgeBlock[offset+v*nedgemodes+m];
837  gmat->SetValue(v,m,EdgeValue);
838 
839  }
840  }
841 
842  m_BlkMat->SetBlock(1+loc,1+loc, gmat);
843  offset+=edgemodeoffset[loc];
844  }
845 
846  offset=0;
847 
848  Array<OneD, int> globalToUniversalMap = m_locToGloMap->GetGlobalToUniversalBndMap();
849  //Build the face matrices from the vector
850  for(int loc=0; loc<nNonDirFaceIDs; ++loc)
851  {
852  nfacemodes=n_blks[1+nNonDirEdgeIDs+loc];
854  (nfacemodes,nfacemodes,zero,storage);
855 
856  for (v=0; v<nfacemodes; ++v)
857  {
858  for (m=0; m<nfacemodes; ++m)
859  {
860  NekDouble FaceValue = GlobalFaceBlock[offset+v*nfacemodes+m];
861  gmat->SetValue(v,m,FaceValue);
862 
863  }
864  }
865  m_BlkMat->SetBlock(1+nNonDirEdgeIDs+loc,1+nNonDirEdgeIDs+loc, gmat);
866  offset+=facemodeoffset[loc];
867  }
868 
869  int totblks=m_BlkMat->GetNumberOfBlockRows();
870  for (i=1; i< totblks; ++i)
871  {
872  unsigned int nmodes=m_BlkMat->GetNumberOfRowsInBlockRow(i);
873  if(nmodes)
874  {
875  DNekMatSharedPtr tmp_mat =
877  (nmodes,nmodes,zero,storage);
878 
879  tmp_mat=m_BlkMat->GetBlock(i,i);
880  tmp_mat->Invert();
881 
882  m_BlkMat->SetBlock(i,i,tmp_mat);
883  }
884  }
885  }
886 
887 
888  /**
889  * Apply the low energy preconditioner during the conjugate gradient
890  * routine
891  */
893  const Array<OneD, NekDouble>& pInput,
894  Array<OneD, NekDouble>& pOutput)
895  {
896  int nDir = m_locToGloMap->GetNumGlobalDirBndCoeffs();
897  int nGlobal = m_locToGloMap->GetNumGlobalBndCoeffs();
898  int nNonDir = nGlobal-nDir;
899  DNekBlkMat &M = (*m_BlkMat);
900 
901  NekVector<NekDouble> r(nNonDir,pInput,eWrapper);
902  NekVector<NekDouble> z(nNonDir,pOutput,eWrapper);
903 
904  z = M * r;
905  }
906 
907 
908  /**
909  * Set a block transformation matrices for each element type. These are
910  * needed in routines that transform the schur complement matrix to and
911  * from the low energy basis.
912  */
914  {
915  boost::shared_ptr<MultiRegions::ExpList>
916  expList=((m_linsys.lock())->GetLocMat()).lock();
918 
919  int n, nel;
920 
921  const Array<OneD,const unsigned int>& nbdry_size
922  = m_locToGloMap->GetNumLocalBndCoeffsPerPatch();
923 
924  int n_exp=expList->GetNumElmts();
925 
926  //maps for different element types
927  map<LibUtilities::ShapeType,DNekScalMatSharedPtr> transmatrixmap;
928  map<LibUtilities::ShapeType,DNekScalMatSharedPtr> transposedtransmatrixmap;
929  map<LibUtilities::ShapeType,DNekScalMatSharedPtr> invtransmatrixmap;
930  map<LibUtilities::ShapeType,DNekScalMatSharedPtr> invtransposedtransmatrixmap;
931 
932  //Transformation matrix map
933  transmatrixmap[LibUtilities::eTetrahedron]=m_Rtet;
934  transmatrixmap[LibUtilities::ePrism]=m_Rprism;
935  transmatrixmap[LibUtilities::eHexahedron]=m_Rhex;
936 
937  //Transposed transformation matrix map
938  transposedtransmatrixmap[LibUtilities::eTetrahedron]=m_RTtet;
939  transposedtransmatrixmap[LibUtilities::ePrism]=m_RTprism;
940  transposedtransmatrixmap[LibUtilities::eHexahedron]=m_RThex;
941 
942  //Inverse transfomation map
943  invtransmatrixmap[LibUtilities::eTetrahedron]=m_Rinvtet;
944  invtransmatrixmap[LibUtilities::ePrism]=m_Rinvprism;
945  invtransmatrixmap[LibUtilities::eHexahedron]=m_Rinvhex;
946 
947  //Inverse transposed transformation map
948  invtransposedtransmatrixmap[LibUtilities::eTetrahedron]=m_RTinvtet;
949  invtransposedtransmatrixmap[LibUtilities::ePrism]=m_RTinvprism;
950  invtransposedtransmatrixmap[LibUtilities::eHexahedron]=m_RTinvhex;
951 
952  MatrixStorage blkmatStorage = eDIAGONAL;
953 
954  //Variants of R matrices required for low energy preconditioning
956  ::AllocateSharedPtr(nbdry_size, nbdry_size , blkmatStorage);
958  ::AllocateSharedPtr(nbdry_size, nbdry_size , blkmatStorage);
960  ::AllocateSharedPtr(nbdry_size, nbdry_size , blkmatStorage);
962  ::AllocateSharedPtr(nbdry_size, nbdry_size , blkmatStorage);
963 
964  for(n=0; n < n_exp; ++n)
965  {
966  nel = expList->GetOffset_Elmt_Id(n);
967 
968  locExpansion = expList->GetExp(nel);
969  LibUtilities::ShapeType eType=locExpansion->DetShapeType();
970 
971  //Block R matrix
972  m_RBlk->SetBlock(n,n, transmatrixmap[eType]);
973 
974  //Block RT matrix
975  m_RTBlk->SetBlock(n,n, transposedtransmatrixmap[eType]);
976 
977  //Block inverse R matrix
978  m_InvRBlk->SetBlock(n,n, invtransmatrixmap[eType]);
979 
980  //Block inverse RT matrix
981  m_InvRTBlk->SetBlock(n,n, invtransposedtransmatrixmap[eType]);
982  }
983  }
984 
985 
986 
987  /**
988  * \brief Transform the solution vector vector to low energy.
989  *
990  * As the conjugate gradient system is solved for the low energy basis,
991  * the solution vector \f$\mathbf{x}\f$ must be transformed to the low
992  * energy basis i.e. \f$\overline{\mathbf{x}}=\mathbf{R}\mathbf{x}\f$.
993  */
995  Array<OneD, NekDouble>& pInOut,
996  int offset)
997  {
998  int nGlobBndDofs = m_locToGloMap->GetNumGlobalBndCoeffs();
999  int nDirBndDofs = m_locToGloMap->GetNumGlobalDirBndCoeffs();
1000  int nGlobHomBndDofs = nGlobBndDofs - nDirBndDofs;
1001  int nLocBndDofs = m_locToGloMap->GetNumLocalBndCoeffs();
1002 
1003  //Non-dirichlet boundary dofs
1004  NekVector<NekDouble> F_HomBnd(nGlobHomBndDofs,pInOut+offset,
1005  eWrapper);
1006 
1007  //Block transformation matrix
1008  DNekScalBlkMat &R = *m_RBlk;
1009 
1010  Array<OneD, NekDouble> pLocal(nLocBndDofs, 0.0);
1011  NekVector<NekDouble> F_LocBnd(nLocBndDofs,pLocal,eWrapper);
1012  m_map = m_locToGloMap->GetLocalToGlobalBndMap();
1013 
1014  //Not actually needed but we should only work with the Global boundary dofs
1015  Array<OneD,NekDouble> tmp(nGlobBndDofs,0.0);
1016  Vmath::Vcopy(nGlobBndDofs, pInOut.get(), 1, tmp.get(), 1);
1017 
1018  //Global boundary (with dirichlet values) to local boundary with multiplicity
1019  Vmath::Gathr(m_map.num_elements(), m_locToGloSignMult.get(), tmp.get(), m_map.get(), pLocal.get());
1020 
1021  //Multiply by the block transformation matrix
1022  F_LocBnd=R*F_LocBnd;
1023 
1024  //Assemble local boundary to global non-dirichlet Dofs
1025  m_locToGloMap->AssembleBnd(F_LocBnd,F_HomBnd, nDirBndDofs);
1026  }
1027 
1028  /**
1029  * \brief Transform the solution vector vector to low energy.
1030  *
1031  * As the conjugate gradient system is solved for the low energy basis,
1032  * the solution vector \f$\mathbf{x}\f$ must be transformed to the low
1033  * energy basis i.e. \f$\overline{\mathbf{x}}=\mathbf{R}\mathbf{x}\f$.
1034  */
1036  const Array<OneD, NekDouble>& pInput,
1037  Array<OneD, NekDouble>& pOutput)
1038  {
1039  int nGlobBndDofs = m_locToGloMap->GetNumGlobalBndCoeffs();
1040  int nDirBndDofs = m_locToGloMap->GetNumGlobalDirBndCoeffs();
1041  int nGlobHomBndDofs = nGlobBndDofs - nDirBndDofs;
1042  int nLocBndDofs = m_locToGloMap->GetNumLocalBndCoeffs();
1043 
1044  //Input/output vectors should be length nGlobHomBndDofs
1045  ASSERTL1(pInput.num_elements() >= nGlobHomBndDofs,
1046  "Input array is greater than the nGlobHomBndDofs");
1047  ASSERTL1(pOutput.num_elements() >= nGlobHomBndDofs,
1048  "Output array is greater than the nGlobHomBndDofs");
1049 
1050  //vectors of length number of non-dirichlet boundary dofs
1051  NekVector<NekDouble> F_GlobBnd(nGlobHomBndDofs,pInput,eWrapper);
1052  NekVector<NekDouble> F_HomBnd(nGlobHomBndDofs,pOutput,
1053  eWrapper);
1054  //Block transformation matrix
1055  DNekScalBlkMat &R = *m_RBlk;
1056 
1057  Array<OneD, NekDouble> pLocal(nLocBndDofs, 0.0);
1058  NekVector<NekDouble> F_LocBnd(nLocBndDofs,pLocal,eWrapper);
1059  m_map = m_locToGloMap->GetLocalToGlobalBndMap();
1060 
1061  // Allocated array of size number of global boundary dofs and copy
1062  // the input array to the tmp array offset by Dirichlet boundary
1063  // conditions.
1064  Array<OneD,NekDouble> tmp(nGlobBndDofs,0.0);
1065  Vmath::Vcopy(nGlobHomBndDofs, pInput.get(), 1, tmp.get() + nDirBndDofs, 1);
1066 
1067  //Global boundary dofs (with zeroed dirichlet values) to local boundary dofs
1068  Vmath::Gathr(m_map.num_elements(), m_locToGloSignMult.get(), tmp.get(), m_map.get(), pLocal.get());
1069 
1070  //Multiply by the block transformation matrix
1071  F_LocBnd=R*F_LocBnd;
1072 
1073  //Assemble local boundary to global non-dirichlet boundary
1074  m_locToGloMap->AssembleBnd(F_LocBnd,F_HomBnd,nDirBndDofs);
1075  }
1076 
1077  /**
1078  * \brief transform the solution vector from low energy back to the
1079  * original basis.
1080  *
1081  * After the conjugate gradient routine the output vector is in the low
1082  * energy basis and must be trasnformed back to the original basis in
1083  * order to get the correct solution out. the solution vector
1084  * i.e. \f$\mathbf{x}=\mathbf{R^{T}}\mathbf{\overline{x}}\f$.
1085  */
1087  Array<OneD, NekDouble>& pInOut)
1088  {
1089  int nGlobBndDofs = m_locToGloMap->GetNumGlobalBndCoeffs();
1090  int nDirBndDofs = m_locToGloMap->GetNumGlobalDirBndCoeffs();
1091  int nGlobHomBndDofs = nGlobBndDofs - nDirBndDofs;
1092  int nLocBndDofs = m_locToGloMap->GetNumLocalBndCoeffs();
1093 
1094  ASSERTL1(pInOut.num_elements() >= nGlobBndDofs,
1095  "Output array is greater than the nGlobBndDofs");
1096 
1097  //Block transposed transformation matrix
1098  DNekScalBlkMat &RT = *m_RTBlk;
1099 
1100  NekVector<NekDouble> V_GlobHomBnd(nGlobHomBndDofs,pInOut+nDirBndDofs,
1101  eWrapper);
1102 
1103  Array<OneD, NekDouble> pLocal(nLocBndDofs, 0.0);
1104  NekVector<NekDouble> V_LocBnd(nLocBndDofs,pLocal,eWrapper);
1105  m_map = m_locToGloMap->GetLocalToGlobalBndMap();
1106  Array<OneD,NekDouble> tmp(nGlobBndDofs,0.0);
1107 
1108  //Global boundary (less dirichlet) to local boundary
1109  m_locToGloMap->GlobalToLocalBnd(V_GlobHomBnd,V_LocBnd, nDirBndDofs);
1110 
1111  //Multiply by the block transposed transformation matrix
1112  V_LocBnd=RT*V_LocBnd;
1113 
1114 
1115  //Assemble local boundary to global boundary
1116  Vmath::Assmb(nLocBndDofs, m_locToGloSignMult.get(),pLocal.get(), m_map.get(), tmp.get());
1117 
1118  //Universal assemble across processors
1119  m_locToGloMap->UniversalAssembleBnd(tmp);
1120 
1121  //copy non-dirichlet boundary values
1122  Vmath::Vcopy(nGlobBndDofs-nDirBndDofs, tmp.get() + nDirBndDofs, 1, pInOut.get() + nDirBndDofs, 1);
1123  }
1124 
1125  /**
1126  * \brief Multiply by the block inverse transformation matrix
1127  */
1129  const Array<OneD, NekDouble>& pInput,
1130  Array<OneD, NekDouble>& pOutput)
1131  {
1132  int nGlobBndDofs = m_locToGloMap->GetNumGlobalBndCoeffs();
1133  int nDirBndDofs = m_locToGloMap->GetNumGlobalDirBndCoeffs();
1134  int nGlobHomBndDofs = nGlobBndDofs - nDirBndDofs;
1135  int nLocBndDofs = m_locToGloMap->GetNumLocalBndCoeffs();
1136 
1137  ASSERTL1(pInput.num_elements() >= nGlobHomBndDofs,
1138  "Input array is greater than the nGlobHomBndDofs");
1139  ASSERTL1(pOutput.num_elements() >= nGlobHomBndDofs,
1140  "Output array is greater than the nGlobHomBndDofs");
1141 
1142  //vectors of length number of non-dirichlet boundary dofs
1143  NekVector<NekDouble> F_GlobBnd(nGlobHomBndDofs,pInput,eWrapper);
1144  NekVector<NekDouble> F_HomBnd(nGlobHomBndDofs,pOutput,
1145  eWrapper);
1146  //Block inverse transformation matrix
1147  DNekScalBlkMat &invR = *m_InvRBlk;
1148 
1149  Array<OneD, NekDouble> pLocal(nLocBndDofs, 0.0);
1150  NekVector<NekDouble> F_LocBnd(nLocBndDofs,pLocal,eWrapper);
1151  m_map = m_locToGloMap->GetLocalToGlobalBndMap();
1152 
1153  // Allocated array of size number of global boundary dofs and copy
1154  // the input array to the tmp array offset by Dirichlet boundary
1155  // conditions.
1156  Array<OneD,NekDouble> tmp(nGlobBndDofs,0.0);
1157  Vmath::Vcopy(nGlobHomBndDofs, pInput.get(), 1, tmp.get() + nDirBndDofs, 1);
1158 
1159  //Global boundary dofs (with zeroed dirichlet values) to local boundary dofs
1160  Vmath::Gathr(m_map.num_elements(), m_locToGloSignMult.get(), tmp.get(), m_map.get(), pLocal.get());
1161 
1162  //Multiply by block inverse transformation matrix
1163  F_LocBnd=invR*F_LocBnd;
1164 
1165  //Assemble local boundary to global non-dirichlet boundary
1166  m_locToGloMap->AssembleBnd(F_LocBnd,F_HomBnd,nDirBndDofs);
1167 
1168  }
1169 
1170  /**
1171  * \brief Multiply by the block tranposed inverse transformation matrix
1172  */
1174  const Array<OneD, NekDouble>& pInput,
1175  Array<OneD, NekDouble>& pOutput)
1176  {
1177  int nGlobBndDofs = m_locToGloMap->GetNumGlobalBndCoeffs();
1178  int nDirBndDofs = m_locToGloMap->GetNumGlobalDirBndCoeffs();
1179  int nGlobHomBndDofs = nGlobBndDofs - nDirBndDofs;
1180  int nLocBndDofs = m_locToGloMap->GetNumLocalBndCoeffs();
1181 
1182  ASSERTL1(pInput.num_elements() >= nGlobHomBndDofs,
1183  "Input array is greater than the nGlobHomBndDofs");
1184  ASSERTL1(pOutput.num_elements() >= nGlobHomBndDofs,
1185  "Output array is greater than the nGlobHomBndDofs");
1186 
1187  //vectors of length number of non-dirichlet boundary dofs
1188  NekVector<NekDouble> F_GlobBnd(nGlobHomBndDofs,pInput,eWrapper);
1189  NekVector<NekDouble> F_HomBnd(nGlobHomBndDofs,pOutput,
1190  eWrapper);
1191  //Block inverse transformation matrix
1192  DNekScalBlkMat &invRT = *m_InvRTBlk;
1193 
1194  Array<OneD, NekDouble> pLocal(nLocBndDofs, 0.0);
1195  NekVector<NekDouble> F_LocBnd(nLocBndDofs,pLocal,eWrapper);
1196  m_map = m_locToGloMap->GetLocalToGlobalBndMap();
1197 
1198  m_locToGloMap->GlobalToLocalBnd(pInput,pLocal, nDirBndDofs);
1199 
1200  //Multiply by the block transposed transformation matrix
1201  F_LocBnd=invRT*F_LocBnd;
1202 
1203  m_locToGloMap->AssembleBnd(pLocal,pOutput, nDirBndDofs);
1204 
1205  Vmath::Vmul(nGlobHomBndDofs,pOutput,1,m_multiplicity,1,pOutput,1);
1206  }
1207 
1208 
1209  /**
1210  * \brief Set up the transformed block matrix system
1211  *
1212  * Sets up a block elemental matrix in which each of the block matrix is
1213  * the low energy equivalent
1214  * i.e. \f$\mathbf{S}_{2}=\mathbf{R}\mathbf{S}_{1}\mathbf{R}^{T}\f$
1215  */
1218  int offset,
1219  const boost::shared_ptr<DNekScalMat > &loc_mat)
1220  {
1221  boost::shared_ptr<MultiRegions::ExpList>
1222  expList=((m_linsys.lock())->GetLocMat()).lock();
1223 
1224  StdRegions::StdExpansionSharedPtr locExpansion;
1225  locExpansion = expList->GetExp(offset);
1226  unsigned int nbnd=locExpansion->NumBndryCoeffs();
1227 
1228  //This is the SC elemental matrix in the orginal basis (S1)
1229  DNekScalMatSharedPtr pS1=loc_mat;
1230 
1231  //Transformation matrices
1232  map<LibUtilities::ShapeType,DNekScalMatSharedPtr> transmatrixmap;
1233  map<LibUtilities::ShapeType,DNekScalMatSharedPtr> transposedtransmatrixmap;
1234  transmatrixmap[LibUtilities::eTetrahedron]=m_Rtet;
1235  transmatrixmap[LibUtilities::ePrism]=m_Rprism;
1236  transmatrixmap[LibUtilities::eHexahedron]=m_Rhex;
1237  transposedtransmatrixmap[LibUtilities::eTetrahedron]=m_RTtet;
1238  transposedtransmatrixmap[LibUtilities::ePrism]=m_RTprism;
1239  transposedtransmatrixmap[LibUtilities::eHexahedron]=m_RThex;
1240 
1241  DNekScalMat &S1 = (*pS1);
1242 
1243  MatrixStorage storage = eFULL;
1244 
1245  DNekMatSharedPtr pS2 = MemoryManager<DNekMat>::AllocateSharedPtr(nbnd,nbnd,0.0,storage);
1246  DNekMatSharedPtr pRS1 = MemoryManager<DNekMat>::AllocateSharedPtr(nbnd,nbnd,0.0,storage);
1247 
1249  (expList->GetExp(offset))->DetShapeType();
1250 
1251  //transformation matrices
1252  DNekScalMat &R = (*(transmatrixmap[eType]));
1253  DNekScalMat &RT = (*(transposedtransmatrixmap[eType]));
1254 
1255  //create low energy matrix
1256  DNekMat &RS1 = (*pRS1);
1257  DNekMat &S2 = (*pS2);
1258 
1259  //setup S2
1260  RS1=R*S1;
1261  S2=RS1*RT;
1262 
1263  DNekScalMatSharedPtr tmp_mat;
1265 
1266  return tmp_mat;
1267  }
1268 
1269  /**
1270  * Create the inverse multiplicity map.
1271  */
1273  {
1274  unsigned int nGlobalBnd = m_locToGloMap->GetNumGlobalBndCoeffs();
1275  unsigned int nEntries = m_locToGloMap->GetNumLocalBndCoeffs();
1276  unsigned int i;
1277 
1278  const Array<OneD, const int> &vMap
1279  = m_locToGloMap->GetLocalToGlobalBndMap();
1280 
1282  = m_locToGloMap->GetLocalToGlobalBndSign();
1283 
1284  bool m_signChange=m_locToGloMap->GetSignChange();
1285 
1286  // Count the multiplicity of each global DOF on this process
1287  Array<OneD, NekDouble> vCounts(nGlobalBnd, 0.0);
1288  for (i = 0; i < nEntries; ++i)
1289  {
1290  vCounts[vMap[i]] += 1.0;
1291  }
1292 
1293  // Get universal multiplicity by globally assembling counts
1294  m_locToGloMap->UniversalAssembleBnd(vCounts);
1295 
1296  // Construct a map of 1/multiplicity
1298  for (i = 0; i < nEntries; ++i)
1299  {
1300  if(m_signChange)
1301  {
1302  m_locToGloSignMult[i] = sign[i]*1.0/vCounts[vMap[i]];
1303  }
1304  else
1305  {
1306  m_locToGloSignMult[i] = 1.0/vCounts[vMap[i]];
1307  }
1308  }
1309 
1310  int nDirBnd = m_locToGloMap->GetNumGlobalDirBndCoeffs();
1311  int nGlobHomBnd = nGlobalBnd - nDirBnd;
1312  int nLocBnd = m_locToGloMap->GetNumLocalBndCoeffs();
1313 
1314  //Set up multiplicity array for inverse transposed transformation matrix
1315  Array<OneD,NekDouble> tmp(nGlobHomBnd,1.0);
1316  m_multiplicity = Array<OneD,NekDouble>(nGlobHomBnd,1.0);
1317  Array<OneD,NekDouble> loc(nLocBnd,1.0);
1318 
1319  m_locToGloMap->GlobalToLocalBnd(tmp,loc, nDirBnd);
1320  m_locToGloMap->AssembleBnd(loc,m_multiplicity, nDirBnd);
1321  Vmath::Sdiv(nGlobHomBnd,1.0,m_multiplicity,1,m_multiplicity,1);
1322 
1323  }
1324 
1325  /**
1326  *\brief Sets up the reference prismatic element needed to construct
1327  *a low energy basis
1328  */
1330  {
1331  //////////////////////////
1332  // Set up Prism element //
1333  //////////////////////////
1334 
1335  const int three=3;
1336  const int nVerts = 6;
1337  const double point[][3] = {
1338  {-1,-1,0}, {1,-1,0}, {1,1,0},
1339  {-1,1,0}, {0,-1,sqrt(double(3))}, {0,1,sqrt(double(3))},
1340  };
1341 
1342  //boost::shared_ptr<SpatialDomains::PointGeom> verts[6];
1344  for(int i=0; i < nVerts; ++i)
1345  {
1347  ( three, i, point[i][0], point[i][1], point[i][2] );
1348  }
1349  const int nEdges = 9;
1350  const int vertexConnectivity[][2] = {
1351  {0,1}, {1,2}, {3,2}, {0,3}, {0,4},
1352  {1,4}, {2,5}, {3,5}, {4,5}
1353  };
1354 
1355  // Populate the list of edges
1356  SpatialDomains::SegGeomSharedPtr edges[nEdges];
1357  for(int i=0; i < nEdges; ++i){
1358  SpatialDomains::PointGeomSharedPtr vertsArray[2];
1359  for(int j=0; j<2; ++j)
1360  {
1361  vertsArray[j] = verts[vertexConnectivity[i][j]];
1362  }
1363  edges[i] = MemoryManager<SpatialDomains::SegGeom>::AllocateSharedPtr(i, three, vertsArray);
1364  }
1365 
1366  ////////////////////////
1367  // Set up Prism faces //
1368  ////////////////////////
1369 
1370  const int nFaces = 5;
1371  //quad-edge connectivity base-face0, vertical-quadface2, vertical-quadface4
1372  const int quadEdgeConnectivity[][4] = { {0,1,2,3}, {1,6,8,5}, {3,7,8,4} };
1373  const bool isQuadEdgeFlipped[][4] = { {0,0,1,1}, {0,0,1,1}, {0,0,1,1} };
1374  // QuadId ordered as 0, 1, 2, otherwise return false
1375  const int quadId[] = { 0,-1,1,-1,2 };
1376 
1377  //triangle-edge connectivity side-triface-1, side triface-3
1378  const int triEdgeConnectivity[][3] = { {0,5,4}, {2,6,7} };
1379  const bool isTriEdgeFlipped[][3] = { {0,0,1}, {0,0,1} };
1380  // TriId ordered as 0, 1, otherwise return false
1381  const int triId[] = { -1,0,-1,1,-1 };
1382 
1383  // Populate the list of faces
1384  SpatialDomains::Geometry2DSharedPtr faces[nFaces];
1385  for(int f = 0; f < nFaces; ++f){
1386  if(f == 1 || f == 3) {
1387  int i = triId[f];
1388  SpatialDomains::SegGeomSharedPtr edgeArray[3];
1389  StdRegions::Orientation eorientArray[3];
1390  for(int j = 0; j < 3; ++j){
1391  edgeArray[j] = edges[triEdgeConnectivity[i][j]];
1392  eorientArray[j] = isTriEdgeFlipped[i][j] ? StdRegions::eBackwards : StdRegions::eForwards;
1393  }
1394  faces[f] = MemoryManager<SpatialDomains::TriGeom>::AllocateSharedPtr(f, edgeArray, eorientArray);
1395  }
1396  else {
1397  int i = quadId[f];
1398  SpatialDomains::SegGeomSharedPtr edgeArray[4];
1399  StdRegions::Orientation eorientArray[4];
1400  for(int j=0; j < 4; ++j){
1401  edgeArray[j] = edges[quadEdgeConnectivity[i][j]];
1402  eorientArray[j] = isQuadEdgeFlipped[i][j] ? StdRegions::eBackwards : StdRegions::eForwards;
1403  }
1404  faces[f] = MemoryManager<SpatialDomains::QuadGeom>::AllocateSharedPtr(f, edgeArray, eorientArray);
1405  }
1406  }
1407 
1409 
1410  geom->SetOwnData();
1411 
1412  return geom;
1413  }
1414 
1415  /**
1416  *\brief Sets up the reference tretrahedral element needed to construct
1417  *a low energy basis
1418  */
1420  {
1421  /////////////////////////////////
1422  // Set up Tetrahedron vertices //
1423  /////////////////////////////////
1424 
1425  int i,j;
1426  const int three=3;
1427  const int nVerts = 4;
1428  const double point[][3] = {
1429  {-1,-1/sqrt(double(3)),-1/sqrt(double(6))},
1430  {1,-1/sqrt(double(3)),-1/sqrt(double(6))},
1431  {0,2/sqrt(double(3)),-1/sqrt(double(6))},
1432  {0,0,3/sqrt(double(6))}};
1433 
1434  boost::shared_ptr<SpatialDomains::PointGeom> verts[4];
1435  for(i=0; i < nVerts; ++i)
1436  {
1437  verts[i] =
1440  ( three, i, point[i][0], point[i][1], point[i][2] );
1441  }
1442 
1443  //////////////////////////////
1444  // Set up Tetrahedron Edges //
1445  //////////////////////////////
1446 
1447  // SegGeom (int id, const int coordim), EdgeComponent(id, coordim)
1448  const int nEdges = 6;
1449  const int vertexConnectivity[][2] = {
1450  {0,1},{1,2},{0,2},{0,3},{1,3},{2,3}
1451  };
1452 
1453  // Populate the list of edges
1454  SpatialDomains::SegGeomSharedPtr edges[nEdges];
1455  for(i=0; i < nEdges; ++i)
1456  {
1457  boost::shared_ptr<SpatialDomains::PointGeom>
1458  vertsArray[2];
1459  for(j=0; j<2; ++j)
1460  {
1461  vertsArray[j] = verts[vertexConnectivity[i][j]];
1462  }
1463 
1465  ::AllocateSharedPtr(i, three, vertsArray);
1466  }
1467 
1468  //////////////////////////////
1469  // Set up Tetrahedron faces //
1470  //////////////////////////////
1471 
1472  const int nFaces = 4;
1473  const int edgeConnectivity[][3] = {
1474  {0,1,2}, {0,4,3}, {1,5,4}, {2,5,3}
1475  };
1476  const bool isEdgeFlipped[][3] = {
1477  {0,0,1}, {0,0,1}, {0,0,1}, {0,0,1}
1478  };
1479 
1480  // Populate the list of faces
1481  SpatialDomains::TriGeomSharedPtr faces[nFaces];
1482  for(i=0; i < nFaces; ++i)
1483  {
1484  SpatialDomains::SegGeomSharedPtr edgeArray[3];
1485  StdRegions::Orientation eorientArray[3];
1486  for(j=0; j < 3; ++j)
1487  {
1488  edgeArray[j] = edges[edgeConnectivity[i][j]];
1489  eorientArray[j] = isEdgeFlipped[i][j] ?
1491  }
1492 
1493 
1495  ::AllocateSharedPtr(i, edgeArray, eorientArray);
1496  }
1497 
1500  (faces);
1501 
1502  geom->SetOwnData();
1503 
1504  return geom;
1505  }
1506 
1507  /**
1508  *\brief Sets up the reference hexahedral element needed to construct
1509  *a low energy basis
1510  */
1512  {
1513  ////////////////////////////////
1514  // Set up Hexahedron vertices //
1515  ////////////////////////////////
1516 
1517  const int three=3;
1518 
1519  const int nVerts = 8;
1520  const double point[][3] = {
1521  {0,0,0}, {1,0,0}, {1,1,0}, {0,1,0},
1522  {0,0,1}, {1,0,1}, {1,1,1}, {0,1,1}
1523  };
1524 
1525  // Populate the list of verts
1527  for( int i = 0; i < nVerts; ++i ) {
1529  ::AllocateSharedPtr(three, i, point[i][0],
1530  point[i][1], point[i][2]);
1531  }
1532 
1533  /////////////////////////////
1534  // Set up Hexahedron Edges //
1535  /////////////////////////////
1536 
1537  // SegGeom (int id, const int coordim), EdgeComponent(id, coordim)
1538  const int nEdges = 12;
1539  const int vertexConnectivity[][2] = {
1540  {0,1}, {1,2}, {2,3}, {0,3}, {0,4}, {1,5},
1541  {2,6}, {3,7}, {4,5}, {5,6}, {6,7}, {4,7}
1542  };
1543 
1544  // Populate the list of edges
1545  SpatialDomains::SegGeomSharedPtr edges[nEdges];
1546  for( int i = 0; i < nEdges; ++i ) {
1547  SpatialDomains::PointGeomSharedPtr vertsArray[2];
1548  for( int j = 0; j < 2; ++j ) {
1549  vertsArray[j] = verts[vertexConnectivity[i][j]];
1550  }
1552  AllocateSharedPtr( i, three, vertsArray);
1553  }
1554 
1555  /////////////////////////////
1556  // Set up Hexahedron faces //
1557  /////////////////////////////
1558 
1559  const int nFaces = 6;
1560  const int edgeConnectivity[][4] = {
1561  {0,1,2,3}, {0,5,8,4}, {1,6,9,5},
1562  {2,7,10,6}, {3,7,11,4}, {8,9,10,11}
1563  };
1564  const bool isEdgeFlipped[][4] = {
1565  {0,0,0,1}, {0,0,1,1}, {0,0,1,1},
1566  {0,0,1,1}, {0,0,1,1}, {0,0,0,1}
1567  };
1568 
1569  // Populate the list of faces
1570  SpatialDomains::QuadGeomSharedPtr faces[nFaces];
1571  for( int i = 0; i < nFaces; ++i ) {
1572  SpatialDomains::SegGeomSharedPtr edgeArray[4];
1573  StdRegions::Orientation eorientArray[4];
1574  for( int j = 0; j < 4; ++j ) {
1575  edgeArray[j] = edges[edgeConnectivity[i][j]];
1576  eorientArray[j] = isEdgeFlipped[i][j] ?
1578  }
1580  eorientArray);
1581  }
1582 
1585  (faces);
1586 
1587  geom->SetOwnData();
1588 
1589  return geom;
1590  }
1591 
1592 
1593  /**
1594  * \brief Sets up the reference elements needed by the preconditioner
1595  *
1596  * Sets up reference elements which are used to preconditioning the
1597  * corresponding matrices. Currently we support tetrahedral, prismatic
1598  * and hexahedral elements
1599  */
1601  {
1602  int cnt,i,j;
1603  boost::shared_ptr<MultiRegions::ExpList>
1604  expList=((m_linsys.lock())->GetLocMat()).lock();
1605  GlobalLinSysKey m_linSysKey=(m_linsys.lock())->GetKey();
1606  StdRegions::VarCoeffMap vVarCoeffMap;
1607  StdRegions::StdExpansionSharedPtr locExpansion;
1608  locExpansion = expList->GetExp(0);
1609 
1610  DNekScalBlkMatSharedPtr RtetBlk, RprismBlk;
1611  DNekScalBlkMatSharedPtr RTtetBlk, RTprismBlk;
1612 
1613  DNekScalMatSharedPtr Rprismoriginal;
1614  DNekScalMatSharedPtr RTprismoriginal;
1615  DNekMatSharedPtr Rtettmp, RTtettmp, Rhextmp, RThextmp, Rprismtmp, RTprismtmp ;
1616 
1617  /*
1618  * Set up a Tetrahral & prismatic element which comprises
1619  * equilateral triangles as all faces for the tet and the end faces
1620  * for the prism. Using these elements a new expansion is created
1621  * (which is the same as the expansion specified in the input
1622  * file).
1623  */
1627 
1628  //Expansion as specified in the input file - here we need to alter
1629  //this so we can read in different exapansions for different element
1630  //types
1631  int nummodes=locExpansion->GetBasisNumModes(0);
1632 
1633  //Bases for Tetrahedral element
1634  const LibUtilities::BasisKey TetBa(
1635  LibUtilities::eModified_A, nummodes,
1637  const LibUtilities::BasisKey TetBb(
1638  LibUtilities::eModified_B, nummodes,
1640  const LibUtilities::BasisKey TetBc(
1641  LibUtilities::eModified_C, nummodes,
1643 
1644  //Create reference tetrahedral expansion
1646 
1648  ::AllocateSharedPtr(TetBa,TetBb,TetBc,
1649  tetgeom);
1650 
1651  //Bases for prismatic element
1652  const LibUtilities::BasisKey PrismBa(
1653  LibUtilities::eModified_A, nummodes,
1655  const LibUtilities::BasisKey PrismBb(
1656  LibUtilities::eModified_A, nummodes,
1658  const LibUtilities::BasisKey PrismBc(
1659  LibUtilities::eModified_B, nummodes,
1661 
1662  //Create reference prismatic expansion
1664 
1666  ::AllocateSharedPtr(PrismBa,PrismBb,PrismBc,
1667  prismgeom);
1668 
1669  //Bases for prismatic element
1670  const LibUtilities::BasisKey HexBa(
1671  LibUtilities::eModified_A, nummodes,
1673  const LibUtilities::BasisKey HexBb(
1674  LibUtilities::eModified_A, nummodes,
1676  const LibUtilities::BasisKey HexBc(
1677  LibUtilities::eModified_A, nummodes,
1679 
1680  //Create reference prismatic expansion
1682 
1684  ::AllocateSharedPtr(HexBa,HexBb,HexBc,
1685  hexgeom);
1686 
1687 
1688  // retrieve variable coefficient
1689  if(m_linSysKey.GetNVarCoeffs() > 0)
1690  {
1691  StdRegions::VarCoeffMap::const_iterator x;
1692  cnt = expList->GetPhys_Offset(0);
1693  for (x = m_linSysKey.GetVarCoeffs().begin();
1694  x != m_linSysKey.GetVarCoeffs().end(); ++x)
1695  {
1696  vVarCoeffMap[x->first] = x->second + cnt;
1697  }
1698  }
1699 
1700  StdRegions::MatrixType PreconR,PreconRT;
1701 
1702  if(m_linSysKey.GetMatrixType() == StdRegions::eMass)
1703  {
1704  PreconR = StdRegions::ePreconRMass;
1705  PreconRT = StdRegions::ePreconRTMass;
1706  }
1707  else
1708  {
1709  PreconR = StdRegions::ePreconR;
1710  PreconRT = StdRegions::ePreconRT;
1711  }
1712 
1713 
1714 
1715  /*
1716  * Matrix keys - for each element type there are two matrix keys
1717  * corresponding to the transformation matrix R and its transpose
1718  */
1719 
1720 
1721  //Matrix keys for tetrahedral element transformation matrix
1723  (PreconR, LibUtilities::eTetrahedron,
1724  *TetExp, m_linSysKey.GetConstFactors(),
1725  vVarCoeffMap);
1726 
1727  //Matrix keys for tetrahedral transposed transformation matrix
1729  (PreconRT, LibUtilities::eTetrahedron,
1730  *TetExp, m_linSysKey.GetConstFactors(),
1731  vVarCoeffMap);
1732 
1733  //Matrix keys for prismatic element transformation matrix
1735  (PreconR, LibUtilities::ePrism,
1736  *PrismExp, m_linSysKey.GetConstFactors(),
1737  vVarCoeffMap);
1738 
1739  //Matrix keys for prismatic element transposed transformation matrix
1740  LocalRegions::MatrixKey PrismRT
1741  (PreconRT, LibUtilities::ePrism,
1742  *PrismExp, m_linSysKey.GetConstFactors(),
1743  vVarCoeffMap);
1744 
1745  //Matrix keys for hexahedral element transformation matrix
1747  (PreconR, LibUtilities::eHexahedron,
1748  *HexExp, m_linSysKey.GetConstFactors(),
1749  vVarCoeffMap);
1750 
1751  //Matrix keys for hexahedral element transposed transformation
1752  //matrix
1754  (PreconRT, LibUtilities::eHexahedron,
1755  *HexExp, m_linSysKey.GetConstFactors(),
1756  vVarCoeffMap);
1757 
1758  /*
1759  * Create transformation matrices for the tetrahedral element
1760  */
1761 
1762  //Get tetrahedral transformation matrix
1763  m_Rtet = TetExp->GetLocMatrix(TetR);
1764 
1765  //Get tetrahedral transposed transformation matrix
1766  m_RTtet = TetExp->GetLocMatrix(TetRT);
1767 
1768  // Using the transformation matrix and the inverse transformation
1769  // matrix create the inverse matrices
1770  Rtettmp=TetExp->BuildInverseTransformationMatrix(m_Rtet);
1771 
1772  //Inverse transposed transformation matrix
1773  RTtettmp=TetExp->BuildInverseTransformationMatrix(m_Rtet);
1774  RTtettmp->Transpose();
1775 
1777  ::AllocateSharedPtr(1.0,Rtettmp);
1779  ::AllocateSharedPtr(1.0,RTtettmp);
1780 
1781  /*
1782  * Create transformation matrices for the hexahedral element
1783  */
1784 
1785  //Get hexahedral transformation matrix
1786  m_Rhex = HexExp->GetLocMatrix(HexR);
1787  //Get hexahedral transposed transformation matrix
1788  m_RThex = HexExp->GetLocMatrix(HexRT);
1789 
1790  // Using the transformation matrix and the inverse transformation
1791  // matrix create the inverse matrices
1792  Rhextmp=HexExp->BuildInverseTransformationMatrix(m_Rhex);
1793  //Inverse transposed transformation matrix
1794  RThextmp=HexExp->BuildInverseTransformationMatrix(m_Rhex);
1795  RThextmp->Transpose();
1796 
1798  ::AllocateSharedPtr(1.0,Rhextmp);
1800  ::AllocateSharedPtr(1.0,RThextmp);
1801 
1802  /*
1803  * Create transformation matrices for the prismatic element
1804  */
1805 
1806  //Get prism transformation matrix
1807  Rprismoriginal = PrismExp->GetLocMatrix(PrismR);
1808  //Get prism transposed transformation matrix
1809  RTprismoriginal = PrismExp->GetLocMatrix(PrismRT);
1810 
1811  unsigned int nRows=Rprismoriginal->GetRows();
1812  NekDouble zero=0.0;
1814  AllocateSharedPtr(nRows,nRows,zero,eFULL);
1816  AllocateSharedPtr(nRows,nRows,zero,eFULL);
1817  NekDouble Rvalue, RTvalue;
1818 
1819  //Copy values from the prism transformation matrix
1820  for(i=0; i<nRows; ++i)
1821  {
1822  for(j=0; j<nRows; ++j)
1823  {
1824  Rvalue=(*Rprismoriginal)(i,j);
1825  RTvalue=(*RTprismoriginal)(i,j);
1826  Rtmpprism->SetValue(i,j,Rvalue);
1827  RTtmpprism->SetValue(i,j,RTvalue);
1828  }
1829  }
1830 
1831  //Replace triangular faces and edges of the prims transformation
1832  //matrix with the corresponding values of the tetrahedral
1833  //transformation matrix.
1834  ModifyPrismTransformationMatrix(TetExp,PrismExp,Rtmpprism,RTtmpprism);
1835 
1837  ::AllocateSharedPtr(1.0,Rtmpprism);
1838 
1840  ::AllocateSharedPtr(1.0,RTtmpprism);
1841 
1842  //Inverse transformation matrix
1843  Rprismtmp=PrismExp->BuildInverseTransformationMatrix(m_Rprism);
1844 
1845  //Inverse transposed transformation matrix
1846  RTprismtmp=PrismExp->BuildInverseTransformationMatrix(m_Rprism);
1847  RTprismtmp->Transpose();
1848 
1850  ::AllocateSharedPtr(1.0,Rprismtmp);
1851 
1853  ::AllocateSharedPtr(1.0,RTprismtmp);
1854  }
1855 
1856  /**
1857  * \brief Modify the prism transformation matrix to align with the
1858  * tetrahedral modes.
1859  *
1860  * This routine replaces the edge and triangular face components of the
1861  * prismatic vertex transformation matrices \f$\mathbf{R}_{ve}\f$ and
1862  * \f$\mathbf{R}_{vf}\f$ with the corresponding components from the
1863  * tetrahedral transformation matrices. Additionally, triangular face
1864  * components in the prismatic edge transformation matrix
1865  * \f$\mathbf{R}_{ef}\f$ with the corresponding component from the
1866  * tetrahedral transformation matrix.
1867  */
1871  DNekMatSharedPtr Rmodprism,
1872  DNekMatSharedPtr RTmodprism)
1873  {
1874  NekDouble Rvalue, RTvalue;
1875  int i, j;
1876 
1877  //For a tet element the bottom face is made up of the following:
1878  //vertices: 0, 1 and 2 edges: 0, 1 and 2 face: 0. We first need to
1879  //determine the mode locations of these vertices, edges and face so
1880  //we can extract the correct values from the tetrahedral R matrix.
1881 
1882  //These are the vertex mode locations of R which need to be replaced
1883  //in the prism element
1884  int TetVertex0=TetExp->GetVertexMap(0);
1885  int TetVertex1=TetExp->GetVertexMap(1);
1886  int TetVertex2=TetExp->GetVertexMap(2);
1887  int TetVertex3=TetExp->GetVertexMap(3);
1888 
1889 
1890  //These are the edge mode locations of R which need to be replaced
1891  //in the prism element
1892  Array<OneD, unsigned int> TetEdge0=TetExp->GetEdgeInverseBoundaryMap(0);
1893  Array<OneD, unsigned int> TetEdge1=TetExp->GetEdgeInverseBoundaryMap(1);
1894  Array<OneD, unsigned int> TetEdge2=TetExp->GetEdgeInverseBoundaryMap(2);
1895  Array<OneD, unsigned int> TetEdge3=TetExp->GetEdgeInverseBoundaryMap(3);
1896  Array<OneD, unsigned int> TetEdge4=TetExp->GetEdgeInverseBoundaryMap(4);
1897  Array<OneD, unsigned int> TetEdge5=TetExp->GetEdgeInverseBoundaryMap(5);
1898 
1899  //These are the face mode locations of R which need to be replaced
1900  //in the prism element
1901  Array<OneD, unsigned int> TetFace=TetExp->GetFaceInverseBoundaryMap(1);
1902 
1903  //Prism vertex modes
1904  int PrismVertex0=PrismExp->GetVertexMap(0);
1905  int PrismVertex1=PrismExp->GetVertexMap(1);
1906  int PrismVertex2=PrismExp->GetVertexMap(2);
1907  int PrismVertex3=PrismExp->GetVertexMap(3);
1908  int PrismVertex4=PrismExp->GetVertexMap(4);
1909  int PrismVertex5=PrismExp->GetVertexMap(5);
1910 
1911  //Prism edge modes
1912  Array<OneD, unsigned int> PrismEdge0=
1913  PrismExp->GetEdgeInverseBoundaryMap(0);
1914  Array<OneD, unsigned int> PrismEdge1=
1915  PrismExp->GetEdgeInverseBoundaryMap(1);
1916  Array<OneD, unsigned int> PrismEdge2=
1917  PrismExp->GetEdgeInverseBoundaryMap(2);
1918  Array<OneD, unsigned int> PrismEdge3=
1919  PrismExp->GetEdgeInverseBoundaryMap(3);
1920  Array<OneD, unsigned int> PrismEdge4=
1921  PrismExp->GetEdgeInverseBoundaryMap(4);
1922  Array<OneD, unsigned int> PrismEdge5=
1923  PrismExp->GetEdgeInverseBoundaryMap(5);
1924  Array<OneD, unsigned int> PrismEdge6=
1925  PrismExp->GetEdgeInverseBoundaryMap(6);
1926  Array<OneD, unsigned int> PrismEdge7=
1927  PrismExp->GetEdgeInverseBoundaryMap(7);
1928  Array<OneD, unsigned int> PrismEdge8=
1929  PrismExp->GetEdgeInverseBoundaryMap(8);
1930 
1931  //Prism face 1 & 3 face modes
1932  Array<OneD, unsigned int> PrismFace1=
1933  PrismExp->GetFaceInverseBoundaryMap(1);
1934  Array<OneD, unsigned int> PrismFace3=
1935  PrismExp->GetFaceInverseBoundaryMap(3);
1936  Array<OneD, unsigned int> PrismFace0=
1937  PrismExp->GetFaceInverseBoundaryMap(0);
1938  Array<OneD, unsigned int> PrismFace2=
1939  PrismExp->GetFaceInverseBoundaryMap(2);
1940  Array<OneD, unsigned int> PrismFace4=
1941  PrismExp->GetFaceInverseBoundaryMap(4);
1942 
1943  //vertex 0 edge 0 3 & 4
1944  for(i=0; i< PrismEdge0.num_elements(); ++i)
1945  {
1946  Rvalue=(*m_Rtet)(TetVertex0,TetEdge0[i]);
1947  Rmodprism->SetValue(PrismVertex0,PrismEdge0[i],Rvalue);
1948  Rvalue=(*m_Rtet)(TetVertex0,TetEdge2[i]);
1949  Rmodprism->SetValue(PrismVertex0,PrismEdge3[i],Rvalue);
1950  Rvalue=(*m_Rtet)(TetVertex0,TetEdge3[i]);
1951  Rmodprism->SetValue(PrismVertex0,PrismEdge4[i],Rvalue);
1952 
1953  //transposed values
1954  RTvalue=(*m_RTtet)(TetEdge0[i],TetVertex0);
1955  RTmodprism->SetValue(PrismEdge0[i],PrismVertex0,RTvalue);
1956  RTvalue=(*m_RTtet)(TetEdge2[i],TetVertex0);
1957  RTmodprism->SetValue(PrismEdge3[i],PrismVertex0,RTvalue);
1958  RTvalue=(*m_RTtet)(TetEdge3[i],TetVertex0);
1959  RTmodprism->SetValue(PrismEdge4[i],PrismVertex0,RTvalue);
1960  }
1961 
1962  //vertex 1 edge 0 1 & 5
1963  for(i=0; i< PrismEdge1.num_elements(); ++i)
1964  {
1965  Rvalue=(*m_Rtet)(TetVertex1,TetEdge0[i]);
1966  Rmodprism->SetValue(PrismVertex1,PrismEdge0[i],Rvalue);
1967  Rvalue=(*m_Rtet)(TetVertex1,TetEdge1[i]);
1968  Rmodprism->SetValue(PrismVertex1,PrismEdge1[i],Rvalue);
1969  Rvalue=(*m_Rtet)(TetVertex1,TetEdge4[i]);
1970  Rmodprism->SetValue(PrismVertex1,PrismEdge5[i],Rvalue);
1971 
1972  //transposed values
1973  RTvalue=(*m_RTtet)(TetEdge0[i],TetVertex1);
1974  RTmodprism->SetValue(PrismEdge0[i],PrismVertex1,RTvalue);
1975  RTvalue=(*m_RTtet)(TetEdge1[i],TetVertex1);
1976  RTmodprism->SetValue(PrismEdge1[i],PrismVertex1,RTvalue);
1977  RTvalue=(*m_RTtet)(TetEdge4[i],TetVertex1);
1978  RTmodprism->SetValue(PrismEdge5[i],PrismVertex1,RTvalue);
1979  }
1980 
1981  //vertex 2 edge 1 2 & 6
1982  for(i=0; i< PrismEdge2.num_elements(); ++i)
1983  {
1984  Rvalue=(*m_Rtet)(TetVertex2,TetEdge1[i]);
1985  Rmodprism->SetValue(PrismVertex2,PrismEdge1[i],Rvalue);
1986  Rvalue=(*m_Rtet)(TetVertex1,TetEdge0[i]);
1987  Rmodprism->SetValue(PrismVertex2,PrismEdge2[i],Rvalue);
1988  Rvalue=(*m_Rtet)(TetVertex2,TetEdge5[i]);
1989  Rmodprism->SetValue(PrismVertex2,PrismEdge6[i],Rvalue);
1990 
1991  //transposed values
1992  RTvalue=(*m_RTtet)(TetEdge1[i],TetVertex2);
1993  RTmodprism->SetValue(PrismEdge1[i],PrismVertex2,RTvalue);
1994  RTvalue=(*m_RTtet)(TetEdge0[i],TetVertex1);
1995  RTmodprism->SetValue(PrismEdge2[i],PrismVertex2,RTvalue);
1996  RTvalue=(*m_RTtet)(TetEdge5[i],TetVertex2);
1997  RTmodprism->SetValue(PrismEdge6[i],PrismVertex2,RTvalue);
1998  }
1999 
2000  //vertex 3 edge 3 2 & 7
2001  for(i=0; i< PrismEdge3.num_elements(); ++i)
2002  {
2003  Rvalue=(*m_Rtet)(TetVertex2,TetEdge2[i]);
2004  Rmodprism->SetValue(PrismVertex3,PrismEdge3[i],Rvalue);
2005  Rvalue=(*m_Rtet)(TetVertex0,TetEdge0[i]);
2006  Rmodprism->SetValue(PrismVertex3,PrismEdge2[i],Rvalue);
2007  Rvalue=(*m_Rtet)(TetVertex2,TetEdge5[i]);
2008  Rmodprism->SetValue(PrismVertex3,PrismEdge7[i],Rvalue);
2009 
2010  //transposed values
2011  RTvalue=(*m_RTtet)(TetEdge2[i],TetVertex2);
2012  RTmodprism->SetValue(PrismEdge3[i],PrismVertex3,RTvalue);
2013  RTvalue=(*m_RTtet)(TetEdge0[i],TetVertex0);
2014  RTmodprism->SetValue(PrismEdge2[i],PrismVertex3,RTvalue);
2015  RTvalue=(*m_RTtet)(TetEdge5[i],TetVertex2);
2016  RTmodprism->SetValue(PrismEdge7[i],PrismVertex3,RTvalue);
2017  }
2018 
2019  //vertex 4 edge 4 5 & 8
2020  for(i=0; i< PrismEdge4.num_elements(); ++i)
2021  {
2022  Rvalue=(*m_Rtet)(TetVertex3,TetEdge3[i]);
2023  Rmodprism->SetValue(PrismVertex4,PrismEdge4[i],Rvalue);
2024  Rvalue=(*m_Rtet)(TetVertex3,TetEdge4[i]);
2025  Rmodprism->SetValue(PrismVertex4,PrismEdge5[i],Rvalue);
2026  Rvalue=(*m_Rtet)(TetVertex0,TetEdge2[i]);
2027  Rmodprism->SetValue(PrismVertex4,PrismEdge8[i],Rvalue);
2028 
2029  //transposed values
2030  RTvalue=(*m_RTtet)(TetEdge3[i],TetVertex3);
2031  RTmodprism->SetValue(PrismEdge4[i],PrismVertex4,RTvalue);
2032  RTvalue=(*m_RTtet)(TetEdge4[i],TetVertex3);
2033  RTmodprism->SetValue(PrismEdge5[i],PrismVertex4,RTvalue);
2034  RTvalue=(*m_RTtet)(TetEdge2[i],TetVertex0);
2035  RTmodprism->SetValue(PrismEdge8[i],PrismVertex4,RTvalue);
2036  }
2037 
2038  //vertex 5 edge 6 7 & 8
2039  for(i=0; i< PrismEdge5.num_elements(); ++i)
2040  {
2041  Rvalue=(*m_Rtet)(TetVertex3,TetEdge3[i]);
2042  Rmodprism->SetValue(PrismVertex5,PrismEdge6[i],Rvalue);
2043  Rvalue=(*m_Rtet)(TetVertex3,TetEdge4[i]);
2044  Rmodprism->SetValue(PrismVertex5,PrismEdge7[i],Rvalue);
2045  Rvalue=(*m_Rtet)(TetVertex2,TetEdge2[i]);
2046  Rmodprism->SetValue(PrismVertex5,PrismEdge8[i],Rvalue);
2047 
2048  //transposed values
2049  RTvalue=(*m_RTtet)(TetEdge3[i],TetVertex3);
2050  RTmodprism->SetValue(PrismEdge6[i],PrismVertex5,RTvalue);
2051  RTvalue=(*m_RTtet)(TetEdge4[i],TetVertex3);
2052  RTmodprism->SetValue(PrismEdge7[i],PrismVertex5,RTvalue);
2053  RTvalue=(*m_RTtet)(TetEdge2[i],TetVertex2);
2054  RTmodprism->SetValue(PrismEdge8[i],PrismVertex5,RTvalue);
2055  }
2056 
2057  // face 1 vertices 0 1 4
2058  for(i=0; i< PrismFace1.num_elements(); ++i)
2059  {
2060  Rvalue=(*m_Rtet)(TetVertex0,TetFace[i]);
2061  Rmodprism->SetValue(PrismVertex0,PrismFace1[i],Rvalue);
2062  Rvalue=(*m_Rtet)(TetVertex1,TetFace[i]);
2063  Rmodprism->SetValue(PrismVertex1,PrismFace1[i],Rvalue);
2064  Rvalue=(*m_Rtet)(TetVertex3,TetFace[i]);
2065  Rmodprism->SetValue(PrismVertex4,PrismFace1[i],Rvalue);
2066 
2067  //transposed values
2068  RTvalue=(*m_RTtet)(TetFace[i],TetVertex0);
2069  RTmodprism->SetValue(PrismFace1[i],PrismVertex0,RTvalue);
2070  RTvalue=(*m_RTtet)(TetFace[i],TetVertex1);
2071  RTmodprism->SetValue(PrismFace1[i],PrismVertex1,RTvalue);
2072  RTvalue=(*m_RTtet)(TetFace[i],TetVertex3);
2073  RTmodprism->SetValue(PrismFace1[i],PrismVertex4,RTvalue);
2074  }
2075 
2076  // face 3 vertices 2, 3 & 5
2077  for(i=0; i< PrismFace3.num_elements(); ++i)
2078  {
2079  Rvalue=(*m_Rtet)(TetVertex1,TetFace[i]);
2080  Rmodprism->SetValue(PrismVertex2,PrismFace3[i],Rvalue);
2081  Rvalue=(*m_Rtet)(TetVertex0,TetFace[i]);
2082  Rmodprism->SetValue(PrismVertex3,PrismFace3[i],Rvalue);
2083  Rvalue=(*m_Rtet)(TetVertex3,TetFace[i]);
2084  Rmodprism->SetValue(PrismVertex5,PrismFace3[i],Rvalue);
2085 
2086  //transposed values
2087  RTvalue=(*m_RTtet)(TetFace[i],TetVertex1);
2088  RTmodprism->SetValue(PrismFace3[i],PrismVertex2,RTvalue);
2089  RTvalue=(*m_RTtet)(TetFace[i],TetVertex0);
2090  RTmodprism->SetValue(PrismFace3[i],PrismVertex3,RTvalue);
2091  RTvalue=(*m_RTtet)(TetFace[i],TetVertex3);
2092  RTmodprism->SetValue(PrismFace3[i],PrismVertex5,RTvalue);
2093  }
2094 
2095  // Face 1 edge 0 4 5
2096  for(i=0; i< PrismFace1.num_elements(); ++i)
2097  {
2098  for(j=0; j<PrismEdge0.num_elements(); ++j)
2099  {
2100  Rvalue=(*m_Rtet)(TetEdge0[j],TetFace[i]);
2101  Rmodprism->SetValue(PrismEdge0[j],PrismFace1[i],Rvalue);
2102  Rvalue=(*m_Rtet)(TetEdge3[j],TetFace[i]);
2103  Rmodprism->SetValue(PrismEdge4[j],PrismFace1[i],Rvalue);
2104  Rvalue=(*m_Rtet)(TetEdge4[j],TetFace[i]);
2105  Rmodprism->SetValue(PrismEdge5[j],PrismFace1[i],Rvalue);
2106 
2107  //transposed values
2108  RTvalue=(*m_RTtet)(TetFace[i],TetEdge0[j]);
2109  RTmodprism->SetValue(PrismFace1[i],PrismEdge0[j],RTvalue);
2110  RTvalue=(*m_RTtet)(TetFace[i],TetEdge3[j]);
2111  RTmodprism->SetValue(PrismFace1[i],PrismEdge4[j],RTvalue);
2112  RTvalue=(*m_RTtet)(TetFace[i],TetEdge4[j]);
2113  RTmodprism->SetValue(PrismFace1[i],PrismEdge5[j],RTvalue);
2114  }
2115  }
2116 
2117  // Face 3 edge 2 6 7
2118  for(i=0; i< PrismFace3.num_elements(); ++i)
2119  {
2120  for(j=0; j<PrismEdge2.num_elements(); ++j)
2121  {
2122  Rvalue=(*m_Rtet)(TetEdge0[j],TetFace[i]);
2123  Rmodprism->SetValue(PrismEdge2[j],PrismFace3[i],Rvalue);
2124  Rvalue=(*m_Rtet)(TetEdge4[j],TetFace[i]);
2125  Rmodprism->SetValue(PrismEdge6[j],PrismFace3[i],Rvalue);
2126  Rvalue=(*m_Rtet)(TetEdge3[j],TetFace[i]);
2127  Rmodprism->SetValue(PrismEdge7[j],PrismFace3[i],Rvalue);
2128 
2129  RTvalue=(*m_RTtet)(TetFace[i],TetEdge0[j]);
2130  RTmodprism->SetValue(PrismFace3[i],PrismEdge2[j],RTvalue);
2131  RTvalue=(*m_RTtet)(TetFace[i],TetEdge4[j]);
2132  RTmodprism->SetValue(PrismFace3[i],PrismEdge6[j],RTvalue);
2133  RTvalue=(*m_RTtet)(TetFace[i],TetEdge3[j]);
2134  RTmodprism->SetValue(PrismFace3[i],PrismEdge7[j],RTvalue);
2135  }
2136  }
2137  }
2138 
2139  }
2140 }
2141 
2142 
2143 
2144 
2145 
2146 
const StdRegions::VarCoeffMap & GetVarCoeffs() const
LibUtilities::CommSharedPtr m_comm
virtual void v_DoPreconditioner(const Array< OneD, NekDouble > &pInput, Array< OneD, NekDouble > &pOutput)
PreconditionerLowEnergy(const boost::shared_ptr< GlobalLinSys > &plinsys, const AssemblyMapSharedPtr &pLocToGloMap)
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:161
Principle Modified Functions .
Definition: BasisType.h:51
static void Gather(Nektar::Array< OneD, NekDouble > pU, gs_op pOp, gs_data *pGsh, Nektar::Array< OneD, NekDouble > pBuffer=NullNekDouble1DArray)
Performs a gather-scatter operation of the provided values.
Definition: GsLib.hpp:223
virtual void v_DoMultiplybyInverseTransposedTransformationMatrix(const Array< OneD, NekDouble > &pInput, Array< OneD, NekDouble > &pOutput)
Multiply by the block tranposed inverse transformation matrix.
void Gathr(int n, const T *x, const int *y, T *z)
Gather vector z[i] = x[y[i]].
Definition: Vmath.cpp:630
static boost::shared_ptr< DataType > AllocateSharedPtr()
Allocate a shared pointer from the memory pool.
std::map< int, vector< PeriodicEntity > > PeriodicMap
#define sign(a, b)
return the sign(b)*a
Definition: Polylib.cpp:22
boost::shared_ptr< AssemblyMap > AssemblyMapSharedPtr
Definition: AssemblyMap.h:53
boost::shared_ptr< QuadGeom > QuadGeomSharedPtr
Definition: QuadGeom.h:54
static gs_data * Init(const Nektar::Array< OneD, long > pId, const LibUtilities::CommSharedPtr &pComm)
Initialise Gather-Scatter map.
Definition: GsLib.hpp:150
Principle Modified Functions .
Definition: BasisType.h:49
PreconFactory & GetPreconFactory()
void Sdiv(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Scalar multiply y = alpha/y.
Definition: Vmath.cpp:257
boost::shared_ptr< HexExp > HexExpSharedPtr
Definition: HexExp.h:57
const StdRegions::ConstFactorMap & GetConstFactors() const
Returns all the constants.
boost::shared_ptr< HexGeom > HexGeomSharedPtr
Definition: HexGeom.h:110
int GetEdgeNcoeffs(const int i) const
This function returns the number of expansion coefficients belonging to the i-th edge.
Definition: StdExpansion.h:287
boost::shared_ptr< DNekMat > DNekMatSharedPtr
Definition: NekTypeDefs.hpp:70
boost::shared_ptr< TetExp > TetExpSharedPtr
Definition: TetExp.h:223
boost::shared_ptr< DNekScalMat > DNekScalMatSharedPtr
Gauss Radau pinned at x=-1, .
Definition: PointsType.h:57
SpatialDomains::HexGeomSharedPtr CreateRefHexGeom(void)
Sets up the reference hexahedral element needed to construct a low energy basis.
boost::shared_ptr< StdExpansion2D > StdExpansion2DSharedPtr
virtual DNekScalMatSharedPtr v_TransformedSchurCompl(int offset, const boost::shared_ptr< DNekScalMat > &loc_mat)
Set up the transformed block matrix system.
virtual void v_BuildPreconditioner()
Construct the low energy preconditioner from .
int GetFaceIntNcoeffs(const int i) const
Definition: StdExpansion.h:359
void SetUpReferenceElements(void)
Sets up the reference elements needed by the preconditioner.
static PreconditionerSharedPtr create(const boost::shared_ptr< GlobalLinSys > &plinsys, const boost::shared_ptr< AssemblyMap > &pLocToGloMap)
Creates an instance of this class.
std::map< StdRegions::VarCoeffType, Array< OneD, NekDouble > > VarCoeffMap
Definition: StdRegions.hpp:226
boost::shared_ptr< SegGeom > SegGeomSharedPtr
Definition: Geometry2D.h:60
Principle Modified Functions .
Definition: BasisType.h:50
StdRegions::Orientation DeterminePeriodicFaceOrient(StdRegions::Orientation faceOrient, StdRegions::Orientation perFaceOrient)
Determine relative orientation between two faces.
boost::shared_ptr< DNekScalBlkMat > DNekScalBlkMatSharedPtr
Definition: NekTypeDefs.hpp:74
virtual void v_DoTransformToLowEnergy(Array< OneD, NekDouble > &pInOut, int offset)
Transform the solution vector vector to low energy.
Defines a specification for a set of points.
Definition: Points.h:58
double NekDouble
void Assmb(int n, const T *x, const int *y, T *z)
Assemble z[y[i]] += x[i]; z should be zero'd first.
Definition: Vmath.cpp:695
boost::shared_ptr< Expansion > ExpansionSharedPtr
Definition: Expansion.h:68
boost::shared_ptr< PrismExp > PrismExpSharedPtr
Definition: PrismExp.h:217
boost::shared_ptr< T > as()
virtual void v_DoMultiplybyInverseTransformationMatrix(const Array< OneD, NekDouble > &pInput, Array< OneD, NekDouble > &pOutput)
Multiply by the block inverse transformation matrix.
Describe a linear system.
virtual void v_DoTransformFromLowEnergy(Array< OneD, NekDouble > &pInOut)
transform the solution vector from low energy back to the original basis.
StdRegions::MatrixType GetMatrixType() const
Return the matrix type.
boost::shared_ptr< Geometry2D > Geometry2DSharedPtr
Definition: Geometry2D.h:59
SpatialDomains::TetGeomSharedPtr CreateRefTetGeom(void)
Sets up the reference tretrahedral element needed to construct a low energy basis.
void ModifyPrismTransformationMatrix(LocalRegions::TetExpSharedPtr TetExp, LocalRegions::PrismExpSharedPtr PrismExp, DNekMatSharedPtr Rmodprism, DNekMatSharedPtr RTmodprism)
Modify the prism transformation matrix to align with the tetrahedral modes.
boost::shared_ptr< PrismGeom > PrismGeomSharedPtr
Definition: PrismGeom.h:109
Gauss Radau pinned at x=-1, .
Definition: PointsType.h:58
boost::shared_ptr< TetGeom > TetGeomSharedPtr
Definition: TetGeom.h:106
boost::shared_ptr< TriGeom > TriGeomSharedPtr
Definition: TriGeom.h:58
SpatialDomains::PrismGeomSharedPtr CreateRefPrismGeom(void)
Sets up the reference prismatic element needed to construct a low energy basis.
const boost::weak_ptr< GlobalLinSys > m_linsys
boost::shared_ptr< StdExpansion > StdExpansionSharedPtr
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode...
Definition: ErrorUtil.hpp:191
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.cpp:1047
Describes the specification for a Basis.
Definition: Basis.h:50
boost::shared_ptr< PointGeom > PointGeomSharedPtr
Definition: Geometry.h:60
1D Gauss-Lobatto-Legendre quadrature points
Definition: PointsType.h:50
void Vmul(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Multiply vector z = x*y.
Definition: Vmath.cpp:169
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, tDescription pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:215