Intrepid
/usr/src/RPM/BUILD/trilinos10-10.6.4/packages/intrepid/src/Cell/Intrepid_CellToolsDef.hpp
Go to the documentation of this file.
00001 // @HEADER
00002 // ************************************************************************
00003 //
00004 //                           Intrepid Package
00005 //                 Copyright (2007) Sandia Corporation
00006 //
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 //
00010 // This library is free software; you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as
00012 // published by the Free Software Foundation; either version 2.1 of the
00013 // License, or (at your option) any later version.
00014 //
00015 // This library is distributed in the hope that it will be useful, but
00016 // WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00023 // USA
00024 // Questions? Contact Pavel Bochev  (pbboche@sandia.gov)
00025 //                    Denis Ridzal  (dridzal@sandia.gov), or
00026 //                    Kara Peterson (kjpeter@sandia.gov) 
00027 //
00028 // ************************************************************************
00029 // @HEADER
00030 
00031 
00036 #ifndef INTREPID_CELLTOOLSDEF_HPP
00037 #define INTREPID_CELLTOOLSDEF_HPP
00038 
00039 
00040 namespace Intrepid {
00041 
00042   template<class Scalar>
00043   const FieldContainer<double>& CellTools<Scalar>::getSubcellParametrization(const int subcellDim,
00044                                                                              const shards::CellTopology& parentCell){
00045     
00046 #ifdef HAVE_INTREPID_DEBUG
00047     TEST_FOR_EXCEPTION( !(hasReferenceCell(parentCell) ), std::invalid_argument, 
00048                         ">>> ERROR (Intrepid::CellTools::getSubcellParametrization): the specified cell topology does not have a reference cell.");
00049 
00050     TEST_FOR_EXCEPTION( !( (1 <= subcellDim) && (subcellDim <= 2 ) ), std::invalid_argument,
00051                            ">>> ERROR (Intrepid::CellTools::getSubcellParametrization): parametrization defined only for 1 and 2-dimensional subcells.");    
00052 #endif
00053     
00054     // Coefficients of the coordinate functions defining the parametrization maps are stored in 
00055     // rank-3 arrays with dimensions (SC, PCD, COEF) where:
00056     //  - SC    is the subcell count of subcells with the specified dimension in the parent cell
00057     //  - PCD   is Parent Cell Dimension, which gives the number of coordinate functions in the map:
00058     //          PCD = 2 for standard 2D cells and non-standard 2D cells: shell line and beam
00059     //          PCD = 3 for standard 3D cells and non-standard 3D cells: shell Tri and Quad
00060     //  - COEF  is number of coefficients needed to specify a coordinate function:
00061     //          COEFF = 2 for edge parametrizations
00062     //          COEFF = 3 for both Quad and Tri face parametrizations. Because all Quad reference faces
00063     //          are affine, the coefficient of the bilinear term u*v is zero and is not stored, i.e.,
00064     //          3 coefficients are sufficient to store Quad face parameterization maps.
00065     //
00066     // Arrays are sized and filled only when parametrization of a particular subcell is requested
00067     // by setSubcellParametrization.
00068     
00069     // Edge maps for 2D non-standard cells: ShellLine and Beam
00070     static FieldContainer<double> lineEdges;        static int lineEdgesSet = 0;
00071     
00072     // Edge maps for 2D standard cells: Triangle and Quadrilateral
00073     static FieldContainer<double> triEdges;         static int triEdgesSet  = 0;
00074     static FieldContainer<double> quadEdges;        static int quadEdgesSet = 0;
00075 
00076     // Edge maps for 3D non-standard cells: Shell Tri and Quad
00077     static FieldContainer<double> shellTriEdges;    static int shellTriEdgesSet  = 0;
00078     static FieldContainer<double> shellQuadEdges;   static int shellQuadEdgesSet = 0;
00079     
00080     // Edge maps for 3D standard cells:
00081     static FieldContainer<double> tetEdges;         static int tetEdgesSet = 0;
00082     static FieldContainer<double> hexEdges;         static int hexEdgesSet = 0;
00083     static FieldContainer<double> pyrEdges;         static int pyrEdgesSet = 0;
00084     static FieldContainer<double> wedgeEdges;       static int wedgeEdgesSet = 0;
00085 
00086 
00087     // Face maps for 3D non-standard cells: Shell Triangle and Quadrilateral
00088     static FieldContainer<double> shellTriFaces;    static int shellTriFacesSet  = 0;
00089     static FieldContainer<double> shellQuadFaces;   static int shellQuadFacesSet = 0;
00090 
00091     // Face maps for 3D standard cells:
00092     static FieldContainer<double> tetFaces;         static int tetFacesSet = 0;
00093     static FieldContainer<double> hexFaces;         static int hexFacesSet = 0;
00094     static FieldContainer<double> pyrFaces;         static int pyrFacesSet = 0;
00095     static FieldContainer<double> wedgeFaces;       static int wedgeFacesSet = 0;
00096 
00097     // Select subcell parametrization according to its parent cell type
00098     switch(parentCell.getKey() ) {
00099       
00100       // Tet cells
00101       case shards::Tetrahedron<4>::key:
00102       case shards::Tetrahedron<8>::key:
00103       case shards::Tetrahedron<10>::key:
00104         if(subcellDim == 2) {
00105           if(!tetFacesSet){
00106             setSubcellParametrization(tetFaces, subcellDim, parentCell);
00107             tetFacesSet = 1;
00108           }
00109           return tetFaces;
00110         }
00111         else if(subcellDim == 1) {
00112           if(!tetEdgesSet){
00113             setSubcellParametrization(tetEdges, subcellDim, parentCell);
00114             tetEdgesSet = 1;
00115           }
00116           return tetEdges;
00117         }
00118         else{
00119           TEST_FOR_EXCEPTION( (subcellDim != 1 || subcellDim != 2), std::invalid_argument, 
00120                               ">>> ERROR (Intrepid::CellTools::getSubcellParametrization): Tet parametrizations defined for 1 and 2-subcells only");
00121         }
00122         break;
00123         
00124       // Hex cells
00125       case shards::Hexahedron<8>::key:
00126       case shards::Hexahedron<20>::key:
00127       case shards::Hexahedron<27>::key:
00128         if(subcellDim == 2) {
00129           if(!hexFacesSet){
00130             setSubcellParametrization(hexFaces, subcellDim, parentCell);
00131             hexFacesSet = 1;
00132           }
00133           return hexFaces;
00134         }
00135         else if(subcellDim == 1) {
00136           if(!hexEdgesSet){
00137             setSubcellParametrization(hexEdges, subcellDim, parentCell);
00138             hexEdgesSet = 1;
00139           }
00140           return hexEdges;
00141         }
00142         else{
00143           TEST_FOR_EXCEPTION( (subcellDim != 1 || subcellDim != 2), std::invalid_argument, 
00144                               ">>> ERROR (Intrepid::CellTools::getSubcellParametrization): Hex parametrizations defined for 1 and 2-subcells only");
00145         }
00146         break;
00147         
00148       // Pyramid cells
00149       case shards::Pyramid<5>::key:
00150       case shards::Pyramid<13>::key:
00151       case shards::Pyramid<14>::key:
00152         if(subcellDim == 2) {
00153           if(!pyrFacesSet){
00154             setSubcellParametrization(pyrFaces, subcellDim, parentCell);
00155             pyrFacesSet = 1;
00156           }
00157           return pyrFaces;
00158         }
00159         else if(subcellDim == 1) {
00160           if(!pyrEdgesSet){
00161             setSubcellParametrization(pyrEdges, subcellDim, parentCell);
00162             pyrEdgesSet = 1;
00163           }
00164           return pyrEdges;
00165         }
00166         else {
00167           TEST_FOR_EXCEPTION( (subcellDim != 1 || subcellDim != 2), std::invalid_argument, 
00168                               ">>> ERROR (Intrepid::CellTools::getSubcellParametrization): Pyramid parametrizations defined for 1 and 2-subcells only");
00169         }
00170         break;
00171         
00172       // Wedge cells
00173       case shards::Wedge<6>::key:
00174       case shards::Wedge<15>::key:
00175       case shards::Wedge<18>::key:
00176         if(subcellDim == 2) {
00177           if(!wedgeFacesSet){
00178             setSubcellParametrization(wedgeFaces, subcellDim, parentCell);
00179             wedgeFacesSet = 1;
00180           }
00181           return wedgeFaces;
00182         }
00183         else if(subcellDim == 1) {
00184           if(!wedgeEdgesSet){
00185             setSubcellParametrization(wedgeEdges, subcellDim, parentCell);
00186             wedgeEdgesSet = 1;
00187           }
00188           return wedgeEdges;
00189         }
00190         else {
00191           TEST_FOR_EXCEPTION( (subcellDim != 1 || subcellDim != 2), std::invalid_argument, 
00192                               ">>> ERROR (Intrepid::CellTools::getSubcellParametrization): Wedge parametrization defined for 1 and 2-subcells only");
00193         }
00194         break;
00195       //
00196       // Standard 2D cells have only 1-subcells
00197       //
00198       case shards::Triangle<3>::key:
00199       case shards::Triangle<4>::key:
00200       case shards::Triangle<6>::key:
00201         if(subcellDim == 1) {
00202           if(!triEdgesSet){
00203             setSubcellParametrization(triEdges, subcellDim, parentCell);
00204             triEdgesSet = 1;
00205           }
00206           return triEdges;
00207         }
00208         else{
00209           TEST_FOR_EXCEPTION( true, std::invalid_argument, 
00210                               ">>> ERROR (Intrepid::CellTools::getSubcellParametrization): Triangle parametrizations defined for 1-subcells only");
00211         }
00212         break;
00213                   
00214       case shards::Quadrilateral<4>::key:
00215       case shards::Quadrilateral<8>::key:
00216       case shards::Quadrilateral<9>::key:
00217         if(subcellDim == 1) {
00218           if(!quadEdgesSet){
00219             setSubcellParametrization(quadEdges, subcellDim, parentCell);
00220             quadEdgesSet = 1;
00221           }
00222           return quadEdges;
00223         }
00224         else{
00225           TEST_FOR_EXCEPTION( true, std::invalid_argument, 
00226                               ">>> ERROR (Intrepid::CellTools::getSubcellParametrization): Quad parametrizations defined for 1-subcells only");
00227         }
00228         break;        
00229       //
00230       // Non-standard 3D Shell Tri and Quad cells have 1 and 2-subcells. Because they are 3D cells
00231       // can't reuse edge parametrization arrays for 2D Triangle and Quadrilateral.
00232       //
00233       case shards::ShellTriangle<3>::key:
00234       case shards::ShellTriangle<6>::key:
00235         if(subcellDim == 2) {
00236           if(!shellTriFacesSet){
00237             setSubcellParametrization(shellTriFaces, subcellDim, parentCell);
00238             shellTriFacesSet = 1;
00239           }
00240           return shellTriFaces;
00241         }
00242         else if(subcellDim == 1) {
00243           if(!shellTriEdgesSet){
00244             setSubcellParametrization(shellTriEdges, subcellDim, parentCell);
00245             shellTriEdgesSet = 1;
00246           }
00247           return shellTriEdges;
00248         }
00249         else if( subcellDim != 1 || subcellDim != 2){
00250           TEST_FOR_EXCEPTION( true, std::invalid_argument, 
00251                               ">>> ERROR (Intrepid::CellTools::getSubcellParametrization): Shell Triangle parametrizations defined for 1 and 2-subcells only");
00252         }
00253         break;
00254         
00255       case shards::ShellQuadrilateral<4>::key:
00256       case shards::ShellQuadrilateral<8>::key:
00257       case shards::ShellQuadrilateral<9>::key:
00258         if(subcellDim == 2) {
00259           if(!shellQuadFacesSet){
00260             setSubcellParametrization(shellQuadFaces, subcellDim, parentCell);
00261             shellQuadFacesSet = 1;
00262           }
00263           return shellQuadFaces;
00264         }
00265         else if(subcellDim == 1) {
00266           if(!shellQuadEdgesSet){
00267             setSubcellParametrization(shellQuadEdges, subcellDim, parentCell);
00268             shellQuadEdgesSet = 1;
00269           }
00270           return shellQuadEdges;
00271         }
00272         else if( subcellDim != 1 || subcellDim != 2){
00273           TEST_FOR_EXCEPTION( true, std::invalid_argument, 
00274                               ">>> ERROR (Intrepid::CellTools::getSubcellParametrization): Shell Quad parametrizations defined for 1 and 2-subcells only");
00275         }
00276         break;
00277         
00278       //
00279       // Non-standard 2D cells: Shell Lines and Beams have 1-subcells
00280       //
00281       case shards::ShellLine<2>::key:
00282       case shards::ShellLine<3>::key:
00283       case shards::Beam<2>::key:
00284       case shards::Beam<3>::key:
00285         if(subcellDim == 1) {
00286           if(!lineEdgesSet){
00287             setSubcellParametrization(lineEdges, subcellDim, parentCell);
00288             lineEdgesSet = 1;
00289           }
00290           return lineEdges;
00291         }
00292         else{
00293           TEST_FOR_EXCEPTION( true, std::invalid_argument, 
00294                               ">>> ERROR (Intrepid::CellTools::getSubcellParametrization): shell line/beam parametrizations defined for 1-subcells only");
00295         }
00296         break;        
00297 
00298       default:
00299         TEST_FOR_EXCEPTION( true, std::invalid_argument, 
00300                             ">>> ERROR (Intrepid::CellTools::getSubcellParametrization): invalid cell topology.");
00301     }//cell key
00302     // To disable compiler warning, should never be reached
00303     return lineEdges;
00304   }
00305   
00306   
00307   
00308   template<class Scalar>
00309   void CellTools<Scalar>::setSubcellParametrization(FieldContainer<double>&     subcellParametrization,
00310                                                     const int                   subcellDim,
00311                                                     const shards::CellTopology& parentCell)
00312   {
00313 #ifdef HAVE_INTREPID_DEBUG
00314     TEST_FOR_EXCEPTION( !(hasReferenceCell(parentCell) ), std::invalid_argument, 
00315                         ">>> ERROR (Intrepid::CellTools::setSubcellParametrization): the specified cell topology does not have a reference cell.");
00316 
00317     TEST_FOR_EXCEPTION( !( (1 <= subcellDim) && (subcellDim <= 2 ) ), std::invalid_argument,
00318                         ">>> ERROR (Intrepid::CellTools::setSubcellParametrization): parametrization defined only for 1 and 2-dimensional subcells.");    
00319 #endif
00320                         // subcellParametrization is rank-3 FieldContainer with dimensions (SC, PCD, COEF) where:
00321     //  - SC    is the subcell count of subcells with the specified dimension in the parent cell
00322     //  - PCD   is Parent Cell Dimension, which gives the number of coordinate functions in the map
00323     //          PCD = 2 for standard 2D cells and non-standard 2D cells: shell line and beam
00324     //          PCD = 3 for standard 3D cells and non-standard 3D cells: shell Tri and Quad
00325     //  - COEF  is number of coefficients needed to specify a coordinate function:
00326     //          COEFF = 2 for edge parametrizations
00327     //          COEFF = 3 for both Quad and Tri face parametrizations. Because all Quad reference faces
00328     //          are affine, the coefficient of the bilinear term u*v is zero and is not stored, i.e.,
00329     //          3 coefficients are sufficient to store Quad face parameterization maps.
00330     //  
00331     // Edge parametrization maps [-1,1] to edge defined by (v0, v1)
00332     // Face parametrization maps [-1,1]^2 to quadrilateral face (v0, v1, v2, v3), or
00333     // standard 2-simplex  {(0,0),(1,0),(0,1)} to traingle face (v0, v1, v2).
00334     // This defines orientation-preserving parametrizations with respect to reference edge and
00335     // face orientations induced by their vertex order. 
00336 
00337     // get subcellParametrization dimensions: (sc, pcd, coeff)
00338     unsigned sc    = parentCell.getSubcellCount(subcellDim);
00339     unsigned pcd   = parentCell.getDimension();   
00340     unsigned coeff = (subcellDim == 1) ? 2 : 3;
00341     
00342     
00343     // Resize container
00344     subcellParametrization.resize(sc, pcd, coeff);
00345     
00346     // Edge parametrizations of 2D and 3D cells (shell lines and beams are 2D cells with edges)
00347     if(subcellDim == 1){      
00348       for(unsigned subcellOrd = 0; subcellOrd < sc; subcellOrd++){
00349         
00350         int v0ord = parentCell.getNodeMap(subcellDim, subcellOrd, 0);
00351         int v1ord = parentCell.getNodeMap(subcellDim, subcellOrd, 1);
00352         
00353         // vertexK[0] = x_k; vertexK[1] = y_k; vertexK[2] = z_k; z_k = 0 for 2D cells
00354         // Note that ShellLine and Beam are 2D cells!
00355         const double* v0 = getReferenceVertex(parentCell, v0ord);
00356         const double* v1 = getReferenceVertex(parentCell, v1ord);
00357         
00358         // x(t) = (x0 + x1)/2 + t*(x1 - x0)/2 
00359         subcellParametrization(subcellOrd, 0, 0) = (v0[0] + v1[0])/2.0;
00360         subcellParametrization(subcellOrd, 0, 1) = (v1[0] - v0[0])/2.0;
00361         
00362         // y(t) = (y0 + y1)/2 + t*(y1 - y0)/2 
00363         subcellParametrization(subcellOrd, 1, 0) = (v0[1] + v1[1])/2.0;
00364         subcellParametrization(subcellOrd, 1, 1) = (v1[1] - v0[1])/2.0;
00365         
00366         if( pcd == 3 ) {
00367           // z(t) = (z0 + z1)/2 + t*(z1 - z0)/2 
00368           subcellParametrization(subcellOrd, 2, 0) = (v0[2] + v1[2])/2.0;
00369           subcellParametrization(subcellOrd, 2, 1) = (v1[2] - v0[2])/2.0;
00370         }
00371       }// for loop over 1-subcells
00372     }
00373       
00374       // Face parametrizations of 3D cells: (shell Tri and Quad are 3D cells with faces)
00375       // A 3D cell can have both Tri and Quad faces, but because they are affine images of the
00376       // parametrization domain, 3 coefficients are enough to store them in both cases.
00377       else if(subcellDim == 2) {
00378         for(unsigned subcellOrd = 0; subcellOrd < sc; subcellOrd++){
00379           
00380           switch(parentCell.getKey(subcellDim,subcellOrd)){
00381             
00382             // Admissible triangular faces for 3D cells in Shards:
00383             case shards::Triangle<3>::key:
00384             case shards::Triangle<4>::key:
00385             case shards::Triangle<6>::key: 
00386               {
00387                 int v0ord = parentCell.getNodeMap(subcellDim, subcellOrd, 0);
00388                 int v1ord = parentCell.getNodeMap(subcellDim, subcellOrd, 1);
00389                 int v2ord = parentCell.getNodeMap(subcellDim, subcellOrd, 2);
00390                 const double* v0 = getReferenceVertex(parentCell, v0ord);
00391                 const double* v1 = getReferenceVertex(parentCell, v1ord);
00392                 const double* v2 = getReferenceVertex(parentCell, v2ord);
00393                 
00394                 // x(u,v) = x0 + (x1 - x0)*u + (x2 - x0)*v
00395                 subcellParametrization(subcellOrd, 0, 0) = v0[0];
00396                 subcellParametrization(subcellOrd, 0, 1) = v1[0] - v0[0];
00397                 subcellParametrization(subcellOrd, 0, 2) = v2[0] - v0[0];
00398                   
00399                 // y(u,v) = y0 + (y1 - y0)*u + (y2 - y0)*v
00400                 subcellParametrization(subcellOrd, 1, 0) = v0[1];
00401                 subcellParametrization(subcellOrd, 1, 1) = v1[1] - v0[1];
00402                 subcellParametrization(subcellOrd, 1, 2) = v2[1] - v0[1];
00403                 
00404                 // z(u,v) = z0 + (z1 - z0)*u + (z2 - z0)*v
00405                 subcellParametrization(subcellOrd, 2, 0) = v0[2];
00406                 subcellParametrization(subcellOrd, 2, 1) = v1[2] - v0[2];
00407                 subcellParametrization(subcellOrd, 2, 2) = v2[2] - v0[2];
00408               }
00409               break;
00410               
00411             // Admissible quadrilateral faces for 3D cells in Shards:
00412             case shards::Quadrilateral<4>::key:
00413             case shards::Quadrilateral<8>::key:
00414             case shards::Quadrilateral<9>::key:
00415               {
00416                 int v0ord = parentCell.getNodeMap(subcellDim, subcellOrd, 0);
00417                 int v1ord = parentCell.getNodeMap(subcellDim, subcellOrd, 1);
00418                 int v2ord = parentCell.getNodeMap(subcellDim, subcellOrd, 2);
00419                 int v3ord = parentCell.getNodeMap(subcellDim, subcellOrd, 3);
00420                 const double* v0 = getReferenceVertex(parentCell, v0ord);
00421                 const double* v1 = getReferenceVertex(parentCell, v1ord);
00422                 const double* v2 = getReferenceVertex(parentCell, v2ord);
00423                 const double* v3 = getReferenceVertex(parentCell, v3ord);
00424                 
00425                 // x(u,v) = (x0+x1+x2+x3)/4+u*(-x0+x1+x2-x3)/4+v*(-x0-x1+x2+x3)/4+uv*(0=x0-x1+x2-x3)/4 
00426                 subcellParametrization(subcellOrd, 0, 0) = ( v0[0] + v1[0] + v2[0] + v3[0])/4.0;
00427                 subcellParametrization(subcellOrd, 0, 1) = (-v0[0] + v1[0] + v2[0] - v3[0])/4.0;
00428                 subcellParametrization(subcellOrd, 0, 2) = (-v0[0] - v1[0] + v2[0] + v3[0])/4.0;
00429                 
00430                 // y(u,v) = (y0+y1+y2+y3)/4+u*(-y0+y1+y2-y3)/4+v*(-y0-y1+y2+y3)/4+uv*(0=y0-y1+y2-y3)/4 
00431                 subcellParametrization(subcellOrd, 1, 0) = ( v0[1] + v1[1] + v2[1] + v3[1])/4.0;
00432                 subcellParametrization(subcellOrd, 1, 1) = (-v0[1] + v1[1] + v2[1] - v3[1])/4.0;
00433                 subcellParametrization(subcellOrd, 1, 2) = (-v0[1] - v1[1] + v2[1] + v3[1])/4.0;
00434                 
00435                 // z(u,v) = (z0+z1+z2+z3)/4+u*(-z0+z1+z2-z3)/4+v*(-z0-z1+z2+z3)/4+uv*(0=z0-z1+z2-z3)/4 
00436                 subcellParametrization(subcellOrd, 2, 0) = ( v0[2] + v1[2] + v2[2] + v3[2])/4.0;
00437                 subcellParametrization(subcellOrd, 2, 1) = (-v0[2] + v1[2] + v2[2] - v3[2])/4.0;
00438                 subcellParametrization(subcellOrd, 2, 2) = (-v0[2] - v1[2] + v2[2] + v3[2])/4.0;
00439               }                
00440               break;
00441             default:
00442               TEST_FOR_EXCEPTION( true, std::invalid_argument, 
00443                                   ">>> ERROR (Intrepid::CellTools::setSubcellParametrization): parametrization not defined for the specified face topology.");
00444              
00445           }// switch face topology key
00446         }// for subcellOrd
00447       }
00448   }
00449   
00450   
00451   
00452   template<class Scalar>
00453   const double* CellTools<Scalar>::getReferenceVertex(const shards::CellTopology& cell,
00454                                                       const int                   vertexOrd){
00455     
00456 #ifdef HAVE_INTREPID_DEBUG
00457     TEST_FOR_EXCEPTION( !(hasReferenceCell(cell) ), std::invalid_argument, 
00458                         ">>> ERROR (Intrepid::CellTools::getReferenceVertex): the specified cell topology does not have a reference cell.");
00459     
00460     TEST_FOR_EXCEPTION( !( (0 <= vertexOrd) && (vertexOrd < (int)cell.getVertexCount() ) ), std::invalid_argument,
00461                         ">>> ERROR (Intrepid::CellTools::getReferenceVertex): invalid node ordinal for the specified cell topology. ");
00462 #endif
00463     
00464     // Simply call getReferenceNode with the base topology of the cell
00465     return getReferenceNode(cell.getBaseTopology(), vertexOrd);
00466   }
00467     
00468   
00469   
00470   template<class Scalar>
00471   template<class ArraySubcellVert>
00472   void CellTools<Scalar>::getReferenceSubcellVertices(ArraySubcellVert &          subcellVertices,
00473                                                       const int                   subcellDim,
00474                                                       const int                   subcellOrd,
00475                                                       const shards::CellTopology& parentCell){
00476 #ifdef HAVE_INTREPID_DEBUG
00477     TEST_FOR_EXCEPTION( !(hasReferenceCell(parentCell) ), std::invalid_argument, 
00478                         ">>> ERROR (Intrepid::CellTools::getReferenceSubcellVertices): the specified cell topology does not have a reference cell.");
00479 
00480     // subcellDim can equal the cell dimension because the cell itself is a valid subcell! In this case
00481     // the method will return all cell cellWorkset.
00482     TEST_FOR_EXCEPTION( !( (0 <= subcellDim) && (subcellDim <= (int)parentCell.getDimension()) ), std::invalid_argument,
00483                         ">>> ERROR (Intrepid::CellTools::getReferenceSubcellVertices): subcell dimension out of range.");
00484     
00485     TEST_FOR_EXCEPTION( !( (0 <= subcellOrd) && (subcellOrd < (int)parentCell.getSubcellCount(subcellDim) ) ), std::invalid_argument,
00486                         ">>> ERROR (Intrepid::CellTools::getReferenceSubcellVertices): subcell ordinal out of range.");
00487         
00488     // Verify subcellVertices rank and dimensions
00489     {
00490       std::string errmsg = ">>> ERROR (Intrepid::CellTools::getReferenceSubcellVertices):";
00491       TEST_FOR_EXCEPTION( !( requireRankRange(errmsg, subcellVertices, 2, 2) ), std::invalid_argument, errmsg);
00492       
00493       int subcVertexCount = parentCell.getVertexCount(subcellDim, subcellOrd);
00494       int spaceDim = parentCell.getDimension();
00495         
00496       TEST_FOR_EXCEPTION( !( requireDimensionRange(errmsg, subcellVertices, 0,  subcVertexCount, subcVertexCount) ),
00497                           std::invalid_argument, errmsg);
00498       
00499       TEST_FOR_EXCEPTION( !( requireDimensionRange(errmsg, subcellVertices, 1,  spaceDim, spaceDim) ),
00500                           std::invalid_argument, errmsg);
00501     }
00502 #endif 
00503     
00504     // Simply call getReferenceNodes with the base topology
00505     getReferenceSubcellNodes(subcellVertices, subcellDim, subcellOrd, parentCell.getBaseTopology() );
00506   }  
00507 
00508   
00509   
00510   template<class Scalar>
00511   const double* CellTools<Scalar>::getReferenceNode(const shards::CellTopology& cell,
00512                                                     const int                   nodeOrd){
00513     
00514 #ifdef HAVE_INTREPID_DEBUG
00515     TEST_FOR_EXCEPTION( !(hasReferenceCell(cell) ), std::invalid_argument, 
00516                         ">>> ERROR (Intrepid::CellTools::getReferenceNode): the specified cell topology does not have a reference cell.");
00517 
00518     TEST_FOR_EXCEPTION( !( (0 <= nodeOrd) && (nodeOrd < (int)cell.getNodeCount() ) ), std::invalid_argument,
00519                         ">>> ERROR (Intrepid::CellTools::getReferenceNode): invalid node ordinal for the specified cell topology. ");
00520 #endif
00521     
00522     // Cartesian coordinates of supported reference cell cellWorkset, padded to three-dimensions.
00523     // Node order follows cell topology definition in Shards
00524     static const double line[2][3] ={
00525       {-1.0, 0.0, 0.0}, { 1.0, 0.0, 0.0} 
00526     };
00527     static const double line_3[3][3] = {
00528       {-1.0, 0.0, 0.0}, { 1.0, 0.0, 0.0},     
00529       // Extension node: edge midpoint
00530       { 0.0, 0.0, 0.0}
00531     };
00532     
00533     
00534     // Triangle topologies
00535     static const double triangle[3][3] = {
00536       { 0.0, 0.0, 0.0}, { 1.0, 0.0, 0.0}, { 0.0, 1.0, 0.0} 
00537     };
00538     static const double triangle_4[4][3] = {
00539       { 0.0, 0.0, 0.0}, { 1.0, 0.0, 0.0}, { 0.0, 1.0, 0.0},
00540       // Extension node: cell center
00541       { 1/3, 1/3, 0.0}
00542     };
00543     static const double triangle_6[6][3] = {
00544       { 0.0, 0.0, 0.0}, { 1.0, 0.0, 0.0}, { 0.0, 1.0, 0.0},
00545       // Extension cellWorkset: 3 edge midpoints
00546       { 0.5, 0.0, 0.0}, { 0.5, 0.5, 0.0}, { 0.0, 0.5, 0.0}
00547     };
00548     
00549     
00550     // Quadrilateral topologies
00551     static const double quadrilateral[4][3] = {
00552       {-1.0,-1.0, 0.0}, { 1.0,-1.0, 0.0}, { 1.0, 1.0, 0.0}, {-1.0, 1.0, 0.0}
00553     };
00554     static const double quadrilateral_8[8][3] = {
00555       {-1.0,-1.0, 0.0}, { 1.0,-1.0, 0.0}, { 1.0, 1.0, 0.0}, {-1.0, 1.0, 0.0},
00556       // Extension cellWorkset: 4 edge midpoints
00557       { 0.0,-1.0, 0.0}, { 1.0, 0.0, 0.0}, { 0.0, 1.0, 0.0}, {-1.0, 0.0, 0.0}
00558     };
00559     static const double quadrilateral_9[9][3] = {
00560       {-1.0,-1.0, 0.0}, { 1.0,-1.0, 0.0}, { 1.0, 1.0, 0.0}, {-1.0, 1.0, 0.0},
00561       // Extension cellWorkset: 4 edge midpoints + 1 cell center
00562       { 0.0,-1.0, 0.0}, { 1.0, 0.0, 0.0}, { 0.0, 1.0, 0.0}, {-1.0, 0.0, 0.0}, { 0.0, 0.0, 0.0}
00563     };
00564     
00565     
00566     // Tetrahedron topologies
00567     static const double tetrahedron[4][3] = {
00568       { 0.0, 0.0, 0.0}, { 1.0, 0.0, 0.0}, { 0.0, 1.0, 0.0}, { 0.0, 0.0, 1.0}
00569     };
00570     static const double tetrahedron_8[8][3] = {
00571       { 0.0, 0.0, 0.0}, { 1.0, 0.0, 0.0}, { 0.0, 1.0, 0.0}, { 0.0, 0.0, 1.0},
00572       // Extension cellWorkset: 4 face centers (do not follow natural face order - see the cell topology!)
00573       { 1/3, 0.0, 1/3}, { 1/3, 1/3, 1/3}, { 1/3, 1/3, 0.0}, { 0.0, 1/3, 1/3} 
00574     };
00575     static const double tetrahedron_10[10][3] = {
00576       { 0.0, 0.0, 0.0}, { 1.0, 0.0, 0.0}, { 0.0, 1.0, 0.0}, { 0.0, 0.0, 1.0},
00577       // Extension cellWorkset: 6 edge midpoints
00578       { 0.5, 0.0, 0.0}, { 0.5, 0.5, 0.0}, { 0.0, 0.5, 0.0}, { 0.0, 0.0, 0.5}, { 0.5, 0.0, 0.5}, { 0.0, 0.5, 0.5}
00579     };
00580 
00581     
00582     // Hexahedron topologies
00583     static const double hexahedron[8][3] = {
00584       {-1.0,-1.0,-1.0}, { 1.0,-1.0,-1.0}, { 1.0, 1.0,-1.0}, {-1.0, 1.0,-1.0},
00585       {-1.0,-1.0, 1.0}, { 1.0,-1.0, 1.0}, { 1.0, 1.0, 1.0}, {-1.0, 1.0, 1.0}
00586     };
00587     static const double hexahedron_20[20][3] = {
00588       {-1.0,-1.0,-1.0}, { 1.0,-1.0,-1.0}, { 1.0, 1.0,-1.0}, {-1.0, 1.0,-1.0},
00589       {-1.0,-1.0, 1.0}, { 1.0,-1.0, 1.0}, { 1.0, 1.0, 1.0}, {-1.0, 1.0, 1.0},
00590       // Extension cellWorkset: 12 edge midpoints (do not follow natural edge order - see cell topology!)
00591       { 0.0,-1.0,-1.0}, { 1.0, 0.0,-1.0}, { 0.0, 1.0,-1.0}, {-1.0, 0.0,-1.0}, 
00592       {-1.0,-1.0, 0.0}, { 1.0,-1.0, 0.0}, { 1.0, 1.0, 0.0}, {-1.0, 1.0, 0.0},
00593       { 0.0,-1.0, 1.0}, { 1.0, 0.0, 1.0}, { 0.0, 1.0, 1.0}, {-1.0, 0.0, 1.0}
00594     };
00595     static const double hexahedron_27[27][3] = {
00596       {-1.0,-1.0,-1.0}, { 1.0,-1.0,-1.0}, { 1.0, 1.0,-1.0}, {-1.0, 1.0,-1.0},
00597       {-1.0,-1.0, 1.0}, { 1.0,-1.0, 1.0}, { 1.0, 1.0, 1.0}, {-1.0, 1.0, 1.0},
00598       // Extension cellWorkset: 12 edge midpoints + 1 cell center + 6 face centers  (do not follow natural subcell order!)
00599       { 0.0,-1.0,-1.0}, { 1.0, 0.0,-1.0}, { 0.0, 1.0,-1.0}, {-1.0, 0.0,-1.0}, 
00600       {-1.0,-1.0, 0.0}, { 1.0,-1.0, 0.0}, { 1.0, 1.0, 0.0}, {-1.0, 1.0, 0.0},
00601       { 0.0,-1.0, 1.0}, { 1.0, 0.0, 1.0}, { 0.0, 1.0, 1.0}, {-1.0, 0.0, 1.0},
00602       { 0.0, 0.0, 0.0},
00603       { 0.0, 0.0,-1.0}, { 0.0, 0.0, 1.0}, {-1.0, 0.0, 0.0}, { 1.0, 0.0, 0.0}, {0.0,-1.0, 0.0}, {0.0, 1.0, 0.0} 
00604     };
00605     
00606     
00607     // Pyramid topologies
00608     static const double pyramid[5][3] = {
00609       {-1.0,-1.0, 0.0}, { 1.0,-1.0, 0.0}, { 1.0, 1.0, 0.0}, {-1.0, 1.0, 0.0}, { 0.0, 0.0, 1.0}
00610     };
00611     static const double pyramid_13[13][3] = {
00612       {-1.0,-1.0, 0.0}, { 1.0,-1.0, 0.0}, { 1.0, 1.0, 0.0}, {-1.0, 1.0, 0.0}, { 0.0, 0.0, 1.0},
00613       // Extension cellWorkset: 8 edge midpoints 
00614       { 0.0,-1.0, 0.0}, { 1.0, 0.0, 0.0}, { 0.0, 1.0, 0.0}, {-1.0, 0.0, 0.0},
00615       {-0.5,-0.5, 0.5}, { 0.5,-0.5, 0.5}, { 0.5, 0.5, 0.5}, {-0.5, 0.5, 0.5}   
00616     };
00617     static const double pyramid_14[14][3] = {
00618       {-1.0,-1.0, 0.0}, { 1.0,-1.0, 0.0}, { 1.0, 1.0, 0.0}, {-1.0, 1.0, 0.0}, { 0.0, 0.0, 1.0},
00619       // Extension cellWorkset: 8 edge midpoints + quadrilateral face midpoint 
00620       { 0.0,-1.0, 0.0}, { 1.0, 0.0, 0.0}, { 0.0, 1.0, 0.0}, {-1.0, 0.0, 0.0},
00621       {-0.5,-0.5, 0.5}, { 0.5,-0.5, 0.5}, { 0.5, 0.5, 0.5}, {-0.5, 0.5, 0.5}, { 0.0, 0.0, 0.0}  
00622     };
00623     
00624     
00625     // Wedge topologies
00626     static const double wedge[6][3] = {
00627       { 0.0, 0.0,-1.0}, { 1.0, 0.0,-1.0}, { 0.0, 1.0,-1.0}, { 0.0, 0.0, 1.0}, { 1.0, 0.0, 1.0}, { 0.0, 1.0, 1.0} 
00628     };
00629     static const double wedge_15[15][3] = {
00630       { 0.0, 0.0,-1.0}, { 1.0, 0.0,-1.0}, { 0.0, 1.0,-1.0}, { 0.0, 0.0, 1.0}, { 1.0, 0.0, 1.0}, { 0.0, 1.0, 1.0},
00631       // Extension cellWorkset: 9 edge midpoints (do not follow natural edge order - see cell topology!)
00632       { 0.5, 0.0,-1.0}, { 0.5, 0.5,-1.0}, { 0.0, 0.5,-1.0}, { 0.0, 0.0, 0.0}, { 1.0, 0.0, 0.0}, { 0.0, 1.0, 0.0},
00633       { 0.5, 0.0, 1.0}, { 0.5, 0.5, 1.0}, { 0.0, 0.5, 1.0}
00634     };
00635     static const double wedge_18[18][3] = {
00636       { 0.0, 0.0,-1.0}, { 1.0, 0.0,-1.0}, { 0.0, 1.0,-1.0}, { 0.0, 0.0, 1.0}, { 1.0, 0.0, 1.0}, { 0.0, 1.0, 1.0},
00637       // Extension cellWorkset: 9 edge midpoints + 3 quad face centers (do not follow natural subcell order - see cell topology!)
00638       { 0.5, 0.0,-1.0}, { 0.5, 0.5,-1.0}, { 0.0, 0.5,-1.0}, { 0.0, 0.0, 0.0}, { 1.0, 0.0, 0.0}, { 0.0, 1.0, 0.0},
00639       { 0.5, 0.0, 1.0}, { 0.5, 0.5, 1.0}, { 0.0, 0.5, 1.0},
00640       { 0.5, 0.0, 0.0}, { 0.5, 0.5, 0.0}, { 0.0, 0.5, 0.0}
00641     };
00642     
00643     
00644     switch(cell.getKey() ) {
00645       
00646       // Base line topologies
00647       case shards::Line<2>::key:
00648       case shards::ShellLine<2>::key:
00649       case shards::Beam<2>::key:
00650         return line[nodeOrd];
00651         break;
00652         
00653       // Extended line topologies
00654       case shards::Line<3>::key:
00655       case shards::ShellLine<3>::key:
00656       case shards::Beam<3>::key:
00657         return line_3[nodeOrd];
00658         break;
00659         
00660         
00661       // Base triangle topologies
00662       case shards::Triangle<3>::key:
00663       case shards::ShellTriangle<3>::key:
00664         return triangle[nodeOrd];
00665         break;
00666         
00667       // Extened Triangle topologies
00668       case shards::Triangle<4>::key:
00669         return triangle_4[nodeOrd];
00670         break;
00671       case shards::Triangle<6>::key:
00672       case shards::ShellTriangle<6>::key:
00673         return triangle_6[nodeOrd];
00674         break;
00675         
00676         
00677       // Base Quadrilateral topologies  
00678       case shards::Quadrilateral<4>::key:
00679       case shards::ShellQuadrilateral<4>::key:
00680         return quadrilateral[nodeOrd];
00681         break;
00682         
00683       // Extended Quadrilateral topologies
00684       case shards::Quadrilateral<8>::key:
00685       case shards::ShellQuadrilateral<8>::key:
00686         return quadrilateral_8[nodeOrd];
00687         break;
00688       case shards::Quadrilateral<9>::key:
00689       case shards::ShellQuadrilateral<9>::key:
00690         return quadrilateral_9[nodeOrd];
00691         break;
00692         
00693         
00694       // Base Tetrahedron topology
00695       case shards::Tetrahedron<4>::key:
00696         return tetrahedron[nodeOrd];
00697         break;
00698         
00699       // Extended Tetrahedron topologies
00700       case shards::Tetrahedron<8>::key:
00701         return tetrahedron_8[nodeOrd];
00702         break;
00703       case shards::Tetrahedron<10>::key:
00704         return tetrahedron_10[nodeOrd];
00705         break;
00706 
00707         
00708       // Base Hexahedron topology
00709       case shards::Hexahedron<8>::key:
00710         return hexahedron[nodeOrd];
00711         break;
00712         
00713       // Extended Hexahedron topologies
00714       case shards::Hexahedron<20>::key:
00715         return hexahedron_20[nodeOrd];
00716         break;
00717       case shards::Hexahedron<27>::key:
00718         return hexahedron_27[nodeOrd];
00719         break;
00720 
00721         
00722       // Base Pyramid topology  
00723       case shards::Pyramid<5>::key:
00724         return pyramid[nodeOrd];
00725         break;
00726         
00727       // Extended pyramid topologies
00728       case shards::Pyramid<13>::key:
00729         return pyramid_13[nodeOrd];
00730         break;
00731      case shards::Pyramid<14>::key:
00732         return pyramid_14[nodeOrd];
00733         break;
00734       
00735         
00736       // Base Wedge topology
00737       case shards::Wedge<6>::key:
00738         return wedge[nodeOrd];
00739         break;
00740         
00741       // Extended Wedge topologies
00742       case shards::Wedge<15>::key:
00743         return wedge_15[nodeOrd];
00744         break;
00745       case shards::Wedge<18>::key:
00746         return wedge_18[nodeOrd];
00747         break;
00748         
00749       default:
00750         TEST_FOR_EXCEPTION( true, std::invalid_argument, 
00751                             ">>> ERROR (Intrepid::CellTools::getReferenceNode): invalid cell topology.");
00752     }
00753     // To disable compiler warning, should never be reached
00754     return line[0];
00755   }
00756   
00757   
00758   
00759   template<class Scalar>
00760   template<class ArraySubcellNode>
00761   void CellTools<Scalar>::getReferenceSubcellNodes(ArraySubcellNode &          subcellNodes,
00762                                                    const int                   subcellDim,
00763                                                    const int                   subcellOrd,
00764                                                    const shards::CellTopology& parentCell){
00765 #ifdef HAVE_INTREPID_DEBUG
00766     TEST_FOR_EXCEPTION( !(hasReferenceCell(parentCell) ), std::invalid_argument, 
00767                         ">>> ERROR (Intrepid::CellTools::getReferenceSubcellNodes): the specified cell topology does not have a reference cell.");
00768     
00769     // subcellDim can equal the cell dimension because the cell itself is a valid subcell! In this case
00770     // the method will return all cell cellWorkset.
00771     TEST_FOR_EXCEPTION( !( (0 <= subcellDim) && (subcellDim <= (int)parentCell.getDimension()) ), std::invalid_argument,
00772                         ">>> ERROR (Intrepid::CellTools::getReferenceSubcellNodes): subcell dimension out of range.");
00773     
00774     TEST_FOR_EXCEPTION( !( (0 <= subcellOrd) && (subcellOrd < (int)parentCell.getSubcellCount(subcellDim) ) ), std::invalid_argument,
00775                         ">>> ERROR (Intrepid::CellTools::getReferenceSubcellNodes): subcell ordinal out of range.");
00776     
00777     // Verify subcellNodes rank and dimensions
00778     {
00779       std::string errmsg = ">>> ERROR (Intrepid::CellTools::getReferenceSubcellNodes):";
00780       TEST_FOR_EXCEPTION( !( requireRankRange(errmsg, subcellNodes, 2, 2) ), std::invalid_argument, errmsg);
00781       
00782       int subcNodeCount = parentCell.getNodeCount(subcellDim, subcellOrd);
00783       int spaceDim = parentCell.getDimension();
00784       
00785       TEST_FOR_EXCEPTION( !( requireDimensionRange(errmsg, subcellNodes, 0,  subcNodeCount, subcNodeCount) ),
00786                           std::invalid_argument, errmsg);
00787       
00788       TEST_FOR_EXCEPTION( !( requireDimensionRange(errmsg, subcellNodes, 1,  spaceDim, spaceDim) ),
00789                           std::invalid_argument, errmsg);
00790     }
00791 #endif 
00792     
00793     // Find how many cellWorkset does the specified subcell have.
00794     int subcNodeCount = parentCell.getNodeCount(subcellDim, subcellOrd);
00795     
00796     // Loop over subcell cellWorkset
00797     for(int subcNodeOrd = 0; subcNodeOrd < subcNodeCount; subcNodeOrd++){
00798       
00799       // Get the node number relative to the parent reference cell
00800       int cellNodeOrd = parentCell.getNodeMap(subcellDim, subcellOrd, subcNodeOrd);
00801             
00802       // Loop over node's Cartesian coordinates
00803       for(int dim = 0; dim < (int)parentCell.getDimension(); dim++){
00804         subcellNodes(subcNodeOrd, dim) = CellTools::getReferenceNode(parentCell, cellNodeOrd)[dim];
00805       }
00806     }
00807   }  
00808   
00809   
00810   
00811   template<class Scalar>
00812   int CellTools<Scalar>::hasReferenceCell(const shards::CellTopology& cell) {
00813     
00814     switch(cell.getKey() ) {
00815       case shards::Line<2>::key:
00816       case shards::Line<3>::key:
00817       case shards::ShellLine<2>::key:
00818       case shards::ShellLine<3>::key:
00819       case shards::Beam<2>::key:
00820       case shards::Beam<3>::key:
00821         
00822       case shards::Triangle<3>::key:
00823       case shards::Triangle<4>::key:
00824       case shards::Triangle<6>::key:
00825       case shards::ShellTriangle<3>::key:
00826       case shards::ShellTriangle<6>::key:
00827         
00828       case shards::Quadrilateral<4>::key:
00829       case shards::Quadrilateral<8>::key:
00830       case shards::Quadrilateral<9>::key:
00831       case shards::ShellQuadrilateral<4>::key:
00832       case shards::ShellQuadrilateral<8>::key:
00833       case shards::ShellQuadrilateral<9>::key:
00834         
00835       case shards::Tetrahedron<4>::key:
00836       case shards::Tetrahedron<8>::key:
00837       case shards::Tetrahedron<10>::key:
00838         
00839       case shards::Hexahedron<8>::key:
00840       case shards::Hexahedron<20>::key:
00841       case shards::Hexahedron<27>::key:
00842         
00843       case shards::Pyramid<5>::key:
00844       case shards::Pyramid<13>::key:
00845       case shards::Pyramid<14>::key:
00846         
00847       case shards::Wedge<6>::key:
00848       case shards::Wedge<15>::key:
00849       case shards::Wedge<18>::key:
00850         return 1;
00851         break;
00852         
00853       default:
00854         return 0;
00855     }
00856     return 0;
00857   }
00858   
00859   //============================================================================================//
00860   //                                                                                            //
00861   //                     Jacobian, inverse Jacobian and Jacobian determinant                    //
00862   //                                                                                            //
00863   //============================================================================================//  
00864   
00865   template<class Scalar>
00866   template<class ArrayJac, class ArrayPoint, class ArrayCell>
00867   void CellTools<Scalar>::setJacobian(ArrayJac &                   jacobian,
00868                                       const ArrayPoint &           points,
00869                                       const ArrayCell  &           cellWorkset,
00870                                       const shards::CellTopology & cellTopo,
00871                                       const int &                  whichCell) 
00872   {
00873     INTREPID_VALIDATE( validateArguments_setJacobian(jacobian, points, cellWorkset, whichCell,  cellTopo) );
00874     
00875     int spaceDim  = (int)cellTopo.getDimension();
00876     int numCells  = cellWorkset.dimension(0);
00877     //points can be rank-2 (P,D), or rank-3 (C,P,D)
00878     int numPoints = (points.rank() == 2) ? points.dimension(0) : points.dimension(1);
00879     
00880     // Jacobian is computed using gradients of an appropriate H(grad) basis function: define RCP to the base class
00881     Teuchos::RCP< Basis< Scalar, FieldContainer<Scalar> > > HGRAD_Basis;
00882     
00883     // Choose the H(grad) basis depending on the cell topology. \todo define maps for shells and beams
00884     switch( cellTopo.getKey() ){
00885       
00886       // Standard Base topologies (number of cellWorkset = number of vertices)
00887       case shards::Line<2>::key:
00888         HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_LINE_C1_FEM<Scalar, FieldContainer<Scalar> >() );
00889         break;
00890         
00891       case shards::Triangle<3>::key:
00892         HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_TRI_C1_FEM<Scalar, FieldContainer<Scalar> >() );
00893         break;
00894         
00895       case shards::Quadrilateral<4>::key:
00896         HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_QUAD_C1_FEM<Scalar, FieldContainer<Scalar> >() );
00897         break;
00898         
00899       case shards::Tetrahedron<4>::key:
00900         HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_TET_C1_FEM<Scalar, FieldContainer<Scalar> >() );
00901         break;
00902         
00903       case shards::Hexahedron<8>::key:
00904         HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_HEX_C1_FEM<Scalar, FieldContainer<Scalar> >() );
00905         break;
00906         
00907       case shards::Wedge<6>::key:
00908         HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_WEDGE_C1_FEM<Scalar, FieldContainer<Scalar> >() );
00909         break;
00910         
00911       // Standard Extended topologies
00912       case shards::Triangle<6>::key:    
00913         HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_TRI_C2_FEM<Scalar, FieldContainer<Scalar> >() );
00914         break;
00915       case shards::Quadrilateral<9>::key:
00916         HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_QUAD_C2_FEM<Scalar, FieldContainer<Scalar> >() );
00917         break;
00918         
00919       case shards::Tetrahedron<10>::key:
00920         HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_TET_C2_FEM<Scalar, FieldContainer<Scalar> >() );
00921         break;
00922         
00923       case shards::Hexahedron<27>::key:
00924         HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_HEX_C2_FEM<Scalar, FieldContainer<Scalar> >() );
00925         break;
00926         
00927       case shards::Wedge<18>::key:
00928         HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_WEDGE_C2_FEM<Scalar, FieldContainer<Scalar> >() );
00929         break;
00930         
00931         // These extended topologies are not used for mapping purposes
00932       case shards::Quadrilateral<8>::key:
00933       case shards::Hexahedron<20>::key:
00934       case shards::Wedge<15>::key:
00935         TEST_FOR_EXCEPTION( (true), std::invalid_argument, 
00936                             ">>> ERROR (Intrepid::CellTools::setJacobian): Cell topology not supported. ");
00937         break;
00938         
00939         // Base and Extended Line, Beam and Shell topologies  
00940       case shards::Line<3>::key:
00941       case shards::Beam<2>::key:
00942       case shards::Beam<3>::key:
00943       case shards::ShellLine<2>::key:
00944       case shards::ShellLine<3>::key:
00945       case shards::ShellTriangle<3>::key:
00946       case shards::ShellTriangle<6>::key:
00947       case shards::ShellQuadrilateral<4>::key:
00948       case shards::ShellQuadrilateral<8>::key:
00949       case shards::ShellQuadrilateral<9>::key:
00950         TEST_FOR_EXCEPTION( (true), std::invalid_argument, 
00951                             ">>> ERROR (Intrepid::CellTools::setJacobian): Cell topology not supported. ");
00952         break;
00953       default:
00954         TEST_FOR_EXCEPTION( (true), std::invalid_argument, 
00955                             ">>> ERROR (Intrepid::CellTools::setJacobian): Cell topology not supported.");        
00956     }// switch  
00957     
00958     // Temp (F,P,D) array for the values of basis functions gradients at the reference points
00959     int basisCardinality = HGRAD_Basis -> getCardinality();
00960     FieldContainer<Scalar> basisGrads(basisCardinality, numPoints, spaceDim);
00961     
00962     // Initialize jacobian
00963     for(int i = 0; i < jacobian.size(); i++){
00964       jacobian[i] = 0.0;
00965     }
00966         
00967     // Handle separately rank-2 (P,D) and rank-3 (C,P,D) cases of points arrays.
00968     switch(points.rank()) {
00969       
00970       // refPoints is (P,D): a single or multiple cell jacobians computed for a single set of ref. points
00971       case 2:
00972         {
00973           // getValues requires rank-2 (P,D) input array, but points cannot be passed directly as argument because they are a user type
00974           FieldContainer<Scalar> tempPoints( points.dimension(0), points.dimension(1) );
00975           // Copy point set corresponding to this cell oridinal to the temp (P,D) array
00976           for(int pt = 0; pt < points.dimension(0); pt++){
00977             for(int dm = 0; dm < points.dimension(1) ; dm++){
00978               tempPoints(pt, dm) = points(pt, dm);
00979             }//dm
00980           }//pt
00981           HGRAD_Basis -> getValues(basisGrads, tempPoints, OPERATOR_GRAD);
00982           
00983           // The outer loops select the multi-index of the Jacobian entry: cell, point, row, col
00984           // If whichCell = -1, all jacobians are computed, otherwise a single cell jacobian is computed
00985           int cellLoop = (whichCell == -1) ? numCells : 1 ;
00986           
00987           for(int cellOrd = 0; cellOrd < cellLoop; cellOrd++) {
00988             for(int pointOrd = 0; pointOrd < numPoints; pointOrd++) {
00989               for(int row = 0; row < spaceDim; row++){
00990                 for(int col = 0; col < spaceDim; col++){
00991                   
00992                   // The entry is computed by contracting the basis index. Number of basis functions and vertices must be the same
00993                   for(int bfOrd = 0; bfOrd < basisCardinality; bfOrd++){
00994                     
00995                     if(whichCell == -1) {
00996                       jacobian(cellOrd, pointOrd, row, col) += cellWorkset(cellOrd, bfOrd, row)*basisGrads(bfOrd, pointOrd, col);
00997                     }
00998                     else {
00999                       jacobian(pointOrd, row, col) += cellWorkset(whichCell, bfOrd, row)*basisGrads(bfOrd, pointOrd, col);
01000                     }
01001                   } // bfOrd
01002                 } // col
01003               } // row
01004             } // pointOrd
01005           } // cellOrd
01006         }// case 2
01007         break;
01008         
01009         // points is (C,P,D): multiple jacobians computed at multiple point sets, one jacobian per cell  
01010       case 3:
01011         {
01012           // getValues requires rank-2 (P,D) input array, refPoints cannot be used as argument: need temp (P,D) array
01013           FieldContainer<Scalar> tempPoints( points.dimension(1), points.dimension(2) );
01014           
01015           for(int cellOrd = 0; cellOrd < numCells; cellOrd++) {
01016             
01017             // Copy point set corresponding to this cell oridinal to the temp (P,D) array
01018             for(int pt = 0; pt < points.dimension(1); pt++){
01019               for(int dm = 0; dm < points.dimension(2) ; dm++){
01020                 tempPoints(pt, dm) = points(cellOrd, pt, dm);
01021               }//dm
01022             }//pt
01023             
01024             // Compute gradients of basis functions at this set of ref. points
01025             HGRAD_Basis -> getValues(basisGrads, tempPoints, OPERATOR_GRAD);
01026             
01027             // Compute jacobians for the point set corresponding to the current cellordinal
01028             for(int pointOrd = 0; pointOrd < numPoints; pointOrd++) {
01029               for(int row = 0; row < spaceDim; row++){
01030                 for(int col = 0; col < spaceDim; col++){
01031                   
01032                   // The entry is computed by contracting the basis index. Number of basis functions and vertices must be the same
01033                   for(int bfOrd = 0; bfOrd < basisCardinality; bfOrd++){
01034                     jacobian(cellOrd, pointOrd, row, col) += cellWorkset(cellOrd, bfOrd, row)*basisGrads(bfOrd, pointOrd, col);
01035                   } // bfOrd
01036                 } // col
01037               } // row
01038             } // pointOrd
01039           }//cellOrd
01040         }// case 3
01041         
01042         break;
01043         
01044       default:
01045         TEST_FOR_EXCEPTION( !( (points.rank() == 2) && (points.rank() == 3) ), std::invalid_argument,
01046                             ">>> ERROR (Intrepid::CellTools::setJacobian): rank 2 or 3 required for points array. ");        
01047     }//switch
01048   }
01049   
01050 
01051 
01052 template<class Scalar>
01053 template<class ArrayJacInv, class ArrayJac>
01054 void CellTools<Scalar>::setJacobianInv(ArrayJacInv &     jacobianInv,
01055                                        const ArrayJac &  jacobian) 
01056 {
01057   INTREPID_VALIDATE( validateArguments_setJacobianInv(jacobianInv, jacobian) );
01058 
01059   RealSpaceTools<Scalar>::inverse(jacobianInv, jacobian);
01060 }
01061 
01062 
01063 
01064 template<class Scalar>
01065 template<class ArrayJacDet, class ArrayJac>
01066 void CellTools<Scalar>::setJacobianDet(ArrayJacDet &     jacobianDet,
01067                                        const ArrayJac &  jacobian)
01068 {
01069   INTREPID_VALIDATE( validateArguments_setJacobianDetArgs(jacobianDet, jacobian) );
01070 
01071   RealSpaceTools<Scalar>::det(jacobianDet, jacobian);
01072 }
01073 
01074 //============================================================================================//
01075 //                                                                                            //
01076 //                      Reference-to-physical frame mapping and its inverse                   //
01077 //                                                                                            //
01078 //============================================================================================//
01079 
01080 template<class Scalar>
01081 template<class ArrayPhysPoint, class ArrayRefPoint, class ArrayCell>
01082 void CellTools<Scalar>::mapToPhysicalFrame(ArrayPhysPoint      &        physPoints,
01083                                            const ArrayRefPoint &        refPoints,
01084                                            const ArrayCell     &        cellWorkset,
01085                                            const shards::CellTopology & cellTopo,
01086                                            const int &                  whichCell)
01087 {
01088   INTREPID_VALIDATE(validateArguments_mapToPhysicalFrame( physPoints, refPoints, cellWorkset, cellTopo, whichCell) );
01089   
01090   int spaceDim  = (int)cellTopo.getDimension();
01091   int numCells  = cellWorkset.dimension(0);
01092   //points can be rank-2 (P,D), or rank-3 (C,P,D)
01093   int numPoints = (refPoints.rank() == 2) ? refPoints.dimension(0) : refPoints.dimension(1);
01094     
01095   // Mapping is computed using an appropriate H(grad) basis function: define RCP to the base class
01096   Teuchos::RCP<Basis<Scalar, FieldContainer<Scalar> > > HGRAD_Basis;
01097   
01098   // Choose the H(grad) basis depending on the cell topology. \todo define maps for shells and beams
01099   switch( cellTopo.getKey() ){
01100     
01101     // Standard Base topologies (number of cellWorkset = number of vertices)
01102     case shards::Line<2>::key:
01103       HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_LINE_C1_FEM<Scalar, FieldContainer<Scalar> >() );
01104       break;
01105       
01106     case shards::Triangle<3>::key:
01107       HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_TRI_C1_FEM<Scalar, FieldContainer<Scalar> >() );
01108       break;
01109       
01110     case shards::Quadrilateral<4>::key:
01111       HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_QUAD_C1_FEM<Scalar, FieldContainer<Scalar> >() );
01112       break;
01113       
01114     case shards::Tetrahedron<4>::key:
01115       HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_TET_C1_FEM<Scalar, FieldContainer<Scalar> >() );
01116       break;
01117       
01118     case shards::Hexahedron<8>::key:
01119       HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_HEX_C1_FEM<Scalar, FieldContainer<Scalar> >() );
01120       break;
01121       
01122     case shards::Wedge<6>::key:
01123       HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_WEDGE_C1_FEM<Scalar, FieldContainer<Scalar> >() );
01124       break;
01125       
01126     // Standard Extended topologies
01127     case shards::Triangle<6>::key:    
01128       HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_TRI_C2_FEM<Scalar, FieldContainer<Scalar> >() );
01129       break;
01130       
01131     case shards::Quadrilateral<9>::key:
01132       HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_QUAD_C2_FEM<Scalar, FieldContainer<Scalar> >() );
01133       break;
01134       
01135     case shards::Tetrahedron<10>::key:
01136       HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_TET_C2_FEM<Scalar, FieldContainer<Scalar> >() );
01137       break;
01138       
01139     case shards::Hexahedron<27>::key:
01140       HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_HEX_C2_FEM<Scalar, FieldContainer<Scalar> >() );
01141       break;
01142       
01143     case shards::Wedge<18>::key:
01144       HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_WEDGE_C2_FEM<Scalar, FieldContainer<Scalar> >() );
01145       break;
01146       
01147     // These extended topologies are not used for mapping purposes
01148     case shards::Quadrilateral<8>::key:
01149     case shards::Hexahedron<20>::key:
01150     case shards::Wedge<15>::key:
01151       TEST_FOR_EXCEPTION( (true), std::invalid_argument, 
01152                           ">>> ERROR (Intrepid::CellTools::mapToPhysicalFrame): Cell topology not supported. ");
01153       break;
01154       
01155     // Base and Extended Line, Beam and Shell topologies  
01156     case shards::Line<3>::key:
01157     case shards::Beam<2>::key:
01158     case shards::Beam<3>::key:
01159     case shards::ShellLine<2>::key:
01160     case shards::ShellLine<3>::key:
01161     case shards::ShellTriangle<3>::key:
01162     case shards::ShellTriangle<6>::key:
01163     case shards::ShellQuadrilateral<4>::key:
01164     case shards::ShellQuadrilateral<8>::key:
01165     case shards::ShellQuadrilateral<9>::key:
01166       TEST_FOR_EXCEPTION( (true), std::invalid_argument, 
01167                           ">>> ERROR (Intrepid::CellTools::mapToPhysicalFrame): Cell topology not supported. ");
01168       break;
01169     default:
01170       TEST_FOR_EXCEPTION( (true), std::invalid_argument, 
01171                           ">>> ERROR (Intrepid::CellTools::mapToPhysicalFrame): Cell topology not supported.");        
01172   }// switch  
01173 
01174   // Temp (F,P) array for the values of nodal basis functions at the reference points
01175   int basisCardinality = HGRAD_Basis -> getCardinality();
01176   FieldContainer<Scalar> basisVals(basisCardinality, numPoints);
01177   
01178   // Initialize physPoints
01179   for(int i = 0; i < physPoints.size(); i++){
01180     physPoints[i] = 0.0;
01181   }
01182   
01183   // handle separately rank-2 (P,D) and rank-3 (C,P,D) cases of refPoints
01184   switch(refPoints.rank()) {
01185     
01186     // refPoints is (P,D): single set of ref. points is mapped to one or multiple physical cells
01187     case 2:
01188       {
01189         // getValues requires rank-2 (P,D) input array, but refPoints cannot be passed directly as argument because they are a user type
01190         FieldContainer<Scalar> tempPoints( refPoints.dimension(0), refPoints.dimension(1) );
01191         // Copy point set corresponding to this cell oridinal to the temp (P,D) array
01192         for(int pt = 0; pt < refPoints.dimension(0); pt++){
01193           for(int dm = 0; dm < refPoints.dimension(1) ; dm++){
01194             tempPoints(pt, dm) = refPoints(pt, dm);
01195           }//dm
01196         }//pt
01197         HGRAD_Basis -> getValues(basisVals, tempPoints, OPERATOR_VALUE);
01198         
01199         // If whichCell = -1, ref pt. set is mapped to all cells, otherwise, the set is mapped to one cell only
01200         int cellLoop = (whichCell == -1) ? numCells : 1 ;
01201         
01202         // Compute the map F(refPoints) = sum node_coordinate*basis(refPoints)
01203         for(int cellOrd = 0; cellOrd < cellLoop; cellOrd++) {
01204           for(int pointOrd = 0; pointOrd < numPoints; pointOrd++) {
01205             for(int dim = 0; dim < spaceDim; dim++){
01206               for(int bfOrd = 0; bfOrd < basisCardinality; bfOrd++){
01207                 
01208                 if(whichCell == -1){
01209                   physPoints(cellOrd, pointOrd, dim) += cellWorkset(cellOrd, bfOrd, dim)*basisVals(bfOrd, pointOrd);
01210                 }
01211                 else{
01212                   physPoints(pointOrd, dim) += cellWorkset(whichCell, bfOrd, dim)*basisVals(bfOrd, pointOrd);
01213                 }
01214               } // bfOrd
01215             }// dim
01216           }// pointOrd
01217         }//cellOrd
01218       }// case 2
01219       break;
01220       
01221     // refPoints is (C,P,D): multiple sets of ref. points are mapped to matching number of physical cells.  
01222     case 3:
01223       {
01224         // getValues requires rank-2 (P,D) input array, refPoints cannot be used as argument: need temp (P,D) array
01225         FieldContainer<Scalar> tempPoints( refPoints.dimension(1), refPoints.dimension(2) );
01226         
01227         // Compute the map F(refPoints) = sum node_coordinate*basis(refPoints)
01228         for(int cellOrd = 0; cellOrd < numCells; cellOrd++) {
01229           
01230           // Copy point set corresponding to this cell oridinal to the temp (P,D) array
01231           for(int pt = 0; pt < refPoints.dimension(1); pt++){
01232             for(int dm = 0; dm < refPoints.dimension(2) ; dm++){
01233               tempPoints(pt, dm) = refPoints(cellOrd, pt, dm);
01234             }//dm
01235           }//pt
01236           
01237           // Compute basis values for this set of ref. points
01238           HGRAD_Basis -> getValues(basisVals, tempPoints, OPERATOR_VALUE);
01239           
01240           for(int pointOrd = 0; pointOrd < numPoints; pointOrd++) {
01241             for(int dim = 0; dim < spaceDim; dim++){
01242               for(int bfOrd = 0; bfOrd < basisCardinality; bfOrd++){
01243                 
01244                 physPoints(cellOrd, pointOrd, dim) += cellWorkset(cellOrd, bfOrd, dim)*basisVals(bfOrd, pointOrd);
01245                 
01246               } // bfOrd
01247             }// dim
01248           }// pointOrd
01249         }//cellOrd        
01250       }// case 3
01251       break;
01252       
01253     default:
01254       TEST_FOR_EXCEPTION( !( (refPoints.rank() == 2) && (refPoints.rank() == 3) ), std::invalid_argument,
01255                              ">>> ERROR (Intrepid::CellTools::mapToPhysicalFrame): rank 2 or 3 required for refPoints array. ");
01256   }
01257 }
01258 
01259 
01260 
01261 template<class Scalar>
01262 template<class ArrayRefPoint, class ArrayPhysPoint, class ArrayCell>
01263 void CellTools<Scalar>::mapToReferenceFrame(ArrayRefPoint        &        refPoints,
01264                                             const ArrayPhysPoint &        physPoints,
01265                                             const ArrayCell      &        cellWorkset,
01266                                             const shards::CellTopology &  cellTopo,
01267                                             const int &                   whichCell)
01268 {
01269   INTREPID_VALIDATE( validateArguments_mapToReferenceFrame(refPoints, physPoints, cellWorkset, cellTopo, whichCell) );
01270   
01271   int spaceDim  = (int)cellTopo.getDimension();
01272   int numPoints;
01273   int numCells;
01274   
01275   // Define initial guesses to be  the Cell centers of the reference cell topology
01276   FieldContainer<Scalar> cellCenter(spaceDim);
01277   switch( cellTopo.getKey() ){
01278     // Standard Base topologies (number of cellWorkset = number of vertices)
01279     case shards::Line<2>::key:
01280       cellCenter(0) = 0.0;    break;
01281       
01282     case shards::Triangle<3>::key:
01283     case shards::Triangle<6>::key:    
01284       cellCenter(0) = 1./3.;    cellCenter(1) = 1./3.;  break;
01285       
01286     case shards::Quadrilateral<4>::key:
01287     case shards::Quadrilateral<9>::key:
01288       cellCenter(0) = 0.0;      cellCenter(1) = 0.0;    break;
01289       
01290     case shards::Tetrahedron<4>::key:
01291     case shards::Tetrahedron<10>::key:
01292       cellCenter(0) = 1./6.;    cellCenter(1) =  1./6.;    cellCenter(2) =  1./6.;  break;
01293       
01294     case shards::Hexahedron<8>::key:
01295     case shards::Hexahedron<27>::key:
01296       cellCenter(0) = 0.0;      cellCenter(1) =  0.0;       cellCenter(2) =  0.0;   break;
01297       
01298     case shards::Wedge<6>::key:
01299     case shards::Wedge<18>::key:
01300       cellCenter(0) = 1./3.;    cellCenter(1) =  1./3.;     cellCenter(2) = 0.0;    break;
01301       
01302       // These extended topologies are not used for mapping purposes
01303     case shards::Quadrilateral<8>::key:
01304     case shards::Hexahedron<20>::key:
01305     case shards::Wedge<15>::key:
01306       TEST_FOR_EXCEPTION( (true), std::invalid_argument, 
01307                           ">>> ERROR (Intrepid::CellTools::mapToReferenceFrame): Cell topology not supported. ");
01308       break;
01309       
01310       // Base and Extended Line, Beam and Shell topologies  
01311     case shards::Line<3>::key:
01312     case shards::Beam<2>::key:
01313     case shards::Beam<3>::key:
01314     case shards::ShellLine<2>::key:
01315     case shards::ShellLine<3>::key:
01316     case shards::ShellTriangle<3>::key:
01317     case shards::ShellTriangle<6>::key:
01318     case shards::ShellQuadrilateral<4>::key:
01319     case shards::ShellQuadrilateral<8>::key:
01320     case shards::ShellQuadrilateral<9>::key:
01321       TEST_FOR_EXCEPTION( (true), std::invalid_argument, 
01322                           ">>> ERROR (Intrepid::CellTools::mapToReferenceFrame): Cell topology not supported. ");
01323       break;
01324     default:
01325       TEST_FOR_EXCEPTION( (true), std::invalid_argument, 
01326                           ">>> ERROR (Intrepid::CellTools::mapToReferenceFrame): Cell topology not supported.");        
01327   }// switch key 
01328   
01329   // Resize initial guess depending on the rank of the physical points array
01330   FieldContainer<Scalar> initGuess;
01331   
01332   // Default: map (C,P,D) array of physical pt. sets to (C,P,D) array. Requires (C,P,D) initial guess.
01333   if(whichCell == -1){
01334     numPoints = physPoints.dimension(1);
01335     numCells = cellWorkset.dimension(0);
01336     initGuess.resize(numCells, numPoints, spaceDim);
01337     // Set initial guess:
01338     for(int c = 0; c < numCells; c++){
01339       for(int p = 0; p < numPoints; p++){
01340         for(int d = 0; d < spaceDim; d++){
01341           initGuess(c, p, d) = cellCenter(d);
01342         }// d
01343       }// p
01344     }// c
01345   }
01346   // Custom: map (P,D) array of physical pts. to (P,D) array. Requires (P,D) initial guess.
01347   else {
01348     numPoints = physPoints.dimension(0);
01349     initGuess.resize(numPoints, spaceDim);
01350     // Set initial guess:
01351     for(int p = 0; p < numPoints; p++){
01352       for(int d = 0; d < spaceDim; d++){
01353         initGuess(p, d) = cellCenter(d);
01354       }// d
01355     }// p
01356   }
01357   
01358   // Call method with initial guess
01359   mapToReferenceFrameInitGuess(refPoints, initGuess, physPoints, cellWorkset, cellTopo, whichCell);  
01360 }
01361   
01362   
01363 
01364 template<class Scalar>
01365 template<class ArrayRefPoint, class ArrayInitGuess, class ArrayPhysPoint, class ArrayCell>
01366 void CellTools<Scalar>::mapToReferenceFrameInitGuess(ArrayRefPoint        &        refPoints,
01367                                                      const ArrayInitGuess &        initGuess,
01368                                                      const ArrayPhysPoint &        physPoints,
01369                                                      const ArrayCell      &        cellWorkset,
01370                                                      const shards::CellTopology &  cellTopo,
01371                                                      const int &                   whichCell)
01372 {
01373   INTREPID_VALIDATE( validateArguments_mapToReferenceFrame(refPoints, initGuess, physPoints, cellWorkset, cellTopo, whichCell) );
01374 
01375   int spaceDim  = (int)cellTopo.getDimension();
01376   int numPoints;
01377   int numCells=0;
01378   
01379   // Temp arrays for Newton iterates and Jacobians. Resize according to rank of ref. point array
01380   FieldContainer<Scalar> xOld;
01381   FieldContainer<Scalar> xTem;  
01382   FieldContainer<Scalar> jacobian;
01383   FieldContainer<Scalar> jacobInv;
01384   FieldContainer<Scalar> error; 
01385   FieldContainer<Scalar> cellCenter(spaceDim);
01386   
01387   // Default: map (C,P,D) array of physical pt. sets to (C,P,D) array. Requires (C,P,D) temp arrays and (C,P,D,D) Jacobians.
01388   if(whichCell == -1){
01389     numPoints = physPoints.dimension(1);
01390     numCells = cellWorkset.dimension(0);
01391     xOld.resize(numCells, numPoints, spaceDim);
01392     xTem.resize(numCells, numPoints, spaceDim);  
01393     jacobian.resize(numCells,numPoints, spaceDim, spaceDim);
01394     jacobInv.resize(numCells,numPoints, spaceDim, spaceDim);
01395     error.resize(numCells,numPoints); 
01396     // Set initial guess to xOld
01397     for(int c = 0; c < numCells; c++){
01398       for(int p = 0; p < numPoints; p++){
01399         for(int d = 0; d < spaceDim; d++){
01400           xOld(c, p, d) = initGuess(c, p, d);
01401         }// d
01402       }// p
01403     }// c
01404   }
01405   // Custom: map (P,D) array of physical pts. to (P,D) array. Requires (P,D) temp arrays and (P,D,D) Jacobians.
01406   else {
01407     numPoints = physPoints.dimension(0);
01408     xOld.resize(numPoints, spaceDim);
01409     xTem.resize(numPoints, spaceDim);  
01410     jacobian.resize(numPoints, spaceDim, spaceDim);
01411     jacobInv.resize(numPoints, spaceDim, spaceDim);
01412     error.resize(numPoints); 
01413     // Set initial guess to xOld
01414     for(int p = 0; p < numPoints; p++){
01415       for(int d = 0; d < spaceDim; d++){
01416         xOld(p, d) = initGuess(p, d);
01417       }// d
01418     }// p
01419   }
01420   
01421   
01422   // Newton method to solve the equation F(refPoints) - physPoints = 0:
01423   // refPoints = xOld - DF^{-1}(xOld)*(F(xOld) - physPoints) = xOld + DF^{-1}(xOld)*(physPoints - F(xOld))
01424   for(int iter = 0; iter < INTREPID_MAX_NEWTON; ++iter) {
01425     
01426     // Jacobians at the old iterates and their inverses. 
01427     setJacobian(jacobian, xOld, cellWorkset, cellTopo, whichCell);
01428     setJacobianInv(jacobInv, jacobian);
01429         
01430     // The Newton step.
01431     mapToPhysicalFrame( xTem, xOld, cellWorkset, cellTopo, whichCell );      // xTem <- F(xOld)
01432     RealSpaceTools<Scalar>::subtract( xTem, physPoints, xTem );        // xTem <- physPoints - F(xOld)
01433     RealSpaceTools<Scalar>::matvec( refPoints, jacobInv, xTem);        // refPoints <- DF^{-1}( physPoints - F(xOld) )
01434     RealSpaceTools<Scalar>::add( refPoints, xOld );                    // refPoints <- DF^{-1}( physPoints - F(xOld) ) + xOld
01435     
01436     // l2 error (Euclidean distance) between old and new iterates: |xOld - xNew|
01437     RealSpaceTools<Scalar>::subtract( xTem, xOld, refPoints );
01438     RealSpaceTools<Scalar>::vectorNorm( error, xTem, NORM_TWO );
01439     
01440     // Average L2 error for a multiple sets of physical points: error is rank-2 (C,P) array 
01441     double totalError;
01442     if(whichCell == -1) {
01443       FieldContainer<Scalar> cellWiseError(numCells);
01444       // error(C,P) -> cellWiseError(P)
01445       RealSpaceTools<Scalar>::vectorNorm( cellWiseError, error, NORM_ONE );
01446       totalError = RealSpaceTools<Scalar>::vectorNorm( cellWiseError, NORM_ONE );
01447     }
01448     //Average L2 error for a single set of physical points: error is rank-1 (P) array
01449     else{
01450       totalError = RealSpaceTools<Scalar>::vectorNorm( error, NORM_ONE );   
01451       totalError = totalError;
01452     }
01453     
01454     // Stopping criterion:
01455     if (totalError < INTREPID_TOL) {
01456       break;
01457     } 
01458     else if ( iter > INTREPID_MAX_NEWTON) {
01459       INTREPID_VALIDATE(std::cout << " Intrepid::CellTools::mapToReferenceFrameInitGuess failed to converge to desired tolerance within " 
01460                       << INTREPID_MAX_NEWTON  << " iterations\n" );
01461       break;
01462     }
01463     
01464     // initialize next Newton step
01465     xOld = refPoints;
01466   } // for(iter)
01467 }
01468 
01469 
01470 
01471 template<class Scalar>
01472 template<class ArraySubcellPoint, class ArrayParamPoint>
01473 void CellTools<Scalar>::mapToReferenceSubcell(ArraySubcellPoint     &       refSubcellPoints,
01474                                               const ArrayParamPoint &       paramPoints,
01475                                               const int                     subcellDim,
01476                                               const int                     subcellOrd,
01477                                               const shards::CellTopology &  parentCell){
01478   
01479   int cellDim = parentCell.getDimension();
01480   int numPts  = paramPoints.dimension(0);
01481 
01482 #ifdef HAVE_INTREPID_DEBUG
01483   TEST_FOR_EXCEPTION( !(hasReferenceCell(parentCell) ), std::invalid_argument, 
01484                       ">>> ERROR (Intrepid::CellTools::mapToReferenceSubcell): the specified cell topology does not have a reference cell.");
01485   
01486   TEST_FOR_EXCEPTION( !( (1 <= subcellDim) && (subcellDim <= 2 ) ), std::invalid_argument,
01487                       ">>> ERROR (Intrepid::CellTools::mapToReferenceSubcell): method defined only for 1 and 2-dimensional subcells.");  
01488   
01489   TEST_FOR_EXCEPTION( !( (0 <= subcellOrd) && (subcellOrd < (int)parentCell.getSubcellCount(subcellDim) ) ), std::invalid_argument,
01490                       ">>> ERROR (Intrepid::CellTools::mapToReferenceSubcell): subcell ordinal out of range.");
01491   
01492   // refSubcellPoints is rank-2 (P,D1), D1 = cell dimension
01493   std::string errmsg = ">>> ERROR (Intrepid::mapToReferenceSubcell):";
01494   TEST_FOR_EXCEPTION( !requireRankRange(errmsg, refSubcellPoints, 2,2), std::invalid_argument, errmsg);
01495   TEST_FOR_EXCEPTION( !requireDimensionRange(errmsg, refSubcellPoints, 1, cellDim, cellDim), std::invalid_argument, errmsg);
01496                     
01497   // paramPoints is rank-2 (P,D2) with D2 = subcell dimension
01498   TEST_FOR_EXCEPTION( !requireRankRange(errmsg, paramPoints, 2,2), std::invalid_argument, errmsg);
01499   TEST_FOR_EXCEPTION( !requireDimensionRange(errmsg, paramPoints, 1, subcellDim, subcellDim), std::invalid_argument, errmsg);    
01500   
01501   // cross check: refSubcellPoints and paramPoints: dimension 0 must match
01502   TEST_FOR_EXCEPTION( !requireDimensionMatch(errmsg, refSubcellPoints, 0,  paramPoints, 0), std::invalid_argument, errmsg);      
01503 #endif
01504   
01505   
01506   // Get the subcell map, i.e., the coefficients of the parametrization function for the subcell
01507   const FieldContainer<double>& subcellMap = getSubcellParametrization(subcellDim, parentCell);
01508 
01509   // Apply the parametrization map to every point in parameter domain
01510   if(subcellDim == 2) {
01511     for(int pt = 0; pt < numPts; pt++){
01512       double u = paramPoints(pt,0);
01513       double v = paramPoints(pt,1);
01514       
01515       // map_dim(u,v) = c_0(dim) + c_1(dim)*u + c_2(dim)*v because both Quad and Tri ref faces are affine!
01516       for(int  dim = 0; dim < cellDim; dim++){
01517         refSubcellPoints(pt, dim) = subcellMap(subcellOrd, dim, 0) + \
01518                                     subcellMap(subcellOrd, dim, 1)*u + \
01519                                     subcellMap(subcellOrd, dim, 2)*v;
01520       }
01521     }
01522   }
01523   else if(subcellDim == 1) {    
01524     for(int pt = 0; pt < numPts; pt++){
01525       for(int dim = 0; dim < cellDim; dim++) {
01526         refSubcellPoints(pt, dim) = subcellMap(subcellOrd, dim, 0) + subcellMap(subcellOrd, dim, 1)*paramPoints(pt,0);
01527       }
01528     }
01529   }
01530   else{
01531     TEST_FOR_EXCEPTION( !( (subcellDim == 1) || (subcellDim == 2) ), std::invalid_argument, 
01532                         ">>> ERROR (Intrepid::CellTools::mapToReferenceSubcell): method defined only for 1 and 2-subcells");
01533   }
01534 }
01535 
01536 
01537 
01538 template<class Scalar>
01539 template<class ArrayEdgeTangent>
01540 void CellTools<Scalar>::getReferenceEdgeTangent(ArrayEdgeTangent &            refEdgeTangent,
01541                                                 const int &                   edgeOrd,
01542                                                 const shards::CellTopology &  parentCell){
01543   
01544   int spaceDim  = parentCell.getDimension();
01545   
01546 #ifdef HAVE_INTREPID_DEBUG
01547   
01548   TEST_FOR_EXCEPTION( !( (spaceDim == 2) || (spaceDim == 3) ), std::invalid_argument, 
01549                       ">>> ERROR (Intrepid::CellTools::getReferenceFaceTangents): two or three-dimensional parent cell required");
01550   
01551   TEST_FOR_EXCEPTION( !( (0 <= edgeOrd) && (edgeOrd < (int)parentCell.getSubcellCount(1) ) ), std::invalid_argument,
01552                       ">>> ERROR (Intrepid::CellTools::getReferenceFaceTangents): edge ordinal out of bounds");  
01553   
01554   TEST_FOR_EXCEPTION( !( refEdgeTangent.size() == spaceDim ), std::invalid_argument,
01555                       ">>> ERROR (Intrepid::CellTools::getReferenceFaceTangents): output array size is required to match space dimension");  
01556 #endif
01557   
01558   // Edge parametrizations are computed in setSubcellParametrization and stored in rank-3 array 
01559   // (subcOrd, coordinate, coefficient)
01560   const FieldContainer<double>& edgeMap = getSubcellParametrization(1, parentCell);
01561   
01562   // All ref. edge maps have affine coordinate functions: f_dim(u) = C_0(dim) + C_1(dim)*u, 
01563   //                                     => edge Tangent: -> C_1(*)
01564   refEdgeTangent(0) = edgeMap(edgeOrd, 0, 1);
01565   refEdgeTangent(1) = edgeMap(edgeOrd, 1, 1);
01566   
01567   // Skip last coordinate for 2D parent cells
01568   if(spaceDim == 3) {
01569     refEdgeTangent(2) = edgeMap(edgeOrd, 2, 1);  
01570   }
01571 }
01572 
01573 
01574 
01575 template<class Scalar>
01576 template<class ArrayFaceTangentU, class ArrayFaceTangentV>
01577 void CellTools<Scalar>::getReferenceFaceTangents(ArrayFaceTangentU &           uTan,
01578                                                  ArrayFaceTangentV &           vTan,
01579                                                  const int &                   faceOrd,
01580                                                  const shards::CellTopology &  parentCell){
01581   
01582 #ifdef HAVE_INTREPID_DEBUG
01583   int spaceDim  = parentCell.getDimension();
01584   TEST_FOR_EXCEPTION( !(spaceDim == 3), std::invalid_argument, 
01585                       ">>> ERROR (Intrepid::CellTools::getReferenceFaceTangents): three-dimensional parent cell required");  
01586   
01587   TEST_FOR_EXCEPTION( !( (0 <= faceOrd) && (faceOrd < (int)parentCell.getSubcellCount(2) ) ), std::invalid_argument,
01588                       ">>> ERROR (Intrepid::CellTools::getReferenceFaceTangents): face ordinal out of bounds");  
01589 
01590   TEST_FOR_EXCEPTION( !( (uTan.rank() == 1)  && (vTan.rank() == 1) ), std::invalid_argument,  
01591                       ">>> ERROR (Intrepid::CellTools::getReferenceFaceTangents): rank = 1 required for output arrays"); 
01592   
01593   TEST_FOR_EXCEPTION( !( uTan.dimension(0) == spaceDim ), std::invalid_argument,
01594                       ">>> ERROR (Intrepid::CellTools::getReferenceFaceTangents): dim0 (spatial dim) must match that of parent cell");  
01595 
01596   TEST_FOR_EXCEPTION( !( vTan.dimension(0) == spaceDim ), std::invalid_argument,
01597                       ">>> ERROR (Intrepid::CellTools::getReferenceFaceTangents): dim0 (spatial dim) must match that of parent cell");  
01598 #endif
01599   
01600   // Face parametrizations are computed in setSubcellParametrization and stored in rank-3 array 
01601   // (subcOrd, coordinate, coefficient): retrieve this array
01602   const FieldContainer<double>& faceMap = getSubcellParametrization(2, parentCell);
01603   
01604   /*  All ref. face maps have affine coordinate functions:  f_dim(u,v) = C_0(dim) + C_1(dim)*u + C_2(dim)*v
01605    *                           `   => Tangent vectors are:  uTan -> C_1(*);    vTan -> C_2(*)
01606    */
01607     // set uTan -> C_1(*)
01608     uTan(0) = faceMap(faceOrd, 0, 1);
01609     uTan(1) = faceMap(faceOrd, 1, 1);
01610     uTan(2) = faceMap(faceOrd, 2, 1);
01611     
01612      // set vTan -> C_2(*)
01613     vTan(0) = faceMap(faceOrd, 0, 2);
01614     vTan(1) = faceMap(faceOrd, 1, 2);
01615     vTan(2) = faceMap(faceOrd, 2, 2);
01616 }
01617 
01618 
01619 
01620 template<class Scalar>
01621 template<class ArraySideNormal>
01622 void CellTools<Scalar>::getReferenceSideNormal(ArraySideNormal &             refSideNormal,
01623                                                const int &                   sideOrd,
01624                                                const shards::CellTopology &  parentCell){
01625   int spaceDim  = parentCell.getDimension();
01626 #ifdef HAVE_INTREPID_DEBUG
01627   
01628   TEST_FOR_EXCEPTION( !( (spaceDim == 2) || (spaceDim == 3) ), std::invalid_argument, 
01629                       ">>> ERROR (Intrepid::CellTools::getReferenceSideNormal): two or three-dimensional parent cell required");
01630   
01631   // Check side ordinal: by definition side is subcell whose dimension = spaceDim-1
01632   TEST_FOR_EXCEPTION( !( (0 <= sideOrd) && (sideOrd < (int)parentCell.getSubcellCount(spaceDim - 1) ) ), std::invalid_argument,
01633                       ">>> ERROR (Intrepid::CellTools::getReferenceSideNormal): side ordinal out of bounds");    
01634 #endif  
01635   
01636   if(spaceDim == 2){
01637     
01638     // 2D parent cells: side = 1D subcell (edge), call the edge tangent method and rotate tangents
01639     getReferenceEdgeTangent(refSideNormal, sideOrd, parentCell);
01640     
01641     // rotate t(t1, t2) to get n(t2, -t1) so that (n,t) is positively oriented: det(n1,n2/t1,t2)>0
01642     Scalar temp = refSideNormal(0);
01643     refSideNormal(0) = refSideNormal(1);
01644     refSideNormal(1) = -temp;
01645   }
01646   else{
01647     // 3D parent cell: side = 2D subcell (face), call the face normal method.
01648     getReferenceFaceNormal(refSideNormal, sideOrd, parentCell);
01649   }
01650 }
01651   
01652 
01653 
01654 template<class Scalar>
01655 template<class ArrayFaceNormal>
01656 void CellTools<Scalar>::getReferenceFaceNormal(ArrayFaceNormal &             refFaceNormal,
01657                                                const int &                   faceOrd,
01658                                                const shards::CellTopology &  parentCell){
01659   int spaceDim  = parentCell.getDimension();
01660   
01661 #ifdef HAVE_INTREPID_DEBUG
01662   
01663   TEST_FOR_EXCEPTION( !(spaceDim == 3), std::invalid_argument, 
01664                       ">>> ERROR (Intrepid::CellTools::getReferenceFaceNormal): three-dimensional parent cell required");  
01665   
01666   TEST_FOR_EXCEPTION( !( (0 <= faceOrd) && (faceOrd < (int)parentCell.getSubcellCount(2) ) ), std::invalid_argument,
01667                       ">>> ERROR (Intrepid::CellTools::getReferenceFaceNormal): face ordinal out of bounds");  
01668   
01669   TEST_FOR_EXCEPTION( !( refFaceNormal.rank() == 1 ), std::invalid_argument,  
01670                       ">>> ERROR (Intrepid::CellTools::getReferenceFaceNormal): rank = 1 required for output array"); 
01671     
01672   TEST_FOR_EXCEPTION( !( refFaceNormal.dimension(0) == spaceDim ), std::invalid_argument,
01673                       ">>> ERROR (Intrepid::CellTools::getReferenceFaceNormal): dim0 (spatial dim) must match that of parent cell");  
01674 #endif
01675 
01676   // Reference face normal = vector product of reference face tangents. Allocate temp FC storage:
01677   FieldContainer<Scalar> uTan(spaceDim);
01678   FieldContainer<Scalar> vTan(spaceDim);
01679   getReferenceFaceTangents(uTan, vTan, faceOrd, parentCell);
01680   
01681   // Compute the vector product of the reference face tangents:
01682   RealSpaceTools<Scalar>::vecprod(refFaceNormal, uTan, vTan);
01683 }
01684 
01685 
01686 
01687 template<class Scalar>
01688 template<class ArrayEdgeTangent, class ArrayJac>
01689 void CellTools<Scalar>::getPhysicalEdgeTangents(ArrayEdgeTangent &            edgeTangents,
01690                                                 const ArrayJac &              worksetJacobians,
01691                                                 const int &                   worksetEdgeOrd,
01692                                                 const shards::CellTopology &  parentCell){
01693   int worksetSize = worksetJacobians.dimension(0);
01694   int edgePtCount = worksetJacobians.dimension(1); 
01695   int pCellDim    = parentCell.getDimension();
01696   
01697 #ifdef HAVE_INTREPID_DEBUG
01698   std::string errmsg = ">>> ERROR (Intrepid::CellTools::getPhysicalEdgeTangents):";
01699   
01700   TEST_FOR_EXCEPTION( !( (pCellDim == 3) || (pCellDim == 2) ), std::invalid_argument, 
01701                       ">>> ERROR (Intrepid::CellTools::getPhysicalEdgeTangents): 2D or 3D parent cell required");  
01702   
01703   // (1) edgeTangents is rank-3 (C,P,D) and D=2, or 3 is required
01704   TEST_FOR_EXCEPTION( !requireRankRange(errmsg, edgeTangents, 3,3), std::invalid_argument, errmsg);
01705   TEST_FOR_EXCEPTION( !requireDimensionRange(errmsg, edgeTangents, 2, 2,3), std::invalid_argument, errmsg);
01706  
01707   // (2) worksetJacobians in rank-4 (C,P,D,D) and D=2, or 3 is required
01708   TEST_FOR_EXCEPTION( !requireRankRange(errmsg, worksetJacobians, 4,4), std::invalid_argument, errmsg);
01709   TEST_FOR_EXCEPTION( !requireDimensionRange(errmsg, worksetJacobians, 2, 2,3), std::invalid_argument, errmsg);
01710   TEST_FOR_EXCEPTION( !requireDimensionRange(errmsg, worksetJacobians, 3, 2,3), std::invalid_argument, errmsg);
01711   
01712   // (4) cross-check array dimensions: edgeTangents (C,P,D) vs. worksetJacobians (C,P,D,D)
01713   TEST_FOR_EXCEPTION( !requireDimensionMatch(errmsg, edgeTangents, 0,1,2,2,  worksetJacobians, 0,1,2,3), std::invalid_argument, errmsg);      
01714   
01715 #endif
01716   
01717   // Temp storage for constant reference edge tangent: rank-1 (D) arrays
01718   FieldContainer<double> refEdgeTan(pCellDim);
01719   getReferenceEdgeTangent(refEdgeTan, worksetEdgeOrd, parentCell);
01720   
01721   // Loop over workset faces and edge points
01722   for(int pCell = 0; pCell < worksetSize; pCell++){
01723     for(int pt = 0; pt < edgePtCount; pt++){
01724       
01725       // Apply parent cell Jacobian to ref. edge tangent
01726       for(int i = 0; i < pCellDim; i++){
01727         edgeTangents(pCell, pt, i) = 0.0;
01728         for(int j = 0; j < pCellDim; j++){
01729           edgeTangents(pCell, pt, i) +=  worksetJacobians(pCell, pt, i, j)*refEdgeTan(j);
01730         }// for j
01731       }// for i
01732     }// for pt
01733   }// for pCell
01734 }
01735 
01736 
01737 
01738 template<class Scalar>
01739 template<class ArrayFaceTangentU, class ArrayFaceTangentV, class ArrayJac>
01740 void CellTools<Scalar>::getPhysicalFaceTangents(ArrayFaceTangentU &           faceTanU,
01741                                                 ArrayFaceTangentV &           faceTanV,
01742                                                 const ArrayJac &              worksetJacobians,
01743                                                 const int &                   worksetFaceOrd,
01744                                                 const shards::CellTopology &  parentCell){
01745   int worksetSize = worksetJacobians.dimension(0);
01746   int facePtCount = worksetJacobians.dimension(1); 
01747   int pCellDim    = parentCell.getDimension();
01748   
01749 #ifdef HAVE_INTREPID_DEBUG
01750   std::string errmsg = ">>> ERROR (Intrepid::CellTools::getPhysicalFaceTangents):";
01751 
01752   TEST_FOR_EXCEPTION( !(pCellDim == 3), std::invalid_argument, 
01753                       ">>> ERROR (Intrepid::CellTools::getPhysicalFaceTangents): three-dimensional parent cell required");  
01754   
01755   // (1) faceTanU and faceTanV are rank-3 (C,P,D) and D=3 is required
01756   TEST_FOR_EXCEPTION( !requireRankRange(errmsg, faceTanU, 3,3), std::invalid_argument, errmsg);
01757   TEST_FOR_EXCEPTION( !requireDimensionRange(errmsg, faceTanU, 2, 3,3), std::invalid_argument, errmsg);
01758 
01759   TEST_FOR_EXCEPTION( !requireRankRange(errmsg, faceTanV, 3,3), std::invalid_argument, errmsg);
01760   TEST_FOR_EXCEPTION( !requireDimensionRange(errmsg, faceTanV, 2, 3,3), std::invalid_argument, errmsg);
01761 
01762   TEST_FOR_EXCEPTION( !requireDimensionMatch(errmsg, faceTanU,  faceTanV), std::invalid_argument, errmsg);      
01763 
01764   // (3) worksetJacobians in rank-4 (C,P,D,D) and D=3 is required
01765   TEST_FOR_EXCEPTION( !requireRankRange(errmsg, worksetJacobians, 4,4), std::invalid_argument, errmsg);
01766   TEST_FOR_EXCEPTION( !requireDimensionRange(errmsg, worksetJacobians, 2, 3,3), std::invalid_argument, errmsg);
01767   TEST_FOR_EXCEPTION( !requireDimensionRange(errmsg, worksetJacobians, 3, 3,3), std::invalid_argument, errmsg);
01768 
01769   // (4) cross-check array dimensions: faceTanU (C,P,D) vs. worksetJacobians (C,P,D,D)
01770   TEST_FOR_EXCEPTION( !requireDimensionMatch(errmsg, faceTanU, 0,1,2,2,  worksetJacobians, 0,1,2,3), std::invalid_argument, errmsg);      
01771 
01772 #endif
01773     
01774   // Temp storage for the pair of constant ref. face tangents: rank-1 (D) arrays
01775   FieldContainer<double> refFaceTanU(pCellDim);
01776   FieldContainer<double> refFaceTanV(pCellDim);
01777   getReferenceFaceTangents(refFaceTanU, refFaceTanV, worksetFaceOrd, parentCell);
01778 
01779   // Loop over workset faces and face points
01780   for(int pCell = 0; pCell < worksetSize; pCell++){
01781     for(int pt = 0; pt < facePtCount; pt++){
01782       
01783       // Apply parent cell Jacobian to ref. face tangents
01784       for(int dim = 0; dim < pCellDim; dim++){
01785         faceTanU(pCell, pt, dim) = 0.0;
01786         faceTanV(pCell, pt, dim) = 0.0;
01787         
01788         // Unroll loops: parent cell dimension can only be 3
01789         faceTanU(pCell, pt, dim) = \
01790           worksetJacobians(pCell, pt, dim, 0)*refFaceTanU(0) + \
01791           worksetJacobians(pCell, pt, dim, 1)*refFaceTanU(1) + \
01792           worksetJacobians(pCell, pt, dim, 2)*refFaceTanU(2);
01793         faceTanV(pCell, pt, dim) = \
01794           worksetJacobians(pCell, pt, dim, 0)*refFaceTanV(0) + \
01795           worksetJacobians(pCell, pt, dim, 1)*refFaceTanV(1) + \
01796           worksetJacobians(pCell, pt, dim, 2)*refFaceTanV(2);
01797       }// for dim
01798     }// for pt
01799   }// for pCell
01800 }
01801 
01802 
01803 template<class Scalar>
01804 template<class ArraySideNormal, class ArrayJac>
01805 void CellTools<Scalar>::getPhysicalSideNormals(ArraySideNormal &             sideNormals,
01806                                                const ArrayJac &              worksetJacobians,
01807                                                const int &                   worksetSideOrd,
01808                                                const shards::CellTopology &  parentCell){
01809   int worksetSize = worksetJacobians.dimension(0);
01810   int sidePtCount = worksetJacobians.dimension(1);   
01811   int spaceDim  = parentCell.getDimension();
01812   
01813 #ifdef HAVE_INTREPID_DEBUG
01814   TEST_FOR_EXCEPTION( !( (spaceDim == 2) || (spaceDim == 3) ), std::invalid_argument, 
01815                       ">>> ERROR (Intrepid::CellTools::getPhysicalSideNormals): two or three-dimensional parent cell required");
01816   
01817   // Check side ordinal: by definition side is subcell whose dimension = spaceDim-1
01818   TEST_FOR_EXCEPTION( !( (0 <= worksetSideOrd) && (worksetSideOrd < (int)parentCell.getSubcellCount(spaceDim - 1) ) ), std::invalid_argument,
01819                       ">>> ERROR (Intrepid::CellTools::getPhysicalSideNormals): side ordinal out of bounds");  
01820 #endif  
01821   
01822   if(spaceDim == 2){
01823 
01824     // 2D parent cells: side = 1D subcell (edge), call the edge tangent method and rotate tangents
01825     getPhysicalEdgeTangents(sideNormals, worksetJacobians, worksetSideOrd, parentCell);
01826     
01827     // rotate t(t1, t2) to get n(t2, -t1) so that (n,t) is positively oriented: det(n1,n2/t1,t2)>0
01828     for(int cell = 0; cell < worksetSize; cell++){
01829       for(int pt = 0; pt < sidePtCount; pt++){
01830         Scalar temp = sideNormals(cell, pt, 0);
01831         sideNormals(cell, pt, 0) = sideNormals(cell, pt, 1);
01832         sideNormals(cell, pt, 1) = -temp;
01833       }// for pt
01834     }// for cell
01835   }
01836   else{
01837     // 3D parent cell: side = 2D subcell (face), call the face normal method.
01838     getPhysicalFaceNormals(sideNormals, worksetJacobians, worksetSideOrd, parentCell);
01839   }
01840 }
01841   
01842   
01843   
01844 template<class Scalar>
01845 template<class ArrayFaceNormal, class ArrayJac>
01846 void CellTools<Scalar>::getPhysicalFaceNormals(ArrayFaceNormal &             faceNormals,
01847                                                const ArrayJac &              worksetJacobians,
01848                                                const int &                   worksetFaceOrd,
01849                                                const shards::CellTopology &  parentCell){
01850   int worksetSize = worksetJacobians.dimension(0);
01851   int facePtCount = worksetJacobians.dimension(1); 
01852   int pCellDim    = parentCell.getDimension();
01853   
01854 #ifdef HAVE_INTREPID_DEBUG
01855   std::string errmsg = ">>> ERROR (Intrepid::CellTools::getPhysicalFaceNormals):";
01856   
01857   TEST_FOR_EXCEPTION( !(pCellDim == 3), std::invalid_argument, 
01858                       ">>> ERROR (Intrepid::CellTools::getPhysicalFaceNormals): three-dimensional parent cell required");  
01859   
01860   // (1) faceNormals is rank-3 (C,P,D) and D=3 is required
01861   TEST_FOR_EXCEPTION( !requireRankRange(errmsg, faceNormals, 3,3), std::invalid_argument, errmsg);
01862   TEST_FOR_EXCEPTION( !requireDimensionRange(errmsg, faceNormals, 2, 3,3), std::invalid_argument, errmsg);
01863   
01864   // (3) worksetJacobians in rank-4 (C,P,D,D) and D=3 is required
01865   TEST_FOR_EXCEPTION( !requireRankRange(errmsg, worksetJacobians, 4,4), std::invalid_argument, errmsg);
01866   TEST_FOR_EXCEPTION( !requireDimensionRange(errmsg, worksetJacobians, 2, 3,3), std::invalid_argument, errmsg);
01867   TEST_FOR_EXCEPTION( !requireDimensionRange(errmsg, worksetJacobians, 3, 3,3), std::invalid_argument, errmsg);
01868   
01869   // (4) cross-check array dimensions: faceNormals (C,P,D) vs. worksetJacobians (C,P,D,D)
01870   TEST_FOR_EXCEPTION( !requireDimensionMatch(errmsg, faceNormals, 0,1,2,2,  worksetJacobians, 0,1,2,3), std::invalid_argument, errmsg);        
01871 #endif
01872   
01873   // Temp storage for physical face tangents: rank-3 (C,P,D) arrays
01874   FieldContainer<double> faceTanU(worksetSize, facePtCount, pCellDim);
01875   FieldContainer<double> faceTanV(worksetSize, facePtCount, pCellDim);
01876   getPhysicalFaceTangents(faceTanU, faceTanV, worksetJacobians, worksetFaceOrd, parentCell);
01877   
01878   // Compute the vector product of the physical face tangents:
01879   RealSpaceTools<Scalar>::vecprod(faceNormals, faceTanU, faceTanV);
01880   
01881   
01882 }
01883 
01884 //============================================================================================//
01885 //                                                                                            //
01886 //                                        Inclusion tests                                     //
01887 //                                                                                            //
01888 //============================================================================================//
01889 
01890 
01891 template<class Scalar>
01892 int CellTools<Scalar>::checkPointInclusion(const Scalar*                 point,
01893                                            const int                     pointDim,
01894                                            const shards::CellTopology &  cellTopo,
01895                                            const double &                threshold) {
01896 #ifdef HAVE_INTREPID_DEBUG
01897   TEST_FOR_EXCEPTION( !(pointDim == (int)cellTopo.getDimension() ), std::invalid_argument,
01898                       ">>> ERROR (Intrepid::CellTools::checkPointInclusion): Point and cell dimensions do not match. ");
01899 #endif
01900   int testResult = 1;
01901   
01902   // Using these values in the tests effectievly inflates the reference element to a larger one
01903   double minus_one = -1.0 - threshold;
01904   double plus_one  =  1.0 + threshold;
01905   double minus_zero = - threshold;
01906   
01907   // A cell with extended topology has the same reference cell as a cell with base topology. 
01908   // => testing for inclusion in a reference Triangle<> and a reference Triangle<6> relies on 
01909   // on the same set of inequalities. To eliminate unnecessary cases we switch on the base topology
01910   unsigned key = cellTopo.getBaseTopology() -> key ;
01911   switch( key ) {
01912     
01913     case shards::Line<>::key :
01914       if( !(minus_one <= point[0] && point[0] <= plus_one))  testResult = 0;
01915       break;
01916       
01917     case shards::Triangle<>::key : {
01918       Scalar distance = std::max( std::max( -point[0], -point[1] ), point[0] + point[1] - 1.0 );
01919       if( distance > threshold ) testResult = 0;
01920       break;
01921     }
01922       
01923     case shards::Quadrilateral<>::key :
01924       if(!( (minus_one <= point[0] && point[0] <= plus_one) && \
01925             (minus_one <= point[1] && point[1] <= plus_one) ) ) testResult = 0;   
01926       break;
01927       
01928     case shards::Tetrahedron<>::key : {
01929       Scalar distance = std::max(  std::max(-point[0],-point[1]), \
01930                                    std::max(-point[2], point[0] + point[1] + point[2] - 1)  );
01931       if( distance > threshold ) testResult = 0;
01932       break;
01933     }
01934       
01935     case shards::Hexahedron<>::key :
01936       if(!((minus_one <= point[0] && point[0] <= plus_one) && \
01937            (minus_one <= point[1] && point[1] <= plus_one) && \
01938            (minus_one <= point[2] && point[2] <= plus_one)))  \
01939              testResult = 0;
01940       break;
01941       
01942     // The base of the reference prism is the same as the reference triangle => apply triangle test
01943     // to X and Y coordinates and test whether Z is in [-1,1]
01944     case shards::Wedge<>::key : {
01945       Scalar distance = std::max( std::max( -point[0], -point[1] ), point[0] + point[1] - 1 );
01946       if( distance > threshold  || \
01947           point[2] < minus_one || point[2] > plus_one) \
01948             testResult = 0;
01949       break;
01950     }
01951 
01952     // The base of the reference pyramid is the same as the reference quad cell => a horizontal plane
01953     // through a point P(x,y,z) intersects the pyramid at a quadrilateral that equals the base quad 
01954     // scaled by (1-z) => P(x,y,z) is inside the pyramid <=> (x,y) is in [-1+z,1-z]^2 && 0 <= Z <= 1 
01955     case shards::Pyramid<>::key : {
01956       Scalar left  = minus_one + point[2];
01957       Scalar right = plus_one  - point[2];
01958       if(!( (left       <= point[0] && point[0] <= right) && \
01959             (left       <= point[1] && point[1] <= right) && 
01960             (minus_zero <= point[2] && point[2] <= plus_one) ) )  \
01961              testResult = 0;  
01962       break;
01963     }
01964       
01965     default:
01966       TEST_FOR_EXCEPTION( !( (key == shards::Line<>::key ) ||
01967                              (key == shards::Triangle<>::key)  ||
01968                              (key == shards::Quadrilateral<>::key) ||
01969                              (key == shards::Tetrahedron<>::key)  ||
01970                              (key == shards::Hexahedron<>::key)  ||
01971                              (key == shards::Wedge<>::key)  ||
01972                              (key == shards::Pyramid<>::key) ),
01973                           std::invalid_argument,
01974                           ">>> ERROR (Intrepid::CellTools::checkPointInclusion): Invalid cell topology. ");
01975   }
01976   return testResult;
01977 }
01978 
01979 
01980 
01981 template<class Scalar>
01982 template<class ArrayPoint>
01983 int CellTools<Scalar>::checkPointsetInclusion(const ArrayPoint&             points,
01984                                               const shards::CellTopology &  cellTopo, 
01985                                               const double &                threshold) {
01986   
01987   int rank = points.rank();  
01988   
01989 #ifdef HAVE_INTREPID_DEBUG
01990   TEST_FOR_EXCEPTION( !( (1 <= points.rank() ) && (points.rank() <= 3) ), std::invalid_argument,
01991                       ">>> ERROR (Intrepid::CellTools::checkPointsetInclusion): rank-1, 2 or 3 required for input points array. ");
01992 
01993   // The last dimension of points array at (rank - 1) is the spatial dimension. Must equal the cell dimension.
01994   TEST_FOR_EXCEPTION( !( points.dimension(rank - 1) == (int)cellTopo.getDimension() ), std::invalid_argument,
01995                       ">>> ERROR (Intrepid::CellTools::checkPointsetInclusion): Point and cell dimensions do not match. ");
01996 #endif
01997   
01998   // create temp output array depending on the rank of the input array 
01999   FieldContainer<int> inRefCell;
02000   switch(rank) {
02001     case 1: inRefCell.resize(1); break;
02002     case 2: inRefCell.resize( points.dimension(0) ); break;
02003     case 3: inRefCell.resize( points.dimension(0), points.dimension(1) ); break;
02004   }
02005 
02006   // Call the inclusion method which returns inclusion results for all points
02007   checkPointwiseInclusion(inRefCell, points, cellTopo, threshold);
02008   
02009   // Check if any points were outside, break when finding the first one
02010   int allInside = 1;
02011   for(int i = 0; i < inRefCell.size(); i++ ){
02012     if (inRefCell[i] == 0) {
02013       allInside = 0;
02014       break;
02015     }
02016   }
02017    return allInside;
02018 }
02019 
02020 
02021 
02022 template<class Scalar>
02023 template<class ArrayIncl, class ArrayPoint>
02024 void CellTools<Scalar>::checkPointwiseInclusion(ArrayIncl &                   inRefCell,
02025                                                 const ArrayPoint &            points,
02026                                                 const shards::CellTopology &  cellTopo, 
02027                                                 const double &                threshold) {
02028   int apRank   = points.rank();
02029   
02030 #ifdef HAVE_INTREPID_DEBUG
02031   
02032   // Verify that points and inRefCell have correct ranks and dimensions
02033   std::string errmsg = ">>> ERROR (Intrepid::CellTools::checkPointwiseInclusion):";
02034   if(points.rank() == 1) {
02035     TEST_FOR_EXCEPTION( !(inRefCell.rank() == 1 ), std::invalid_argument, 
02036                         ">>> ERROR (Intrepid::CellTools::checkPointwiseInclusion): rank-1 input array requires rank-1 output array.");  
02037     TEST_FOR_EXCEPTION( !(inRefCell.dimension(0) == 1), std::invalid_argument,
02038                         ">>> ERROR (Intrepid::CellTools::checkPointwiseInclusion): rank-1 input array requires dim0 = 1 for output array.");  
02039   }
02040   else if(points.rank() == 2){
02041     TEST_FOR_EXCEPTION( !(inRefCell.rank() == 1 ), std::invalid_argument, 
02042                         ">>> ERROR (Intrepid::CellTools::checkPointwiseInclusion): rank-2 input array requires rank-1 output array.");  
02043     // dimension 0 of the arrays must match
02044     TEST_FOR_EXCEPTION( !requireDimensionMatch( errmsg, inRefCell, 0,  points, 0), std::invalid_argument, errmsg);
02045   }
02046   else if (points.rank() == 3) {
02047     TEST_FOR_EXCEPTION( !(inRefCell.rank() == 2 ), std::invalid_argument, 
02048                         ">>> ERROR (Intrepid::CellTools::checkPointwiseInclusion): rank-3 input array requires rank-2 output array.");  
02049     // dimensions 0 and 1 of the arrays must match
02050     TEST_FOR_EXCEPTION( !requireDimensionMatch( errmsg, inRefCell, 0,1,  points, 0,1), std::invalid_argument, errmsg);
02051   }
02052   else{
02053     TEST_FOR_EXCEPTION( !( (points.rank() == 1) || (points.rank() == 2) || (points.rank() == 3) ), std::invalid_argument,
02054                         ">>> ERROR (Intrepid::CellTools::checkPointwiseInclusion): rank-1, 2 or 3 required for input points array. ");      
02055   }    
02056   
02057   // The last dimension of points array at (rank - 1) is the spatial dimension. Must equal the cell dimension.
02058   TEST_FOR_EXCEPTION( !( points.dimension(apRank - 1) == (int)cellTopo.getDimension() ), std::invalid_argument,
02059                       ">>> ERROR (Intrepid::CellTools::checkPointwiseInclusion): Point and cell dimensions do not match. ");
02060   
02061 #endif
02062   
02063   // Initializations
02064   int dim0     = 1;
02065   int dim1     = 1;
02066   int pointDim = 0;
02067   switch(apRank) {
02068     case 1:
02069       pointDim = points.dimension(0);
02070       break;
02071     case 2:
02072       dim1     = points.dimension(0);
02073       pointDim = points.dimension(1);
02074       break;
02075     case 3:
02076       dim0     = points.dimension(0);
02077       dim1     = points.dimension(1);
02078       pointDim = points.dimension(2);
02079       break;
02080     default:
02081       TEST_FOR_EXCEPTION( !( (1 <= points.rank() ) && (points.rank() <= 3) ), std::invalid_argument,
02082                           ">>> ERROR (Intrepid::CellTools::checkPointwiseInclusion): rank-1, 2 or 3 required for input points array. ");      
02083   }// switch
02084   
02085   
02086   // This method can handle up to rank-3 input arrays. The spatial dim must be the last dimension. 
02087   // The method uses [] accessor because array rank is determined at runtime and the appropriate
02088   // (i,j,..,k) accessor is not known. Use of [] requires the following offsets:
02089   //    for input array  = i0*dim1*pointDim + i1*dim1  (computed in 2 pieces: inPtr0 and inPtr1, resp)
02090   //    for output array = i0*dim1                     (computed in one piece: outPtr0)
02091   int inPtr0  = 0;
02092   int inPtr1  = 0;
02093   int outPtr0 = 0;
02094   Scalar point[3] = {0.0, 0.0, 0.0};
02095   
02096   for(int i0 = 0; i0 < dim0; i0++){
02097     outPtr0 = i0*dim1;
02098     inPtr0  = outPtr0*pointDim;
02099     
02100     for(int i1 = 0; i1 < dim1; i1++) {
02101       inPtr1 = inPtr0 + i1*pointDim;      
02102       point[0] = points[inPtr1];
02103       if(pointDim > 1) {
02104         point[1] = points[inPtr1 + 1];
02105         if(pointDim > 2) {
02106           point[2] = points[inPtr1 + 2];
02107           if(pointDim > 3) {
02108             TEST_FOR_EXCEPTION( !( (1 <= pointDim) && (pointDim <= 3)), std::invalid_argument, 
02109                                 ">>> ERROR (Intrepid::CellTools::checkPointwiseInclusion): Input array specifies invalid point dimension ");      
02110           }
02111         }
02112       } //if(pointDim > 1)
02113       inRefCell[outPtr0 + i1] = checkPointInclusion(point, pointDim, cellTopo, threshold);
02114     } // for (i1)
02115   } // for(i2)
02116 
02117 }  
02118 
02119 
02120 template<class Scalar>
02121 template<class ArrayIncl, class ArrayPoint, class ArrayCell>
02122 void CellTools<Scalar>::checkPointwiseInclusion(ArrayIncl &                   inCell,
02123                                                 const ArrayPoint &            points,
02124                                                 const ArrayCell &             cellWorkset,
02125                                                 const shards::CellTopology &  cell,
02126                                                 const int &                   whichCell, 
02127                                                 const double &                threshold)
02128 {
02129   INTREPID_VALIDATE( validateArguments_checkPointwiseInclusion(inCell, points, cellWorkset, whichCell, cell) );
02130   
02131   // For cell topologies with reference cells this test maps the points back to the reference cell
02132   // and uses the method for reference cells
02133   unsigned baseKey = cell.getBaseTopology() -> key;
02134   
02135   switch(baseKey){
02136     
02137     case shards::Line<>::key :
02138     case shards::Triangle<>::key:
02139     case shards::Quadrilateral<>::key :
02140     case shards::Tetrahedron<>::key :
02141     case shards::Hexahedron<>::key :
02142     case shards::Wedge<>::key :
02143     case shards::Pyramid<>::key :
02144       {
02145         FieldContainer<Scalar> refPoints;
02146         
02147         if(points.rank() == 2){
02148           refPoints.resize(points.dimension(0), points.dimension(1) );
02149           mapToReferenceFrame(refPoints, points, cellWorkset, cell, whichCell);
02150           checkPointwiseInclusion(inCell, refPoints, cell, threshold );
02151         }
02152         else if(points.rank() == 3){
02153           refPoints.resize(points.dimension(0), points.dimension(1), points.dimension(2) );
02154           mapToReferenceFrame(refPoints, points, cellWorkset, cell, whichCell);
02155           checkPointwiseInclusion(inCell, refPoints, cell, threshold );          
02156         }
02157         break;
02158       }
02159     default: 
02160       TEST_FOR_EXCEPTION( true, std::invalid_argument, 
02161                           ">>> ERROR (Intrepid::CellTools::checkPointwiseInclusion): cell topology not supported");
02162   }// switch
02163   
02164 }
02165 
02166 
02167 //============================================================================================//
02168 //                                                                                            //
02169 //                  Validation of input/output arguments for CellTools methods                //
02170 //                                                                                            //
02171 //============================================================================================//
02172 
02173 template<class Scalar>
02174 template<class ArrayJac, class ArrayPoint, class ArrayCell>
02175 void CellTools<Scalar>::validateArguments_setJacobian(const ArrayJac    &          jacobian,
02176                                                       const ArrayPoint  &          points,
02177                                                       const ArrayCell   &          cellWorkset,
02178                                                       const int &                  whichCell,
02179                                                       const shards::CellTopology & cellTopo){
02180   
02181   // Validate cellWorkset array
02182   TEST_FOR_EXCEPTION( (cellWorkset.rank() != 3), std::invalid_argument,
02183                       ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): rank = 3 required for cellWorkset array");
02184   
02185   TEST_FOR_EXCEPTION( (cellWorkset.dimension(0) <= 0), std::invalid_argument,
02186                       ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 0 (number of cells) >= 1 required for cellWorkset array");
02187   
02188   TEST_FOR_EXCEPTION( (cellWorkset.dimension(1) != (int)cellTopo.getSubcellCount(0) ), std::invalid_argument,
02189                       ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 1 (number of cell nodes) of cellWorkset array does not match cell topology");
02190   
02191   TEST_FOR_EXCEPTION( (cellWorkset.dimension(2) != (int)cellTopo.getDimension() ), std::invalid_argument,
02192                       ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 2 (spatial dimension) of cellWorkset array  does not match cell dimension");
02193     
02194   // validate whichCell. It can be either -1 (default value) or a valid cell ordinal.
02195   TEST_FOR_EXCEPTION( !( ( (0 <= whichCell ) && (whichCell < cellWorkset.dimension(0) ) ) || (whichCell == -1) ), std::invalid_argument,
02196                       ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): whichCell = -1 or a valid cell ordinal is required.");
02197   
02198   
02199   // Validate points array: can be rank-2 (P,D) or rank-3 (C,P,D)
02200   // If rank-2: admissible jacobians: rank-3 (P,D,D) or rank-4 (C,P,D,D); admissible whichCell: -1 (default) or cell ordinal.
02201   if(points.rank() == 2) {
02202     TEST_FOR_EXCEPTION( (points.dimension(0) <= 0), std::invalid_argument,
02203                         ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 0 (number of points) >= 1 required for points array ");
02204     
02205     TEST_FOR_EXCEPTION( (points.dimension(1) != (int)cellTopo.getDimension() ), std::invalid_argument,
02206                         ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 1 (spatial dimension) of points array does not match cell dimension");
02207     
02208     // Validate the output array for the Jacobian: if whichCell == -1 all Jacobians are computed, rank-4 (C,P,D,D) required
02209     if(whichCell == -1) {
02210       TEST_FOR_EXCEPTION( (jacobian.rank() != 4), std::invalid_argument, 
02211                           ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): rank = 4 required for jacobian array");
02212       
02213       TEST_FOR_EXCEPTION( (jacobian.dimension(0) != cellWorkset.dimension(0)), std::invalid_argument,
02214                           ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 0 (number of cells) of jacobian array must equal dim 0 of cellWorkset array");
02215       
02216       TEST_FOR_EXCEPTION( (jacobian.dimension(1) != points.dimension(0)), std::invalid_argument,
02217                           ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 1 (number of points) of jacobian array must equal dim 0 of points array");
02218 
02219       TEST_FOR_EXCEPTION( (jacobian.dimension(2) != points.dimension(1)), std::invalid_argument,
02220                           ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 2 (spatial dimension) of jacobian array must equal dim 1 of points array");
02221       
02222       TEST_FOR_EXCEPTION( !(jacobian.dimension(2) == jacobian.dimension(3) ), std::invalid_argument,
02223                           ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 2 = dim 3 (same spatial dimensions) required for jacobian array. ");
02224       
02225       TEST_FOR_EXCEPTION( !( (0 < jacobian.dimension(3) ) && (jacobian.dimension(3) < 4) ), std::invalid_argument,
02226                           ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 2 and dim 3 (spatial dimensions) must be between 1 and 3. ");
02227     }     
02228     // A single cell Jacobian is computed when whichCell != -1 (whichCell has been already validated), rank-3 (P,D,D) required
02229     else {
02230       TEST_FOR_EXCEPTION( (jacobian.rank() != 3), std::invalid_argument, 
02231                           ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): rank = 3 required for jacobian array");
02232       
02233       TEST_FOR_EXCEPTION( (jacobian.dimension(0) != points.dimension(0)), std::invalid_argument,
02234                           ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 0 (number of points) of jacobian array must equal dim 0 of points array");
02235 
02236       TEST_FOR_EXCEPTION( (jacobian.dimension(1) != points.dimension(1)), std::invalid_argument,
02237                           ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 1 (spatial dimension) of jacobian array must equal dim 1 of points array");
02238       
02239       TEST_FOR_EXCEPTION( !(jacobian.dimension(1) == jacobian.dimension(2) ), std::invalid_argument,
02240                           ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 1 = dim 2 (same spatial dimensions) required for jacobian array. ");
02241       
02242       TEST_FOR_EXCEPTION( !( (0 < jacobian.dimension(1) ) && (jacobian.dimension(1) < 4) ), std::invalid_argument,
02243                           ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 1 and dim 2 (spatial dimensions) must be between 1 and 3. ");
02244     }
02245   }
02246   // Point array is rank-3 (C,P,D): requires whichCell = -1 and rank-4 (C,P,D,D) jacobians
02247   else if(points.rank() ==3){
02248     std::string errmsg  = ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian):";
02249     TEST_FOR_EXCEPTION( (points.dimension(0) != cellWorkset.dimension(0) ), std::invalid_argument,
02250                         ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 0 (number of cells) of points array must equal dim 0 of cellWorkset array");
02251 
02252     TEST_FOR_EXCEPTION( (points.dimension(1) <= 0), std::invalid_argument,
02253                         ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 1 (number of points) >= 1 required for points array ");
02254     
02255     TEST_FOR_EXCEPTION( (points.dimension(2) != (int)cellTopo.getDimension() ), std::invalid_argument,
02256                         ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 2 (spatial dimension) of points array does not match cell dimension");
02257     
02258     TEST_FOR_EXCEPTION( (whichCell != -1), std::invalid_argument,
02259                         ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): default value whichCell=-1 required for rank-3 input points");
02260     
02261     // rank-4 (C,P,D,D) jacobian required for rank-3 (C,P,D) input points
02262     TEST_FOR_EXCEPTION( !requireRankRange(errmsg, jacobian,  4, 4), std::invalid_argument,errmsg);
02263     
02264     TEST_FOR_EXCEPTION( (jacobian.dimension(0) != points.dimension(0)), std::invalid_argument,
02265                         ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 0 (number of cells) of jacobian array must equal dim 0 of points array");
02266     
02267     TEST_FOR_EXCEPTION( (jacobian.dimension(1) != points.dimension(1)), std::invalid_argument,
02268                         ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 1 (number of points) of jacobian array must equal dim 1 of points array");
02269   
02270     TEST_FOR_EXCEPTION( (jacobian.dimension(2) != points.dimension(2)), std::invalid_argument,
02271                         ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 2 (spatial dimension) of jacobian array must equal dim 2 of points array");
02272     
02273     TEST_FOR_EXCEPTION( !(jacobian.dimension(2) == jacobian.dimension(3) ), std::invalid_argument,
02274                         ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 2 = dim 3 (same spatial dimensions) required for jacobian array. ");
02275     
02276     TEST_FOR_EXCEPTION( !( (0 < jacobian.dimension(3) ) && (jacobian.dimension(3) < 4) ), std::invalid_argument,
02277                         ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 2 and dim 3 (spatial dimensions) must be between 1 and 3. ");
02278   }
02279   else {
02280     TEST_FOR_EXCEPTION( !( (points.rank() == 2) && (points.rank() ==3) ), std::invalid_argument,
02281                         ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): rank = 2 or 3 required for points array");
02282   }  
02283 }
02284 
02285 
02286 
02287 template<class Scalar>
02288 template<class ArrayJacInv, class ArrayJac>
02289 void CellTools<Scalar>::validateArguments_setJacobianInv(const ArrayJacInv & jacobianInv,
02290                                                          const ArrayJac &    jacobian)
02291 {
02292   // Validate input jacobian array: admissible ranks & dimensions are: 
02293   // - rank-4 with dimensions (C,P,D,D), or rank-3 with dimensions (P,D,D).
02294   int jacobRank = jacobian.rank();
02295   TEST_FOR_EXCEPTION( !( (jacobRank == 4) || (jacobRank == 3) ), std::invalid_argument,
02296                       ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobianInv): rank = 4 or 3 required for jacobian array. ");
02297   
02298   // Verify correctness of spatial dimensions - they are the last two dimensions of the array: rank-2 and rank-1
02299   TEST_FOR_EXCEPTION( !(jacobian.dimension(jacobRank - 1) == jacobian.dimension(jacobRank - 2) ), std::invalid_argument,
02300                       ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobianInv): dim(rank-2) = dim(rank-2) (same spatial dimensions) required for jacobian array. ");
02301   
02302   TEST_FOR_EXCEPTION( !( (0 < jacobian.dimension(jacobRank - 1) ) && (jacobian.dimension(jacobRank - 1) < 4) ), std::invalid_argument,
02303                       ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobianInv): dim(rank-1) and dim(rank-2) (spatial dimensions) must be between 1 and 3. ");
02304   
02305   // Validate output jacobianInv array: must have the same rank and dimensions as the input array.
02306   std::string errmsg = ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobianInv):";
02307 
02308   TEST_FOR_EXCEPTION( !(requireRankMatch(errmsg, jacobianInv, jacobian) ), std::invalid_argument, errmsg);
02309   
02310   TEST_FOR_EXCEPTION( !(requireDimensionMatch(errmsg, jacobianInv, jacobian) ), std::invalid_argument, errmsg);
02311 }
02312 
02313 
02314 
02315 template<class Scalar>
02316 template<class ArrayJacDet, class ArrayJac>
02317 void CellTools<Scalar>::validateArguments_setJacobianDetArgs(const ArrayJacDet &  jacobianDet,
02318                                                              const ArrayJac    &  jacobian)
02319 {
02320   // Validate input jacobian array: admissible ranks & dimensions are: 
02321   // - rank-4 with dimensions (C,P,D,D), or rank-3 with dimensions (P,D,D).
02322   int jacobRank = jacobian.rank();
02323   TEST_FOR_EXCEPTION( !( (jacobRank == 4) || (jacobRank == 3) ), std::invalid_argument,
02324                       ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobianInv): rank = 4 or 3 required for jacobian array. ");
02325   
02326   // Verify correctness of spatial dimensions - they are the last two dimensions of the array: rank-2 and rank-1
02327   TEST_FOR_EXCEPTION( !(jacobian.dimension(jacobRank - 1) == jacobian.dimension(jacobRank - 2) ), std::invalid_argument,
02328                       ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobianInv): dim(rank-2) = dim(rank-2) (same spatial dimensions) required for jacobian array. ");
02329   
02330   TEST_FOR_EXCEPTION( !( (0 < jacobian.dimension(jacobRank - 1) ) && (jacobian.dimension(jacobRank - 1) < 4) ), std::invalid_argument,
02331                       ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobianInv): dim(rank-1) and dim(rank-2) (spatial dimensions) must be between 1 and 3. ");
02332 
02333   
02334   // Validate output jacobianDet array: must be rank-2 with dimensions (C,P) if jacobian was rank-4:
02335   if(jacobRank == 4){
02336     TEST_FOR_EXCEPTION( !(jacobianDet.rank() == 2), std::invalid_argument,
02337                         ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobianDetArgs): rank = 2 required for jacobianDet if jacobian is rank-4. ");
02338     
02339     TEST_FOR_EXCEPTION( !(jacobianDet.dimension(0) == jacobian.dimension(0) ), std::invalid_argument,
02340                         ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobianDetArgs): dim 0 (number of cells) of jacobianDet array must equal dim 0 of jacobian array. ");
02341     
02342     TEST_FOR_EXCEPTION( !(jacobianDet.dimension(1) == jacobian.dimension(1) ), std::invalid_argument,
02343                         ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobianDetArgs): dim 1 (number of points) of jacobianDet array must equal dim 1 of jacobian array.");  
02344   }
02345   
02346   // must be rank-1 with dimension (P) if jacobian was rank-3
02347   else {
02348     TEST_FOR_EXCEPTION( !(jacobianDet.rank() == 1), std::invalid_argument,
02349                         ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobianDetArgs): rank = 1 required for jacobianDet if jacobian is rank-3. ");
02350     
02351     TEST_FOR_EXCEPTION( !(jacobianDet.dimension(0) == jacobian.dimension(0) ), std::invalid_argument,
02352                         ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobianDetArgs): dim 0 (number of points) of jacobianDet array must equal dim 0 of jacobian array.");  
02353   }
02354 }
02355 
02356 
02357 
02358 template<class Scalar>
02359 template<class ArrayPhysPoint, class ArrayRefPoint, class ArrayCell>
02360 void CellTools<Scalar>::validateArguments_mapToPhysicalFrame(const ArrayPhysPoint &        physPoints,
02361                                                              const ArrayRefPoint  &        refPoints,
02362                                                              const ArrayCell      &        cellWorkset,
02363                                                              const shards::CellTopology &  cellTopo,
02364                                                              const int&                    whichCell)
02365 {
02366   std::string errmsg = ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame):";
02367   
02368   // Validate cellWorkset array
02369   TEST_FOR_EXCEPTION( (cellWorkset.rank() != 3), std::invalid_argument,
02370                       ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): rank = 3 required for cellWorkset array");
02371   
02372   TEST_FOR_EXCEPTION( (cellWorkset.dimension(0) <= 0), std::invalid_argument,
02373                       ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 0 (number of cells) >= 1 required for cellWorkset array");
02374   
02375   TEST_FOR_EXCEPTION( (cellWorkset.dimension(1) != (int)cellTopo.getSubcellCount(0) ), std::invalid_argument,
02376                       ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 1 (number of cell nodes) of cellWorkset array does not match cell topology");
02377   
02378   TEST_FOR_EXCEPTION( (cellWorkset.dimension(2) != (int)cellTopo.getDimension() ), std::invalid_argument,
02379                       ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 2 (spatial dimension) of cellWorkset array  does not match cell dimension");
02380   
02381     
02382   // validate whichCell. It can be either -1 (default value) or a valid cell ordinal.
02383   TEST_FOR_EXCEPTION( !( ( (0 <= whichCell ) && (whichCell < cellWorkset.dimension(0) ) ) || (whichCell == -1) ), std::invalid_argument,
02384                       ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): whichCell = -1 or a valid cell ordinal is required.");
02385   
02386   // Validate refPoints array: can be rank-2 (P,D) or rank-3 (C,P,D) array
02387   // If rank-2: admissible output array is (P,D) or (C,P,D); admissible whichCell: -1 (default) or cell ordinal
02388   if(refPoints.rank() == 2) {
02389     TEST_FOR_EXCEPTION( (refPoints.dimension(0) <= 0), std::invalid_argument,
02390                         ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 0 (number of points) >= 1 required for refPoints array ");
02391     
02392     TEST_FOR_EXCEPTION( (refPoints.dimension(1) != (int)cellTopo.getDimension() ), std::invalid_argument,
02393                         ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 1 (spatial dimension) of refPoints array does not match cell dimension");
02394 
02395     // Validate output array: whichCell = -1 requires rank-3 array with dimensions (C,P,D)  
02396     if(whichCell == -1) {
02397       TEST_FOR_EXCEPTION( ( (physPoints.rank() != 3) && (whichCell == -1) ), std::invalid_argument,
02398                           ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): rank = 3 required for physPoints array for the default whichCell value");
02399       
02400       TEST_FOR_EXCEPTION( (physPoints.dimension(0) != cellWorkset.dimension(0)), std::invalid_argument,
02401                           ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 0 (number of cells) of physPoints array must equal dim 0 of cellWorkset array");
02402       
02403       TEST_FOR_EXCEPTION( (physPoints.dimension(1) != refPoints.dimension(0)), std::invalid_argument,
02404                           ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 1 (number of points) of physPoints array must equal dim 0 of refPoints array"); 
02405       
02406       TEST_FOR_EXCEPTION( (physPoints.dimension(2) != (int)cellTopo.getDimension()), std::invalid_argument,
02407                           ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 2 (spatial dimension) does not match cell dimension ");  
02408     }
02409     // 0 <= whichCell < num cells requires rank-2 (P,D) arrays for both refPoints and physPoints
02410     else{
02411       TEST_FOR_EXCEPTION( (physPoints.rank() != 2), std::invalid_argument,
02412                           ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): rank = 2 required for physPoints array");
02413       
02414       TEST_FOR_EXCEPTION( (physPoints.dimension(0) != refPoints.dimension(0)), std::invalid_argument,
02415                           ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 0 (number of points) of physPoints array must equal dim 0 of refPoints array"); 
02416       
02417       TEST_FOR_EXCEPTION( (physPoints.dimension(1) != (int)cellTopo.getDimension()), std::invalid_argument,
02418                           ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 1 (spatial dimension) does not match cell dimension ");      
02419     }
02420   }
02421   // refPoints is (C,P,D): requires physPoints to be (C,P,D) and whichCell=-1  (because all cell mappings are applied)
02422   else if(refPoints.rank() == 3) {
02423     
02424     // 1. validate refPoints dimensions and rank
02425     TEST_FOR_EXCEPTION( (refPoints.dimension(0) != cellWorkset.dimension(0) ), std::invalid_argument,
02426                         ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 0 (number of cells) of refPoints and cellWorkset arraya are required to match ");
02427 
02428     TEST_FOR_EXCEPTION( (refPoints.dimension(1) <= 0), std::invalid_argument,
02429                         ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 1 (number of points) >= 1 required for refPoints array ");
02430     
02431     TEST_FOR_EXCEPTION( (refPoints.dimension(2) != (int)cellTopo.getDimension() ), std::invalid_argument,
02432                         ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 2 (spatial dimension) of refPoints array does not match cell dimension");
02433     
02434     // 2. whichCell  must be -1
02435     TEST_FOR_EXCEPTION( (whichCell != -1), std::invalid_argument, 
02436                         ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): default value is required for rank-3 refPoints array");
02437 
02438     // 3.  physPoints must match rank and dimensions of refPoints
02439     TEST_FOR_EXCEPTION( !requireRankMatch(errmsg, refPoints, physPoints), std::invalid_argument, errmsg );
02440     TEST_FOR_EXCEPTION( !requireDimensionMatch(errmsg, refPoints, physPoints), std::invalid_argument, errmsg);
02441   }
02442   // if rank is not 2 or 3 throw exception
02443   else {
02444     TEST_FOR_EXCEPTION( !( (refPoints.rank() == 2) || (refPoints.rank() == 3) ), std::invalid_argument,
02445                         ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): rank = 2 or 3 required for refPoints array");
02446   }
02447 }
02448 
02449 
02450 
02451 template<class Scalar>
02452 template<class ArrayRefPoint, class ArrayPhysPoint, class ArrayCell>
02453 void CellTools<Scalar>::validateArguments_mapToReferenceFrame(const ArrayRefPoint  &        refPoints,
02454                                                               const ArrayPhysPoint &        physPoints,
02455                                                               const ArrayCell      &        cellWorkset,
02456                                                               const shards::CellTopology &  cellTopo,
02457                                                               const int&                    whichCell)
02458 {
02459   std::string errmsg  = ">>> ERROR (Intrepid::CellTools::validateArguments_mapToReferenceFrame):";
02460   std::string errmsg1 = ">>> ERROR (Intrepid::CellTools::validateArguments_mapToReferenceFrame):";
02461   
02462   // Validate cellWorkset array
02463   TEST_FOR_EXCEPTION( (cellWorkset.rank() != 3), std::invalid_argument,
02464                       ">>> ERROR (Intrepid::CellTools::validateArguments_mapToReferenceFrame): rank = 3 required for cellWorkset array");
02465   
02466   TEST_FOR_EXCEPTION( (cellWorkset.dimension(0) <= 0), std::invalid_argument,
02467                       ">>> ERROR (Intrepid::CellTools::validateArguments_mapToReferenceFrame): dim 0 (number of cells) >= 1 required for cellWorkset array");
02468   
02469   TEST_FOR_EXCEPTION( (cellWorkset.dimension(1) != (int)cellTopo.getSubcellCount(0) ), std::invalid_argument,
02470                       ">>> ERROR (Intrepid::CellTools::validateArguments_mapToReferenceFrame): dim 1 (number of cell nodes) of cellWorkset array does not match cell topology");
02471   
02472   TEST_FOR_EXCEPTION( (cellWorkset.dimension(2) != (int)cellTopo.getDimension() ), std::invalid_argument,
02473                       ">>> ERROR (Intrepid::CellTools::validateArguments_mapToReferenceFrame): dim 2 (spatial dimension) of cellWorkset array  does not match cell dimension");
02474     
02475   // Validate whichCell. It can be either -1 (default value) or a valid cell ordinal.
02476   TEST_FOR_EXCEPTION( !( ( (0 <= whichCell ) && (whichCell < cellWorkset.dimension(0) ) ) || (whichCell == -1) ), std::invalid_argument,
02477                       ">>> ERROR (Intrepid::CellTools::validateArguments_mapToReferenceFrame): whichCell = -1 or a valid cell ordinal is required.");
02478   
02479   // Admissible ranks and dimensions of refPoints and physPoints depend on whichCell value:
02480   // default is to map multiple sets of points to multiple sets of points. (C,P,D) arrays required
02481   int validRank;
02482   if(whichCell == -1) {
02483     validRank = 3;
02484     errmsg1 += " default value of whichCell requires rank-3 arrays:";
02485   }
02486   // whichCell is valid cell ordinal => we map single set of pts to a single set of pts. (P,D) arrays required
02487   else{
02488     errmsg1 += " rank-2 arrays required when whichCell is valid cell ordinal";
02489     validRank = 2;
02490   }
02491   TEST_FOR_EXCEPTION( !requireRankRange(errmsg1, refPoints,  validRank,validRank), std::invalid_argument, errmsg1);
02492   TEST_FOR_EXCEPTION( !requireRankMatch(errmsg1, physPoints, refPoints),           std::invalid_argument, errmsg1);
02493   TEST_FOR_EXCEPTION( !requireDimensionMatch(errmsg1, refPoints, physPoints),      std::invalid_argument, errmsg1);
02494 }
02495 
02496 
02497 
02498 template<class Scalar>
02499 template<class ArrayRefPoint, class ArrayInitGuess, class ArrayPhysPoint, class ArrayCell>
02500 void CellTools<Scalar>::validateArguments_mapToReferenceFrame(const ArrayRefPoint  &        refPoints,
02501                                                               const ArrayInitGuess &        initGuess,
02502                                                               const ArrayPhysPoint &        physPoints,
02503                                                               const ArrayCell      &        cellWorkset,
02504                                                               const shards::CellTopology &  cellTopo,
02505                                                               const int&                    whichCell)
02506 {
02507   // Call the method that validates arguments with the default initial guess selection
02508   validateArguments_mapToReferenceFrame(refPoints, physPoints, cellWorkset, cellTopo, whichCell);
02509   
02510   // Then check initGuess: its rank and dimensions must match those of physPoints.
02511   std::string errmsg = ">>> ERROR (Intrepid::CellTools::validateArguments_mapToReferenceFrame):";
02512   TEST_FOR_EXCEPTION( !requireDimensionMatch(errmsg, initGuess, physPoints), std::invalid_argument, errmsg);  
02513 }
02514 
02515 
02516 template<class Scalar>
02517 template<class ArrayIncl, class ArrayPoint, class ArrayCell>
02518 void CellTools<Scalar>::validateArguments_checkPointwiseInclusion(ArrayIncl &                   inCell,
02519                                                                   const ArrayPoint &            physPoints,
02520                                                                   const ArrayCell &             cellWorkset,
02521                                                                   const int &                   whichCell,
02522                                                                   const shards::CellTopology &  cell)
02523 {
02524   // Validate cellWorkset array
02525   TEST_FOR_EXCEPTION( (cellWorkset.rank() != 3), std::invalid_argument,
02526                       ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): rank = 3 required for cellWorkset array");
02527   
02528   TEST_FOR_EXCEPTION( (cellWorkset.dimension(0) <= 0), std::invalid_argument,
02529                       ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): dim 0 (number of cells) >= 1 required for cellWorkset array");
02530   
02531   TEST_FOR_EXCEPTION( (cellWorkset.dimension(1) != (int)cell.getSubcellCount(0) ), std::invalid_argument,
02532                       ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): dim 1 (number of cell nodes) of cellWorkset array does not match cell topology");
02533   
02534   TEST_FOR_EXCEPTION( (cellWorkset.dimension(2) != (int)cell.getDimension() ), std::invalid_argument,
02535                       ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): dim 2 (spatial dimension) of cellWorkset array  does not match cell dimension");
02536   
02537   
02538   // Validate whichCell It can be either -1 (default value) or a valid cell ordinal.
02539   TEST_FOR_EXCEPTION( !( ( (0 <= whichCell ) && (whichCell < cellWorkset.dimension(0) ) ) || (whichCell == -1) ), std::invalid_argument,
02540                       ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): whichCell = -1 or a valid cell ordinal is required.");
02541   
02542   
02543   // Validate points array: can be rank-2 (P,D) or rank-3 (C,P,D)
02544   // If rank-2: admissible inCell is rank-1 (P); admissible whichCell is valid cell ordinal but not -1.
02545   if(physPoints.rank() == 2) {
02546     
02547     TEST_FOR_EXCEPTION( (whichCell == -1), std::invalid_argument,
02548                         ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): whichCell = a valid cell ordinal is required with rank-2 input array.");
02549 
02550     TEST_FOR_EXCEPTION( (physPoints.dimension(0) <= 0), std::invalid_argument,
02551                         ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): dim 0 (number of points) >= 1 required for physPoints array ");
02552     
02553     TEST_FOR_EXCEPTION( (physPoints.dimension(1) != (int)cell.getDimension() ), std::invalid_argument,
02554                         ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): dim 1 (spatial dimension) of physPoints array does not match cell dimension");
02555     
02556     // Validate inCell
02557     TEST_FOR_EXCEPTION( (inCell.rank() != 1), std::invalid_argument, 
02558                         ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): rank = 1 required for inCell array");
02559     
02560     TEST_FOR_EXCEPTION( (inCell.dimension(0) != physPoints.dimension(0)), std::invalid_argument,
02561                         ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): dim 0 (number of points) of inCell array must equal dim 0 of physPoints array");
02562   }
02563   // If rank-3: admissible inCell is rank-2 (C,P); admissible whichCell = -1.
02564   else if (physPoints.rank() == 3){
02565     
02566     TEST_FOR_EXCEPTION( !(whichCell == -1), std::invalid_argument,
02567                         ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): whichCell = -1 is required with rank-3 input array.");
02568     
02569     TEST_FOR_EXCEPTION( (physPoints.dimension(0) != cellWorkset.dimension(0) ), std::invalid_argument,
02570                         ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): dim 0 (number of cells)  of physPoints array must equal dim 0 of cellWorkset array ");
02571 
02572     TEST_FOR_EXCEPTION( (physPoints.dimension(1) <= 0), std::invalid_argument,
02573                         ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): dim 1 (number of points) >= 1 required for physPoints array ");
02574     
02575     TEST_FOR_EXCEPTION( (physPoints.dimension(2) != (int)cell.getDimension() ), std::invalid_argument,
02576                         ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): dim 2 (spatial dimension) of physPoints array does not match cell dimension");
02577     
02578     // Validate inCell
02579     TEST_FOR_EXCEPTION( (inCell.rank() != 2), std::invalid_argument, 
02580                         ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): rank = 2 required for inCell array");
02581     
02582     TEST_FOR_EXCEPTION( (inCell.dimension(0) != physPoints.dimension(0)), std::invalid_argument,
02583                         ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): dim 0 (number of cells) of inCell array must equal dim 0 of physPoints array");    
02584 
02585     TEST_FOR_EXCEPTION( (inCell.dimension(1) != physPoints.dimension(1)), std::invalid_argument,
02586                         ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): dim 1 (number of points) of inCell array must equal dim 1 of physPoints array");    
02587   }
02588   else {
02589     TEST_FOR_EXCEPTION( !( (physPoints.rank() == 2) && (physPoints.rank() ==3) ), std::invalid_argument,
02590                         ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): rank = 2 or 3 required for points array");
02591   }
02592 }
02593 
02594 
02595 
02596 //============================================================================================//
02597 //                                                                                            //
02598 //                                           Debug                                            //
02599 //                                                                                            //
02600 //============================================================================================//
02601 
02602 
02603 template<class Scalar>
02604 void CellTools<Scalar>::printSubcellVertices(const int subcellDim,
02605                                              const int subcellOrd,
02606                                              const shards::CellTopology & parentCell){
02607   
02608   // Get number of vertices for the specified subcell and parent cell dimension
02609   int subcVertexCount = parentCell.getVertexCount(subcellDim, subcellOrd);
02610   int cellDim         = parentCell.getDimension();
02611   
02612   // Allocate space for the subcell vertex coordinates
02613   FieldContainer<double> subcellVertices(subcVertexCount, cellDim);
02614   
02615   // Retrieve the vertex coordinates
02616   getReferenceSubcellVertices(subcellVertices,
02617                               subcellDim,
02618                               subcellOrd,
02619                               parentCell);
02620   
02621   // Print the vertices
02622   std::cout 
02623     << " Subcell " << std::setw(2) << subcellOrd 
02624     <<  " is " << parentCell.getName(subcellDim, subcellOrd) << " with vertices = {";
02625   
02626   // Loop over subcell vertices
02627   for(int subcVertOrd = 0; subcVertOrd < subcVertexCount; subcVertOrd++){
02628     std::cout<< "(";
02629     
02630     // Loop over vertex Cartesian coordinates
02631     for(int dim = 0; dim < (int)parentCell.getDimension(); dim++){
02632       std::cout << subcellVertices(subcVertOrd, dim);
02633       if(dim < (int)parentCell.getDimension()-1 ) { std::cout << ","; }
02634     }
02635     std::cout<< ")";
02636     if(subcVertOrd < subcVertexCount - 1) { std::cout << ", "; }
02637   }
02638   std::cout << "}\n";
02639 }
02640   
02641 
02642 template<class Scalar>
02643 template<class ArrayCell>
02644 void CellTools<Scalar>::printWorksetSubcell(const ArrayCell &             cellWorkset,
02645                                             const shards::CellTopology &  parentCell,
02646                                             const int&                    pCellOrd,
02647                                             const int&                    subcellDim,
02648                                             const int&                    subcellOrd,
02649                                             const int&                    fieldWidth){
02650   
02651   // Get the ordinals, relative to reference cell, of subcell cellWorkset
02652   int subcNodeCount = parentCell.getNodeCount(subcellDim, subcellOrd);
02653   int pCellDim      = parentCell.getDimension();
02654   std::vector<int> subcNodeOrdinals(subcNodeCount);
02655   
02656   for(int i = 0; i < subcNodeCount; i++){
02657     subcNodeOrdinals[i] = parentCell.getNodeMap(subcellDim, subcellOrd, i);
02658   }
02659   
02660   // Loop over parent cells and print subcell cellWorkset
02661   
02662   std::cout 
02663     << " Subcell " << subcellOrd << " on parent cell " << pCellOrd << " is " 
02664     << parentCell.getName(subcellDim, subcellOrd) << " with node(s) \n ({";
02665   
02666   for(int i = 0; i < subcNodeCount; i++){
02667     
02668     // print Cartesian coordinates of the node
02669     for(int dim = 0; dim < pCellDim; dim++){
02670       std::cout
02671       << std::setw(fieldWidth) << std::right << cellWorkset(pCellOrd, subcNodeOrdinals[i], dim); 
02672       if(dim < pCellDim - 1){ std::cout << ","; }
02673     }
02674     std::cout << "}";
02675     if(i < subcNodeCount - 1){ std::cout <<", {"; }
02676   }
02677   std::cout << ")\n\n";
02678 }
02679 
02680 
02681 
02682 } // namespace Intrepid
02683 #endif