1 // @HEADER
2 // ************************************************************************
3 //
4 //               Rapid Optimization Library (ROL) Package
5 //                 Copyright (2014) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact lead developers:
38 //              Drew Kouri   (dpkouri@sandia.gov) and
39 //              Denis Ridzal (dridzal@sandia.gov)
40 //
41 // ************************************************************************
42 // @HEADER
43 
44 /*! \file  dofmanager.hpp
45     \brief Given a mesh with connectivity information, sets up data
46            structures for the indexing of the global degrees of
47            freedom (Dofs).
48 */
49 
50 #ifndef DOFMANAGER_HPP
51 #define DOFMANAGER_HPP
52 
53 #include "Teuchos_ParameterList.hpp"
54 #include "Intrepid_FieldContainer.hpp"
55 #include "Intrepid_Basis.hpp"
56 #include "meshmanager.hpp"
57 
58 template <class Real>
59 class DofManager {
60 
61 private:
62   ROL::Ptr<MeshManager<Real> > meshManager_;
63   std::vector<ROL::Ptr<Intrepid::Basis<Real, Intrepid::FieldContainer<Real> > > > intrepidBasis_;
64 
65   int cellDim_;          // cell dimension
66 
67   int numCells_;         // number of mesh cells
68   int numNodes_;         // number of mesh nodes
69   int numEdges_;         // number of mesh edges
70   int numFaces_;         // number of mesh faces
71 
72   ROL::Ptr<Intrepid::FieldContainer<int> > meshCellToNodeMap_;
73   ROL::Ptr<Intrepid::FieldContainer<int> > meshCellToEdgeMap_;
74   ROL::Ptr<Intrepid::FieldContainer<int> > meshCellToFaceMap_;
75 
76   // Local dof information.
77   int numBases_;                                  // number of bases (fields)
78   int numLocalNodes_;                             // number of nodes in the basic cell topology
79   int numLocalEdges_;                             // number of edges in the basic cell topology
80   int numLocalFaces_;                             // number of faces in the basic cell topology
81   int numLocalVoids_;                             // number of voids in the basic cell topology, =1
82   int numLocalNodeDofs_;                          // number of local (single-cell) node dofs for all bases
83   int numLocalEdgeDofs_;                          // number of local (single-cell) edge dofs for all bases
84   int numLocalFaceDofs_;                          // number of local (single-cell) face dofs for all bases
85   int numLocalVoidDofs_;                          // number of local (single-cell) face dofs for all bases
86   int numLocalDofs_;                              // total number of local (single-cell) face dofs for all bases
87   std::vector<int> numDofsPerNode_;               // number of dofs per node in a cell (assumed constant), per basis
88   std::vector<int> numDofsPerEdge_;               // number of dofs per edge in a cell (assumed constant), per basis
89   std::vector<int> numDofsPerFace_;               // number of dofs per face in a cell (assumed constant), per basis
90   std::vector<int> numDofsPerVoid_;               // number of dofs per void in a cell (assumed constant), per basis
91   std::vector<std::vector<int> > fieldPattern_;   // local indexing of fields into the array [0,1,...,numLocalDofs-1];
92                                                   // contains [number of bases] index vectors, where each index vector
93                                                   // is of size [basis cardinality]
94   // Global dof information.
95   int numNodeDofs_;  // number of global node dofs
96   int numEdgeDofs_;  // number of global edge dofs
97   int numFaceDofs_;  // number of global face dofs
98   int numVoidDofs_;  // number of global void dofs
99   int numDofs_;      // total number of global dofs
100 
101   ROL::Ptr<Intrepid::FieldContainer<int> > nodeDofs_;  // global node dofs, of size [numNodes_ x numLocalNodeDofs_]
102   ROL::Ptr<Intrepid::FieldContainer<int> > edgeDofs_;  // global edge dofs, of size [numEdges_ x numLocalEdgeDofs_]
103   ROL::Ptr<Intrepid::FieldContainer<int> > faceDofs_;  // global face dofs, of size [numFaces_ x numLocalFaceDofs_]
104   ROL::Ptr<Intrepid::FieldContainer<int> > voidDofs_;  // global face dofs, of size [numFaces_ x numLocalFaceDofs_]
105   ROL::Ptr<Intrepid::FieldContainer<int> > cellDofs_;  // global cell dofs, of size [numCells_ x numLocalDofs_];
106                                                            // ordered by subcell (node, then edge, then face) and basis index
107   std::vector<int> mapToIntrepidPattern_;
108   std::vector<int> mapToFieldPattern_;
109 
110   std::vector<ROL::Ptr<Intrepid::FieldContainer<int> > > fieldDofs_;  // global cell dofs, indexed by field/basis, of size [numCells_ x basis cardinality];
111                                                                           // ordered by subcell (node, then edge, then face)
112 
113 public:
114 
DofManager(ROL::Ptr<MeshManager<Real>> & meshManager,std::vector<ROL::Ptr<Intrepid::Basis<Real,Intrepid::FieldContainer<Real>>>> & intrepidBasis)115   DofManager(ROL::Ptr<MeshManager<Real> >                                                    &meshManager,
116              std::vector<ROL::Ptr<Intrepid::Basis<Real, Intrepid::FieldContainer<Real> > > > &intrepidBasis) {
117 
118     meshManager_ = meshManager;
119     intrepidBasis_ = intrepidBasis;
120     cellDim_  = intrepidBasis_[0]->getBaseCellTopology().getDimension();
121     numCells_ = meshManager_->getNumCells();
122     numNodes_ = meshManager_->getNumNodes();
123     numEdges_ = meshManager_->getNumEdges();
124     numFaces_ = meshManager_->getNumFaces();
125 
126     // Mesh data structures.
127     meshCellToNodeMap_ = meshManager_->getCellToNodeMap();
128     meshCellToEdgeMap_ = meshManager_->getCellToEdgeMap();
129     meshCellToFaceMap_ = meshManager_->getCellToFaceMap();
130 
131     // Local degree-of-freedom footprint.
132     numBases_ = static_cast<int>(intrepidBasis_.size());
133     numDofsPerNode_.resize(numBases_, 0);
134     numDofsPerEdge_.resize(numBases_, 0);
135     numDofsPerFace_.resize(numBases_, 0);
136     numDofsPerVoid_.resize(numBases_, 0);
137     numLocalDofs_ = 0;
138     for (int i=0; i<numBases_; ++i) {
139       std::vector<std::vector<int> > dofTags = (intrepidBasis_[i])->getAllDofTags();
140       for (int j=0; j<(intrepidBasis_[i])->getCardinality(); ++j) {
141         if (dofTags[j][0] == 0) {
142           numDofsPerNode_[i] = dofTags[j][3];
143         }
144         else if (dofTags[j][0] == 1) {
145           if (cellDim_ == 1) { // 1D
146             numDofsPerVoid_[i] = dofTags[j][3];
147           }
148           else { // 2D, 3D
149             numDofsPerEdge_[i] = dofTags[j][3];
150           }
151         }
152         else if (dofTags[j][0] == 2) {
153           if (cellDim_ == 2) { // 2D
154             numDofsPerVoid_[i] = dofTags[j][3];
155           }
156           else { // 3D
157             numDofsPerFace_[i] = dofTags[j][3];
158           }
159         }
160         else if (dofTags[j][0] == 3) {
161           numDofsPerVoid_[i] = dofTags[j][3];
162         }
163       }
164       numLocalDofs_ += (intrepidBasis_[i])->getCardinality();
165     }
166     numLocalNodeDofs_ = 0;
167     numLocalEdgeDofs_ = 0;
168     numLocalFaceDofs_ = 0;
169     numLocalVoidDofs_ = 0;
170     for (int i=0; i<numBases_; ++i) {
171       numLocalNodeDofs_ += numDofsPerNode_[i];
172       numLocalEdgeDofs_ += numDofsPerEdge_[i];
173       numLocalFaceDofs_ += numDofsPerFace_[i];
174       numLocalVoidDofs_ += numDofsPerVoid_[i];
175     }
176     numLocalNodes_ = static_cast<int>( (intrepidBasis_[0])->getBaseCellTopology().getVertexCount() );
177     numLocalEdges_ = static_cast<int>( (intrepidBasis_[0])->getBaseCellTopology().getEdgeCount() );
178     numLocalFaces_ = static_cast<int>( (intrepidBasis_[0])->getBaseCellTopology().getFaceCount() );
179     numLocalVoids_ = 1;
180     computeFieldPattern();
181 
182     // Global data structures.
183     computeDofArrays();
184     computeCellDofs();
185     computeFieldDofs();
186     computeDofTransforms();
187   }
188 
189 
getNodeDofs() const190   ROL::Ptr<Intrepid::FieldContainer<int> > getNodeDofs() const {
191     return nodeDofs_;
192   }
193 
194 
getEdgeDofs() const195   ROL::Ptr<Intrepid::FieldContainer<int> > getEdgeDofs() const {
196     return edgeDofs_;
197   }
198 
199 
getFaceDofs() const200   ROL::Ptr<Intrepid::FieldContainer<int> > getFaceDofs() const {
201     return faceDofs_;
202   }
203 
204 
getVoidDofs() const205   ROL::Ptr<Intrepid::FieldContainer<int> > getVoidDofs() const {
206     return voidDofs_;
207   }
208 
209 
getCellDofs() const210   ROL::Ptr<Intrepid::FieldContainer<int> > getCellDofs() const {
211     return cellDofs_;
212   }
213 
214 
getFieldDofs() const215   std::vector<ROL::Ptr<Intrepid::FieldContainer<int> > > getFieldDofs() const {
216     return fieldDofs_;
217   }
218 
219 
getFieldDofs(const int & fieldNumber) const220   ROL::Ptr<Intrepid::FieldContainer<int> > getFieldDofs(const int & fieldNumber) const {
221     return fieldDofs_[fieldNumber];
222   }
223 
224 
getNumNodeDofs() const225   int getNumNodeDofs() const {
226     return numNodeDofs_;
227   }
228 
229 
getNumEdgeDofs() const230   int getNumEdgeDofs() const {
231     return numEdgeDofs_;
232   }
233 
234 
getNumFaceDofs() const235   int getNumFaceDofs() const {
236     return numFaceDofs_;
237   }
238 
239 
getNumVoidDofs() const240   int getNumVoidDofs() const {
241     return numVoidDofs_;
242   }
243 
244 
getNumDofs() const245   int getNumDofs() const {
246     return numDofs_;
247   }
248 
249 
getNumFields() const250   int getNumFields() const {
251     return numBases_;
252   }
253 
254 
getLocalFieldSize() const255   int getLocalFieldSize() const {
256     return numLocalDofs_;
257   }
258 
259 
getLocalFieldSize(const int & fieldNumber) const260   int getLocalFieldSize(const int & fieldNumber) const {
261     return (intrepidBasis_[fieldNumber])->getCardinality();
262   }
263 
264 
getFieldPattern() const265   std::vector<std::vector<int> > getFieldPattern() const {
266     return fieldPattern_;
267   }
268 
269 
getFieldPattern(const int & fieldNumber) const270   std::vector<int> getFieldPattern(const int & fieldNumber) const {
271     return fieldPattern_[fieldNumber];
272   }
273 
transformToIntrepidPattern(const ROL::Ptr<Intrepid::FieldContainer<Real>> & array) const274   void transformToIntrepidPattern(const ROL::Ptr<Intrepid::FieldContainer<Real> > &array) const {
275     if ( array != ROL::nullPtr ) {
276       int rank = array->rank();
277       int nc   = array->dimension(0);
278       if ( rank == 2 ) {
279         int nf = array->dimension(1);
280         Intrepid::FieldContainer<Real> tmp(nc, nf);
281         for (int c = 0; c < nc; ++c) {
282           for (int f = 0; f < nf; ++f) {
283             tmp(c, mapToIntrepidPattern_[f]) = (*array)(c, f);
284           }
285         }
286         *array = tmp;
287       }
288       else if (rank == 3 ) {
289         int nf1 = array->dimension(1);
290         int nf2 = array->dimension(2);
291         Intrepid::FieldContainer<Real> tmp(nc, nf1, nf2);
292         for (int c = 0; c < nc; ++c) {
293           for (int f1 = 0; f1 < nf1; ++f1) {
294             for (int f2 = 0; f2 < nf2; ++f2) {
295               tmp(c, mapToIntrepidPattern_[f1], mapToIntrepidPattern_[f2]) = (*array)(c, f1, f2);
296             }
297           }
298         }
299         *array = tmp;
300       }
301       else {
302         TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
303           ">>> PDE-OPT/TOOLS/dofmanager.hpp (transformToIntrepidPattern): Input array rank not 2 or 3!");
304       }
305     }
306   }
307 
mapToFieldPattern(int f) const308   int mapToFieldPattern(int f) const {
309     return mapToFieldPattern_[f];
310   }
311 
transformToFieldPattern(const ROL::Ptr<Intrepid::FieldContainer<Real>> & array) const312   void transformToFieldPattern(const ROL::Ptr<Intrepid::FieldContainer<Real> > &array) const {
313     if ( array != ROL::nullPtr ) {
314       int rank = array->rank();
315       int nc   = array->dimension(0);
316       if ( rank == 2 ) {
317         int nf = array->dimension(1);
318         Intrepid::FieldContainer<Real> tmp(nc, nf);
319         for (int c = 0; c < nc; ++c) {
320           for (int f = 0; f < nf; ++f) {
321             tmp(c, mapToFieldPattern_[f]) = (*array)(c, f);
322           }
323         }
324         *array = tmp;
325       }
326       else if (rank == 3 ) {
327         int nf1 = array->dimension(1);
328         int nf2 = array->dimension(2);
329         Intrepid::FieldContainer<Real> tmp(nc, nf1, nf2);
330         for (int c = 0; c < nc; ++c) {
331           for (int f1 = 0; f1 < nf1; ++f1) {
332             for (int f2 = 0; f2 < nf2; ++f2) {
333               tmp(c, mapToFieldPattern_[f1], mapToFieldPattern_[f2]) = (*array)(c, f1, f2);
334             }
335           }
336         }
337         *array = tmp;
338       }
339       else {
340         TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
341           ">>> PDE-OPT/TOOLS/dofmanager.hpp (transformToFieldPattern): Input array rank not 2 or 3!");
342       }
343     }
344   }
345 
346 private:
347 
computeDofArrays()348   void computeDofArrays() {
349 
350     nodeDofs_ = ROL::makePtr<Intrepid::FieldContainer<int>>(numNodes_, numLocalNodeDofs_);
351     edgeDofs_ = ROL::makePtr<Intrepid::FieldContainer<int>>(numEdges_, numLocalEdgeDofs_);
352     faceDofs_ = ROL::makePtr<Intrepid::FieldContainer<int>>(numFaces_, numLocalFaceDofs_);
353     voidDofs_ = ROL::makePtr<Intrepid::FieldContainer<int>>(numCells_, numLocalVoidDofs_);
354 
355     Intrepid::FieldContainer<int> &nodeDofs = *nodeDofs_;
356     Intrepid::FieldContainer<int> &edgeDofs = *edgeDofs_;
357     Intrepid::FieldContainer<int> &faceDofs = *faceDofs_;
358     Intrepid::FieldContainer<int> &voidDofs = *voidDofs_;
359 
360     int dofCt = -1;
361 
362     //
363     // This is the independent node id --> edge id --> cell id ordering.
364     // For example, for a Q2-Q2-Q1 basis (Taylor-Hood), we would have:
365     //
366     //     Q2   Q2   Q1
367     //     --------------
368     // n1  1    1    1
369     // n2  1    1    1
370     // ...
371     // e1  1    1    0
372     // e2  1    1    0
373     // ...
374     // c1  1    1    0
375     // c2  1    1    0
376     // ...
377     //
378 
379     // count node dofs
380     for (int i=0; i<numNodes_; ++i) {
381       int locNodeCt = -1;
382       for (int j=0; j<numBases_; ++j) {
383         for (int k=0; k<numDofsPerNode_[j]; ++k) {
384           nodeDofs(i, ++locNodeCt) = ++dofCt;
385         }
386       }
387     }
388     numNodeDofs_ = dofCt+1;
389 
390     // count edge dofs
391     for (int i=0; i<numEdges_; ++i) {
392       int locEdgeCt = -1;
393       for (int j=0; j<numBases_; ++j) {
394         for (int k=0; k<numDofsPerEdge_[j]; ++k) {
395           edgeDofs(i, ++locEdgeCt) = ++dofCt;
396         }
397       }
398     }
399     numEdgeDofs_ = dofCt+1-numNodeDofs_;
400 
401     // count face dofs
402     for (int i=0; i<numFaces_; ++i) {
403       int locFaceCt = -1;
404       for (int j=0; j<numBases_; ++j) {
405         for (int k=0; k<numDofsPerFace_[j]; ++k) {
406           faceDofs(i, ++locFaceCt) = ++dofCt;
407         }
408       }
409     }
410     numFaceDofs_ = dofCt+1-numNodeDofs_-numEdgeDofs_;
411 
412     // count void dofs
413     for (int i=0; i<numCells_; ++i) {
414       int locVoidCt = -1;
415       for (int j=0; j<numBases_; ++j) {
416         for (int k=0; k<numDofsPerVoid_[j]; ++k) {
417           voidDofs(i, ++locVoidCt) = ++dofCt;
418         }
419       }
420     }
421     numVoidDofs_ = dofCt+1-numNodeDofs_-numEdgeDofs_-numFaceDofs_;
422 
423     numDofs_ = numNodeDofs_+numEdgeDofs_+numFaceDofs_+numVoidDofs_;
424 
425   } // computeDofArrays
426 
427 
computeCellDofs()428   void computeCellDofs() {
429 
430     cellDofs_ = ROL::makePtr<Intrepid::FieldContainer<int>>(numCells_, numLocalDofs_);
431 
432     // Grab object references, for easier indexing.
433     Intrepid::FieldContainer<int> &cdofs = *cellDofs_;
434     Intrepid::FieldContainer<int> &nodeDofs = *nodeDofs_;
435     Intrepid::FieldContainer<int> &edgeDofs = *edgeDofs_;
436     Intrepid::FieldContainer<int> &faceDofs = *faceDofs_;
437     Intrepid::FieldContainer<int> &voidDofs = *voidDofs_;
438     Intrepid::FieldContainer<int> &ctn = *meshCellToNodeMap_;
439     Intrepid::FieldContainer<int> &cte = *meshCellToEdgeMap_;
440     Intrepid::FieldContainer<int> &ctf = *meshCellToFaceMap_;
441 
442     for (int i=0; i<numCells_; ++i) {
443       int ct = -1;
444       for (int j=0; j<numLocalNodes_; ++j) {
445         for (int k=0; k<numLocalNodeDofs_; ++k) {
446           cdofs(i,++ct) = nodeDofs(ctn(i,j), k);
447         }
448       }
449       for (int j=0; j<numLocalEdges_; ++j) {
450         for (int k=0; k<numLocalEdgeDofs_; ++k) {
451           cdofs(i,++ct) = edgeDofs(cte(i,j), k);
452         }
453       }
454       for (int j=0; j<numLocalFaces_; ++j) {
455         for (int k=0; k<numLocalFaceDofs_; ++k) {
456           cdofs(i,++ct) = faceDofs(ctf(i,j), k);
457         }
458       }
459       for (int j=0; j<numLocalVoids_; ++j) {
460         for (int k=0; k<numLocalVoidDofs_; ++k) {
461           cdofs(i,++ct) = voidDofs(i, k);
462         }
463       }
464     }
465   } // computeCellDofs
466 
467 
computeFieldPattern()468   void computeFieldPattern() {
469 
470     fieldPattern_.resize(numBases_);
471 
472     int dofCt = -1;
473 
474     // count node dofs
475     for (int i=0; i<numLocalNodes_; ++i) {
476       for (int j=0; j<numBases_; ++j) {
477         for (int k=0; k<numDofsPerNode_[j]; ++k) {
478           fieldPattern_[j].push_back(++dofCt);
479         }
480       }
481     }
482 
483     // count edge dofs
484     for (int i=0; i<numLocalEdges_; ++i) {
485       for (int j=0; j<numBases_; ++j) {
486         for (int k=0; k<numDofsPerEdge_[j]; ++k) {
487           fieldPattern_[j].push_back(++dofCt);
488         }
489       }
490     }
491 
492     // count face dofs
493     for (int i=0; i<numLocalFaces_; ++i) {
494       for (int j=0; j<numBases_; ++j) {
495         for (int k=0; k<numDofsPerFace_[j]; ++k) {
496           fieldPattern_[j].push_back(++dofCt);
497         }
498       }
499     }
500 
501     // count void dofs
502     for (int i=0; i<numLocalVoids_; ++i) {
503       for (int j=0; j<numBases_; ++j) {
504         for (int k=0; k<numDofsPerVoid_[j]; ++k) {
505           fieldPattern_[j].push_back(++dofCt);
506         }
507       }
508     }
509 
510   } // computeFieldPattern
511 
512 
computeFieldDofs()513   void computeFieldDofs() {
514 
515     fieldDofs_.resize(numBases_);
516 
517     Intrepid::FieldContainer<int> &cdofs = *cellDofs_;
518 
519     for (int fieldNum=0; fieldNum<numBases_; ++fieldNum) {
520       int basisCard = intrepidBasis_[fieldNum]->getCardinality();
521       fieldDofs_[fieldNum] = ROL::makePtr<Intrepid::FieldContainer<int>>(numCells_, basisCard);
522       Intrepid::FieldContainer<int> &fdofs = *(fieldDofs_[fieldNum]);
523       for (int i=0; i<numCells_; ++i) {
524         for (int j=0; j<basisCard; ++j) {
525           fdofs(i,j) = cdofs(i, fieldPattern_[fieldNum][j]);
526         }
527       }
528     }
529   } // computeFieldDofs
530 
computeDofTransforms(void)531   void computeDofTransforms(void) {
532     // Build basis maps
533     std::vector<std::vector<int> > map2IP(numBases_);
534     std::vector<std::vector<int> > map2FP(numBases_);
535     shards::CellTopology cellType = intrepidBasis_[0]->getBaseCellTopology();
536     int nv = cellType.getVertexCount();
537     for (int f=0; f<numBases_; ++f) {
538       int basisDeg = intrepidBasis_[f]->getDegree();
539       if (cellDim_ == 1) {
540         if (basisDeg == 0) {
541           map2IP[f] = {0};
542           map2FP[f] = {0};
543         }
544         else if (basisDeg == 1) {
545           map2IP[f] = {0, 1};
546           map2FP[f] = {0, 1};
547         }
548         else if (basisDeg == 2) {
549           map2IP[f] = {0, 2, 1};
550           map2FP[f] = {0, 2, 1};
551         }
552         else {
553           TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
554             ">>> PDE-OPT/TOOLS/dofmanager.hpp (ComputeDofTransforms): basisDeg > 2");
555         }
556       }
557       else if (cellDim_ == 2) {
558         if (basisDeg == 0) {
559           map2IP[f] = {0};
560           map2FP[f] = {0};
561         }
562         else if (basisDeg == 1) {
563           map2IP[f].resize(nv);
564           map2FP[f].resize(nv);
565           for (int i = 0; i < nv; ++i) {
566             map2IP[f][i] = i;
567             map2FP[f][i] = i;
568           }
569           //map2IP[f] = {0, 1, 2, 3};
570           //map2FP[f] = {0, 1, 2, 3};
571         }
572         else if (basisDeg == 2) {
573           int lim = (nv==3 ? 6 : 9);
574           map2IP[f].resize(lim);
575           map2FP[f].resize(lim);
576           for (int i = 0; i < lim; ++i) {
577             map2IP[f][i] = i;
578             map2FP[f][i] = i;
579           }
580           //map2IP[f] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
581           //map2FP[f] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
582         }
583         else {
584           TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
585             ">>> PDE-OPT/TOOLS/dofmanager.hpp (ComputeDofTransforms): basisDeg > 2");
586         }
587       }
588       else if (cellDim_ == 3) {
589         if (basisDeg == 0) {
590           map2IP[f] = {0};
591           map2FP[f] = {0};
592         }
593         else if (basisDeg == 1) {
594           map2IP[f] = {0, 1, 2, 3, 4, 5, 6, 7};
595           map2FP[f] = {0, 1, 2, 3, 4, 5, 6, 7};
596         }
597         else if (basisDeg == 2) {
598           map2IP[f] = {0, 1, 2, 3, 4 ,5, 6, 7,                       // Nodes
599                        8, 9, 10, 11, 16, 17, 18, 19, 12, 13, 14, 15, // Edges
600                        25, 24, 26, 23, 21, 22,                       // Faces
601                        20};                                          // Voids
602           map2FP[f] = {0, 1, 2, 3, 4 ,5, 6, 7,                       // Nodes
603                        8, 9, 10, 11, 16, 17, 18, 19, 12, 13, 14, 15, // Edges
604                        26,                                           // Voids
605                        24, 25, 23, 21, 20, 22};                      // Faces
606         }
607         else {
608           TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
609             ">>> PDE-OPT/TOOLS/dofmanager.hpp (ComputeDofTransforms): basisDeg > 2");
610         }
611       }
612     }
613     // Apply transformation to ind
614     mapToIntrepidPattern_.clear(); mapToIntrepidPattern_.resize(numDofs_);
615     mapToFieldPattern_.clear();    mapToFieldPattern_.resize(numDofs_);
616     for (int i = 0; i < numBases_; ++i) {
617       for (int j = 0; j < static_cast<int>(map2IP[i].size()); ++j) {
618         mapToIntrepidPattern_[fieldPattern_[i][j]] = fieldPattern_[i][map2IP[i][j]];
619         mapToFieldPattern_[fieldPattern_[i][j]]    = fieldPattern_[i][map2FP[i][j]];
620       }
621     }
622   }
623 
624 }; // DofManager
625 
626 #endif
627