Intrepid
Intrepid_CellToolsDef.hpp
Go to the documentation of this file.
1 // @HEADER
2 // ************************************************************************
3 //
4 // Intrepid Package
5 // Copyright (2007) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Pavel Bochev (pbboche@sandia.gov)
38 // Denis Ridzal (dridzal@sandia.gov), or
39 // Kara Peterson (kjpeter@sandia.gov)
40 //
41 // ************************************************************************
42 // @HEADER
43 
44 
49 #ifndef INTREPID_CELLTOOLSDEF_HPP
50 #define INTREPID_CELLTOOLSDEF_HPP
51 
52 // disable clang warnings
53 #if defined (__clang__) && !defined (__INTEL_COMPILER)
54 #pragma clang system_header
55 #endif
56 
57 namespace Intrepid {
58 
59  template<class Scalar>
61  const shards::CellTopology& parentCell){
62 
63 #ifdef HAVE_INTREPID_DEBUG
64  TEUCHOS_TEST_FOR_EXCEPTION( !(hasReferenceCell(parentCell) ), std::invalid_argument,
65  ">>> ERROR (Intrepid::CellTools::getSubcellParametrization): the specified cell topology does not have a reference cell.");
66 
67  TEUCHOS_TEST_FOR_EXCEPTION( !( (1 <= subcellDim) && (subcellDim <= 2 ) ), std::invalid_argument,
68  ">>> ERROR (Intrepid::CellTools::getSubcellParametrization): parametrization defined only for 1 and 2-dimensional subcells.");
69 #endif
70 
71  // Coefficients of the coordinate functions defining the parametrization maps are stored in
72  // rank-3 arrays with dimensions (SC, PCD, COEF) where:
73  // - SC is the subcell count of subcells with the specified dimension in the parent cell
74  // - PCD is Parent Cell Dimension, which gives the number of coordinate functions in the map:
75  // PCD = 2 for standard 2D cells and non-standard 2D cells: shell line and beam
76  // PCD = 3 for standard 3D cells and non-standard 3D cells: shell Tri and Quad
77  // - COEF is number of coefficients needed to specify a coordinate function:
78  // COEFF = 2 for edge parametrizations
79  // COEFF = 3 for both Quad and Tri face parametrizations. Because all Quad reference faces
80  // are affine, the coefficient of the bilinear term u*v is zero and is not stored, i.e.,
81  // 3 coefficients are sufficient to store Quad face parameterization maps.
82  //
83  // Arrays are sized and filled only when parametrization of a particular subcell is requested
84  // by setSubcellParametrization.
85 
86  // Edge maps for 2D non-standard cells: ShellLine and Beam
87  static FieldContainer<double> lineEdges; static int lineEdgesSet = 0;
88 
89  // Edge maps for 2D standard cells: Triangle and Quadrilateral
90  static FieldContainer<double> triEdges; static int triEdgesSet = 0;
91  static FieldContainer<double> quadEdges; static int quadEdgesSet = 0;
92 
93  // Edge maps for 3D non-standard cells: Shell Tri and Quad
94  static FieldContainer<double> shellTriEdges; static int shellTriEdgesSet = 0;
95  static FieldContainer<double> shellQuadEdges; static int shellQuadEdgesSet = 0;
96 
97  // Edge maps for 3D standard cells:
98  static FieldContainer<double> tetEdges; static int tetEdgesSet = 0;
99  static FieldContainer<double> hexEdges; static int hexEdgesSet = 0;
100  static FieldContainer<double> pyrEdges; static int pyrEdgesSet = 0;
101  static FieldContainer<double> wedgeEdges; static int wedgeEdgesSet = 0;
102 
103 
104  // Face maps for 3D non-standard cells: Shell Triangle and Quadrilateral
105  static FieldContainer<double> shellTriFaces; static int shellTriFacesSet = 0;
106  static FieldContainer<double> shellQuadFaces; static int shellQuadFacesSet = 0;
107 
108  // Face maps for 3D standard cells:
109  static FieldContainer<double> tetFaces; static int tetFacesSet = 0;
110  static FieldContainer<double> hexFaces; static int hexFacesSet = 0;
111  static FieldContainer<double> pyrFaces; static int pyrFacesSet = 0;
112  static FieldContainer<double> wedgeFaces; static int wedgeFacesSet = 0;
113 
114  // Select subcell parametrization according to its parent cell type
115  switch(parentCell.getKey() ) {
116 
117  // Tet cells
118  case shards::Tetrahedron<4>::key:
119  case shards::Tetrahedron<8>::key:
120  case shards::Tetrahedron<10>::key:
121  case shards::Tetrahedron<11>::key:
122  if(subcellDim == 2) {
123  if(!tetFacesSet){
124  setSubcellParametrization(tetFaces, subcellDim, parentCell);
125  tetFacesSet = 1;
126  }
127  return tetFaces;
128  }
129  else if(subcellDim == 1) {
130  if(!tetEdgesSet){
131  setSubcellParametrization(tetEdges, subcellDim, parentCell);
132  tetEdgesSet = 1;
133  }
134  return tetEdges;
135  }
136  else{
137  TEUCHOS_TEST_FOR_EXCEPTION( (subcellDim != 1 || subcellDim != 2), std::invalid_argument,
138  ">>> ERROR (Intrepid::CellTools::getSubcellParametrization): Tet parametrizations defined for 1 and 2-subcells only");
139  }
140  break;
141 
142  // Hex cells
143  case shards::Hexahedron<8>::key:
144  case shards::Hexahedron<20>::key:
145  case shards::Hexahedron<27>::key:
146  if(subcellDim == 2) {
147  if(!hexFacesSet){
148  setSubcellParametrization(hexFaces, subcellDim, parentCell);
149  hexFacesSet = 1;
150  }
151  return hexFaces;
152  }
153  else if(subcellDim == 1) {
154  if(!hexEdgesSet){
155  setSubcellParametrization(hexEdges, subcellDim, parentCell);
156  hexEdgesSet = 1;
157  }
158  return hexEdges;
159  }
160  else{
161  TEUCHOS_TEST_FOR_EXCEPTION( (subcellDim != 1 || subcellDim != 2), std::invalid_argument,
162  ">>> ERROR (Intrepid::CellTools::getSubcellParametrization): Hex parametrizations defined for 1 and 2-subcells only");
163  }
164  break;
165 
166  // Pyramid cells
167  case shards::Pyramid<5>::key:
168  case shards::Pyramid<13>::key:
169  case shards::Pyramid<14>::key:
170  if(subcellDim == 2) {
171  if(!pyrFacesSet){
172  setSubcellParametrization(pyrFaces, subcellDim, parentCell);
173  pyrFacesSet = 1;
174  }
175  return pyrFaces;
176  }
177  else if(subcellDim == 1) {
178  if(!pyrEdgesSet){
179  setSubcellParametrization(pyrEdges, subcellDim, parentCell);
180  pyrEdgesSet = 1;
181  }
182  return pyrEdges;
183  }
184  else {
185  TEUCHOS_TEST_FOR_EXCEPTION( (subcellDim != 1 || subcellDim != 2), std::invalid_argument,
186  ">>> ERROR (Intrepid::CellTools::getSubcellParametrization): Pyramid parametrizations defined for 1 and 2-subcells only");
187  }
188  break;
189 
190  // Wedge cells
191  case shards::Wedge<6>::key:
192  case shards::Wedge<15>::key:
193  case shards::Wedge<18>::key:
194  if(subcellDim == 2) {
195  if(!wedgeFacesSet){
196  setSubcellParametrization(wedgeFaces, subcellDim, parentCell);
197  wedgeFacesSet = 1;
198  }
199  return wedgeFaces;
200  }
201  else if(subcellDim == 1) {
202  if(!wedgeEdgesSet){
203  setSubcellParametrization(wedgeEdges, subcellDim, parentCell);
204  wedgeEdgesSet = 1;
205  }
206  return wedgeEdges;
207  }
208  else {
209  TEUCHOS_TEST_FOR_EXCEPTION( (subcellDim != 1 || subcellDim != 2), std::invalid_argument,
210  ">>> ERROR (Intrepid::CellTools::getSubcellParametrization): Wedge parametrization defined for 1 and 2-subcells only");
211  }
212  break;
213  //
214  // Standard 2D cells have only 1-subcells
215  //
216  case shards::Triangle<3>::key:
217  case shards::Triangle<4>::key:
218  case shards::Triangle<6>::key:
219  if(subcellDim == 1) {
220  if(!triEdgesSet){
221  setSubcellParametrization(triEdges, subcellDim, parentCell);
222  triEdgesSet = 1;
223  }
224  return triEdges;
225  }
226  else{
227  TEUCHOS_TEST_FOR_EXCEPTION( true, std::invalid_argument,
228  ">>> ERROR (Intrepid::CellTools::getSubcellParametrization): Triangle parametrizations defined for 1-subcells only");
229  }
230  break;
231 
232  case shards::Quadrilateral<4>::key:
233  case shards::Quadrilateral<8>::key:
234  case shards::Quadrilateral<9>::key:
235  if(subcellDim == 1) {
236  if(!quadEdgesSet){
237  setSubcellParametrization(quadEdges, subcellDim, parentCell);
238  quadEdgesSet = 1;
239  }
240  return quadEdges;
241  }
242  else{
243  TEUCHOS_TEST_FOR_EXCEPTION( true, std::invalid_argument,
244  ">>> ERROR (Intrepid::CellTools::getSubcellParametrization): Quad parametrizations defined for 1-subcells only");
245  }
246  break;
247  //
248  // Non-standard 3D Shell Tri and Quad cells have 1 and 2-subcells. Because they are 3D cells
249  // can't reuse edge parametrization arrays for 2D Triangle and Quadrilateral.
250  //
251  case shards::ShellTriangle<3>::key:
252  case shards::ShellTriangle<6>::key:
253  if(subcellDim == 2) {
254  if(!shellTriFacesSet){
255  setSubcellParametrization(shellTriFaces, subcellDim, parentCell);
256  shellTriFacesSet = 1;
257  }
258  return shellTriFaces;
259  }
260  else if(subcellDim == 1) {
261  if(!shellTriEdgesSet){
262  setSubcellParametrization(shellTriEdges, subcellDim, parentCell);
263  shellTriEdgesSet = 1;
264  }
265  return shellTriEdges;
266  }
267  else if( subcellDim != 1 || subcellDim != 2){
268  TEUCHOS_TEST_FOR_EXCEPTION( true, std::invalid_argument,
269  ">>> ERROR (Intrepid::CellTools::getSubcellParametrization): Shell Triangle parametrizations defined for 1 and 2-subcells only");
270  }
271  break;
272 
273  case shards::ShellQuadrilateral<4>::key:
274  case shards::ShellQuadrilateral<8>::key:
275  case shards::ShellQuadrilateral<9>::key:
276  if(subcellDim == 2) {
277  if(!shellQuadFacesSet){
278  setSubcellParametrization(shellQuadFaces, subcellDim, parentCell);
279  shellQuadFacesSet = 1;
280  }
281  return shellQuadFaces;
282  }
283  else if(subcellDim == 1) {
284  if(!shellQuadEdgesSet){
285  setSubcellParametrization(shellQuadEdges, subcellDim, parentCell);
286  shellQuadEdgesSet = 1;
287  }
288  return shellQuadEdges;
289  }
290  else if( subcellDim != 1 || subcellDim != 2){
291  TEUCHOS_TEST_FOR_EXCEPTION( true, std::invalid_argument,
292  ">>> ERROR (Intrepid::CellTools::getSubcellParametrization): Shell Quad parametrizations defined for 1 and 2-subcells only");
293  }
294  break;
295 
296  //
297  // Non-standard 2D cells: Shell Lines and Beams have 1-subcells
298  //
299  case shards::ShellLine<2>::key:
300  case shards::ShellLine<3>::key:
301  case shards::Beam<2>::key:
302  case shards::Beam<3>::key:
303  if(subcellDim == 1) {
304  if(!lineEdgesSet){
305  setSubcellParametrization(lineEdges, subcellDim, parentCell);
306  lineEdgesSet = 1;
307  }
308  return lineEdges;
309  }
310  else{
311  TEUCHOS_TEST_FOR_EXCEPTION( true, std::invalid_argument,
312  ">>> ERROR (Intrepid::CellTools::getSubcellParametrization): shell line/beam parametrizations defined for 1-subcells only");
313  }
314  break;
315 
316  default:
317  TEUCHOS_TEST_FOR_EXCEPTION( true, std::invalid_argument,
318  ">>> ERROR (Intrepid::CellTools::getSubcellParametrization): invalid cell topology.");
319  }//cell key
320  // To disable compiler warning, should never be reached
321  return lineEdges;
322  }
323 
324 
325 
326  template<class Scalar>
328  const int subcellDim,
329  const shards::CellTopology& parentCell)
330  {
331 #ifdef HAVE_INTREPID_DEBUG
332  TEUCHOS_TEST_FOR_EXCEPTION( !(hasReferenceCell(parentCell) ), std::invalid_argument,
333  ">>> ERROR (Intrepid::CellTools::setSubcellParametrization): the specified cell topology does not have a reference cell.");
334 
335  TEUCHOS_TEST_FOR_EXCEPTION( !( (1 <= subcellDim) && (subcellDim <= 2 ) ), std::invalid_argument,
336  ">>> ERROR (Intrepid::CellTools::setSubcellParametrization): parametrization defined only for 1 and 2-dimensional subcells.");
337 #endif
338  // subcellParametrization is rank-3 FieldContainer with dimensions (SC, PCD, COEF) where:
339  // - SC is the subcell count of subcells with the specified dimension in the parent cell
340  // - PCD is Parent Cell Dimension, which gives the number of coordinate functions in the map
341  // PCD = 2 for standard 2D cells and non-standard 2D cells: shell line and beam
342  // PCD = 3 for standard 3D cells and non-standard 3D cells: shell Tri and Quad
343  // - COEF is number of coefficients needed to specify a coordinate function:
344  // COEFF = 2 for edge parametrizations
345  // COEFF = 3 for both Quad and Tri face parametrizations. Because all Quad reference faces
346  // are affine, the coefficient of the bilinear term u*v is zero and is not stored, i.e.,
347  // 3 coefficients are sufficient to store Quad face parameterization maps.
348  //
349  // Edge parametrization maps [-1,1] to edge defined by (v0, v1)
350  // Face parametrization maps [-1,1]^2 to quadrilateral face (v0, v1, v2, v3), or
351  // standard 2-simplex {(0,0),(1,0),(0,1)} to traingle face (v0, v1, v2).
352  // This defines orientation-preserving parametrizations with respect to reference edge and
353  // face orientations induced by their vertex order.
354 
355  // get subcellParametrization dimensions: (sc, pcd, coeff)
356  unsigned sc = parentCell.getSubcellCount(subcellDim);
357  unsigned pcd = parentCell.getDimension();
358  unsigned coeff = (subcellDim == 1) ? 2 : 3;
359 
360 
361  // Resize container
362  subcellParametrization.resize(sc, pcd, coeff);
363 
364  // Edge parametrizations of 2D and 3D cells (shell lines and beams are 2D cells with edges)
365  if(subcellDim == 1){
366  for(unsigned subcellOrd = 0; subcellOrd < sc; subcellOrd++){
367 
368  int v0ord = parentCell.getNodeMap(subcellDim, subcellOrd, 0);
369  int v1ord = parentCell.getNodeMap(subcellDim, subcellOrd, 1);
370 
371  // vertexK[0] = x_k; vertexK[1] = y_k; vertexK[2] = z_k; z_k = 0 for 2D cells
372  // Note that ShellLine and Beam are 2D cells!
373  const double* v0 = getReferenceVertex(parentCell, v0ord);
374  const double* v1 = getReferenceVertex(parentCell, v1ord);
375 
376  // x(t) = (x0 + x1)/2 + t*(x1 - x0)/2
377  subcellParametrization(subcellOrd, 0, 0) = (v0[0] + v1[0])/2.0;
378  subcellParametrization(subcellOrd, 0, 1) = (v1[0] - v0[0])/2.0;
379 
380  // y(t) = (y0 + y1)/2 + t*(y1 - y0)/2
381  subcellParametrization(subcellOrd, 1, 0) = (v0[1] + v1[1])/2.0;
382  subcellParametrization(subcellOrd, 1, 1) = (v1[1] - v0[1])/2.0;
383 
384  if( pcd == 3 ) {
385  // z(t) = (z0 + z1)/2 + t*(z1 - z0)/2
386  subcellParametrization(subcellOrd, 2, 0) = (v0[2] + v1[2])/2.0;
387  subcellParametrization(subcellOrd, 2, 1) = (v1[2] - v0[2])/2.0;
388  }
389  }// for loop over 1-subcells
390  }
391 
392  // Face parametrizations of 3D cells: (shell Tri and Quad are 3D cells with faces)
393  // A 3D cell can have both Tri and Quad faces, but because they are affine images of the
394  // parametrization domain, 3 coefficients are enough to store them in both cases.
395  else if(subcellDim == 2) {
396  for(unsigned subcellOrd = 0; subcellOrd < sc; subcellOrd++){
397 
398  switch(parentCell.getKey(subcellDim,subcellOrd)){
399 
400  // Admissible triangular faces for 3D cells in Shards:
401  case shards::Triangle<3>::key:
402  case shards::Triangle<4>::key:
403  case shards::Triangle<6>::key:
404  {
405  int v0ord = parentCell.getNodeMap(subcellDim, subcellOrd, 0);
406  int v1ord = parentCell.getNodeMap(subcellDim, subcellOrd, 1);
407  int v2ord = parentCell.getNodeMap(subcellDim, subcellOrd, 2);
408  const double* v0 = getReferenceVertex(parentCell, v0ord);
409  const double* v1 = getReferenceVertex(parentCell, v1ord);
410  const double* v2 = getReferenceVertex(parentCell, v2ord);
411 
412  // x(u,v) = x0 + (x1 - x0)*u + (x2 - x0)*v
413  subcellParametrization(subcellOrd, 0, 0) = v0[0];
414  subcellParametrization(subcellOrd, 0, 1) = v1[0] - v0[0];
415  subcellParametrization(subcellOrd, 0, 2) = v2[0] - v0[0];
416 
417  // y(u,v) = y0 + (y1 - y0)*u + (y2 - y0)*v
418  subcellParametrization(subcellOrd, 1, 0) = v0[1];
419  subcellParametrization(subcellOrd, 1, 1) = v1[1] - v0[1];
420  subcellParametrization(subcellOrd, 1, 2) = v2[1] - v0[1];
421 
422  // z(u,v) = z0 + (z1 - z0)*u + (z2 - z0)*v
423  subcellParametrization(subcellOrd, 2, 0) = v0[2];
424  subcellParametrization(subcellOrd, 2, 1) = v1[2] - v0[2];
425  subcellParametrization(subcellOrd, 2, 2) = v2[2] - v0[2];
426  }
427  break;
428 
429  // Admissible quadrilateral faces for 3D cells in Shards:
430  case shards::Quadrilateral<4>::key:
431  case shards::Quadrilateral<8>::key:
432  case shards::Quadrilateral<9>::key:
433  {
434  int v0ord = parentCell.getNodeMap(subcellDim, subcellOrd, 0);
435  int v1ord = parentCell.getNodeMap(subcellDim, subcellOrd, 1);
436  int v2ord = parentCell.getNodeMap(subcellDim, subcellOrd, 2);
437  int v3ord = parentCell.getNodeMap(subcellDim, subcellOrd, 3);
438  const double* v0 = getReferenceVertex(parentCell, v0ord);
439  const double* v1 = getReferenceVertex(parentCell, v1ord);
440  const double* v2 = getReferenceVertex(parentCell, v2ord);
441  const double* v3 = getReferenceVertex(parentCell, v3ord);
442 
443  // 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
444  subcellParametrization(subcellOrd, 0, 0) = ( v0[0] + v1[0] + v2[0] + v3[0])/4.0;
445  subcellParametrization(subcellOrd, 0, 1) = (-v0[0] + v1[0] + v2[0] - v3[0])/4.0;
446  subcellParametrization(subcellOrd, 0, 2) = (-v0[0] - v1[0] + v2[0] + v3[0])/4.0;
447 
448  // 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
449  subcellParametrization(subcellOrd, 1, 0) = ( v0[1] + v1[1] + v2[1] + v3[1])/4.0;
450  subcellParametrization(subcellOrd, 1, 1) = (-v0[1] + v1[1] + v2[1] - v3[1])/4.0;
451  subcellParametrization(subcellOrd, 1, 2) = (-v0[1] - v1[1] + v2[1] + v3[1])/4.0;
452 
453  // 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
454  subcellParametrization(subcellOrd, 2, 0) = ( v0[2] + v1[2] + v2[2] + v3[2])/4.0;
455  subcellParametrization(subcellOrd, 2, 1) = (-v0[2] + v1[2] + v2[2] - v3[2])/4.0;
456  subcellParametrization(subcellOrd, 2, 2) = (-v0[2] - v1[2] + v2[2] + v3[2])/4.0;
457  }
458  break;
459  default:
460  TEUCHOS_TEST_FOR_EXCEPTION( true, std::invalid_argument,
461  ">>> ERROR (Intrepid::CellTools::setSubcellParametrization): parametrization not defined for the specified face topology.");
462 
463  }// switch face topology key
464  }// for subcellOrd
465  }
466  }
467 
468 
469 
470  template<class Scalar>
471  const double* CellTools<Scalar>::getReferenceVertex(const shards::CellTopology& cell,
472  const int vertexOrd){
473 
474 #ifdef HAVE_INTREPID_DEBUG
475  TEUCHOS_TEST_FOR_EXCEPTION( !(hasReferenceCell(cell) ), std::invalid_argument,
476  ">>> ERROR (Intrepid::CellTools::getReferenceVertex): the specified cell topology does not have a reference cell.");
477 
478  TEUCHOS_TEST_FOR_EXCEPTION( !( (0 <= vertexOrd) && (vertexOrd < (int)cell.getVertexCount() ) ), std::invalid_argument,
479  ">>> ERROR (Intrepid::CellTools::getReferenceVertex): invalid node ordinal for the specified cell topology. ");
480 #endif
481 
482  // Simply call getReferenceNode with the base topology of the cell
483  return getReferenceNode(cell.getBaseCellTopologyData(), vertexOrd);
484  }
485 
486 
487 
488  template<class Scalar>
489  template<class ArraySubcellVert>
490  void CellTools<Scalar>::getReferenceSubcellVertices(ArraySubcellVert & subcellVertices,
491  const int subcellDim,
492  const int subcellOrd,
493  const shards::CellTopology& parentCell){
494 #ifdef HAVE_INTREPID_DEBUG
495  TEUCHOS_TEST_FOR_EXCEPTION( !(hasReferenceCell(parentCell) ), std::invalid_argument,
496  ">>> ERROR (Intrepid::CellTools::getReferenceSubcellVertices): the specified cell topology does not have a reference cell.");
497 
498  // subcellDim can equal the cell dimension because the cell itself is a valid subcell! In this case
499  // the method will return all cell cellWorkset.
500  TEUCHOS_TEST_FOR_EXCEPTION( !( (0 <= subcellDim) && (subcellDim <= (int)parentCell.getDimension()) ), std::invalid_argument,
501  ">>> ERROR (Intrepid::CellTools::getReferenceSubcellVertices): subcell dimension out of range.");
502 
503  TEUCHOS_TEST_FOR_EXCEPTION( !( (0 <= subcellOrd) && (subcellOrd < (int)parentCell.getSubcellCount(subcellDim) ) ), std::invalid_argument,
504  ">>> ERROR (Intrepid::CellTools::getReferenceSubcellVertices): subcell ordinal out of range.");
505 
506  // Verify subcellVertices rank and dimensions
507  {
508  std::string errmsg = ">>> ERROR (Intrepid::CellTools::getReferenceSubcellVertices):";
509  TEUCHOS_TEST_FOR_EXCEPTION( !( requireRankRange(errmsg, subcellVertices, 2, 2) ), std::invalid_argument, errmsg);
510 
511  int subcVertexCount = parentCell.getVertexCount(subcellDim, subcellOrd);
512  int spaceDim = parentCell.getDimension();
513 
514  TEUCHOS_TEST_FOR_EXCEPTION( !( requireDimensionRange(errmsg, subcellVertices, 0, subcVertexCount, subcVertexCount) ),
515  std::invalid_argument, errmsg);
516 
517  TEUCHOS_TEST_FOR_EXCEPTION( !( requireDimensionRange(errmsg, subcellVertices, 1, spaceDim, spaceDim) ),
518  std::invalid_argument, errmsg);
519  }
520 #endif
521 
522  // Simply call getReferenceNodes with the base topology
523  getReferenceSubcellNodes(subcellVertices, subcellDim, subcellOrd, parentCell.getBaseCellTopologyData() );
524  }
525 
526 
527 
528  template<class Scalar>
529  const double* CellTools<Scalar>::getReferenceNode(const shards::CellTopology& cell,
530  const int nodeOrd){
531 
532 #ifdef HAVE_INTREPID_DEBUG
533  TEUCHOS_TEST_FOR_EXCEPTION( !(hasReferenceCell(cell) ), std::invalid_argument,
534  ">>> ERROR (Intrepid::CellTools::getReferenceNode): the specified cell topology does not have a reference cell.");
535 
536  TEUCHOS_TEST_FOR_EXCEPTION( !( (0 <= nodeOrd) && (nodeOrd < (int)cell.getNodeCount() ) ), std::invalid_argument,
537  ">>> ERROR (Intrepid::CellTools::getReferenceNode): invalid node ordinal for the specified cell topology. ");
538 #endif
539 
540  // Cartesian coordinates of supported reference cell cellWorkset, padded to three-dimensions.
541  // Node order follows cell topology definition in Shards
542  static const double line[2][3] ={
543  {-1.0, 0.0, 0.0}, { 1.0, 0.0, 0.0}
544  };
545  static const double line_3[3][3] = {
546  {-1.0, 0.0, 0.0}, { 1.0, 0.0, 0.0},
547  // Extension node: edge midpoint
548  { 0.0, 0.0, 0.0}
549  };
550 
551 
552  // Triangle topologies
553  static const double triangle[3][3] = {
554  { 0.0, 0.0, 0.0}, { 1.0, 0.0, 0.0}, { 0.0, 1.0, 0.0}
555  };
556  static const double triangle_4[4][3] = {
557  { 0.0, 0.0, 0.0}, { 1.0, 0.0, 0.0}, { 0.0, 1.0, 0.0},
558  // Extension node: cell center
559  { 1/3, 1/3, 0.0}
560  };
561  static const double triangle_6[6][3] = {
562  { 0.0, 0.0, 0.0}, { 1.0, 0.0, 0.0}, { 0.0, 1.0, 0.0},
563  // Extension cellWorkset: 3 edge midpoints
564  { 0.5, 0.0, 0.0}, { 0.5, 0.5, 0.0}, { 0.0, 0.5, 0.0}
565  };
566 
567 
568  // Quadrilateral topologies
569  static const double quadrilateral[4][3] = {
570  {-1.0,-1.0, 0.0}, { 1.0,-1.0, 0.0}, { 1.0, 1.0, 0.0}, {-1.0, 1.0, 0.0}
571  };
572  static const double quadrilateral_8[8][3] = {
573  {-1.0,-1.0, 0.0}, { 1.0,-1.0, 0.0}, { 1.0, 1.0, 0.0}, {-1.0, 1.0, 0.0},
574  // Extension cellWorkset: 4 edge midpoints
575  { 0.0,-1.0, 0.0}, { 1.0, 0.0, 0.0}, { 0.0, 1.0, 0.0}, {-1.0, 0.0, 0.0}
576  };
577  static const double quadrilateral_9[9][3] = {
578  {-1.0,-1.0, 0.0}, { 1.0,-1.0, 0.0}, { 1.0, 1.0, 0.0}, {-1.0, 1.0, 0.0},
579  // Extension cellWorkset: 4 edge midpoints + 1 cell center
580  { 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}
581  };
582 
583 
584  // Tetrahedron topologies
585  static const double tetrahedron[4][3] = {
586  { 0.0, 0.0, 0.0}, { 1.0, 0.0, 0.0}, { 0.0, 1.0, 0.0}, { 0.0, 0.0, 1.0}
587  };
588  static const double tetrahedron_8[8][3] = {
589  { 0.0, 0.0, 0.0}, { 1.0, 0.0, 0.0}, { 0.0, 1.0, 0.0}, { 0.0, 0.0, 1.0},
590  // Extension cellWorkset: 4 face centers (do not follow natural face order - see the cell topology!)
591  { 1/3, 0.0, 1/3}, { 1/3, 1/3, 1/3}, { 1/3, 1/3, 0.0}, { 0.0, 1/3, 1/3}
592  };
593  static const double tetrahedron_10[10][3] = {
594  { 0.0, 0.0, 0.0}, { 1.0, 0.0, 0.0}, { 0.0, 1.0, 0.0}, { 0.0, 0.0, 1.0},
595  // Extension cellWorkset: 6 edge midpoints
596  { 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}
597  };
598 
599  static const double tetrahedron_11[10][3] = {
600  { 0.0, 0.0, 0.0}, { 1.0, 0.0, 0.0}, { 0.0, 1.0, 0.0}, { 0.0, 0.0, 1.0},
601  // Extension cellWorkset: 6 edge midpoints
602  { 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}
603  };
604 
605 
606  // Hexahedron topologies
607  static const double hexahedron[8][3] = {
608  {-1.0,-1.0,-1.0}, { 1.0,-1.0,-1.0}, { 1.0, 1.0,-1.0}, {-1.0, 1.0,-1.0},
609  {-1.0,-1.0, 1.0}, { 1.0,-1.0, 1.0}, { 1.0, 1.0, 1.0}, {-1.0, 1.0, 1.0}
610  };
611  static const double hexahedron_20[20][3] = {
612  {-1.0,-1.0,-1.0}, { 1.0,-1.0,-1.0}, { 1.0, 1.0,-1.0}, {-1.0, 1.0,-1.0},
613  {-1.0,-1.0, 1.0}, { 1.0,-1.0, 1.0}, { 1.0, 1.0, 1.0}, {-1.0, 1.0, 1.0},
614  // Extension cellWorkset: 12 edge midpoints (do not follow natural edge order - see cell topology!)
615  { 0.0,-1.0,-1.0}, { 1.0, 0.0,-1.0}, { 0.0, 1.0,-1.0}, {-1.0, 0.0,-1.0},
616  {-1.0,-1.0, 0.0}, { 1.0,-1.0, 0.0}, { 1.0, 1.0, 0.0}, {-1.0, 1.0, 0.0},
617  { 0.0,-1.0, 1.0}, { 1.0, 0.0, 1.0}, { 0.0, 1.0, 1.0}, {-1.0, 0.0, 1.0}
618  };
619  static const double hexahedron_27[27][3] = {
620  {-1.0,-1.0,-1.0}, { 1.0,-1.0,-1.0}, { 1.0, 1.0,-1.0}, {-1.0, 1.0,-1.0},
621  {-1.0,-1.0, 1.0}, { 1.0,-1.0, 1.0}, { 1.0, 1.0, 1.0}, {-1.0, 1.0, 1.0},
622  // Extension cellWorkset: 12 edge midpoints + 1 cell center + 6 face centers (do not follow natural subcell order!)
623  { 0.0,-1.0,-1.0}, { 1.0, 0.0,-1.0}, { 0.0, 1.0,-1.0}, {-1.0, 0.0,-1.0},
624  {-1.0,-1.0, 0.0}, { 1.0,-1.0, 0.0}, { 1.0, 1.0, 0.0}, {-1.0, 1.0, 0.0},
625  { 0.0,-1.0, 1.0}, { 1.0, 0.0, 1.0}, { 0.0, 1.0, 1.0}, {-1.0, 0.0, 1.0},
626  { 0.0, 0.0, 0.0},
627  { 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}
628  };
629 
630 
631  // Pyramid topologies
632  static const double pyramid[5][3] = {
633  {-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}
634  };
635  static const double pyramid_13[13][3] = {
636  {-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},
637  // Extension cellWorkset: 8 edge midpoints
638  { 0.0,-1.0, 0.0}, { 1.0, 0.0, 0.0}, { 0.0, 1.0, 0.0}, {-1.0, 0.0, 0.0},
639  {-0.5,-0.5, 0.5}, { 0.5,-0.5, 0.5}, { 0.5, 0.5, 0.5}, {-0.5, 0.5, 0.5}
640  };
641  static const double pyramid_14[14][3] = {
642  {-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},
643  // Extension cellWorkset: 8 edge midpoints + quadrilateral face midpoint
644  { 0.0,-1.0, 0.0}, { 1.0, 0.0, 0.0}, { 0.0, 1.0, 0.0}, {-1.0, 0.0, 0.0},
645  {-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}
646  };
647 
648 
649  // Wedge topologies
650  static const double wedge[6][3] = {
651  { 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}
652  };
653  static const double wedge_15[15][3] = {
654  { 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},
655  // Extension cellWorkset: 9 edge midpoints (do not follow natural edge order - see cell topology!)
656  { 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},
657  { 0.5, 0.0, 1.0}, { 0.5, 0.5, 1.0}, { 0.0, 0.5, 1.0}
658  };
659  static const double wedge_18[18][3] = {
660  { 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},
661  // Extension cellWorkset: 9 edge midpoints + 3 quad face centers (do not follow natural subcell order - see cell topology!)
662  { 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},
663  { 0.5, 0.0, 1.0}, { 0.5, 0.5, 1.0}, { 0.0, 0.5, 1.0},
664  { 0.5, 0.0, 0.0}, { 0.5, 0.5, 0.0}, { 0.0, 0.5, 0.0}
665  };
666 
667 
668  switch(cell.getKey() ) {
669 
670  // Base line topologies
671  case shards::Line<2>::key:
672  case shards::ShellLine<2>::key:
673  case shards::Beam<2>::key:
674  return line[nodeOrd];
675  break;
676 
677  // Extended line topologies
678  case shards::Line<3>::key:
679  case shards::ShellLine<3>::key:
680  case shards::Beam<3>::key:
681  return line_3[nodeOrd];
682  break;
683 
684 
685  // Base triangle topologies
686  case shards::Triangle<3>::key:
687  case shards::ShellTriangle<3>::key:
688  return triangle[nodeOrd];
689  break;
690 
691  // Extened Triangle topologies
692  case shards::Triangle<4>::key:
693  return triangle_4[nodeOrd];
694  break;
695  case shards::Triangle<6>::key:
696  case shards::ShellTriangle<6>::key:
697  return triangle_6[nodeOrd];
698  break;
699 
700 
701  // Base Quadrilateral topologies
702  case shards::Quadrilateral<4>::key:
703  case shards::ShellQuadrilateral<4>::key:
704  return quadrilateral[nodeOrd];
705  break;
706 
707  // Extended Quadrilateral topologies
708  case shards::Quadrilateral<8>::key:
709  case shards::ShellQuadrilateral<8>::key:
710  return quadrilateral_8[nodeOrd];
711  break;
712  case shards::Quadrilateral<9>::key:
713  case shards::ShellQuadrilateral<9>::key:
714  return quadrilateral_9[nodeOrd];
715  break;
716 
717 
718  // Base Tetrahedron topology
719  case shards::Tetrahedron<4>::key:
720  return tetrahedron[nodeOrd];
721  break;
722 
723  // Extended Tetrahedron topologies
724  case shards::Tetrahedron<8>::key:
725  return tetrahedron_8[nodeOrd];
726  break;
727  case shards::Tetrahedron<10>::key:
728  return tetrahedron_10[nodeOrd];
729  break;
730  case shards::Tetrahedron<11>::key:
731  return tetrahedron_11[nodeOrd];
732  break;
733 
734 
735  // Base Hexahedron topology
736  case shards::Hexahedron<8>::key:
737  return hexahedron[nodeOrd];
738  break;
739 
740  // Extended Hexahedron topologies
741  case shards::Hexahedron<20>::key:
742  return hexahedron_20[nodeOrd];
743  break;
744  case shards::Hexahedron<27>::key:
745  return hexahedron_27[nodeOrd];
746  break;
747 
748 
749  // Base Pyramid topology
750  case shards::Pyramid<5>::key:
751  return pyramid[nodeOrd];
752  break;
753 
754  // Extended pyramid topologies
755  case shards::Pyramid<13>::key:
756  return pyramid_13[nodeOrd];
757  break;
758  case shards::Pyramid<14>::key:
759  return pyramid_14[nodeOrd];
760  break;
761 
762 
763  // Base Wedge topology
764  case shards::Wedge<6>::key:
765  return wedge[nodeOrd];
766  break;
767 
768  // Extended Wedge topologies
769  case shards::Wedge<15>::key:
770  return wedge_15[nodeOrd];
771  break;
772  case shards::Wedge<18>::key:
773  return wedge_18[nodeOrd];
774  break;
775 
776  default:
777  TEUCHOS_TEST_FOR_EXCEPTION( true, std::invalid_argument,
778  ">>> ERROR (Intrepid::CellTools::getReferenceNode): invalid cell topology.");
779  }
780  // To disable compiler warning, should never be reached
781  return line[0];
782  }
783 
784 
785 
786  template<class Scalar>
787  template<class ArraySubcellNode>
788  void CellTools<Scalar>::getReferenceSubcellNodes(ArraySubcellNode & subcellNodes,
789  const int subcellDim,
790  const int subcellOrd,
791  const shards::CellTopology& parentCell){
792 #ifdef HAVE_INTREPID_DEBUG
793  TEUCHOS_TEST_FOR_EXCEPTION( !(hasReferenceCell(parentCell) ), std::invalid_argument,
794  ">>> ERROR (Intrepid::CellTools::getReferenceSubcellNodes): the specified cell topology does not have a reference cell.");
795 
796  // subcellDim can equal the cell dimension because the cell itself is a valid subcell! In this case
797  // the method will return all cell cellWorkset.
798  TEUCHOS_TEST_FOR_EXCEPTION( !( (0 <= subcellDim) && (subcellDim <= (int)parentCell.getDimension()) ), std::invalid_argument,
799  ">>> ERROR (Intrepid::CellTools::getReferenceSubcellNodes): subcell dimension out of range.");
800 
801  TEUCHOS_TEST_FOR_EXCEPTION( !( (0 <= subcellOrd) && (subcellOrd < (int)parentCell.getSubcellCount(subcellDim) ) ), std::invalid_argument,
802  ">>> ERROR (Intrepid::CellTools::getReferenceSubcellNodes): subcell ordinal out of range.");
803 
804  // Verify subcellNodes rank and dimensions
805  {
806  std::string errmsg = ">>> ERROR (Intrepid::CellTools::getReferenceSubcellNodes):";
807  TEUCHOS_TEST_FOR_EXCEPTION( !( requireRankRange(errmsg, subcellNodes, 2, 2) ), std::invalid_argument, errmsg);
808 
809  int subcNodeCount = parentCell.getNodeCount(subcellDim, subcellOrd);
810  int spaceDim = parentCell.getDimension();
811 
812  TEUCHOS_TEST_FOR_EXCEPTION( !( requireDimensionRange(errmsg, subcellNodes, 0, subcNodeCount, subcNodeCount) ),
813  std::invalid_argument, errmsg);
814 
815  TEUCHOS_TEST_FOR_EXCEPTION( !( requireDimensionRange(errmsg, subcellNodes, 1, spaceDim, spaceDim) ),
816  std::invalid_argument, errmsg);
817  }
818 #endif
819 
820  // Find how many cellWorkset does the specified subcell have.
821  int subcNodeCount = parentCell.getNodeCount(subcellDim, subcellOrd);
822 
823  // Loop over subcell cellWorkset
824  for(int subcNodeOrd = 0; subcNodeOrd < subcNodeCount; subcNodeOrd++){
825 
826  // Get the node number relative to the parent reference cell
827  int cellNodeOrd = parentCell.getNodeMap(subcellDim, subcellOrd, subcNodeOrd);
828 
829  // Loop over node's Cartesian coordinates
830  for(int dim = 0; dim < (int)parentCell.getDimension(); dim++){
831  subcellNodes(subcNodeOrd, dim) = CellTools::getReferenceNode(parentCell, cellNodeOrd)[dim];
832  }
833  }
834  }
835 
836 
837 
838  template<class Scalar>
839  int CellTools<Scalar>::hasReferenceCell(const shards::CellTopology& cell) {
840 
841  switch(cell.getKey() ) {
842  case shards::Line<2>::key:
843  case shards::Line<3>::key:
844  case shards::ShellLine<2>::key:
845  case shards::ShellLine<3>::key:
846  case shards::Beam<2>::key:
847  case shards::Beam<3>::key:
848 
849  case shards::Triangle<3>::key:
850  case shards::Triangle<4>::key:
851  case shards::Triangle<6>::key:
852  case shards::ShellTriangle<3>::key:
853  case shards::ShellTriangle<6>::key:
854 
855  case shards::Quadrilateral<4>::key:
856  case shards::Quadrilateral<8>::key:
857  case shards::Quadrilateral<9>::key:
858  case shards::ShellQuadrilateral<4>::key:
859  case shards::ShellQuadrilateral<8>::key:
860  case shards::ShellQuadrilateral<9>::key:
861 
862  case shards::Tetrahedron<4>::key:
863  case shards::Tetrahedron<8>::key:
864  case shards::Tetrahedron<10>::key:
865  case shards::Tetrahedron<11>::key:
866 
867  case shards::Hexahedron<8>::key:
868  case shards::Hexahedron<20>::key:
869  case shards::Hexahedron<27>::key:
870 
871  case shards::Pyramid<5>::key:
872  case shards::Pyramid<13>::key:
873  case shards::Pyramid<14>::key:
874 
875  case shards::Wedge<6>::key:
876  case shards::Wedge<15>::key:
877  case shards::Wedge<18>::key:
878  return 1;
879  break;
880 
881  default:
882  return 0;
883  }
884  return 0;
885  }
886 
887  //============================================================================================//
888  // //
889  // Jacobian, inverse Jacobian and Jacobian determinant //
890  // //
891  //============================================================================================//
892 
893 
894 
895 
896  template<class Scalar>
897  template<class ArrayJac, class ArrayPoint, class ArrayCell>
898  void CellTools<Scalar>::setJacobian(ArrayJac & jacobian,
899  const ArrayPoint & points,
900  const ArrayCell & cellWorkset,
901  const shards::CellTopology & cellTopo,
902  const int & whichCell)
903  {
904  INTREPID_VALIDATE( validateArguments_setJacobian(jacobian, points, cellWorkset, whichCell, cellTopo) );
905 
906  ArrayWrapper<Scalar,ArrayJac, Rank<ArrayJac >::value, false>jacobianWrap(jacobian);
907  ArrayWrapper<Scalar,ArrayPoint, Rank<ArrayPoint >::value, true>pointsWrap(points);
908  ArrayWrapper<Scalar,ArrayCell, Rank<ArrayCell >::value, true>cellWorksetWrap(cellWorkset);
909  int spaceDim = (size_t)cellTopo.getDimension();
910  size_t numCells = static_cast<size_t>(cellWorkset.dimension(0));
911  //points can be rank-2 (P,D), or rank-3 (C,P,D)
912  size_t numPoints = (getrank(points) == 2) ? static_cast<size_t>(points.dimension(0)) : static_cast<size_t>(points.dimension(1));
913 
914  // Jacobian is computed using gradients of an appropriate H(grad) basis function: define RCP to the base class
915  Teuchos::RCP< Basis< Scalar, FieldContainer<Scalar> > > HGRAD_Basis;
916 
917  // Choose the H(grad) basis depending on the cell topology. \todo define maps for shells and beams
918  switch( cellTopo.getKey() ){
919 
920  // Standard Base topologies (number of cellWorkset = number of vertices)
921  case shards::Line<2>::key:
922  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_LINE_C1_FEM<Scalar, FieldContainer<Scalar> >() );
923  break;
924 
925  case shards::Triangle<3>::key:
926  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_TRI_C1_FEM<Scalar, FieldContainer<Scalar> >() );
927  break;
928 
929  case shards::Quadrilateral<4>::key:
930  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_QUAD_C1_FEM<Scalar, FieldContainer<Scalar> >() );
931  break;
932 
933  case shards::Tetrahedron<4>::key:
934  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_TET_C1_FEM<Scalar, FieldContainer<Scalar> >() );
935  break;
936 
937  case shards::Hexahedron<8>::key:
938  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_HEX_C1_FEM<Scalar, FieldContainer<Scalar> >() );
939  break;
940 
941  case shards::Wedge<6>::key:
942  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_WEDGE_C1_FEM<Scalar, FieldContainer<Scalar> >() );
943  break;
944 
945  case shards::Pyramid<5>::key:
946  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_PYR_C1_FEM<Scalar, FieldContainer<Scalar> >() );
947  break;
948 
949  // Standard Extended topologies
950  case shards::Triangle<6>::key:
951  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_TRI_C2_FEM<Scalar, FieldContainer<Scalar> >() );
952  break;
953  case shards::Quadrilateral<9>::key:
954  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_QUAD_C2_FEM<Scalar, FieldContainer<Scalar> >() );
955  break;
956 
957  case shards::Tetrahedron<10>::key:
958  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_TET_C2_FEM<Scalar, FieldContainer<Scalar> >() );
959  break;
960 
961  case shards::Tetrahedron<11>::key:
962  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_TET_COMP12_FEM<Scalar, FieldContainer<Scalar> >() );
963  break;
964 
965  case shards::Hexahedron<20>::key:
966  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_HEX_I2_FEM<Scalar, FieldContainer<Scalar> >() );
967  break;
968 
969  case shards::Hexahedron<27>::key:
970  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_HEX_C2_FEM<Scalar, FieldContainer<Scalar> >() );
971  break;
972 
973  case shards::Wedge<15>::key:
974  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_WEDGE_I2_FEM<Scalar, FieldContainer<Scalar> >() );
975  break;
976 
977  case shards::Wedge<18>::key:
978  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_WEDGE_C2_FEM<Scalar, FieldContainer<Scalar> >() );
979  break;
980 
981  case shards::Pyramid<13>::key:
982  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_PYR_I2_FEM<Scalar, FieldContainer<Scalar> >() );
983  break;
984 
985  // These extended topologies are not used for mapping purposes
986  case shards::Quadrilateral<8>::key:
987  TEUCHOS_TEST_FOR_EXCEPTION( (true), std::invalid_argument,
988  ">>> ERROR (Intrepid::CellTools::setJacobian): Cell topology not supported. ");
989  break;
990 
991  // Base and Extended Line, Beam and Shell topologies
992  case shards::Line<3>::key:
993  case shards::Beam<2>::key:
994  case shards::Beam<3>::key:
995  case shards::ShellLine<2>::key:
996  case shards::ShellLine<3>::key:
997  case shards::ShellTriangle<3>::key:
998  case shards::ShellTriangle<6>::key:
999  case shards::ShellQuadrilateral<4>::key:
1000  case shards::ShellQuadrilateral<8>::key:
1001  case shards::ShellQuadrilateral<9>::key:
1002  TEUCHOS_TEST_FOR_EXCEPTION( (true), std::invalid_argument,
1003  ">>> ERROR (Intrepid::CellTools::setJacobian): Cell topology not supported. ");
1004  break;
1005  default:
1006  TEUCHOS_TEST_FOR_EXCEPTION( (true), std::invalid_argument,
1007  ">>> ERROR (Intrepid::CellTools::setJacobian): Cell topology not supported.");
1008  }// switch
1009 
1010  // Temp (F,P,D) array for the values of basis functions gradients at the reference points
1011  int basisCardinality = HGRAD_Basis -> getCardinality();
1012  FieldContainer<Scalar> basisGrads(basisCardinality, numPoints, spaceDim);
1013 
1014 
1015 if(getrank(jacobian)==4){
1016  for (size_t i=0; i< static_cast<size_t>(jacobian.dimension(0)); i++){
1017  for (size_t j=0; j< static_cast<size_t>(jacobian.dimension(1)); j++){
1018  for (size_t k=0; k< static_cast<size_t>(jacobian.dimension(2)); k++){
1019  for (size_t l=0; l< static_cast<size_t>(jacobian.dimension(3)); l++){
1020  jacobianWrap(i,j,k,l)=0.0;
1021  }
1022  }
1023  }
1024  }
1025 }
1026 
1027 if(getrank(jacobian)==3){
1028  for (size_t i=0; i< static_cast<size_t>(jacobian.dimension(0)); i++){
1029  for (size_t j=0; j< static_cast<size_t>(jacobian.dimension(1)); j++){
1030  for (size_t k=0; k< static_cast<size_t>(jacobian.dimension(2)); k++){
1031  jacobianWrap(i,j,k)=0.0;
1032  }
1033  }
1034  }
1035 }
1036  // Handle separately rank-2 (P,D) and rank-3 (C,P,D) cases of points arrays.
1037  switch(getrank(points)) {
1038 
1039  // refPoints is (P,D): a single or multiple cell jacobians computed for a single set of ref. points
1040  case 2:
1041  {
1042  // getValues requires rank-2 (P,D) input array, but points cannot be passed directly as argument because they are a user type
1043  FieldContainer<Scalar> tempPoints( static_cast<size_t>(points.dimension(0)), static_cast<size_t>(points.dimension(1)) );
1044  // Copy point set corresponding to this cell oridinal to the temp (P,D) array
1045  for(size_t pt = 0; pt < static_cast<size_t>(points.dimension(0)); pt++){
1046  for(size_t dm = 0; dm < static_cast<size_t>(points.dimension(1)) ; dm++){
1047  tempPoints(pt, dm) = pointsWrap(pt, dm);
1048  }//dm
1049  }//pt
1050 
1051  HGRAD_Basis -> getValues(basisGrads, tempPoints, OPERATOR_GRAD);
1052 
1053  // The outer loops select the multi-index of the Jacobian entry: cell, point, row, col
1054  // If whichCell = -1, all jacobians are computed, otherwise a single cell jacobian is computed
1055  size_t cellLoop = (whichCell == -1) ? numCells : 1 ;
1056 
1057  if(whichCell == -1) {
1058  for(size_t cellOrd = 0; cellOrd < cellLoop; cellOrd++) {
1059  for(size_t pointOrd = 0; pointOrd < numPoints; pointOrd++) {
1060  for(int row = 0; row < spaceDim; row++){
1061  for(int col = 0; col < spaceDim; col++){
1062 
1063  // The entry is computed by contracting the basis index. Number of basis functions and vertices must be the same.
1064  for(int bfOrd = 0; bfOrd < basisCardinality; bfOrd++){
1065  jacobianWrap(cellOrd, pointOrd, row, col) += cellWorksetWrap(cellOrd, bfOrd, row)*basisGrads(bfOrd, pointOrd, col);
1066  } // bfOrd
1067  } // col
1068  } // row
1069  } // pointOrd
1070  } // cellOrd
1071 
1072  //}
1073 
1074  }
1075  else {
1076  for(size_t cellOrd = 0; cellOrd < cellLoop; cellOrd++) {
1077  for(size_t pointOrd = 0; pointOrd < numPoints; pointOrd++) {
1078  for(int row = 0; row < spaceDim; row++){
1079  for(int col = 0; col < spaceDim; col++){
1080 
1081  // The entry is computed by contracting the basis index. Number of basis functions and vertices must be the same.
1082  for(int bfOrd = 0; bfOrd < basisCardinality; bfOrd++){
1083  jacobianWrap(pointOrd, row, col) += cellWorksetWrap(whichCell, bfOrd, row)*basisGrads(bfOrd, pointOrd, col);
1084  } // bfOrd
1085  } // col
1086  } // row
1087  } // pointOrd
1088  } // cellOrd
1089 // }
1090  } // if whichcell
1091  }// case 2
1092  break;
1093 
1094  // points is (C,P,D): multiple jacobians computed at multiple point sets, one jacobian per cell
1095  case 3:
1096  {
1097  // getValues requires rank-2 (P,D) input array, refPoints cannot be used as argument: need temp (P,D) array
1098  FieldContainer<Scalar> tempPoints( static_cast<size_t>(points.dimension(1)), static_cast<size_t>(points.dimension(2)) );
1099  for(size_t cellOrd = 0; cellOrd < numCells; cellOrd++) {
1100 
1101  // Copy point set corresponding to this cell oridinal to the temp (P,D) array
1102  for(size_t pt = 0; pt < static_cast<size_t>(points.dimension(1)); pt++){
1103  for(size_t dm = 0; dm < static_cast<size_t>(points.dimension(2)) ; dm++){
1104  tempPoints(pt, dm) = pointsWrap(cellOrd, pt, dm);
1105  }//dm
1106  }//pt
1107 
1108  // Compute gradients of basis functions at this set of ref. points
1109  HGRAD_Basis -> getValues(basisGrads, tempPoints, OPERATOR_GRAD);
1110 
1111  // Compute jacobians for the point set corresponding to the current cellordinal
1112  for(size_t pointOrd = 0; pointOrd < numPoints; pointOrd++) {
1113  for(int row = 0; row < spaceDim; row++){
1114  for(int col = 0; col < spaceDim; col++){
1115 
1116  // The entry is computed by contracting the basis index. Number of basis functions and vertices must be the same
1117  for(int bfOrd = 0; bfOrd < basisCardinality; bfOrd++){
1118  jacobianWrap(cellOrd, pointOrd, row, col) += cellWorksetWrap(cellOrd, bfOrd, row)*basisGrads(bfOrd, pointOrd, col);
1119  } // bfOrd
1120  } // col
1121  } // row
1122  } // pointOrd
1123  }//cellOrd
1124 // }
1125  }// case 3
1126 
1127  break;
1128 
1129  default:
1130  TEUCHOS_TEST_FOR_EXCEPTION( !( (getrank(points) == 2) && (getrank(points) == 3) ), std::invalid_argument,
1131  ">>> ERROR (Intrepid::CellTools::setJacobian): rank 2 or 3 required for points array. ");
1132  }//switch
1133  }
1134 
1135 
1136  template<class Scalar>
1137  template<class ArrayJac, class ArrayPoint, class ArrayCell>
1138  void CellTools<Scalar>::setJacobian(ArrayJac & jacobian,
1139  const ArrayPoint & points,
1140  const ArrayCell & cellWorkset,
1141  const Teuchos::RCP< Basis< Scalar, FieldContainer<Scalar> > > HGRAD_Basis,
1142  const int & whichCell)
1143  {
1144  //IKT, 10/7/15: OK to not validate arguments for this implementation?
1145  //INTREPID_VALIDATE( validateArguments_setJacobian(jacobian, points, cellWorkset, whichCell, cellTopo) );
1146 
1147  ArrayWrapper<Scalar,ArrayJac, Rank<ArrayJac >::value, false>jacobianWrap(jacobian);
1148  ArrayWrapper<Scalar,ArrayPoint, Rank<ArrayPoint >::value, true>pointsWrap(points);
1149  ArrayWrapper<Scalar,ArrayCell, Rank<ArrayCell >::value, true>cellWorksetWrap(cellWorkset);
1150  int spaceDim = (size_t)HGRAD_Basis->getBaseCellTopology().getDimension();
1151  size_t numCells = static_cast<size_t>(cellWorkset.dimension(0));
1152  //points can be rank-2 (P,D), or rank-3 (C,P,D)
1153  size_t numPoints = (getrank(points) == 2) ? static_cast<size_t>(points.dimension(0)) : static_cast<size_t>(points.dimension(1));
1154 
1155  // Temp (F,P,D) array for the values of basis functions gradients at the reference points
1156  int basisCardinality = HGRAD_Basis -> getCardinality();
1157  FieldContainer<Scalar> basisGrads(basisCardinality, numPoints, spaceDim);
1158 
1159 
1160 if(getrank(jacobian)==4){
1161  for (size_t i=0; i< static_cast<size_t>(jacobian.dimension(0)); i++){
1162  for (size_t j=0; j< static_cast<size_t>(jacobian.dimension(1)); j++){
1163  for (size_t k=0; k< static_cast<size_t>(jacobian.dimension(2)); k++){
1164  for (size_t l=0; l< static_cast<size_t>(jacobian.dimension(3)); l++){
1165  jacobianWrap(i,j,k,l)=0.0;
1166  }
1167  }
1168  }
1169  }
1170 }
1171 
1172 if(getrank(jacobian)==3){
1173  for (size_t i=0; i< static_cast<size_t>(jacobian.dimension(0)); i++){
1174  for (size_t j=0; j< static_cast<size_t>(jacobian.dimension(1)); j++){
1175  for (size_t k=0; k< static_cast<size_t>(jacobian.dimension(2)); k++){
1176  jacobianWrap(i,j,k)=0.0;
1177  }
1178  }
1179  }
1180 }
1181  // Handle separately rank-2 (P,D) and rank-3 (C,P,D) cases of points arrays.
1182  switch(getrank(points)) {
1183 
1184  // refPoints is (P,D): a single or multiple cell jacobians computed for a single set of ref. points
1185  case 2:
1186  {
1187  // getValues requires rank-2 (P,D) input array, but points cannot be passed directly as argument because they are a user type
1188  FieldContainer<Scalar> tempPoints( static_cast<size_t>(points.dimension(0)), static_cast<size_t>(points.dimension(1)) );
1189  // Copy point set corresponding to this cell oridinal to the temp (P,D) array
1190  for(size_t pt = 0; pt < static_cast<size_t>(points.dimension(0)); pt++){
1191  for(size_t dm = 0; dm < static_cast<size_t>(points.dimension(1)) ; dm++){
1192  tempPoints(pt, dm) = pointsWrap(pt, dm);
1193  }//dm
1194  }//pt
1195 
1196  HGRAD_Basis -> getValues(basisGrads, tempPoints, OPERATOR_GRAD);
1197 
1198  // The outer loops select the multi-index of the Jacobian entry: cell, point, row, col
1199  // If whichCell = -1, all jacobians are computed, otherwise a single cell jacobian is computed
1200  size_t cellLoop = (whichCell == -1) ? numCells : 1 ;
1201 
1202  if(whichCell == -1) {
1203  for(size_t cellOrd = 0; cellOrd < cellLoop; cellOrd++) {
1204  for(size_t pointOrd = 0; pointOrd < numPoints; pointOrd++) {
1205  for(int row = 0; row < spaceDim; row++){
1206  for(int col = 0; col < spaceDim; col++){
1207 
1208  // The entry is computed by contracting the basis index. Number of basis functions and vertices must be the same.
1209  for(int bfOrd = 0; bfOrd < basisCardinality; bfOrd++){
1210  jacobianWrap(cellOrd, pointOrd, row, col) += cellWorksetWrap(cellOrd, bfOrd, row)*basisGrads(bfOrd, pointOrd, col);
1211  } // bfOrd
1212  } // col
1213  } // row
1214  } // pointOrd
1215  } // cellOrd
1216 
1217  //}
1218 
1219  }
1220  else {
1221  for(size_t cellOrd = 0; cellOrd < cellLoop; cellOrd++) {
1222  for(size_t pointOrd = 0; pointOrd < numPoints; pointOrd++) {
1223  for(int row = 0; row < spaceDim; row++){
1224  for(int col = 0; col < spaceDim; col++){
1225 
1226  // The entry is computed by contracting the basis index. Number of basis functions and vertices must be the same.
1227  for(int bfOrd = 0; bfOrd < basisCardinality; bfOrd++){
1228  jacobianWrap(pointOrd, row, col) += cellWorksetWrap(whichCell, bfOrd, row)*basisGrads(bfOrd, pointOrd, col);
1229  } // bfOrd
1230  } // col
1231  } // row
1232  } // pointOrd
1233  } // cellOrd
1234 // }
1235  } // if whichcell
1236  }// case 2
1237  break;
1238 
1239  // points is (C,P,D): multiple jacobians computed at multiple point sets, one jacobian per cell
1240  case 3:
1241  {
1242  // getValues requires rank-2 (P,D) input array, refPoints cannot be used as argument: need temp (P,D) array
1243  FieldContainer<Scalar> tempPoints( static_cast<size_t>(points.dimension(1)), static_cast<size_t>(points.dimension(2)) );
1244  for(size_t cellOrd = 0; cellOrd < numCells; cellOrd++) {
1245 
1246  // Copy point set corresponding to this cell oridinal to the temp (P,D) array
1247  for(size_t pt = 0; pt < static_cast<size_t>(points.dimension(1)); pt++){
1248  for(size_t dm = 0; dm < static_cast<size_t>(points.dimension(2)) ; dm++){
1249  tempPoints(pt, dm) = pointsWrap(cellOrd, pt, dm);
1250  }//dm
1251  }//pt
1252 
1253  // Compute gradients of basis functions at this set of ref. points
1254  HGRAD_Basis -> getValues(basisGrads, tempPoints, OPERATOR_GRAD);
1255 
1256  // Compute jacobians for the point set corresponding to the current cellordinal
1257  for(size_t pointOrd = 0; pointOrd < numPoints; pointOrd++) {
1258  for(int row = 0; row < spaceDim; row++){
1259  for(int col = 0; col < spaceDim; col++){
1260 
1261  // The entry is computed by contracting the basis index. Number of basis functions and vertices must be the same
1262  for(int bfOrd = 0; bfOrd < basisCardinality; bfOrd++){
1263  jacobianWrap(cellOrd, pointOrd, row, col) += cellWorksetWrap(cellOrd, bfOrd, row)*basisGrads(bfOrd, pointOrd, col);
1264  } // bfOrd
1265  } // col
1266  } // row
1267  } // pointOrd
1268  }//cellOrd
1269 // }
1270  }// case 3
1271 
1272  break;
1273 
1274  default:
1275  TEUCHOS_TEST_FOR_EXCEPTION( !( (getrank(points) == 2) && (getrank(points) == 3) ), std::invalid_argument,
1276  ">>> ERROR (Intrepid::CellTools::setJacobian): rank 2 or 3 required for points array. ");
1277  }//switch
1278 
1279  }
1280 
1281 template<class Scalar>
1282 template<class ArrayJacInv, class ArrayJac>
1283 void CellTools<Scalar>::setJacobianInv(ArrayJacInv & jacobianInv,
1284  const ArrayJac & jacobian)
1285 {
1286  INTREPID_VALIDATE( validateArguments_setJacobianInv(jacobianInv, jacobian) );
1287 
1288  RealSpaceTools<Scalar>::inverse(jacobianInv, jacobian);
1289 }
1290 /*
1291 template<class Scalar>
1292 template<class ArrayJacInv, class ArrayJac>
1293 void CellTools<Scalar>::setJacobianInvTemp(ArrayJacInv & jacobianInv,
1294  const ArrayJac & jacobian)
1295 {
1296 
1297 
1298  RealSpaceTools<Scalar>::inverseTemp(jacobianInv, jacobian);
1299 }
1300 */
1301 /*
1302 template<class Scalar>
1303 template<class ArrayJacDet, class ArrayJac>
1304 void CellTools<Scalar>::setJacobianDet(ArrayJacDet & jacobianDet,
1305  const ArrayJac & jacobian)
1306 {
1307  INTREPID_VALIDATE( validateArguments_setJacobianDetArgs(jacobianDet, jacobian) );
1308 
1309  RealSpaceTools<Scalar>::det(jacobianDet, jacobian);
1310 }
1311 */
1312 template<class Scalar>
1313 template<class ArrayJacDet, class ArrayJac>
1314 void CellTools<Scalar>::setJacobianDet(ArrayJacDet & jacobianDet,
1315  const ArrayJac & jacobian)
1316 {
1317  INTREPID_VALIDATE( validateArguments_setJacobianDetArgs(jacobianDet, jacobian) );
1318  RealSpaceTools<Scalar>::det(jacobianDet, jacobian);
1319 }
1320 
1321 //============================================================================================//
1322 // //
1323 // Reference-to-physical frame mapping and its inverse //
1324 // //
1325 //============================================================================================//
1326 
1327 template<class Scalar>
1328 template<class ArrayPhysPoint, class ArrayRefPoint, class ArrayCell>
1329 void CellTools<Scalar>::mapToPhysicalFrame(ArrayPhysPoint & physPoints,
1330  const ArrayRefPoint & refPoints,
1331  const ArrayCell & cellWorkset,
1332  const Teuchos::RCP< Basis< Scalar, FieldContainer<Scalar> > > HGRAD_Basis,
1333  const int & whichCell)
1334 {
1335  //INTREPID_VALIDATE(validateArguments_mapToPhysicalFrame( physPoints, refPoints, cellWorkset, cellTopo, whichCell) );
1336 
1337  ArrayWrapper<Scalar,ArrayPhysPoint, Rank<ArrayPhysPoint >::value, false>physPointsWrap(physPoints);
1338  ArrayWrapper<Scalar,ArrayRefPoint, Rank<ArrayRefPoint >::value, true>refPointsWrap(refPoints);
1339  ArrayWrapper<Scalar,ArrayCell, Rank<ArrayCell >::value,true>cellWorksetWrap(cellWorkset);
1340 
1341  size_t spaceDim = (size_t)HGRAD_Basis->getBaseCellTopology().getDimension();
1342 
1343  size_t numCells = static_cast<size_t>(cellWorkset.dimension(0));
1344  //points can be rank-2 (P,D), or rank-3 (C,P,D)
1345  size_t numPoints = (getrank(refPoints) == 2) ? static_cast<size_t>(refPoints.dimension(0)) : static_cast<size_t>(refPoints.dimension(1));
1346 
1347  // Temp (F,P) array for the values of nodal basis functions at the reference points
1348  int basisCardinality = HGRAD_Basis -> getCardinality();
1349  FieldContainer<Scalar> basisVals(basisCardinality, numPoints);
1350 
1351 //#ifndef INTREPID_OLD_KOKKOS_CODE
1352  // Initialize physPoints
1353  if(getrank(physPoints)==3){
1354 for(size_t i = 0; i < static_cast<size_t>(physPoints.dimension(0)); i++) {
1355  for(size_t j = 0; j < static_cast<size_t>(physPoints.dimension(1)); j++){
1356  for(size_t k = 0; k < static_cast<size_t>(physPoints.dimension(2)); k++){
1357  physPointsWrap(i,j,k) = 0.0;
1358  }
1359  }
1360 }
1361  }else if(getrank(physPoints)==2){
1362  for(size_t i = 0; i < static_cast<size_t>(physPoints.dimension(0)); i++){
1363  for(size_t j = 0; j < static_cast<size_t>(physPoints.dimension(1)); j++){
1364  physPointsWrap(i,j) = 0.0;
1365  }
1366  }
1367 
1368  }
1369 
1370 //#else
1371 // Kokkos::deep_copy(physPoints.get_kokkos_view(), Scalar(0.0));
1372 //#endif
1373  // handle separately rank-2 (P,D) and rank-3 (C,P,D) cases of refPoints
1374  switch(getrank(refPoints)) {
1375 
1376  // refPoints is (P,D): single set of ref. points is mapped to one or multiple physical cells
1377  case 2:
1378  {
1379 
1380  // getValues requires rank-2 (P,D) input array, but refPoints cannot be passed directly as argument because they are a user type
1381  FieldContainer<Scalar> tempPoints( static_cast<size_t>(refPoints.dimension(0)), static_cast<size_t>(refPoints.dimension(1)) );
1382  // Copy point set corresponding to this cell oridinal to the temp (P,D) array
1383  for(size_t pt = 0; pt < static_cast<size_t>(refPoints.dimension(0)); pt++){
1384  for(size_t dm = 0; dm < static_cast<size_t>(refPoints.dimension(1)) ; dm++){
1385  tempPoints(pt, dm) = refPointsWrap(pt, dm);
1386  }//dm
1387  }//pt
1388  HGRAD_Basis -> getValues(basisVals, tempPoints, OPERATOR_VALUE);
1389 
1390  // If whichCell = -1, ref pt. set is mapped to all cells, otherwise, the set is mapped to one cell only
1391  size_t cellLoop = (whichCell == -1) ? numCells : 1 ;
1392 
1393  // Compute the map F(refPoints) = sum node_coordinate*basis(refPoints)
1394  for(size_t cellOrd = 0; cellOrd < cellLoop; cellOrd++) {
1395  for(size_t pointOrd = 0; pointOrd < numPoints; pointOrd++) {
1396  for(size_t dim = 0; dim < spaceDim; dim++){
1397  for(int bfOrd = 0; bfOrd < basisCardinality; bfOrd++){
1398 
1399  if(whichCell == -1){
1400  physPointsWrap(cellOrd, pointOrd, dim) += cellWorksetWrap(cellOrd, bfOrd, dim)*basisVals(bfOrd, pointOrd);
1401  }
1402  else{
1403  physPointsWrap(pointOrd, dim) += cellWorksetWrap(whichCell, bfOrd, dim)*basisVals(bfOrd, pointOrd);
1404  }
1405  } // bfOrd
1406  }// dim
1407  }// pointOrd
1408  }//cellOrd
1409  }// case 2
1410 
1411  break;
1412 
1413  // refPoints is (C,P,D): multiple sets of ref. points are mapped to matching number of physical cells.
1414  case 3:
1415  {
1416 
1417  // getValues requires rank-2 (P,D) input array, refPoints cannot be used as argument: need temp (P,D) array
1418  FieldContainer<Scalar> tempPoints( static_cast<size_t>(refPoints.dimension(1)), static_cast<size_t>(refPoints.dimension(2)) );
1419 
1420  // Compute the map F(refPoints) = sum node_coordinate*basis(refPoints)
1421  for(size_t cellOrd = 0; cellOrd < numCells; cellOrd++) {
1422 
1423  // Copy point set corresponding to this cell oridinal to the temp (P,D) array
1424  for(size_t pt = 0; pt < static_cast<size_t>(refPoints.dimension(1)); pt++){
1425  for(size_t dm = 0; dm < static_cast<size_t>(refPoints.dimension(2)) ; dm++){
1426  tempPoints(pt, dm) = refPointsWrap(cellOrd, pt, dm);
1427  }//dm
1428  }//pt
1429 
1430  // Compute basis values for this set of ref. points
1431  HGRAD_Basis -> getValues(basisVals, tempPoints, OPERATOR_VALUE);
1432 
1433  for(size_t pointOrd = 0; pointOrd < numPoints; pointOrd++) {
1434  for(size_t dim = 0; dim < spaceDim; dim++){
1435  for(int bfOrd = 0; bfOrd < basisCardinality; bfOrd++){
1436 
1437  physPointsWrap(cellOrd, pointOrd, dim) += cellWorksetWrap(cellOrd, bfOrd, dim)*basisVals(bfOrd, pointOrd);
1438 
1439  } // bfOrd
1440  }// dim
1441  }// pointOrd
1442  }//cellOrd
1443  }// case 3
1444  break;
1445 
1446  }
1447 }
1448 
1449 template<class Scalar>
1450 template<class ArrayPhysPoint, class ArrayRefPoint, class ArrayCell>
1451 void CellTools<Scalar>::mapToPhysicalFrame(ArrayPhysPoint & physPoints,
1452  const ArrayRefPoint & refPoints,
1453  const ArrayCell & cellWorkset,
1454  const shards::CellTopology & cellTopo,
1455  const int & whichCell)
1456 {
1457  INTREPID_VALIDATE(validateArguments_mapToPhysicalFrame( physPoints, refPoints, cellWorkset, cellTopo, whichCell) );
1458 
1459  ArrayWrapper<Scalar,ArrayPhysPoint, Rank<ArrayPhysPoint >::value, false>physPointsWrap(physPoints);
1460  ArrayWrapper<Scalar,ArrayRefPoint, Rank<ArrayRefPoint >::value, true>refPointsWrap(refPoints);
1461  ArrayWrapper<Scalar,ArrayCell, Rank<ArrayCell >::value,true>cellWorksetWrap(cellWorkset);
1462 
1463  size_t spaceDim = (size_t)cellTopo.getDimension();
1464  size_t numCells = static_cast<size_t>(cellWorkset.dimension(0));
1465  //points can be rank-2 (P,D), or rank-3 (C,P,D)
1466  size_t numPoints = (getrank(refPoints) == 2) ? static_cast<size_t>(refPoints.dimension(0)) : static_cast<size_t>(refPoints.dimension(1));
1467 
1468  // Mapping is computed using an appropriate H(grad) basis function: define RCP to the base class
1469  Teuchos::RCP<Basis<Scalar, FieldContainer<Scalar> > > HGRAD_Basis;
1470 
1471  // Choose the H(grad) basis depending on the cell topology. \todo define maps for shells and beams
1472  switch( cellTopo.getKey() ){
1473 
1474  // Standard Base topologies (number of cellWorkset = number of vertices)
1475  case shards::Line<2>::key:
1476  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_LINE_C1_FEM<Scalar, FieldContainer<Scalar> >() );
1477  break;
1478 
1479  case shards::Triangle<3>::key:
1480  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_TRI_C1_FEM<Scalar, FieldContainer<Scalar> >() );
1481  break;
1482 
1483  case shards::Quadrilateral<4>::key:
1484  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_QUAD_C1_FEM<Scalar, FieldContainer<Scalar> >() );
1485  break;
1486 
1487  case shards::Tetrahedron<4>::key:
1488  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_TET_C1_FEM<Scalar, FieldContainer<Scalar> >() );
1489  break;
1490 
1491  case shards::Hexahedron<8>::key:
1492  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_HEX_C1_FEM<Scalar, FieldContainer<Scalar> >() );
1493  break;
1494 
1495  case shards::Wedge<6>::key:
1496  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_WEDGE_C1_FEM<Scalar, FieldContainer<Scalar> >() );
1497  break;
1498 
1499  case shards::Pyramid<5>::key:
1500  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_PYR_C1_FEM<Scalar, FieldContainer<Scalar> >() );
1501  break;
1502 
1503  // Standard Extended topologies
1504  case shards::Triangle<6>::key:
1505  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_TRI_C2_FEM<Scalar, FieldContainer<Scalar> >() );
1506  break;
1507 
1508  case shards::Quadrilateral<9>::key:
1509  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_QUAD_C2_FEM<Scalar, FieldContainer<Scalar> >() );
1510  break;
1511 
1512  case shards::Tetrahedron<10>::key:
1513  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_TET_C2_FEM<Scalar, FieldContainer<Scalar> >() );
1514  break;
1515 
1516  case shards::Tetrahedron<11>::key:
1517  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_TET_COMP12_FEM<Scalar, FieldContainer<Scalar> >() );
1518  break;
1519 
1520  case shards::Hexahedron<20>::key:
1521  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_HEX_I2_FEM<Scalar, FieldContainer<Scalar> >() );
1522  break;
1523 
1524  case shards::Hexahedron<27>::key:
1525  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_HEX_C2_FEM<Scalar, FieldContainer<Scalar> >() );
1526  break;
1527 
1528  case shards::Wedge<15>::key:
1529  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_WEDGE_I2_FEM<Scalar, FieldContainer<Scalar> >() );
1530  break;
1531 
1532  case shards::Wedge<18>::key:
1533  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_WEDGE_C2_FEM<Scalar, FieldContainer<Scalar> >() );
1534  break;
1535 
1536  case shards::Pyramid<13>::key:
1537  HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_PYR_I2_FEM<Scalar, FieldContainer<Scalar> >() );
1538  break;
1539 
1540  // These extended topologies are not used for mapping purposes
1541  case shards::Quadrilateral<8>::key:
1542  TEUCHOS_TEST_FOR_EXCEPTION( (true), std::invalid_argument,
1543  ">>> ERROR (Intrepid::CellTools::mapToPhysicalFrame): Cell topology not supported. ");
1544  break;
1545 
1546  // Base and Extended Line, Beam and Shell topologies
1547  case shards::Line<3>::key:
1548  case shards::Beam<2>::key:
1549  case shards::Beam<3>::key:
1550  case shards::ShellLine<2>::key:
1551  case shards::ShellLine<3>::key:
1552  case shards::ShellTriangle<3>::key:
1553  case shards::ShellTriangle<6>::key:
1554  case shards::ShellQuadrilateral<4>::key:
1555  case shards::ShellQuadrilateral<8>::key:
1556  case shards::ShellQuadrilateral<9>::key:
1557  TEUCHOS_TEST_FOR_EXCEPTION( (true), std::invalid_argument,
1558  ">>> ERROR (Intrepid::CellTools::mapToPhysicalFrame): Cell topology not supported. ");
1559  break;
1560  default:
1561  TEUCHOS_TEST_FOR_EXCEPTION( (true), std::invalid_argument,
1562  ">>> ERROR (Intrepid::CellTools::mapToPhysicalFrame): Cell topology not supported.");
1563  }// switch
1564 
1565  // Temp (F,P) array for the values of nodal basis functions at the reference points
1566  int basisCardinality = HGRAD_Basis -> getCardinality();
1567  FieldContainer<Scalar> basisVals(basisCardinality, numPoints);
1568 
1569 //#ifndef INTREPID_OLD_KOKKOS_CODE
1570  // Initialize physPoints
1571  if(getrank(physPoints)==3){
1572 for(size_t i = 0; i < static_cast<size_t>(physPoints.dimension(0)); i++) {
1573  for(size_t j = 0; j < static_cast<size_t>(physPoints.dimension(1)); j++){
1574  for(size_t k = 0; k < static_cast<size_t>(physPoints.dimension(2)); k++){
1575  physPointsWrap(i,j,k) = 0.0;
1576  }
1577  }
1578 }
1579  }else if(getrank(physPoints)==2){
1580  for(size_t i = 0; i < static_cast<size_t>(physPoints.dimension(0)); i++){
1581  for(size_t j = 0; j < static_cast<size_t>(physPoints.dimension(1)); j++){
1582  physPointsWrap(i,j) = 0.0;
1583  }
1584  }
1585 
1586  }
1587 
1588 //#else
1589 // Kokkos::deep_copy(physPoints.get_kokkos_view(), Scalar(0.0));
1590 //#endif
1591  // handle separately rank-2 (P,D) and rank-3 (C,P,D) cases of refPoints
1592  switch(getrank(refPoints)) {
1593 
1594  // refPoints is (P,D): single set of ref. points is mapped to one or multiple physical cells
1595  case 2:
1596  {
1597 
1598  // getValues requires rank-2 (P,D) input array, but refPoints cannot be passed directly as argument because they are a user type
1599  FieldContainer<Scalar> tempPoints( static_cast<size_t>(refPoints.dimension(0)), static_cast<size_t>(refPoints.dimension(1)) );
1600  // Copy point set corresponding to this cell oridinal to the temp (P,D) array
1601  for(size_t pt = 0; pt < static_cast<size_t>(refPoints.dimension(0)); pt++){
1602  for(size_t dm = 0; dm < static_cast<size_t>(refPoints.dimension(1)) ; dm++){
1603  tempPoints(pt, dm) = refPointsWrap(pt, dm);
1604  }//dm
1605  }//pt
1606  HGRAD_Basis -> getValues(basisVals, tempPoints, OPERATOR_VALUE);
1607 
1608  // If whichCell = -1, ref pt. set is mapped to all cells, otherwise, the set is mapped to one cell only
1609  size_t cellLoop = (whichCell == -1) ? numCells : 1 ;
1610 
1611  // Compute the map F(refPoints) = sum node_coordinate*basis(refPoints)
1612  for(size_t cellOrd = 0; cellOrd < cellLoop; cellOrd++) {
1613  for(size_t pointOrd = 0; pointOrd < numPoints; pointOrd++) {
1614  for(size_t dim = 0; dim < spaceDim; dim++){
1615  for(int bfOrd = 0; bfOrd < basisCardinality; bfOrd++){
1616 
1617  if(whichCell == -1){
1618  physPointsWrap(cellOrd, pointOrd, dim) += cellWorksetWrap(cellOrd, bfOrd, dim)*basisVals(bfOrd, pointOrd);
1619  }
1620  else{
1621  physPointsWrap(pointOrd, dim) += cellWorksetWrap(whichCell, bfOrd, dim)*basisVals(bfOrd, pointOrd);
1622  }
1623  } // bfOrd
1624  }// dim
1625  }// pointOrd
1626  }//cellOrd
1627  }// case 2
1628 
1629  break;
1630 
1631  // refPoints is (C,P,D): multiple sets of ref. points are mapped to matching number of physical cells.
1632  case 3:
1633  {
1634 
1635  // getValues requires rank-2 (P,D) input array, refPoints cannot be used as argument: need temp (P,D) array
1636  FieldContainer<Scalar> tempPoints( static_cast<size_t>(refPoints.dimension(1)), static_cast<size_t>(refPoints.dimension(2)) );
1637 
1638  // Compute the map F(refPoints) = sum node_coordinate*basis(refPoints)
1639  for(size_t cellOrd = 0; cellOrd < numCells; cellOrd++) {
1640 
1641  // Copy point set corresponding to this cell oridinal to the temp (P,D) array
1642  for(size_t pt = 0; pt < static_cast<size_t>(refPoints.dimension(1)); pt++){
1643  for(size_t dm = 0; dm < static_cast<size_t>(refPoints.dimension(2)) ; dm++){
1644  tempPoints(pt, dm) = refPointsWrap(cellOrd, pt, dm);
1645  }//dm
1646  }//pt
1647 
1648  // Compute basis values for this set of ref. points
1649  HGRAD_Basis -> getValues(basisVals, tempPoints, OPERATOR_VALUE);
1650 
1651  for(size_t pointOrd = 0; pointOrd < numPoints; pointOrd++) {
1652  for(size_t dim = 0; dim < spaceDim; dim++){
1653  for(int bfOrd = 0; bfOrd < basisCardinality; bfOrd++){
1654 
1655  physPointsWrap(cellOrd, pointOrd, dim) += cellWorksetWrap(cellOrd, bfOrd, dim)*basisVals(bfOrd, pointOrd);
1656 
1657  } // bfOrd
1658  }// dim
1659  }// pointOrd
1660  }//cellOrd
1661  }// case 3
1662  break;
1663 
1664 
1665  }
1666 }
1667 
1668 template<class Scalar>
1669 template<class ArrayRefPoint, class ArrayPhysPoint, class ArrayCell>
1670 void CellTools<Scalar>::mapToReferenceFrame(ArrayRefPoint & refPoints,
1671  const ArrayPhysPoint & physPoints,
1672  const ArrayCell & cellWorkset,
1673  const shards::CellTopology & cellTopo,
1674  const int & whichCell)
1675 {
1676  INTREPID_VALIDATE( validateArguments_mapToReferenceFrame(refPoints, physPoints, cellWorkset, cellTopo, whichCell) );
1677 
1678  size_t spaceDim = (size_t)cellTopo.getDimension();
1679  size_t numPoints;
1680  size_t numCells;
1681 
1682  // Define initial guesses to be the Cell centers of the reference cell topology
1683  FieldContainer<Scalar> cellCenter(spaceDim);
1684  switch( cellTopo.getKey() ){
1685  // Standard Base topologies (number of cellWorkset = number of vertices)
1686  case shards::Line<2>::key:
1687  cellCenter(0) = 0.0; break;
1688 
1689  case shards::Triangle<3>::key:
1690  case shards::Triangle<6>::key:
1691  cellCenter(0) = 1./3.; cellCenter(1) = 1./3.; break;
1692 
1693  case shards::Quadrilateral<4>::key:
1694  case shards::Quadrilateral<9>::key:
1695  cellCenter(0) = 0.0; cellCenter(1) = 0.0; break;
1696 
1697  case shards::Tetrahedron<4>::key:
1698  case shards::Tetrahedron<10>::key:
1699  case shards::Tetrahedron<11>::key:
1700  cellCenter(0) = 1./6.; cellCenter(1) = 1./6.; cellCenter(2) = 1./6.; break;
1701 
1702  case shards::Hexahedron<8>::key:
1703  case shards::Hexahedron<20>::key:
1704  case shards::Hexahedron<27>::key:
1705  cellCenter(0) = 0.0; cellCenter(1) = 0.0; cellCenter(2) = 0.0; break;
1706 
1707  case shards::Wedge<6>::key:
1708  case shards::Wedge<15>::key:
1709  case shards::Wedge<18>::key:
1710  cellCenter(0) = 1./3.; cellCenter(1) = 1./3.; cellCenter(2) = 0.0; break;
1711 
1712  case shards::Pyramid<5>::key:
1713  case shards::Pyramid<13>::key:
1714  cellCenter(0) = 0.; cellCenter(1) = 0.; cellCenter(2) = 0.25; break;
1715 
1716  // These extended topologies are not used for mapping purposes
1717  case shards::Quadrilateral<8>::key:
1718  TEUCHOS_TEST_FOR_EXCEPTION( (true), std::invalid_argument,
1719  ">>> ERROR (Intrepid::CellTools::mapToReferenceFrame): Cell topology not supported. ");
1720  break;
1721 
1722  // Base and Extended Line, Beam and Shell topologies
1723  case shards::Line<3>::key:
1724  case shards::Beam<2>::key:
1725  case shards::Beam<3>::key:
1726  case shards::ShellLine<2>::key:
1727  case shards::ShellLine<3>::key:
1728  case shards::ShellTriangle<3>::key:
1729  case shards::ShellTriangle<6>::key:
1730  case shards::ShellQuadrilateral<4>::key:
1731  case shards::ShellQuadrilateral<8>::key:
1732  case shards::ShellQuadrilateral<9>::key:
1733  TEUCHOS_TEST_FOR_EXCEPTION( (true), std::invalid_argument,
1734  ">>> ERROR (Intrepid::CellTools::mapToReferenceFrame): Cell topology not supported. ");
1735  break;
1736  default:
1737  TEUCHOS_TEST_FOR_EXCEPTION( (true), std::invalid_argument,
1738  ">>> ERROR (Intrepid::CellTools::mapToReferenceFrame): Cell topology not supported.");
1739  }// switch key
1740 
1741  // Resize initial guess depending on the rank of the physical points array
1742  FieldContainer<Scalar> initGuess;
1743 
1744  // Default: map (C,P,D) array of physical pt. sets to (C,P,D) array. Requires (C,P,D) initial guess.
1745  if(whichCell == -1){
1746  numPoints = static_cast<size_t>(physPoints.dimension(1));
1747  numCells = static_cast<size_t>(cellWorkset.dimension(0));
1748  initGuess.resize(numCells, numPoints, spaceDim);
1749  // Set initial guess:
1750  for(size_t c = 0; c < numCells; c++){
1751  for(size_t p = 0; p < numPoints; p++){
1752  for(size_t d = 0; d < spaceDim; d++){
1753  initGuess(c, p, d) = cellCenter(d);
1754  }// d
1755  }// p
1756  }// c
1757  }
1758  // Custom: map (P,D) array of physical pts. to (P,D) array. Requires (P,D) initial guess.
1759  else {
1760  numPoints = static_cast<size_t>(physPoints.dimension(0));
1761  initGuess.resize(numPoints, spaceDim);
1762  // Set initial guess:
1763  for(size_t p = 0; p < numPoints; p++){
1764  for(size_t d = 0; d < spaceDim; d++){
1765  initGuess(p, d) = cellCenter(d);
1766  }// d
1767  }// p
1768  }
1769  // Call method with initial guess
1770  mapToReferenceFrameInitGuess(refPoints, initGuess, physPoints, cellWorkset, cellTopo, whichCell);
1771 
1772 }
1773 
1774 
1775 template<class Scalar>
1776 template<class ArrayRefPoint, class ArrayInitGuess, class ArrayPhysPoint, class ArrayCell>
1777 void CellTools<Scalar>::mapToReferenceFrameInitGuess(ArrayRefPoint & refPoints,
1778  const ArrayInitGuess & initGuess,
1779  const ArrayPhysPoint & physPoints,
1780  const ArrayCell & cellWorkset,
1781  const Teuchos::RCP< Basis< Scalar, FieldContainer<Scalar> > > HGRAD_Basis,
1782  const int & whichCell)
1783 {
1784 ArrayWrapper<Scalar,ArrayInitGuess, Rank<ArrayInitGuess >::value, true>initGuessWrap(initGuess);
1785 ArrayWrapper<Scalar,ArrayRefPoint, Rank<ArrayRefPoint >::value, false>refPointsWrap(refPoints);
1786 // INTREPID_VALIDATE( validateArguments_mapToReferenceFrame(refPoints, initGuess, physPoints, cellWorkset, cellTopo, whichCell) );
1787  size_t spaceDim = (size_t)HGRAD_Basis->getBaseCellTopology().getDimension();
1788  size_t numPoints;
1789  size_t numCells=0;
1790 
1791  // Temp arrays for Newton iterates and Jacobians. Resize according to rank of ref. point array
1793  FieldContainer<Scalar> xTem;
1794  FieldContainer<Scalar> jacobian;
1795  FieldContainer<Scalar> jacobInv;
1796  FieldContainer<Scalar> error;
1797  FieldContainer<Scalar> cellCenter(spaceDim);
1798 
1799  // 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.
1800  if(whichCell == -1){
1801  numPoints = static_cast<size_t>(physPoints.dimension(1));
1802  numCells = static_cast<size_t>(cellWorkset.dimension(0));
1803  xOld.resize(numCells, numPoints, spaceDim);
1804  xTem.resize(numCells, numPoints, spaceDim);
1805  jacobian.resize(numCells,numPoints, spaceDim, spaceDim);
1806  jacobInv.resize(numCells,numPoints, spaceDim, spaceDim);
1807  error.resize(numCells,numPoints);
1808  // Set initial guess to xOld
1809  for(size_t c = 0; c < numCells; c++){
1810  for(size_t p = 0; p < numPoints; p++){
1811  for(size_t d = 0; d < spaceDim; d++){
1812  xOld(c, p, d) = initGuessWrap(c, p, d);
1813  }// d
1814  }// p
1815  }// c
1816  }
1817  // Custom: map (P,D) array of physical pts. to (P,D) array. Requires (P,D) temp arrays and (P,D,D) Jacobians.
1818  else {
1819  numPoints = static_cast<size_t>(physPoints.dimension(0));
1820  xOld.resize(numPoints, spaceDim);
1821  xTem.resize(numPoints, spaceDim);
1822  jacobian.resize(numPoints, spaceDim, spaceDim);
1823  jacobInv.resize(numPoints, spaceDim, spaceDim);
1824  error.resize(numPoints);
1825  // Set initial guess to xOld
1826  for(size_t c = 0; c < numCells; c++){
1827  for(size_t p = 0; p < numPoints; p++){
1828  for(size_t d = 0; d < spaceDim; d++){
1829  xOld(c, p, d) = initGuessWrap(c, p, d);
1830  }// d
1831  }// p
1832  }// c
1833  }
1834 
1835  // Newton method to solve the equation F(refPoints) - physPoints = 0:
1836  // refPoints = xOld - DF^{-1}(xOld)*(F(xOld) - physPoints) = xOld + DF^{-1}(xOld)*(physPoints - F(xOld))
1837  for(int iter = 0; iter < INTREPID_MAX_NEWTON; ++iter) {
1838 
1839  // Jacobians at the old iterates and their inverses.
1840  setJacobian(jacobian, xOld, cellWorkset, HGRAD_Basis, whichCell);
1841  setJacobianInv(jacobInv, jacobian);
1842  // The Newton step.
1843  mapToPhysicalFrame( xTem, xOld, cellWorkset, HGRAD_Basis->getBaseCellTopology(), whichCell ); // xTem <- F(xOld)
1844  RealSpaceTools<Scalar>::subtract( xTem, physPoints, xTem ); // xTem <- physPoints - F(xOld)
1845  RealSpaceTools<Scalar>::matvec( refPoints, jacobInv, xTem); // refPoints <- DF^{-1}( physPoints - F(xOld) )
1846  RealSpaceTools<Scalar>::add( refPoints, xOld ); // refPoints <- DF^{-1}( physPoints - F(xOld) ) + xOld
1847 
1848  // l2 error (Euclidean distance) between old and new iterates: |xOld - xNew|
1849  RealSpaceTools<Scalar>::subtract( xTem, xOld, refPoints );
1850  RealSpaceTools<Scalar>::vectorNorm( error, xTem, NORM_TWO );
1851 
1852  // Average L2 error for a multiple sets of physical points: error is rank-2 (C,P) array
1853  Scalar totalError;
1854  if(whichCell == -1) {
1855  FieldContainer<Scalar> cellWiseError(numCells);
1856  // error(C,P) -> cellWiseError(P)
1857 
1858  RealSpaceTools<Scalar>::vectorNorm( cellWiseError, error, NORM_ONE );
1859  totalError = RealSpaceTools<Scalar>::vectorNorm( cellWiseError, NORM_ONE );
1860  }
1861  //Average L2 error for a single set of physical points: error is rank-1 (P) array
1862  else{
1863 
1864  totalError = RealSpaceTools<Scalar>::vectorNorm( error, NORM_ONE );
1865  totalError = totalError;
1866  }
1867 
1868  // Stopping criterion:
1869  if (totalError < INTREPID_TOL) {
1870  break;
1871  }
1872  else if ( iter > INTREPID_MAX_NEWTON) {
1873  INTREPID_VALIDATE(std::cout << " Intrepid::CellTools::mapToReferenceFrameInitGuess failed to converge to desired tolerance within "
1874  << INTREPID_MAX_NEWTON << " iterations\n" );
1875  break;
1876  }
1877 
1878  // initialize next Newton step
1879 // xOld = refPoints;
1880 int refPointsRank=getrank(refPoints);
1881 if (refPointsRank==3){
1882  for(size_t i=0;i<static_cast<size_t>(refPoints.dimension(0));i++){
1883  for(size_t j=0;j<static_cast<size_t>(refPoints.dimension(1));j++){
1884  for(size_t k=0;k<static_cast<size_t>(refPoints.dimension(2));k++){
1885  xOld(i,j,k) = refPointsWrap(i,j,k);
1886  }
1887  }
1888  }
1889 }else if(refPointsRank==2){
1890  for(size_t i=0;i<static_cast<size_t>(refPoints.dimension(0));i++){
1891  for(size_t j=0;j<static_cast<size_t>(refPoints.dimension(1));j++){
1892  xOld(i,j) = refPointsWrap(i,j);
1893  }
1894  }
1895 
1896 }
1897 
1898 
1899 
1900  } // for(iter)
1901 }
1902 
1903 
1904 
1905 template<class Scalar>
1906 template<class ArrayRefPoint, class ArrayInitGuess, class ArrayPhysPoint, class ArrayCell>
1908  const ArrayInitGuess & initGuess,
1909  const ArrayPhysPoint & physPoints,
1910  const ArrayCell & cellWorkset,
1911  const shards::CellTopology & cellTopo,
1912  const int & whichCell)
1913 {
1914 ArrayWrapper<Scalar,ArrayInitGuess, Rank<ArrayInitGuess >::value, true>initGuessWrap(initGuess);
1915 ArrayWrapper<Scalar,ArrayRefPoint, Rank<ArrayRefPoint >::value, false>refPointsWrap(refPoints);
1916  INTREPID_VALIDATE( validateArguments_mapToReferenceFrame(refPoints, initGuess, physPoints, cellWorkset, cellTopo, whichCell) );
1917  size_t spaceDim = (size_t)cellTopo.getDimension();
1918  size_t numPoints;
1919  size_t numCells=0;
1920 
1921  // Temp arrays for Newton iterates and Jacobians. Resize according to rank of ref. point array
1923  FieldContainer<Scalar> xTem;
1924  FieldContainer<Scalar> jacobian;
1925  FieldContainer<Scalar> jacobInv;
1926  FieldContainer<Scalar> error;
1927  FieldContainer<Scalar> cellCenter(spaceDim);
1928 
1929  // 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.
1930  if(whichCell == -1){
1931  numPoints = static_cast<size_t>(physPoints.dimension(1));
1932  numCells = static_cast<size_t>(cellWorkset.dimension(0));
1933  xOld.resize(numCells, numPoints, spaceDim);
1934  xTem.resize(numCells, numPoints, spaceDim);
1935  jacobian.resize(numCells,numPoints, spaceDim, spaceDim);
1936  jacobInv.resize(numCells,numPoints, spaceDim, spaceDim);
1937  error.resize(numCells,numPoints);
1938  // Set initial guess to xOld
1939  for(size_t c = 0; c < numCells; c++){
1940  for(size_t p = 0; p < numPoints; p++){
1941  for(size_t d = 0; d < spaceDim; d++){
1942  xOld(c, p, d) = initGuessWrap(c, p, d);
1943  }// d
1944  }// p
1945  }// c
1946  }
1947  // Custom: map (P,D) array of physical pts. to (P,D) array. Requires (P,D) temp arrays and (P,D,D) Jacobians.
1948  else {
1949  numPoints = static_cast<size_t>(physPoints.dimension(0));
1950  xOld.resize(numPoints, spaceDim);
1951  xTem.resize(numPoints, spaceDim);
1952  jacobian.resize(numPoints, spaceDim, spaceDim);
1953  jacobInv.resize(numPoints, spaceDim, spaceDim);
1954  error.resize(numPoints);
1955  // Set initial guess to xOld
1956  for(size_t p = 0; p < numPoints; p++){
1957  for(size_t d = 0; d < spaceDim; d++){
1958  xOld(p, d) = initGuessWrap(p, d);
1959  }// d
1960  }// p
1961  }
1962 
1963  // Newton method to solve the equation F(refPoints) - physPoints = 0:
1964  // refPoints = xOld - DF^{-1}(xOld)*(F(xOld) - physPoints) = xOld + DF^{-1}(xOld)*(physPoints - F(xOld))
1965  for(int iter = 0; iter < INTREPID_MAX_NEWTON; ++iter) {
1966 
1967  // Jacobians at the old iterates and their inverses.
1968  setJacobian(jacobian, xOld, cellWorkset, cellTopo, whichCell);
1969  setJacobianInv(jacobInv, jacobian);
1970  // The Newton step.
1971  mapToPhysicalFrame( xTem, xOld, cellWorkset, cellTopo, whichCell ); // xTem <- F(xOld)
1972  RealSpaceTools<Scalar>::subtract( xTem, physPoints, xTem ); // xTem <- physPoints - F(xOld)
1973  RealSpaceTools<Scalar>::matvec( refPoints, jacobInv, xTem); // refPoints <- DF^{-1}( physPoints - F(xOld) )
1974  RealSpaceTools<Scalar>::add( refPoints, xOld ); // refPoints <- DF^{-1}( physPoints - F(xOld) ) + xOld
1975 
1976  // l2 error (Euclidean distance) between old and new iterates: |xOld - xNew|
1977  RealSpaceTools<Scalar>::subtract( xTem, xOld, refPoints );
1978  RealSpaceTools<Scalar>::vectorNorm( error, xTem, NORM_TWO );
1979 
1980  // Average L2 error for a multiple sets of physical points: error is rank-2 (C,P) array
1981  Scalar totalError;
1982  if(whichCell == -1) {
1983  FieldContainer<Scalar> cellWiseError(numCells);
1984  // error(C,P) -> cellWiseError(P)
1985 
1986  RealSpaceTools<Scalar>::vectorNorm( cellWiseError, error, NORM_ONE );
1987  totalError = RealSpaceTools<Scalar>::vectorNorm( cellWiseError, NORM_ONE );
1988  }
1989  //Average L2 error for a single set of physical points: error is rank-1 (P) array
1990  else{
1991 
1992  totalError = RealSpaceTools<Scalar>::vectorNorm( error, NORM_ONE );
1993  totalError = totalError;
1994  }
1995 
1996  // Stopping criterion:
1997  if (totalError < INTREPID_TOL) {
1998  break;
1999  }
2000  else if ( iter > INTREPID_MAX_NEWTON) {
2001  INTREPID_VALIDATE(std::cout << " Intrepid::CellTools::mapToReferenceFrameInitGuess failed to converge to desired tolerance within "
2002  << INTREPID_MAX_NEWTON << " iterations\n" );
2003  break;
2004  }
2005 
2006  // initialize next Newton step
2007 // xOld = refPoints;
2008 int refPointsRank=getrank(refPoints);
2009 if (refPointsRank==3){
2010  for(size_t i=0;i<static_cast<size_t>(refPoints.dimension(0));i++){
2011  for(size_t j=0;j<static_cast<size_t>(refPoints.dimension(1));j++){
2012  for(size_t k=0;k<static_cast<size_t>(refPoints.dimension(2));k++){
2013  xOld(i,j,k) = refPointsWrap(i,j,k);
2014  }
2015  }
2016  }
2017 }else if(refPointsRank==2){
2018  for(size_t i=0;i<static_cast<size_t>(refPoints.dimension(0));i++){
2019  for(size_t j=0;j<static_cast<size_t>(refPoints.dimension(1));j++){
2020  xOld(i,j) = refPointsWrap(i,j);
2021  }
2022  }
2023 
2024 }
2025 
2026 
2027 
2028  } // for(iter)
2029 }
2030 
2031 
2032 
2033 template<class Scalar>
2034 template<class ArraySubcellPoint, class ArrayParamPoint>
2035 void CellTools<Scalar>::mapToReferenceSubcell(ArraySubcellPoint & refSubcellPoints,
2036  const ArrayParamPoint & paramPoints,
2037  const int subcellDim,
2038  const int subcellOrd,
2039  const shards::CellTopology & parentCell){
2040 
2041  int cellDim = parentCell.getDimension();
2042  size_t numPts = static_cast<size_t>(paramPoints.dimension(0));
2043 
2044 #ifdef HAVE_INTREPID_DEBUG
2045  TEUCHOS_TEST_FOR_EXCEPTION( !(hasReferenceCell(parentCell) ), std::invalid_argument,
2046  ">>> ERROR (Intrepid::CellTools::mapToReferenceSubcell): the specified cell topology does not have a reference cell.");
2047 
2048  TEUCHOS_TEST_FOR_EXCEPTION( !( (1 <= subcellDim) && (subcellDim <= 2 ) ), std::invalid_argument,
2049  ">>> ERROR (Intrepid::CellTools::mapToReferenceSubcell): method defined only for 1 and 2-dimensional subcells.");
2050 
2051  TEUCHOS_TEST_FOR_EXCEPTION( !( (0 <= subcellOrd) && (subcellOrd < (int)parentCell.getSubcellCount(subcellDim) ) ), std::invalid_argument,
2052  ">>> ERROR (Intrepid::CellTools::mapToReferenceSubcell): subcell ordinal out of range.");
2053 
2054  // refSubcellPoints is rank-2 (P,D1), D1 = cell dimension
2055  std::string errmsg = ">>> ERROR (Intrepid::mapToReferenceSubcell):";
2056  TEUCHOS_TEST_FOR_EXCEPTION( !requireRankRange(errmsg, refSubcellPoints, 2,2), std::invalid_argument, errmsg);
2057  TEUCHOS_TEST_FOR_EXCEPTION( !requireDimensionRange(errmsg, refSubcellPoints, 1, cellDim, cellDim), std::invalid_argument, errmsg);
2058 
2059  // paramPoints is rank-2 (P,D2) with D2 = subcell dimension
2060  TEUCHOS_TEST_FOR_EXCEPTION( !requireRankRange(errmsg, paramPoints, 2,2), std::invalid_argument, errmsg);
2061  TEUCHOS_TEST_FOR_EXCEPTION( !requireDimensionRange(errmsg, paramPoints, 1, subcellDim, subcellDim), std::invalid_argument, errmsg);
2062 
2063  // cross check: refSubcellPoints and paramPoints: dimension 0 must match
2064  TEUCHOS_TEST_FOR_EXCEPTION( !requireDimensionMatch(errmsg, refSubcellPoints, 0, paramPoints, 0), std::invalid_argument, errmsg);
2065 #endif
2066 
2067 
2068  // Get the subcell map, i.e., the coefficients of the parametrization function for the subcell
2069  const FieldContainer<double>& subcellMap = getSubcellParametrization(subcellDim, parentCell);
2070 
2071  // Apply the parametrization map to every point in parameter domain
2072  if(subcellDim == 2) {
2073  for(size_t pt = 0; pt < numPts; pt++){
2074  double u = paramPoints(pt,0);
2075  double v = paramPoints(pt,1);
2076 
2077  // map_dim(u,v) = c_0(dim) + c_1(dim)*u + c_2(dim)*v because both Quad and Tri ref faces are affine!
2078  for(int dim = 0; dim < cellDim; dim++){
2079  refSubcellPoints(pt, dim) = subcellMap(subcellOrd, dim, 0) + \
2080  subcellMap(subcellOrd, dim, 1)*u + \
2081  subcellMap(subcellOrd, dim, 2)*v;
2082  }
2083  }
2084  }
2085  else if(subcellDim == 1) {
2086  for(size_t pt = 0; pt < numPts; pt++){
2087  for(int dim = 0; dim < cellDim; dim++) {
2088  refSubcellPoints(pt, dim) = subcellMap(subcellOrd, dim, 0) + subcellMap(subcellOrd, dim, 1)*paramPoints(pt,0);
2089  }
2090  }
2091  }
2092  else{
2093  TEUCHOS_TEST_FOR_EXCEPTION( !( (subcellDim == 1) || (subcellDim == 2) ), std::invalid_argument,
2094  ">>> ERROR (Intrepid::CellTools::mapToReferenceSubcell): method defined only for 1 and 2-subcells");
2095  }
2096 }
2097 
2098 
2099 
2100 template<class Scalar>
2101 template<class ArrayEdgeTangent>
2102 void CellTools<Scalar>::getReferenceEdgeTangent(ArrayEdgeTangent & refEdgeTangent,
2103  const int & edgeOrd,
2104  const shards::CellTopology & parentCell){
2105 
2106  int spaceDim = parentCell.getDimension();
2107 
2108 #ifdef HAVE_INTREPID_DEBUG
2109 
2110  TEUCHOS_TEST_FOR_EXCEPTION( !( (spaceDim == 2) || (spaceDim == 3) ), std::invalid_argument,
2111  ">>> ERROR (Intrepid::CellTools::getReferenceFaceTangents): two or three-dimensional parent cell required");
2112 
2113  TEUCHOS_TEST_FOR_EXCEPTION( !( (0 <= edgeOrd) && (edgeOrd < (int)parentCell.getSubcellCount(1) ) ), std::invalid_argument,
2114  ">>> ERROR (Intrepid::CellTools::getReferenceFaceTangents): edge ordinal out of bounds");
2115 
2116  TEUCHOS_TEST_FOR_EXCEPTION( !( refEdgeTangent.size() == spaceDim ), std::invalid_argument,
2117  ">>> ERROR (Intrepid::CellTools::getReferenceFaceTangents): output array size is required to match space dimension");
2118 #endif
2119  // Edge parametrizations are computed in setSubcellParametrization and stored in rank-3 array
2120  // (subcOrd, coordinate, coefficient)
2121  const FieldContainer<double>& edgeMap = getSubcellParametrization(1, parentCell);
2122 
2123  // All ref. edge maps have affine coordinate functions: f_dim(u) = C_0(dim) + C_1(dim)*u,
2124  // => edge Tangent: -> C_1(*)
2125  refEdgeTangent(0) = edgeMap(edgeOrd, 0, 1);
2126  refEdgeTangent(1) = edgeMap(edgeOrd, 1, 1);
2127 
2128  // Skip last coordinate for 2D parent cells
2129  if(spaceDim == 3) {
2130  refEdgeTangent(2) = edgeMap(edgeOrd, 2, 1);
2131  }
2132 }
2133 
2134 
2135 
2136 template<class Scalar>
2137 template<class ArrayFaceTangentU, class ArrayFaceTangentV>
2138 void CellTools<Scalar>::getReferenceFaceTangents(ArrayFaceTangentU & uTan,
2139  ArrayFaceTangentV & vTan,
2140  const int & faceOrd,
2141  const shards::CellTopology & parentCell){
2142 
2143 #ifdef HAVE_INTREPID_DEBUG
2144  int spaceDim = parentCell.getDimension();
2145  TEUCHOS_TEST_FOR_EXCEPTION( !(spaceDim == 3), std::invalid_argument,
2146  ">>> ERROR (Intrepid::CellTools::getReferenceFaceTangents): three-dimensional parent cell required");
2147 
2148  TEUCHOS_TEST_FOR_EXCEPTION( !( (0 <= faceOrd) && (faceOrd < (int)parentCell.getSubcellCount(2) ) ), std::invalid_argument,
2149  ">>> ERROR (Intrepid::CellTools::getReferenceFaceTangents): face ordinal out of bounds");
2150 
2151  TEUCHOS_TEST_FOR_EXCEPTION( !( (getrank(uTan) == 1) && (getrank(vTan) == 1) ), std::invalid_argument,
2152  ">>> ERROR (Intrepid::CellTools::getReferenceFaceTangents): rank = 1 required for output arrays");
2153 
2154  TEUCHOS_TEST_FOR_EXCEPTION( !( uTan.dimension(0) == spaceDim ), std::invalid_argument,
2155  ">>> ERROR (Intrepid::CellTools::getReferenceFaceTangents): dim0 (spatial dim) must match that of parent cell");
2156 
2157  TEUCHOS_TEST_FOR_EXCEPTION( !( vTan.dimension(0) == spaceDim ), std::invalid_argument,
2158  ">>> ERROR (Intrepid::CellTools::getReferenceFaceTangents): dim0 (spatial dim) must match that of parent cell");
2159 #endif
2160 
2161  // Face parametrizations are computed in setSubcellParametrization and stored in rank-3 array
2162  // (subcOrd, coordinate, coefficient): retrieve this array
2163  const FieldContainer<double>& faceMap = getSubcellParametrization(2, parentCell);
2164 
2165  /* All ref. face maps have affine coordinate functions: f_dim(u,v) = C_0(dim) + C_1(dim)*u + C_2(dim)*v
2166  * ` => Tangent vectors are: uTan -> C_1(*); vTan -> C_2(*)
2167  */
2168  // set uTan -> C_1(*)
2169  uTan(0) = faceMap(faceOrd, 0, 1);
2170  uTan(1) = faceMap(faceOrd, 1, 1);
2171  uTan(2) = faceMap(faceOrd, 2, 1);
2172 
2173  // set vTan -> C_2(*)
2174  vTan(0) = faceMap(faceOrd, 0, 2);
2175  vTan(1) = faceMap(faceOrd, 1, 2);
2176  vTan(2) = faceMap(faceOrd, 2, 2);
2177 }
2178 
2179 
2180 
2181 template<class Scalar>
2182 template<class ArraySideNormal>
2183 void CellTools<Scalar>::getReferenceSideNormal(ArraySideNormal & refSideNormal,
2184  const int & sideOrd,
2185  const shards::CellTopology & parentCell){
2186  int spaceDim = parentCell.getDimension();
2187 
2188  #ifdef HAVE_INTREPID_DEBUG
2189 
2190  TEUCHOS_TEST_FOR_EXCEPTION( !( (spaceDim == 2) || (spaceDim == 3) ), std::invalid_argument,
2191  ">>> ERROR (Intrepid::CellTools::getReferenceSideNormal): two or three-dimensional parent cell required");
2192 
2193  // Check side ordinal: by definition side is subcell whose dimension = spaceDim-1
2194  TEUCHOS_TEST_FOR_EXCEPTION( !( (0 <= sideOrd) && (sideOrd < (int)parentCell.getSubcellCount(spaceDim - 1) ) ), std::invalid_argument,
2195  ">>> ERROR (Intrepid::CellTools::getReferenceSideNormal): side ordinal out of bounds");
2196 #endif
2197  if(spaceDim == 2){
2198 
2199  // 2D parent cells: side = 1D subcell (edge), call the edge tangent method and rotate tangents
2200  getReferenceEdgeTangent(refSideNormal, sideOrd, parentCell);
2201 
2202  // rotate t(t1, t2) to get n(t2, -t1) so that (n,t) is positively oriented: det(n1,n2/t1,t2)>0
2203  Scalar temp = refSideNormal(0);
2204  refSideNormal(0) = refSideNormal(1);
2205  refSideNormal(1) = -temp;
2206  }
2207  else{
2208  // 3D parent cell: side = 2D subcell (face), call the face normal method.
2209  getReferenceFaceNormal(refSideNormal, sideOrd, parentCell);
2210  }
2211 }
2212 
2213 
2214 
2215 template<class Scalar>
2216 template<class ArrayFaceNormal>
2217 void CellTools<Scalar>::getReferenceFaceNormal(ArrayFaceNormal & refFaceNormal,
2218  const int & faceOrd,
2219  const shards::CellTopology & parentCell){
2220  int spaceDim = parentCell.getDimension();
2221  #ifdef HAVE_INTREPID_DEBUG
2222 
2223  TEUCHOS_TEST_FOR_EXCEPTION( !(spaceDim == 3), std::invalid_argument,
2224  ">>> ERROR (Intrepid::CellTools::getReferenceFaceNormal): three-dimensional parent cell required");
2225 
2226  TEUCHOS_TEST_FOR_EXCEPTION( !( (0 <= faceOrd) && (faceOrd < (int)parentCell.getSubcellCount(2) ) ), std::invalid_argument,
2227  ">>> ERROR (Intrepid::CellTools::getReferenceFaceNormal): face ordinal out of bounds");
2228 
2229  TEUCHOS_TEST_FOR_EXCEPTION( !( getrank(refFaceNormal) == 1 ), std::invalid_argument,
2230  ">>> ERROR (Intrepid::CellTools::getReferenceFaceNormal): rank = 1 required for output array");
2231 
2232  TEUCHOS_TEST_FOR_EXCEPTION( !( static_cast<size_t>(refFaceNormal.dimension(0)) == static_cast<size_t>(spaceDim) ), std::invalid_argument,
2233  ">>> ERROR (Intrepid::CellTools::getReferenceFaceNormal): dim0 (spatial dim) must match that of parent cell");
2234 #endif
2235 
2236  // Reference face normal = vector product of reference face tangents. Allocate temp FC storage:
2237  FieldContainer<Scalar> uTan(spaceDim);
2238  FieldContainer<Scalar> vTan(spaceDim);
2239  getReferenceFaceTangents(uTan, vTan, faceOrd, parentCell);
2240 
2241  // Compute the vector product of the reference face tangents:
2242  RealSpaceTools<Scalar>::vecprod(refFaceNormal, uTan, vTan);
2243 }
2244 
2245 template<class Scalar>
2246 template<class ArrayEdgeTangent, class ArrayJac>
2247 void CellTools<Scalar>::getPhysicalEdgeTangents(ArrayEdgeTangent & edgeTangents,
2248  const ArrayJac & worksetJacobians,
2249  const int & worksetEdgeOrd,
2250  const shards::CellTopology & parentCell){
2251  size_t worksetSize = static_cast<size_t>(worksetJacobians.dimension(0));
2252  size_t edgePtCount = static_cast<size_t>(worksetJacobians.dimension(1));
2253  int pCellDim = parentCell.getDimension();
2254  #ifdef HAVE_INTREPID_DEBUG
2255  std::string errmsg = ">>> ERROR (Intrepid::CellTools::getPhysicalEdgeTangents):";
2256 
2257  TEUCHOS_TEST_FOR_EXCEPTION( !( (pCellDim == 3) || (pCellDim == 2) ), std::invalid_argument,
2258  ">>> ERROR (Intrepid::CellTools::getPhysicalEdgeTangents): 2D or 3D parent cell required");
2259 
2260  // (1) edgeTangents is rank-3 (C,P,D) and D=2, or 3 is required
2261  TEUCHOS_TEST_FOR_EXCEPTION( !requireRankRange(errmsg, edgeTangents, 3,3), std::invalid_argument, errmsg);
2262  TEUCHOS_TEST_FOR_EXCEPTION( !requireDimensionRange(errmsg, edgeTangents, 2, 2,3), std::invalid_argument, errmsg);
2263 
2264  // (2) worksetJacobians in rank-4 (C,P,D,D) and D=2, or 3 is required
2265  TEUCHOS_TEST_FOR_EXCEPTION( !requireRankRange(errmsg, worksetJacobians, 4,4), std::invalid_argument, errmsg);
2266  TEUCHOS_TEST_FOR_EXCEPTION( !requireDimensionRange(errmsg, worksetJacobians, 2, 2,3), std::invalid_argument, errmsg);
2267  TEUCHOS_TEST_FOR_EXCEPTION( !requireDimensionRange(errmsg, worksetJacobians, 3, 2,3), std::invalid_argument, errmsg);
2268 
2269  // (4) cross-check array dimensions: edgeTangents (C,P,D) vs. worksetJacobians (C,P,D,D)
2270  TEUCHOS_TEST_FOR_EXCEPTION( !requireDimensionMatch(errmsg, edgeTangents, 0,1,2,2, worksetJacobians, 0,1,2,3), std::invalid_argument, errmsg);
2271 
2272 #endif
2273 
2274  // Temp storage for constant reference edge tangent: rank-1 (D) arrays
2275  FieldContainer<double> refEdgeTan(pCellDim);
2276  getReferenceEdgeTangent(refEdgeTan, worksetEdgeOrd, parentCell);
2277 
2278  // Loop over workset faces and edge points
2279  for(size_t pCell = 0; pCell < worksetSize; pCell++){
2280  for(size_t pt = 0; pt < edgePtCount; pt++){
2281 
2282  // Apply parent cell Jacobian to ref. edge tangent
2283  for(int i = 0; i < pCellDim; i++){
2284  edgeTangents(pCell, pt, i) = 0.0;
2285  for(int j = 0; j < pCellDim; j++){
2286  edgeTangents(pCell, pt, i) += worksetJacobians(pCell, pt, i, j)*refEdgeTan(j);
2287  }// for j
2288  }// for i
2289  }// for pt
2290  }// for pCell
2291 }
2292 template<class Scalar>
2293 template<class ArrayFaceTangentU, class ArrayFaceTangentV, class ArrayJac>
2294 void CellTools<Scalar>::getPhysicalFaceTangents(ArrayFaceTangentU & faceTanU,
2295  ArrayFaceTangentV & faceTanV,
2296  const ArrayJac & worksetJacobians,
2297  const int & worksetFaceOrd,
2298  const shards::CellTopology & parentCell){
2299  size_t worksetSize = static_cast<size_t>(worksetJacobians.dimension(0));
2300  size_t facePtCount = static_cast<size_t>(worksetJacobians.dimension(1));
2301  int pCellDim = parentCell.getDimension();
2302  #ifdef HAVE_INTREPID_DEBUG
2303  std::string errmsg = ">>> ERROR (Intrepid::CellTools::getPhysicalFaceTangents):";
2304 
2305  TEUCHOS_TEST_FOR_EXCEPTION( !(pCellDim == 3), std::invalid_argument,
2306  ">>> ERROR (Intrepid::CellTools::getPhysicalFaceTangents): three-dimensional parent cell required");
2307 
2308  // (1) faceTanU and faceTanV are rank-3 (C,P,D) and D=3 is required
2309  TEUCHOS_TEST_FOR_EXCEPTION( !requireRankRange(errmsg, faceTanU, 3,3), std::invalid_argument, errmsg);
2310  TEUCHOS_TEST_FOR_EXCEPTION( !requireDimensionRange(errmsg, faceTanU, 2, 3,3), std::invalid_argument, errmsg);
2311 
2312  TEUCHOS_TEST_FOR_EXCEPTION( !requireRankRange(errmsg, faceTanV, 3,3), std::invalid_argument, errmsg);
2313  TEUCHOS_TEST_FOR_EXCEPTION( !requireDimensionRange(errmsg, faceTanV, 2, 3,3), std::invalid_argument, errmsg);
2314 
2315  TEUCHOS_TEST_FOR_EXCEPTION( !requireDimensionMatch(errmsg, faceTanU, faceTanV), std::invalid_argument, errmsg);
2316 
2317  // (3) worksetJacobians in rank-4 (C,P,D,D) and D=3 is required
2318  TEUCHOS_TEST_FOR_EXCEPTION( !requireRankRange(errmsg, worksetJacobians, 4,4), std::invalid_argument, errmsg);
2319  TEUCHOS_TEST_FOR_EXCEPTION( !requireDimensionRange(errmsg, worksetJacobians, 2, 3,3), std::invalid_argument, errmsg);
2320  TEUCHOS_TEST_FOR_EXCEPTION( !requireDimensionRange(errmsg, worksetJacobians, 3, 3,3), std::invalid_argument, errmsg);
2321 
2322  // (4) cross-check array dimensions: faceTanU (C,P,D) vs. worksetJacobians (C,P,D,D)
2323  TEUCHOS_TEST_FOR_EXCEPTION( !requireDimensionMatch(errmsg, faceTanU, 0,1,2,2, worksetJacobians, 0,1,2,3), std::invalid_argument, errmsg);
2324 
2325 #endif
2326 
2327  // Temp storage for the pair of constant ref. face tangents: rank-1 (D) arrays
2328  FieldContainer<double> refFaceTanU(pCellDim);
2329  FieldContainer<double> refFaceTanV(pCellDim);
2330  getReferenceFaceTangents(refFaceTanU, refFaceTanV, worksetFaceOrd, parentCell);
2331 
2332  // Loop over workset faces and face points
2333  for(size_t pCell = 0; pCell < worksetSize; pCell++){
2334  for(size_t pt = 0; pt < facePtCount; pt++){
2335 
2336  // Apply parent cell Jacobian to ref. face tangents
2337  for(int dim = 0; dim < pCellDim; dim++){
2338  faceTanU(pCell, pt, dim) = 0.0;
2339  faceTanV(pCell, pt, dim) = 0.0;
2340 
2341  // Unroll loops: parent cell dimension can only be 3
2342  faceTanU(pCell, pt, dim) = \
2343  worksetJacobians(pCell, pt, dim, 0)*refFaceTanU(0) + \
2344  worksetJacobians(pCell, pt, dim, 1)*refFaceTanU(1) + \
2345  worksetJacobians(pCell, pt, dim, 2)*refFaceTanU(2);
2346  faceTanV(pCell, pt, dim) = \
2347  worksetJacobians(pCell, pt, dim, 0)*refFaceTanV(0) + \
2348  worksetJacobians(pCell, pt, dim, 1)*refFaceTanV(1) + \
2349  worksetJacobians(pCell, pt, dim, 2)*refFaceTanV(2);
2350  }// for dim
2351  }// for pt
2352  }// for pCell
2353 }
2354 
2355 template<class Scalar>
2356 template<class ArraySideNormal, class ArrayJac>
2357 void CellTools<Scalar>::getPhysicalSideNormals(ArraySideNormal & sideNormals,
2358  const ArrayJac & worksetJacobians,
2359  const int & worksetSideOrd,
2360  const shards::CellTopology & parentCell){
2361  size_t worksetSize = static_cast<size_t>(worksetJacobians.dimension(0));
2362  size_t sidePtCount = static_cast<size_t>(worksetJacobians.dimension(1));
2363  int spaceDim = parentCell.getDimension();
2364  #ifdef HAVE_INTREPID_DEBUG
2365  TEUCHOS_TEST_FOR_EXCEPTION( !( (spaceDim == 2) || (spaceDim == 3) ), std::invalid_argument,
2366  ">>> ERROR (Intrepid::CellTools::getPhysicalSideNormals): two or three-dimensional parent cell required");
2367 
2368  // Check side ordinal: by definition side is subcell whose dimension = spaceDim-1
2369  TEUCHOS_TEST_FOR_EXCEPTION( !( (0 <= worksetSideOrd) && (worksetSideOrd < (int)parentCell.getSubcellCount(spaceDim - 1) ) ), std::invalid_argument,
2370  ">>> ERROR (Intrepid::CellTools::getPhysicalSideNormals): side ordinal out of bounds");
2371 #endif
2372 
2373  if(spaceDim == 2){
2374 
2375  // 2D parent cells: side = 1D subcell (edge), call the edge tangent method and rotate tangents
2376  getPhysicalEdgeTangents(sideNormals, worksetJacobians, worksetSideOrd, parentCell);
2377 
2378  // rotate t(t1, t2) to get n(t2, -t1) so that (n,t) is positively oriented: det(n1,n2/t1,t2)>0
2379  for(size_t cell = 0; cell < worksetSize; cell++){
2380  for(size_t pt = 0; pt < sidePtCount; pt++){
2381  Scalar temp = sideNormals(cell, pt, 0);
2382  sideNormals(cell, pt, 0) = sideNormals(cell, pt, 1);
2383  sideNormals(cell, pt, 1) = -temp;
2384  }// for pt
2385  }// for cell
2386  }
2387  else{
2388  // 3D parent cell: side = 2D subcell (face), call the face normal method.
2389  getPhysicalFaceNormals(sideNormals, worksetJacobians, worksetSideOrd, parentCell);
2390  }
2391 }
2392 
2393 
2394 template<class Scalar>
2395 template<class ArrayFaceNormal, class ArrayJac>
2396 void CellTools<Scalar>::getPhysicalFaceNormals(ArrayFaceNormal & faceNormals,
2397  const ArrayJac & worksetJacobians,
2398  const int & worksetFaceOrd,
2399  const shards::CellTopology & parentCell){
2400  size_t worksetSize = static_cast<size_t>(worksetJacobians.dimension(0));
2401  size_t facePtCount = static_cast<size_t>(worksetJacobians.dimension(1));
2402  int pCellDim = parentCell.getDimension();
2403  #ifdef HAVE_INTREPID_DEBUG
2404  std::string errmsg = ">>> ERROR (Intrepid::CellTools::getPhysicalFaceNormals):";
2405 
2406  TEUCHOS_TEST_FOR_EXCEPTION( !(pCellDim == 3), std::invalid_argument,
2407  ">>> ERROR (Intrepid::CellTools::getPhysicalFaceNormals): three-dimensional parent cell required");
2408 
2409  // (1) faceNormals is rank-3 (C,P,D) and D=3 is required
2410  TEUCHOS_TEST_FOR_EXCEPTION( !requireRankRange(errmsg, faceNormals, 3,3), std::invalid_argument, errmsg);
2411  TEUCHOS_TEST_FOR_EXCEPTION( !requireDimensionRange(errmsg, faceNormals, 2, 3,3), std::invalid_argument, errmsg);
2412 
2413  // (3) worksetJacobians in rank-4 (C,P,D,D) and D=3 is required
2414  TEUCHOS_TEST_FOR_EXCEPTION( !requireRankRange(errmsg, worksetJacobians, 4,4), std::invalid_argument, errmsg);
2415  TEUCHOS_TEST_FOR_EXCEPTION( !requireDimensionRange(errmsg, worksetJacobians, 2, 3,3), std::invalid_argument, errmsg);
2416  TEUCHOS_TEST_FOR_EXCEPTION( !requireDimensionRange(errmsg, worksetJacobians, 3, 3,3), std::invalid_argument, errmsg);
2417 
2418  // (4) cross-check array dimensions: faceNormals (C,P,D) vs. worksetJacobians (C,P,D,D)
2419  TEUCHOS_TEST_FOR_EXCEPTION( !requireDimensionMatch(errmsg, faceNormals, 0,1,2,2, worksetJacobians, 0,1,2,3), std::invalid_argument, errmsg);
2420 #endif
2421 
2422  // Temp storage for physical face tangents: rank-3 (C,P,D) arrays
2423  FieldContainer<Scalar> faceTanU(worksetSize, facePtCount, pCellDim);
2424  FieldContainer<Scalar> faceTanV(worksetSize, facePtCount, pCellDim);
2425  getPhysicalFaceTangents(faceTanU, faceTanV, worksetJacobians, worksetFaceOrd, parentCell);
2426 
2427  // Compute the vector product of the physical face tangents:
2428  RealSpaceTools<Scalar>::vecprod(faceNormals, faceTanU, faceTanV);
2429 
2430 
2431 }
2432 //============================================================================================//
2433 // //
2434 // Inclusion tests //
2435 // //
2436 //============================================================================================//
2437 
2438 
2439 template<class Scalar>
2441  const int pointDim,
2442  const shards::CellTopology & cellTopo,
2443  const double & threshold) {
2444 #ifdef HAVE_INTREPID_DEBUG
2445  TEUCHOS_TEST_FOR_EXCEPTION( !(pointDim == (int)cellTopo.getDimension() ), std::invalid_argument,
2446  ">>> ERROR (Intrepid::CellTools::checkPointInclusion): Point and cell dimensions do not match. ");
2447 #endif
2448  int testResult = 1;
2449 
2450  // Using these values in the tests effectievly inflates the reference element to a larger one
2451  double minus_one = -1.0 - threshold;
2452  double plus_one = 1.0 + threshold;
2453  double minus_zero = - threshold;
2454 
2455  // A cell with extended topology has the same reference cell as a cell with base topology.
2456  // => testing for inclusion in a reference Triangle<> and a reference Triangle<6> relies on
2457  // on the same set of inequalities. To eliminate unnecessary cases we switch on the base topology
2458  unsigned key = cellTopo.getBaseCellTopologyData() -> key ;
2459  switch( key ) {
2460 
2461  case shards::Line<>::key :
2462  if( !(minus_one <= point[0] && point[0] <= plus_one)) testResult = 0;
2463  break;
2464 
2465  case shards::Triangle<>::key : {
2466  Scalar distance = std::max( std::max( -point[0], -point[1] ), point[0] + point[1] - 1.0 );
2467  if( distance > threshold ) testResult = 0;
2468  break;
2469  }
2470 
2471  case shards::Quadrilateral<>::key :
2472  if(!( (minus_one <= point[0] && point[0] <= plus_one) && \
2473  (minus_one <= point[1] && point[1] <= plus_one) ) ) testResult = 0;
2474  break;
2475 
2476  case shards::Tetrahedron<>::key : {
2477  Scalar distance = std::max( std::max(-point[0],-point[1]), \
2478  std::max(-point[2], point[0] + point[1] + point[2] - 1) );
2479  if( distance > threshold ) testResult = 0;
2480  break;
2481  }
2482 
2483  case shards::Hexahedron<>::key :
2484  if(!((minus_one <= point[0] && point[0] <= plus_one) && \
2485  (minus_one <= point[1] && point[1] <= plus_one) && \
2486  (minus_one <= point[2] && point[2] <= plus_one))) \
2487  testResult = 0;
2488  break;
2489 
2490  // The base of the reference prism is the same as the reference triangle => apply triangle test
2491  // to X and Y coordinates and test whether Z is in [-1,1]
2492  case shards::Wedge<>::key : {
2493  Scalar distance = std::max( std::max( -point[0], -point[1] ), point[0] + point[1] - 1 );
2494  if( distance > threshold || \
2495  point[2] < minus_one || point[2] > plus_one) \
2496  testResult = 0;
2497  break;
2498  }
2499 
2500  // The base of the reference pyramid is the same as the reference quad cell => a horizontal plane
2501  // through a point P(x,y,z) intersects the pyramid at a quadrilateral that equals the base quad
2502  // scaled by (1-z) => P(x,y,z) is inside the pyramid <=> (x,y) is in [-1+z,1-z]^2 && 0 <= Z <= 1
2503  case shards::Pyramid<>::key : {
2504  Scalar left = minus_one + point[2];
2505  Scalar right = plus_one - point[2];
2506  if(!( (left <= point[0] && point[0] <= right) && \
2507  (left <= point[1] && point[1] <= right) &&
2508  (minus_zero <= point[2] && point[2] <= plus_one) ) ) \
2509  testResult = 0;
2510  break;
2511  }
2512 
2513  default:
2514  TEUCHOS_TEST_FOR_EXCEPTION( !( (key == shards::Line<>::key ) ||
2515  (key == shards::Triangle<>::key) ||
2516  (key == shards::Quadrilateral<>::key) ||
2517  (key == shards::Tetrahedron<>::key) ||
2518  (key == shards::Hexahedron<>::key) ||
2519  (key == shards::Wedge<>::key) ||
2520  (key == shards::Pyramid<>::key) ),
2521  std::invalid_argument,
2522  ">>> ERROR (Intrepid::CellTools::checkPointInclusion): Invalid cell topology. ");
2523  }
2524  return testResult;
2525 }
2526 
2527 
2528 
2529 template<class Scalar>
2530 template<class ArrayPoint>
2531 int CellTools<Scalar>::checkPointsetInclusion(const ArrayPoint& points,
2532  const shards::CellTopology & cellTopo,
2533  const double & threshold) {
2534 
2535  int rank = points.rank();
2536 
2537 #ifdef HAVE_INTREPID_DEBUG
2538  TEUCHOS_TEST_FOR_EXCEPTION( !( (1 <=getrank(points) ) && (getrank(points) <= 3) ), std::invalid_argument,
2539  ">>> ERROR (Intrepid::CellTools::checkPointsetInclusion): rank-1, 2 or 3 required for input points array. ");
2540 
2541  // The last dimension of points array at (rank - 1) is the spatial dimension. Must equal the cell dimension.
2542  TEUCHOS_TEST_FOR_EXCEPTION( !((size_t) points.dimension(rank - 1) == (size_t)cellTopo.getDimension() ), std::invalid_argument,
2543  ">>> ERROR (Intrepid::CellTools::checkPointsetInclusion): Point and cell dimensions do not match. ");
2544 #endif
2545 
2546  // create temp output array depending on the rank of the input array
2547  FieldContainer<int> inRefCell;
2548  switch(rank) {
2549  case 1: inRefCell.resize(1); break;
2550  case 2: inRefCell.resize( static_cast<size_t>(points.dimension(0)) ); break;
2551  case 3: inRefCell.resize( static_cast<size_t>(points.dimension(0)), static_cast<size_t>(points.dimension(1)) ); break;
2552  }
2553 
2554  // Call the inclusion method which returns inclusion results for all points
2555  checkPointwiseInclusion(inRefCell, points, cellTopo, threshold);
2556 
2557  // Check if any points were outside, break when finding the first one
2558  int allInside = 1;
2559  for(int i = 0; i < inRefCell.size(); i++ ){
2560  if (inRefCell[i] == 0) {
2561  allInside = 0;
2562  break;
2563  }
2564  }
2565  return allInside;
2566 }
2567 
2568 
2569 
2570 template<class Scalar>
2571 template<class ArrayIncl, class ArrayPoint>
2573  const ArrayPoint & points,
2574  const shards::CellTopology & cellTopo,
2575  const double & threshold) {
2576  int apRank = points.rank();
2577 
2578 #ifdef HAVE_INTREPID_DEBUG
2579 
2580  // Verify that points and inRefCell have correct ranks and dimensions
2581  std::string errmsg = ">>> ERROR (Intrepid::CellTools::checkPointwiseInclusion):";
2582  if(getrank(points) == 1) {
2583  TEUCHOS_TEST_FOR_EXCEPTION( !(getrank(inRefCell) == 1 ), std::invalid_argument,
2584  ">>> ERROR (Intrepid::CellTools::checkPointwiseInclusion): rank-1 input array requires rank-1 output array.");
2585  TEUCHOS_TEST_FOR_EXCEPTION( !(static_cast<size_t>(inRefCell.dimension(0)) == 1), std::invalid_argument,
2586  ">>> ERROR (Intrepid::CellTools::checkPointwiseInclusion): rank-1 input array requires dim0 = 1 for output array.");
2587  }
2588  else if(getrank(points) == 2){
2589  TEUCHOS_TEST_FOR_EXCEPTION( !(getrank(inRefCell) == 1 ), std::invalid_argument,
2590  ">>> ERROR (Intrepid::CellTools::checkPointwiseInclusion): rank-2 input array requires rank-1 output array.");
2591  // dimension 0 of the arrays must match
2592  TEUCHOS_TEST_FOR_EXCEPTION( !requireDimensionMatch( errmsg, inRefCell, 0, points, 0), std::invalid_argument, errmsg);
2593  }
2594  else if (getrank(points) == 3) {
2595  TEUCHOS_TEST_FOR_EXCEPTION( !(getrank(inRefCell) == 2 ), std::invalid_argument,
2596  ">>> ERROR (Intrepid::CellTools::checkPointwiseInclusion): rank-3 input array requires rank-2 output array.");
2597  // dimensions 0 and 1 of the arrays must match
2598  TEUCHOS_TEST_FOR_EXCEPTION( !requireDimensionMatch( errmsg, inRefCell, 0,1, points, 0,1), std::invalid_argument, errmsg);
2599  }
2600  else{
2601  TEUCHOS_TEST_FOR_EXCEPTION( !( (getrank(points) == 1) || (getrank(points) == 2) || (getrank(points) == 3) ), std::invalid_argument,
2602  ">>> ERROR (Intrepid::CellTools::checkPointwiseInclusion): rank-1, 2 or 3 required for input points array. ");
2603  }
2604 
2605  // The last dimension of points array at (rank - 1) is the spatial dimension. Must equal the cell dimension.
2606  TEUCHOS_TEST_FOR_EXCEPTION( !((size_t)points.dimension(apRank - 1) == (size_t)cellTopo.getDimension() ), std::invalid_argument,
2607  ">>> ERROR (Intrepid::CellTools::checkPointwiseInclusion): Point and cell dimensions do not match. ");
2608 
2609 #endif
2610 
2611  // Initializations
2612  int dim0 = 1;
2613  int dim1 = 1;
2614  int pointDim = 0;
2615  switch(apRank) {
2616  case 1:
2617  pointDim = static_cast<size_t>(points.dimension(0));
2618  break;
2619  case 2:
2620  dim1 = static_cast<size_t>(points.dimension(0));
2621  pointDim = static_cast<size_t>(points.dimension(1));
2622  break;
2623  case 3:
2624  dim0 = static_cast<size_t>(points.dimension(0));
2625  dim1 = static_cast<size_t>(points.dimension(1));
2626  pointDim = static_cast<size_t>(points.dimension(2));
2627  break;
2628  default:
2629  TEUCHOS_TEST_FOR_EXCEPTION( !( (1 <= getrank(points) ) && (getrank(points) <= 3) ), std::invalid_argument,
2630  ">>> ERROR (Intrepid::CellTools::checkPointwiseInclusion): rank-1, 2 or 3 required for input points array. ");
2631  }// switch
2632 
2633 
2634  // This method can handle up to rank-3 input arrays. The spatial dim must be the last dimension.
2635  // The method uses [] accessor because array rank is determined at runtime and the appropriate
2636  // (i,j,..,k) accessor is not known. Use of [] requires the following offsets:
2637  // for input array = i0*dim1*pointDim + i1*dim1 (computed in 2 pieces: inPtr0 and inPtr1, resp)
2638  // for output array = i0*dim1 (computed in one piece: outPtr0)
2639  int inPtr0 = 0;
2640  int inPtr1 = 0;
2641  int outPtr0 = 0;
2642  Scalar point[3] = {0.0, 0.0, 0.0};
2643 
2644  for(int i0 = 0; i0 < dim0; i0++){
2645  outPtr0 = i0*dim1;
2646  inPtr0 = outPtr0*pointDim;
2647 
2648  for(int i1 = 0; i1 < dim1; i1++) {
2649  inPtr1 = inPtr0 + i1*pointDim;
2650  point[0] = points[inPtr1];
2651  if(pointDim > 1) {
2652  point[1] = points[inPtr1 + 1];
2653  if(pointDim > 2) {
2654  point[2] = points[inPtr1 + 2];
2655  if(pointDim > 3) {
2656  TEUCHOS_TEST_FOR_EXCEPTION( !( (1 <= pointDim) && (pointDim <= 3)), std::invalid_argument,
2657  ">>> ERROR (Intrepid::CellTools::checkPointwiseInclusion): Input array specifies invalid point dimension ");
2658  }
2659  }
2660  } //if(pointDim > 1)
2661  inRefCell[outPtr0 + i1] = checkPointInclusion(point, pointDim, cellTopo, threshold);
2662  } // for (i1)
2663  } // for(i2)
2664 
2665 }
2666 
2667 
2668 template<class Scalar>
2669 template<class ArrayIncl, class ArrayPoint, class ArrayCell>
2671  const ArrayPoint & points,
2672  const ArrayCell & cellWorkset,
2673  const shards::CellTopology & cell,
2674  const int & whichCell,
2675  const double & threshold)
2676 {
2677  INTREPID_VALIDATE( validateArguments_checkPointwiseInclusion(inCell, points, cellWorkset, whichCell, cell) );
2678 
2679  // For cell topologies with reference cells this test maps the points back to the reference cell
2680  // and uses the method for reference cells
2681  unsigned baseKey = cell.getBaseCellTopologyData() -> key;
2682 
2683  switch(baseKey){
2684 
2685  case shards::Line<>::key :
2686  case shards::Triangle<>::key:
2687  case shards::Quadrilateral<>::key :
2688  case shards::Tetrahedron<>::key :
2689  case shards::Hexahedron<>::key :
2690  case shards::Wedge<>::key :
2691  case shards::Pyramid<>::key :
2692  {
2693  FieldContainer<Scalar> refPoints;
2694 
2695  if(getrank(points) == 2){
2696  refPoints.resize(static_cast<size_t>(points.dimension(0)), static_cast<size_t>(points.dimension(1)) );
2697  mapToReferenceFrame(refPoints, points, cellWorkset, cell, whichCell);
2698  checkPointwiseInclusion(inCell, refPoints, cell, threshold );
2699  }
2700  else if(getrank(points) == 3){
2701  refPoints.resize(static_cast<size_t>(points.dimension(0)), static_cast<size_t>(points.dimension(1)), static_cast<size_t>(points.dimension(2)) );
2702  mapToReferenceFrame(refPoints, points, cellWorkset, cell, whichCell);
2703  checkPointwiseInclusion(inCell, refPoints, cell, threshold );
2704  }
2705  break;
2706  }
2707  default:
2708  TEUCHOS_TEST_FOR_EXCEPTION( true, std::invalid_argument,
2709  ">>> ERROR (Intrepid::CellTools::checkPointwiseInclusion): cell topology not supported");
2710  }// switch
2711 
2712 }
2713 
2714 
2715 //============================================================================================//
2716 // //
2717 // Validation of input/output arguments for CellTools methods //
2718 // //
2719 //============================================================================================//
2720 
2721 template<class Scalar>
2722 template<class ArrayJac, class ArrayPoint, class ArrayCell>
2724  const ArrayPoint & points,
2725  const ArrayCell & cellWorkset,
2726  const int & whichCell,
2727  const shards::CellTopology & cellTopo){
2728 
2729  // Validate cellWorkset array
2730  TEUCHOS_TEST_FOR_EXCEPTION( (getrank(cellWorkset) != 3), std::invalid_argument,
2731  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): rank = 3 required for cellWorkset array");
2732 
2733  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(cellWorkset.dimension(0)) <= 0), std::invalid_argument,
2734  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 0 (number of cells) >= 1 required for cellWorkset array");
2735 
2736  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(cellWorkset.dimension(1)) != (size_t)cellTopo.getSubcellCount(0) ), std::invalid_argument,
2737  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 1 (number of cell nodes) of cellWorkset array does not match cell topology");
2738 
2739  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(cellWorkset.dimension(2)) != (size_t)cellTopo.getDimension() ), std::invalid_argument,
2740  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 2 (spatial dimension) of cellWorkset array does not match cell dimension");
2741 
2742  // validate whichCell. It can be either -1 (default value) or a valid cell ordinal.
2743  TEUCHOS_TEST_FOR_EXCEPTION( !( ( (0 <= whichCell ) && (static_cast<size_t>(whichCell) < static_cast<size_t>(cellWorkset.dimension(0)) ) ) || (whichCell == -1) ), std::invalid_argument,
2744  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): whichCell = -1 or a valid cell ordinal is required.");
2745 
2746 
2747  // Validate points array: can be rank-2 (P,D) or rank-3 (C,P,D)
2748  // If rank-2: admissible jacobians: rank-3 (P,D,D) or rank-4 (C,P,D,D); admissible whichCell: -1 (default) or cell ordinal.
2749  if(getrank(points) == 2) {
2750  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(points.dimension(0)) <= 0), std::invalid_argument,
2751  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 0 (number of points) >= 1 required for points array ");
2752 
2753  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(points.dimension(1)) != (size_t)cellTopo.getDimension() ), std::invalid_argument,
2754  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 1 (spatial dimension) of points array does not match cell dimension");
2755 
2756  // Validate the output array for the Jacobian: if whichCell == -1 all Jacobians are computed, rank-4 (C,P,D,D) required
2757  if(whichCell == -1) {
2758  TEUCHOS_TEST_FOR_EXCEPTION( (getrank(jacobian) != 4), std::invalid_argument,
2759  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): rank = 4 required for jacobian array");
2760 
2761  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(jacobian.dimension(0)) != static_cast<size_t>(cellWorkset.dimension(0))), std::invalid_argument,
2762  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 0 (number of cells) of jacobian array must equal dim 0 of cellWorkset array");
2763 
2764  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(jacobian.dimension(1)) != static_cast<size_t>(points.dimension(0))), std::invalid_argument,
2765  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 1 (number of points) of jacobian array must equal dim 0 of points array");
2766 
2767  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(jacobian.dimension(2)) != static_cast<size_t>(points.dimension(1))), std::invalid_argument,
2768  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 2 (spatial dimension) of jacobian array must equal dim 1 of points array");
2769 
2770  TEUCHOS_TEST_FOR_EXCEPTION( !(static_cast<size_t>(jacobian.dimension(2)) == static_cast<size_t>(jacobian.dimension(3)) ), std::invalid_argument,
2771  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 2 = dim 3 (same spatial dimensions) required for jacobian array. ");
2772 
2773  TEUCHOS_TEST_FOR_EXCEPTION( !( (0 < static_cast<size_t>(jacobian.dimension(3)) ) && (static_cast<size_t>(jacobian.dimension(3)) < 4) ), std::invalid_argument,
2774  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 2 and dim 3 (spatial dimensions) must be between 1 and 3. ");
2775  }
2776  // A single cell Jacobian is computed when whichCell != -1 (whichCell has been already validated), rank-3 (P,D,D) required
2777  else {
2778  TEUCHOS_TEST_FOR_EXCEPTION( (getrank(jacobian) != 3), std::invalid_argument,
2779  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): rank = 3 required for jacobian array");
2780 
2781  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(jacobian.dimension(0)) != static_cast<size_t>(points.dimension(0))), std::invalid_argument,
2782  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 0 (number of points) of jacobian array must equal dim 0 of points array");
2783 
2784  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(jacobian.dimension(1)) != static_cast<size_t>(points.dimension(1))), std::invalid_argument,
2785  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 1 (spatial dimension) of jacobian array must equal dim 1 of points array");
2786 
2787  TEUCHOS_TEST_FOR_EXCEPTION( !(static_cast<size_t>(jacobian.dimension(1)) == static_cast<size_t>(jacobian.dimension(2)) ), std::invalid_argument,
2788  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 1 = dim 2 (same spatial dimensions) required for jacobian array. ");
2789 
2790  TEUCHOS_TEST_FOR_EXCEPTION( !( (0 < static_cast<size_t>(jacobian.dimension(1)) ) && (static_cast<size_t>(jacobian.dimension(1)) < 4) ), std::invalid_argument,
2791  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 1 and dim 2 (spatial dimensions) must be between 1 and 3. ");
2792  }
2793  }
2794  // Point array is rank-3 (C,P,D): requires whichCell = -1 and rank-4 (C,P,D,D) jacobians
2795  else if(getrank(points) ==3){
2796  std::string errmsg = ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian):";
2797  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(points.dimension(0)) != static_cast<size_t>(cellWorkset.dimension(0)) ), std::invalid_argument,
2798  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 0 (number of cells) of points array must equal dim 0 of cellWorkset array");
2799 
2800  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(points.dimension(1)) <= 0), std::invalid_argument,
2801  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 1 (number of points) >= 1 required for points array ");
2802 
2803  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(points.dimension(2)) != (size_t)cellTopo.getDimension() ), std::invalid_argument,
2804  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 2 (spatial dimension) of points array does not match cell dimension");
2805 
2806  TEUCHOS_TEST_FOR_EXCEPTION( (whichCell != -1), std::invalid_argument,
2807  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): default value whichCell=-1 required for rank-3 input points");
2808 
2809  // rank-4 (C,P,D,D) jacobian required for rank-3 (C,P,D) input points
2810  TEUCHOS_TEST_FOR_EXCEPTION( !requireRankRange(errmsg, jacobian, 4, 4), std::invalid_argument,errmsg);
2811 
2812  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(jacobian.dimension(0)) != static_cast<size_t>(points.dimension(0))), std::invalid_argument,
2813  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 0 (number of cells) of jacobian array must equal dim 0 of points array");
2814 
2815  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(jacobian.dimension(1)) != static_cast<size_t>(points.dimension(1))), std::invalid_argument,
2816  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 1 (number of points) of jacobian array must equal dim 1 of points array");
2817 
2818  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(jacobian.dimension(2)) != static_cast<size_t>(points.dimension(2))), std::invalid_argument,
2819  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 2 (spatial dimension) of jacobian array must equal dim 2 of points array");
2820 
2821  TEUCHOS_TEST_FOR_EXCEPTION( !(static_cast<size_t>(jacobian.dimension(2)) == static_cast<size_t>(jacobian.dimension(3)) ), std::invalid_argument,
2822  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 2 = dim 3 (same spatial dimensions) required for jacobian array. ");
2823 
2824  TEUCHOS_TEST_FOR_EXCEPTION( !( (0 < static_cast<size_t>(jacobian.dimension(3)) ) && (static_cast<size_t>(jacobian.dimension(3)) < 4) ), std::invalid_argument,
2825  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): dim 2 and dim 3 (spatial dimensions) must be between 1 and 3. ");
2826  }
2827  else {
2828  TEUCHOS_TEST_FOR_EXCEPTION( !( (getrank(points) == 2) && (getrank(points) ==3) ), std::invalid_argument,
2829  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobian): rank = 2 or 3 required for points array");
2830  }
2831 }
2832 
2833 
2834 
2835 template<class Scalar>
2836 template<class ArrayJacInv, class ArrayJac>
2837 void CellTools<Scalar>::validateArguments_setJacobianInv(const ArrayJacInv & jacobianInv,
2838  const ArrayJac & jacobian)
2839 {
2840  // Validate input jacobian array: admissible ranks & dimensions are:
2841  // - rank-4 with dimensions (C,P,D,D), or rank-3 with dimensions (P,D,D).
2842  int jacobRank = getrank(jacobian);
2843  TEUCHOS_TEST_FOR_EXCEPTION( !( (jacobRank == 4) || (jacobRank == 3) ), std::invalid_argument,
2844  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobianInv): rank = 4 or 3 required for jacobian array. ");
2845 
2846  // Verify correctness of spatial dimensions - they are the last two dimensions of the array: rank-2 and rank-1
2847  TEUCHOS_TEST_FOR_EXCEPTION( !(jacobian.dimension(jacobRank - 1) == jacobian.dimension(jacobRank - 2) ), std::invalid_argument,
2848  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobianInv): dim(rank-2) = dim(rank-2) (same spatial dimensions) required for jacobian array. ");
2849 
2850  TEUCHOS_TEST_FOR_EXCEPTION( !( (0 < jacobian.dimension(jacobRank - 1) ) && (jacobian.dimension(jacobRank - 1) < 4) ), std::invalid_argument,
2851  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobianInv): dim(rank-1) and dim(rank-2) (spatial dimensions) must be between 1 and 3. ");
2852 
2853  // Validate output jacobianInv array: must have the same rank and dimensions as the input array.
2854  std::string errmsg = ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobianInv):";
2855 
2856  TEUCHOS_TEST_FOR_EXCEPTION( !(requireRankMatch(errmsg, jacobianInv, jacobian) ), std::invalid_argument, errmsg);
2857 
2858  TEUCHOS_TEST_FOR_EXCEPTION( !(requireDimensionMatch(errmsg, jacobianInv, jacobian) ), std::invalid_argument, errmsg);
2859 }
2860 
2861 
2862 
2863 template<class Scalar>
2864 template<class ArrayJacDet, class ArrayJac>
2865 void CellTools<Scalar>::validateArguments_setJacobianDetArgs(const ArrayJacDet & jacobianDet,
2866  const ArrayJac & jacobian)
2867 {
2868  // Validate input jacobian array: admissible ranks & dimensions are:
2869  // - rank-4 with dimensions (C,P,D,D), or rank-3 with dimensions (P,D,D).
2870  int jacobRank = getrank(jacobian);
2871  TEUCHOS_TEST_FOR_EXCEPTION( !( (jacobRank == 4) || (jacobRank == 3) ), std::invalid_argument,
2872  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobianInv): rank = 4 or 3 required for jacobian array. ");
2873 
2874  // Verify correctness of spatial dimensions - they are the last two dimensions of the array: rank-2 and rank-1
2875  TEUCHOS_TEST_FOR_EXCEPTION( !(jacobian.dimension(jacobRank - 1) == jacobian.dimension(jacobRank - 2) ), std::invalid_argument,
2876  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobianInv): dim(rank-2) = dim(rank-2) (same spatial dimensions) required for jacobian array. ");
2877 
2878  TEUCHOS_TEST_FOR_EXCEPTION( !( (0 < jacobian.dimension(jacobRank - 1) ) && (jacobian.dimension(jacobRank - 1) < 4) ), std::invalid_argument,
2879  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobianInv): dim(rank-1) and dim(rank-2) (spatial dimensions) must be between 1 and 3. ");
2880 
2881 
2882  // Validate output jacobianDet array: must be rank-2 with dimensions (C,P) if jacobian was rank-4:
2883  if(jacobRank == 4){
2884  TEUCHOS_TEST_FOR_EXCEPTION( !(getrank(jacobianDet) == 2), std::invalid_argument,
2885  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobianDetArgs): rank = 2 required for jacobianDet if jacobian is rank-4. ");
2886 
2887  TEUCHOS_TEST_FOR_EXCEPTION( !(static_cast<size_t>(jacobianDet.dimension(0)) == static_cast<size_t>(jacobian.dimension(0)) ), std::invalid_argument,
2888  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobianDetArgs): dim 0 (number of cells) of jacobianDet array must equal dim 0 of jacobian array. ");
2889 
2890  TEUCHOS_TEST_FOR_EXCEPTION( !(static_cast<size_t>(jacobianDet.dimension(1)) == static_cast<size_t>(jacobian.dimension(1)) ), std::invalid_argument,
2891  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobianDetArgs): dim 1 (number of points) of jacobianDet array must equal dim 1 of jacobian array.");
2892  }
2893 
2894  // must be rank-1 with dimension (P) if jacobian was rank-3
2895  else {
2896  TEUCHOS_TEST_FOR_EXCEPTION( !(getrank(jacobianDet) == 1), std::invalid_argument,
2897  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobianDetArgs): rank = 1 required for jacobianDet if jacobian is rank-3. ");
2898 
2899  TEUCHOS_TEST_FOR_EXCEPTION( !(static_cast<size_t>(jacobianDet.dimension(0)) == static_cast<size_t>(jacobian.dimension(0)) ), std::invalid_argument,
2900  ">>> ERROR (Intrepid::CellTools::validateArguments_setJacobianDetArgs): dim 0 (number of points) of jacobianDet array must equal dim 0 of jacobian array.");
2901  }
2902 }
2903 
2904 
2905 
2906 template<class Scalar>
2907 template<class ArrayPhysPoint, class ArrayRefPoint, class ArrayCell>
2908 void CellTools<Scalar>::validateArguments_mapToPhysicalFrame(const ArrayPhysPoint & physPoints,
2909  const ArrayRefPoint & refPoints,
2910  const ArrayCell & cellWorkset,
2911  const shards::CellTopology & cellTopo,
2912  const int& whichCell)
2913 {
2914  std::string errmsg = ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame):";
2915 
2916  // Validate cellWorkset array
2917  TEUCHOS_TEST_FOR_EXCEPTION( (getrank(cellWorkset) != 3), std::invalid_argument,
2918  ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): rank = 3 required for cellWorkset array");
2919 
2920  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(cellWorkset.dimension(0)) <= 0), std::invalid_argument,
2921  ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 0 (number of cells) >= 1 required for cellWorkset array");
2922 
2923  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(cellWorkset.dimension(1)) != (size_t)cellTopo.getSubcellCount(0) ), std::invalid_argument,
2924  ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 1 (number of cell nodes) of cellWorkset array does not match cell topology");
2925 
2926  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(cellWorkset.dimension(2)) != (size_t)cellTopo.getDimension() ), std::invalid_argument,
2927  ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 2 (spatial dimension) of cellWorkset array does not match cell dimension");
2928 
2929 
2930 
2931 
2932 TEUCHOS_TEST_FOR_EXCEPTION( !( ( (0 <= whichCell ) && ((size_t)whichCell < (size_t)cellWorkset.dimension(0) ) ) || (whichCell == -1) ), std::invalid_argument,
2933  ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): whichCell = -1 or a valid cell ordinal is required.");
2934 
2935  // Validate refPoints array: can be rank-2 (P,D) or rank-3 (C,P,D) array
2936  // If rank-2: admissible output array is (P,D) or (C,P,D); admissible whichCell: -1 (default) or cell ordinal
2937  if(getrank(refPoints) == 2) {
2938  TEUCHOS_TEST_FOR_EXCEPTION( (refPoints.dimension(0) <= 0), std::invalid_argument,
2939  ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 0 (number of points) >= 1 required for refPoints array ");
2940 
2941  TEUCHOS_TEST_FOR_EXCEPTION( ((size_t)refPoints.dimension(1) != (size_t)cellTopo.getDimension() ), std::invalid_argument,
2942  ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 1 (spatial dimension) of refPoints array does not match cell dimension");
2943 
2944  // Validate output array: whichCell = -1 requires rank-3 array with dimensions (C,P,D)
2945  if(whichCell == -1) {
2946  TEUCHOS_TEST_FOR_EXCEPTION( ( (getrank(physPoints) != 3) && (whichCell == -1) ), std::invalid_argument,
2947  ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): rank = 3 required for physPoints array for the default whichCell value");
2948 
2949  TEUCHOS_TEST_FOR_EXCEPTION( ((size_t)physPoints.dimension(0) != (size_t)cellWorkset.dimension(0)), std::invalid_argument,
2950  ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 0 (number of cells) of physPoints array must equal dim 0 of cellWorkset array");
2951 
2952  TEUCHOS_TEST_FOR_EXCEPTION( ((size_t)physPoints.dimension(1) != (size_t)refPoints.dimension(0)), std::invalid_argument,
2953  ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 1 (number of points) of physPoints array must equal dim 0 of refPoints array");
2954 
2955  TEUCHOS_TEST_FOR_EXCEPTION( ((size_t)physPoints.dimension(2) != (size_t)cellTopo.getDimension()), std::invalid_argument,
2956  ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 2 (spatial dimension) does not match cell dimension ");
2957  }
2958  // 0 <= whichCell < num cells requires rank-2 (P,D) arrays for both refPoints and physPoints
2959  else{
2960  TEUCHOS_TEST_FOR_EXCEPTION( (getrank(physPoints) != 2), std::invalid_argument,
2961  ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): rank = 2 required for physPoints array");
2962 
2963  TEUCHOS_TEST_FOR_EXCEPTION( ((size_t)physPoints.dimension(0) != (size_t)refPoints.dimension(0)), std::invalid_argument,
2964  ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 0 (number of points) of physPoints array must equal dim 0 of refPoints array");
2965 
2966  TEUCHOS_TEST_FOR_EXCEPTION( ((size_t)physPoints.dimension(1) != (size_t)cellTopo.getDimension()), std::invalid_argument,
2967  ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 1 (spatial dimension) does not match cell dimension ");
2968  }
2969  }
2970  // refPoints is (C,P,D): requires physPoints to be (C,P,D) and whichCell=-1 (because all cell mappings are applied)
2971  else if(getrank(refPoints) == 3) {
2972 
2973  // 1. validate refPoints dimensions and rank
2974  TEUCHOS_TEST_FOR_EXCEPTION( ((size_t)refPoints.dimension(0) !=(size_t) cellWorkset.dimension(0) ), std::invalid_argument,
2975  ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 0 (number of cells) of refPoints and cellWorkset arraya are required to match ");
2976 
2977  TEUCHOS_TEST_FOR_EXCEPTION( (refPoints.dimension(1) <= 0), std::invalid_argument,
2978  ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 1 (number of points) >= 1 required for refPoints array ");
2979 
2980  TEUCHOS_TEST_FOR_EXCEPTION( ((size_t)refPoints.dimension(2) != (size_t)cellTopo.getDimension() ), std::invalid_argument,
2981  ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): dim 2 (spatial dimension) of refPoints array does not match cell dimension");
2982 
2983  // 2. whichCell must be -1
2984  TEUCHOS_TEST_FOR_EXCEPTION( (whichCell != -1), std::invalid_argument,
2985  ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): default value is required for rank-3 refPoints array");
2986 
2987  // 3. physPoints must match rank and dimensions of refPoints
2988  TEUCHOS_TEST_FOR_EXCEPTION( !requireRankMatch(errmsg, refPoints, physPoints), std::invalid_argument, errmsg );
2989  TEUCHOS_TEST_FOR_EXCEPTION( !requireDimensionMatch(errmsg, refPoints, physPoints), std::invalid_argument, errmsg);
2990  }
2991  // if rank is not 2 or 3 throw exception
2992  else {
2993  TEUCHOS_TEST_FOR_EXCEPTION( !( (getrank(refPoints) == 2) || (getrank(refPoints) == 3) ), std::invalid_argument,
2994  ">>> ERROR (Intrepid::CellTools::validateArguments_mapToPhysicalFrame): rank = 2 or 3 required for refPoints array");
2995  }
2996 }
2997 template<class Scalar>
2998 template<class ArrayRefPoint, class ArrayPhysPoint, class ArrayCell>
3000  const ArrayPhysPoint & physPoints,
3001  const ArrayCell & cellWorkset,
3002  const shards::CellTopology & cellTopo,
3003  const int& whichCell)
3004 {
3005  std::string errmsg = ">>> ERROR (Intrepid::CellTools::validateArguments_mapToReferenceFrame):";
3006  std::string errmsg1 = ">>> ERROR (Intrepid::CellTools::validateArguments_mapToReferenceFrame):";
3007 
3008  // Validate cellWorkset array
3009  TEUCHOS_TEST_FOR_EXCEPTION( (getrank(cellWorkset) != 3), std::invalid_argument,
3010  ">>> ERROR (Intrepid::CellTools::validateArguments_mapToReferenceFrame): rank = 3 required for cellWorkset array");
3011 
3012  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(cellWorkset.dimension(0)) <= 0), std::invalid_argument,
3013  ">>> ERROR (Intrepid::CellTools::validateArguments_mapToReferenceFrame): dim 0 (number of cells) >= 1 required for cellWorkset array");
3014 
3015  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(cellWorkset.dimension(1)) != (size_t)cellTopo.getSubcellCount(0) ), std::invalid_argument,
3016  ">>> ERROR (Intrepid::CellTools::validateArguments_mapToReferenceFrame): dim 1 (number of cell nodes) of cellWorkset array does not match cell topology");
3017 
3018  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(cellWorkset.dimension(2)) != (size_t)cellTopo.getDimension() ), std::invalid_argument,
3019  ">>> ERROR (Intrepid::CellTools::validateArguments_mapToReferenceFrame): dim 2 (spatial dimension) of cellWorkset array does not match cell dimension");
3020 
3021  // Validate whichCell. It can be either -1 (default value) or a valid celli ordinal.
3022  TEUCHOS_TEST_FOR_EXCEPTION( !( ( (0 <= whichCell ) && ((size_t)whichCell <(size_t) cellWorkset.dimension(0) ) ) || (whichCell == -1) ), std::invalid_argument,
3023  ">>> ERROR (Intrepid::CellTools::validateArguments_mapToReferenceFrame): whichCell = -1 or a valid cell ordinal is required.");
3024  // Admissible ranks and dimensions of refPoints and physPoints depend on whichCell value:
3025  // default is to map multiple sets of points to multiple sets of points. (C,P,D) arrays required
3026  int validRank;
3027  if(whichCell == -1) {
3028  validRank = 3;
3029  errmsg1 += " default value of whichCell requires rank-3 arrays:";
3030  }
3031  // whichCell is valid cell ordinal => we map single set of pts to a single set of pts. (P,D) arrays required
3032  else{
3033  errmsg1 += " rank-2 arrays required when whichCell is valid cell ordinal";
3034  validRank = 2;
3035  }
3036  TEUCHOS_TEST_FOR_EXCEPTION( !requireRankRange(errmsg1, refPoints, validRank,validRank), std::invalid_argument, errmsg1);
3037  TEUCHOS_TEST_FOR_EXCEPTION( !requireRankMatch(errmsg1, physPoints, refPoints), std::invalid_argument, errmsg1);
3038  TEUCHOS_TEST_FOR_EXCEPTION( !requireDimensionMatch(errmsg1, refPoints, physPoints), std::invalid_argument, errmsg1);
3039 }
3040 
3041 
3042 
3043 template<class Scalar>
3044 template<class ArrayRefPoint, class ArrayInitGuess, class ArrayPhysPoint, class ArrayCell>
3046  const ArrayInitGuess & initGuess,
3047  const ArrayPhysPoint & physPoints,
3048  const ArrayCell & cellWorkset,
3049  const shards::CellTopology & cellTopo,
3050  const int& whichCell)
3051 {
3052  // Call the method that validates arguments with the default initial guess selection
3053  validateArguments_mapToReferenceFrame(refPoints, physPoints, cellWorkset, cellTopo, whichCell);
3054 
3055  // Then check initGuess: its rank and dimensions must match those of physPoints.
3056  std::string errmsg = ">>> ERROR (Intrepid::CellTools::validateArguments_mapToReferenceFrame):";
3057  TEUCHOS_TEST_FOR_EXCEPTION( !requireDimensionMatch(errmsg, initGuess, physPoints), std::invalid_argument, errmsg);
3058 }
3059 
3060 
3061 template<class Scalar>
3062 template<class ArrayIncl, class ArrayPoint, class ArrayCell>
3064  const ArrayPoint & physPoints,
3065  const ArrayCell & cellWorkset,
3066  const int & whichCell,
3067  const shards::CellTopology & cell)
3068 {
3069  // Validate cellWorkset array
3070  TEUCHOS_TEST_FOR_EXCEPTION( (getrank(cellWorkset) != 3), std::invalid_argument,
3071  ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): rank = 3 required for cellWorkset array");
3072 
3073  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(cellWorkset.dimension(0)) <= 0), std::invalid_argument,
3074  ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): dim 0 (number of cells) >= 1 required for cellWorkset array");
3075 
3076  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(cellWorkset.dimension(1)) != (size_t)cell.getSubcellCount(0) ), std::invalid_argument,
3077  ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): dim 1 (number of cell nodes) of cellWorkset array does not match cell topology");
3078 
3079  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(cellWorkset.dimension(2)) != (size_t)cell.getDimension() ), std::invalid_argument,
3080  ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): dim 2 (spatial dimension) of cellWorkset array does not match cell dimension");
3081 
3082 
3083  // Validate whichCell It can be either -1 (default value) or a valid cell ordinal.
3084  TEUCHOS_TEST_FOR_EXCEPTION( !( ( (0 <= whichCell ) && (whichCell < cellWorkset.dimension(0) ) ) || (whichCell == -1) ), std::invalid_argument,
3085  ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): whichCell = -1 or a valid cell ordinal is required.");
3086 
3087  // Validate points array: can be rank-2 (P,D) or rank-3 (C,P,D)
3088  // If rank-2: admissible inCell is rank-1 (P); admissible whichCell is valid cell ordinal but not -1.
3089  if(getrank(physPoints) == 2) {
3090 
3091  TEUCHOS_TEST_FOR_EXCEPTION( (whichCell == -1), std::invalid_argument,
3092  ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): whichCell = a valid cell ordinal is required with rank-2 input array.");
3093 
3094  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(physPoints.dimension(0)) <= 0), std::invalid_argument,
3095  ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): dim 0 (number of points) >= 1 required for physPoints array ");
3096 
3097  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(physPoints.dimension(1)) != (size_t)cell.getDimension() ), std::invalid_argument,
3098  ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): dim 1 (spatial dimension) of physPoints array does not match cell dimension");
3099 
3100  // Validate inCell
3101  TEUCHOS_TEST_FOR_EXCEPTION( (getrank(inCell) != 1), std::invalid_argument,
3102  ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): rank = 1 required for inCell array");
3103 
3104  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(inCell.dimension(0)) != static_cast<size_t>(physPoints.dimension(0))), std::invalid_argument,
3105  ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): dim 0 (number of points) of inCell array must equal dim 0 of physPoints array");
3106  }
3107  // If rank-3: admissible inCell is rank-2 (C,P); admissible whichCell = -1.
3108  else if (getrank(physPoints) == 3){
3109 
3110  TEUCHOS_TEST_FOR_EXCEPTION( !(whichCell == -1), std::invalid_argument,
3111  ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): whichCell = -1 is required with rank-3 input array.");
3112 
3113  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(physPoints.dimension(0)) != static_cast<size_t>(cellWorkset.dimension(0)) ), std::invalid_argument,
3114  ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): dim 0 (number of cells) of physPoints array must equal dim 0 of cellWorkset array ");
3115 
3116  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(physPoints.dimension(1)) <= 0), std::invalid_argument,
3117  ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): dim 1 (number of points) >= 1 required for physPoints array ");
3118 
3119  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(physPoints.dimension(2)) != (size_t)cell.getDimension() ), std::invalid_argument,
3120  ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): dim 2 (spatial dimension) of physPoints array does not match cell dimension");
3121 
3122  // Validate inCell
3123  TEUCHOS_TEST_FOR_EXCEPTION( (getrank(inCell) != 2), std::invalid_argument,
3124  ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): rank = 2 required for inCell array");
3125 
3126  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(inCell.dimension(0)) != static_cast<size_t>(physPoints.dimension(0))), std::invalid_argument,
3127  ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): dim 0 (number of cells) of inCell array must equal dim 0 of physPoints array");
3128 
3129  TEUCHOS_TEST_FOR_EXCEPTION( (static_cast<size_t>(inCell.dimension(1)) != static_cast<size_t>(physPoints.dimension(1))), std::invalid_argument,
3130  ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): dim 1 (number of points) of inCell array must equal dim 1 of physPoints array");
3131  }
3132  else {
3133  TEUCHOS_TEST_FOR_EXCEPTION( !( (getrank(physPoints) == 2) && (getrank(physPoints) ==3) ), std::invalid_argument,
3134  ">>> ERROR (Intrepid::CellTools::validateArguments_checkPointwiseInclusion): rank = 2 or 3 required for points array");
3135  }
3136 }
3137 
3138 
3139 
3140 //============================================================================================//
3141 // //
3142 // Debug //
3143 // //
3144 //============================================================================================//
3145 
3146 
3147 template<class Scalar>
3149  const int subcellOrd,
3150  const shards::CellTopology & parentCell){
3151 
3152  // Get number of vertices for the specified subcell and parent cell dimension
3153  int subcVertexCount = parentCell.getVertexCount(subcellDim, subcellOrd);
3154  int cellDim = parentCell.getDimension();
3155 
3156  // Allocate space for the subcell vertex coordinates
3157  FieldContainer<double> subcellVertices(subcVertexCount, cellDim);
3158 
3159  // Retrieve the vertex coordinates
3160  getReferenceSubcellVertices(subcellVertices,
3161  subcellDim,
3162  subcellOrd,
3163  parentCell);
3164 
3165  // Print the vertices
3166  std::cout
3167  << " Subcell " << std::setw(2) << subcellOrd
3168  << " is " << parentCell.getName(subcellDim, subcellOrd) << " with vertices = {";
3169 
3170  // Loop over subcell vertices
3171  for(int subcVertOrd = 0; subcVertOrd < subcVertexCount; subcVertOrd++){
3172  std::cout<< "(";
3173 
3174  // Loop over vertex Cartesian coordinates
3175  for(int dim = 0; dim < (int)parentCell.getDimension(); dim++){
3176  std::cout << subcellVertices(subcVertOrd, dim);
3177  if(dim < (int)parentCell.getDimension()-1 ) { std::cout << ","; }
3178  }
3179  std::cout<< ")";
3180  if(subcVertOrd < subcVertexCount - 1) { std::cout << ", "; }
3181  }
3182  std::cout << "}\n";
3183 }
3184 
3185 
3186 template<class Scalar>
3187 template<class ArrayCell>
3188 void CellTools<Scalar>::printWorksetSubcell(const ArrayCell & cellWorkset,
3189  const shards::CellTopology & parentCell,
3190  const int& pCellOrd,
3191  const int& subcellDim,
3192  const int& subcellOrd,
3193  const int& fieldWidth){
3194 
3195  // Get the ordinals, relative to reference cell, of subcell cellWorkset
3196  int subcNodeCount = parentCell.getNodeCount(subcellDim, subcellOrd);
3197  int pCellDim = parentCell.getDimension();
3198  std::vector<int> subcNodeOrdinals(subcNodeCount);
3199 
3200  for(int i = 0; i < subcNodeCount; i++){
3201  subcNodeOrdinals[i] = parentCell.getNodeMap(subcellDim, subcellOrd, i);
3202  }
3203 
3204  // Loop over parent cells and print subcell cellWorkset
3205 
3206  std::cout
3207  << " Subcell " << subcellOrd << " on parent cell " << pCellOrd << " is "
3208  << parentCell.getName(subcellDim, subcellOrd) << " with node(s) \n ({";
3209 
3210  for(int i = 0; i < subcNodeCount; i++){
3211 
3212  // print Cartesian coordinates of the node
3213  for(int dim = 0; dim < pCellDim; dim++){
3214  std::cout
3215  << std::setw(fieldWidth) << std::right << cellWorkset(pCellOrd, subcNodeOrdinals[i], dim);
3216  if(dim < pCellDim - 1){ std::cout << ","; }
3217  }
3218  std::cout << "}";
3219  if(i < subcNodeCount - 1){ std::cout <<", {"; }
3220  }
3221  std::cout << ")\n\n";
3222 }
3223 //============================================================================================//
3224 // //
3225 // Control Volume Coordinates //
3226 // //
3227 //============================================================================================//
3228 
3229  template<class Scalar>
3230  template<class ArrayCVCoord, class ArrayCellCoord>
3231  void CellTools<Scalar>::getSubCVCoords(ArrayCVCoord & subCVCoords,
3232  const ArrayCellCoord & cellCoords,
3233  const shards::CellTopology& primaryCell)
3234  {
3235 
3236  // get array dimensions
3237  int numCells = cellCoords.dimension(0);
3238  int numNodesPerCell = cellCoords.dimension(1);
3239  int spaceDim = cellCoords.dimension(2);
3240 
3241  // num edges per primary cell
3242  int numEdgesPerCell = primaryCell.getEdgeCount();
3243 
3244  // num faces per primary cell
3245  int numFacesPerCell = 0;
3246  if (spaceDim > 2){
3247  numFacesPerCell = primaryCell.getFaceCount();
3248  }
3249 
3250  // get cell centroids
3251  Intrepid::FieldContainer<Scalar> barycenter(numCells,spaceDim);
3252  getBarycenter(barycenter,cellCoords);
3253 
3254  // loop over cells
3255  for (int icell = 0; icell < numCells; icell++){
3256 
3257  // get primary edge midpoints
3258  Intrepid::FieldContainer<Scalar> edgeMidpts(numEdgesPerCell,spaceDim);
3259  for (int iedge = 0; iedge < numEdgesPerCell; iedge++){
3260  for (int idim = 0; idim < spaceDim; idim++){
3261 
3262  int node0 = primaryCell.getNodeMap(1,iedge,0);
3263  int node1 = primaryCell.getNodeMap(1,iedge,1);
3264  edgeMidpts(iedge,idim) = (cellCoords(icell,node0,idim) +
3265  cellCoords(icell,node1,idim))/2.0;
3266 
3267  } // end loop over dimensions
3268  } // end loop over cell edges
3269 
3270  // get primary face midpoints in 3-D
3271  int numNodesPerFace;
3272  Intrepid::FieldContainer<Scalar> faceMidpts(numFacesPerCell,spaceDim);
3273  if (spaceDim > 2) {
3274  for (int iface = 0; iface < numFacesPerCell; iface++){
3275  numNodesPerFace = primaryCell.getNodeCount(2,iface);
3276 
3277  for (int idim = 0; idim < spaceDim; idim++){
3278 
3279  for (int inode0 = 0; inode0 < numNodesPerFace; inode0++) {
3280  int node1 = primaryCell.getNodeMap(2,iface,inode0);
3281  faceMidpts(iface,idim) += cellCoords(icell,node1,idim)/numNodesPerFace;
3282  }
3283 
3284  } // end loop over dimensions
3285  } // end loop over cell faces
3286  }
3287 
3288  // define coordinates for subcontrol volumes
3289  switch(primaryCell.getKey() ) {
3290 
3291  // 2-d parent cells
3292  case shards::Triangle<3>::key:
3293  case shards::Quadrilateral<4>::key:
3294 
3295  for (int inode = 0; inode < numNodesPerCell; inode++){
3296  for (int idim = 0; idim < spaceDim; idim++){
3297 
3298  // set first node to primary cell node
3299  subCVCoords(icell,inode,0,idim) = cellCoords(icell,inode,idim);
3300 
3301  // set second node to adjacent edge midpoint
3302  subCVCoords(icell,inode,1,idim) = edgeMidpts(inode,idim);
3303 
3304  // set third node to cell barycenter
3305  subCVCoords(icell,inode,2,idim) = barycenter(icell,idim);
3306 
3307  // set fourth node to other adjacent edge midpoint
3308  int jnode = numNodesPerCell-1;
3309  if (inode > 0) jnode = inode - 1;
3310  subCVCoords(icell,inode,3,idim) = edgeMidpts(jnode,idim);
3311 
3312  } // dim loop
3313  } // node loop
3314 
3315  break;
3316 
3317  case shards::Hexahedron<8>::key:
3318 
3319  for (int idim = 0; idim < spaceDim; idim++){
3320 
3321  // loop over the horizontal quads that define the subcontrol volume coords
3322  for (int icount = 0; icount < 4; icount++){
3323 
3324  // set first node of bottom hex to primary cell node
3325  // and fifth node of upper hex
3326  subCVCoords(icell,icount,0,idim) = cellCoords(icell,icount,idim);
3327  subCVCoords(icell,icount+4,4,idim) = cellCoords(icell,icount+4,idim);
3328 
3329  // set second node of bottom hex to adjacent edge midpoint
3330  // and sixth node of upper hex
3331  subCVCoords(icell,icount,1,idim) = edgeMidpts(icount,idim);
3332  subCVCoords(icell,icount+4,5,idim) = edgeMidpts(icount+4,idim);
3333 
3334  // set third node of bottom hex to bottom face midpoint (number 4)
3335  // and seventh node of upper hex to top face midpoint
3336  subCVCoords(icell,icount,2,idim) = faceMidpts(4,idim);
3337  subCVCoords(icell,icount+4,6,idim) = faceMidpts(5,idim);
3338 
3339  // set fourth node of bottom hex to other adjacent edge midpoint
3340  // and eight node of upper hex to other adjacent edge midpoint
3341  int jcount = 3;
3342  if (icount > 0) jcount = icount - 1;
3343  subCVCoords(icell,icount,3,idim) = edgeMidpts(jcount,idim);
3344  subCVCoords(icell,icount+4,7,idim) = edgeMidpts(jcount+4,idim);
3345 
3346  // set fifth node to vertical edge
3347  // same as first node of upper hex
3348  subCVCoords(icell,icount,4,idim) = edgeMidpts(icount+numNodesPerCell,idim);
3349  subCVCoords(icell,icount+4,0,idim) = edgeMidpts(icount+numNodesPerCell,idim);
3350 
3351  // set sixth node to adjacent face midpoint
3352  // same as second node of upper hex
3353  subCVCoords(icell,icount,5,idim) = faceMidpts(icount,idim);
3354  subCVCoords(icell,icount+4,1,idim) = faceMidpts(icount,idim);
3355 
3356  // set seventh node to barycenter
3357  // same as third node of upper hex
3358  subCVCoords(icell,icount,6,idim) = barycenter(icell,idim);
3359  subCVCoords(icell,icount+4,2,idim) = barycenter(icell,idim);
3360 
3361  // set eighth node to other adjacent face midpoint
3362  // same as fourth node of upper hex
3363  jcount = 3;
3364  if (icount > 0) jcount = icount - 1;
3365  subCVCoords(icell,icount,7,idim) = faceMidpts(jcount,idim);
3366  subCVCoords(icell,icount+4,3,idim) = faceMidpts(jcount,idim);
3367 
3368  } // count loop
3369 
3370  } // dim loop
3371 
3372  break;
3373 
3374  case shards::Tetrahedron<4>::key:
3375 
3376  for (int idim = 0; idim < spaceDim; idim++){
3377 
3378  // loop over the three bottom nodes
3379  for (int icount = 0; icount < 3; icount++){
3380 
3381  // set first node of bottom hex to primary cell node
3382  subCVCoords(icell,icount,0,idim) = cellCoords(icell,icount,idim);
3383 
3384  // set second node of bottom hex to adjacent edge midpoint
3385  subCVCoords(icell,icount,1,idim) = edgeMidpts(icount,idim);
3386 
3387  // set third node of bottom hex to bottom face midpoint (number 3)
3388  subCVCoords(icell,icount,2,idim) = faceMidpts(3,idim);
3389 
3390  // set fourth node of bottom hex to other adjacent edge midpoint
3391  int jcount = 2;
3392  if (icount > 0) jcount = icount - 1;
3393  subCVCoords(icell,icount,3,idim) = edgeMidpts(jcount,idim);
3394 
3395  // set fifth node to vertical edge
3396  subCVCoords(icell,icount,4,idim) = edgeMidpts(icount+3,idim);
3397 
3398  // set sixth node to adjacent face midpoint
3399  subCVCoords(icell,icount,5,idim) = faceMidpts(icount,idim);
3400 
3401  // set seventh node to barycenter
3402  subCVCoords(icell,icount,6,idim) = barycenter(icell,idim);
3403 
3404  // set eighth node to other adjacent face midpoint
3405  jcount = 2;
3406  if (icount > 0) jcount = icount - 1;
3407  subCVCoords(icell,icount,7,idim) = faceMidpts(jcount,idim);
3408 
3409  } //count loop
3410 
3411  // Control volume attached to fourth node
3412  // set first node of bottom hex to primary cell node
3413  subCVCoords(icell,3,0,idim) = cellCoords(icell,3,idim);
3414 
3415  // set second node of bottom hex to adjacent edge midpoint
3416  subCVCoords(icell,3,1,idim) = edgeMidpts(3,idim);
3417 
3418  // set third node of bottom hex to bottom face midpoint (number 3)
3419  subCVCoords(icell,3,2,idim) = faceMidpts(2,idim);
3420 
3421  // set fourth node of bottom hex to other adjacent edge midpoint
3422  subCVCoords(icell,3,3,idim) = edgeMidpts(5,idim);
3423 
3424  // set fifth node to vertical edge
3425  subCVCoords(icell,3,4,idim) = edgeMidpts(4,idim);
3426 
3427  // set sixth node to adjacent face midpoint
3428  subCVCoords(icell,3,5,idim) = faceMidpts(0,idim);
3429 
3430  // set seventh node to barycenter
3431  subCVCoords(icell,3,6,idim) = barycenter(icell,idim);
3432 
3433  // set eighth node to other adjacent face midpoint
3434  subCVCoords(icell,3,7,idim) = faceMidpts(1,idim);
3435 
3436  } // dim loop
3437 
3438  break;
3439 
3440  default:
3441  TEUCHOS_TEST_FOR_EXCEPTION( true, std::invalid_argument,
3442  ">>> ERROR (getSubCVCoords: invalid cell topology.");
3443  } // cell key
3444 
3445  } // cell loop
3446 
3447 } // getSubCVCoords
3448 
3449  template<class Scalar>
3450  template<class ArrayCent, class ArrayCellCoord>
3451  void CellTools<Scalar>::getBarycenter(ArrayCent & barycenter, const ArrayCellCoord & cellCoords)
3452 {
3453  // get array dimensions
3454  int numCells = cellCoords.dimension(0);
3455  int numVertsPerCell = cellCoords.dimension(1);
3456  int spaceDim = cellCoords.dimension(2);
3457 
3458  if (spaceDim == 2)
3459  {
3460  // Method for general polygons
3461  for (int icell = 0; icell < numCells; icell++){
3462 
3463  Intrepid::FieldContainer<Scalar> cell_centroid(spaceDim);
3464  Scalar area = 0;
3465 
3466  for (int inode = 0; inode < numVertsPerCell; inode++){
3467 
3468  int jnode = inode + 1;
3469  if (jnode >= numVertsPerCell) {
3470  jnode = 0;
3471  }
3472 
3473  Scalar area_mult = cellCoords(icell,inode,0)*cellCoords(icell,jnode,1)
3474  - cellCoords(icell,jnode,0)*cellCoords(icell,inode,1);
3475  cell_centroid(0) += (cellCoords(icell,inode,0) + cellCoords(icell,jnode,0))*area_mult;
3476  cell_centroid(1) += (cellCoords(icell,inode,1) + cellCoords(icell,jnode,1))*area_mult;
3477 
3478  area += 0.5*area_mult;
3479  }
3480 
3481  barycenter(icell,0) = cell_centroid(0)/(6.0*area);
3482  barycenter(icell,1) = cell_centroid(1)/(6.0*area);
3483  }
3484 
3485  }
3486  else
3487  {
3488  // This method works fine for simplices, but for other 3-d shapes
3489  // is not precisely accurate. Could replace with approximate integration
3490  // perhaps.
3491  for (int icell = 0; icell < numCells; icell++){
3492 
3493  Intrepid::FieldContainer<Scalar> cell_centroid(spaceDim);
3494 
3495  for (int inode = 0; inode < numVertsPerCell; inode++){
3496  for (int idim = 0; idim < spaceDim; idim++){
3497  cell_centroid(idim) += cellCoords(icell,inode,idim)/numVertsPerCell;
3498  }
3499  }
3500  for (int idim = 0; idim < spaceDim; idim++){
3501  barycenter(icell,idim) = cell_centroid(idim);
3502  }
3503  }
3504  }
3505 
3506  } // get Barycenter
3507 } // namespace Intrepid
3508 #endif
int size() const
Returns size of the FieldContainer defined as the product of its dimensions.
Implementation of basic linear algebra functionality in Euclidean space.
static const double * getReferenceNode(const shards::CellTopology &cell, const int nodeOrd)
Retrieves the Cartesian coordinates of a reference cell node.
static void validateArguments_mapToReferenceFrame(const ArrayRefPoint &refPoints, const ArrayPhysPoint &physPoints, const ArrayCell &cellWorkset, const shards::CellTopology &cellTopo, const int &whichCell)
Validates arguments to Intrepid::CellTools::mapToReferenceFrame with default initial guess...
Implementation of the serendipity-family H(grad)-compatible FEM basis of degree 2 on a Hexahedron cel...
static void getReferenceEdgeTangent(ArrayEdgeTangent &refEdgeTangent, const int &edgeOrd, const shards::CellTopology &parentCell)
Computes constant tangent vectors to edges of 2D or 3D reference cells.
static void mapToReferenceSubcell(ArraySubcellPoint &refSubcellPoints, const ArrayParamPoint &paramPoints, const int subcellDim, const int subcellOrd, const shards::CellTopology &parentCell)
Computes parameterization maps of 1- and 2-subcells of reference cells.
Implementation of the default H(grad)-compatible FEM basis of degree 1 on Wedge cell.
static void getPhysicalFaceNormals(ArrayFaceNormal &faceNormals, const ArrayJac &worksetJacobians, const int &worksetFaceOrd, const shards::CellTopology &parentCell)
Computes non-normalized normal vectors to physical faces in a face workset ; (see Subcell worksets fo...
static void setJacobianInv(ArrayJacInv &jacobianInv, const ArrayJac &jacobian)
Computes the inverse of the Jacobian matrix DF of the reference-to-physical frame map F...
Implementation of the default H(grad)-compatible FEM basis of degree 2 on Wedge cell.
static void getPhysicalEdgeTangents(ArrayEdgeTangent &edgeTangents, const ArrayJac &worksetJacobians, const int &worksetEdgeOrd, const shards::CellTopology &parentCell)
Computes non-normalized tangent vectors to physical edges in an edge workset ; (see Subcell worksets ...
static void mapToReferenceFrame(ArrayRefPoint &refPoints, const ArrayPhysPoint &physPoints, const ArrayCell &cellWorkset, const shards::CellTopology &cellTopo, const int &whichCell=-1)
Computes , the inverse of the reference-to-physical frame map using a default initial guess...
#define INTREPID_MAX_NEWTON
Maximum number of Newton iterations used internally in methods such as computing the action of the in...
static void getReferenceSideNormal(ArraySideNormal &refSideNormal, const int &sideOrd, const shards::CellTopology &parentCell)
Computes constant normal vectors to sides of 2D or 3D reference cells.
static void getReferenceFaceTangents(ArrayFaceTangentU &refFaceTanU, ArrayFaceTangentV &refFaceTanV, const int &faceOrd, const shards::CellTopology &parentCell)
Computes pairs of constant tangent vectors to faces of a 3D reference cells.
Implementation of the default H(grad)-compatible FEM basis of degree 2 on Hexahedron cell...
static void printSubcellVertices(const int subcellDim, const int subcellOrd, const shards::CellTopology &parentCell)
Prints the reference space coordinates of the vertices of the specified subcell.
static void add(Scalar *sumArray, const Scalar *inArray1, const Scalar *inArray2, const int size)
Adds contiguous data inArray1 and inArray2 of size size: sumArray = inArray1 + inArray2.
static void getReferenceFaceNormal(ArrayFaceNormal &refFaceNormal, const int &faceOrd, const shards::CellTopology &parentCell)
Computes constant normal vectors to faces of 3D reference cell.
Implementation of the default H(grad)-compatible FEM basis of degree 1 on Line cell.
static void mapToPhysicalFrame(ArrayPhysPoint &physPoints, const ArrayRefPoint &refPoints, const ArrayCell &cellWorkset, const shards::CellTopology &cellTopo, const int &whichCell=-1)
Computes F, the reference-to-physical frame map.
static Scalar vectorNorm(const Scalar *inVec, const size_t dim, const ENorm normType)
Computes norm (1, 2, infinity) of the vector inVec of size dim.
Implementation of the default H(grad)-compatible FEM basis of degree 1 on Triangle cell...
static void getReferenceSubcellVertices(ArraySubcellVert &subcellVertices, const int subcellDim, const int subcellOrd, const shards::CellTopology &parentCell)
Retrieves the Cartesian coordinates of all vertices of a reference subcell.
static void getPhysicalSideNormals(ArraySideNormal &sideNormals, const ArrayJac &worksetJacobians, const int &worksetSideOrd, const shards::CellTopology &parentCell)
Computes non-normalized normal vectors to physical sides in a side workset .
static int checkPointsetInclusion(const ArrayPoint &points, const shards::CellTopology &cellTopo, const double &threshold=INTREPID_THRESHOLD)
Checks if a set of points belongs to a reference cell.
static int hasReferenceCell(const shards::CellTopology &cellTopo)
Checks if a cell topology has reference cell.
Implementation of an H(grad)-compatible FEM basis of degree 2 on Wedge cell.
Implementation of the default H(grad)-compatible FEM basis of degree 1 on Quadrilateral cell...
static void inverse(Scalar *inverseMat, const Scalar *inMat, const size_t dim)
Computes inverse of the square matrix inMat of size dim by dim.
Implementation of the default H(grad)-compatible FEM basis of degree 2 on Tetrahedron cell...
static void mapToReferenceFrameInitGuess(ArrayRefPoint &refPoints, const ArrayInitGuess &initGuess, const ArrayPhysPoint &physPoints, const ArrayCell &cellWorkset, const shards::CellTopology &cellTopo, const int &whichCell=-1)
Computation of , the inverse of the reference-to-physical frame map using user-supplied initial guess...
static void setSubcellParametrization(FieldContainer< double > &subcellParametrization, const int subcellDim, const shards::CellTopology &parentCell)
Defines orientation-preserving parametrizations of reference edges and faces of cell topologies with ...
static void getReferenceSubcellNodes(ArraySubcellNode &subcellNodes, const int subcellDim, const int subcellOrd, const shards::CellTopology &parentCell)
Retrieves the Cartesian coordinates of all nodes of a reference subcell.
An abstract base class that defines interface for concrete basis implementations for Finite Element (...
static int checkPointInclusion(const Scalar *point, const int pointDim, const shards::CellTopology &cellTopo, const double &threshold=INTREPID_THRESHOLD)
Checks if a point belongs to a reference cell.
static const double * getReferenceVertex(const shards::CellTopology &cell, const int vertexOrd)
Retrieves the Cartesian coordinates of a reference cell vertex.
static void printWorksetSubcell(const ArrayCell &cellWorkset, const shards::CellTopology &parentCell, const int &pCellOrd, const int &subcellDim, const int &subcellOrd, const int &fieldWidth=3)
Prints the nodes of a subcell from a cell workset.
static void validateArguments_checkPointwiseInclusion(ArrayIncl &inCell, const ArrayPoint &physPoints, const ArrayCell &cellWorkset, const int &whichCell, const shards::CellTopology &cell)
Validates arguments to Intrepid::CellTools::checkPointwiseInclusion.
Implementation of the default H(grad)-compatible FEM basis of degree 2 on Quadrilateral cell...
void resize(const int dim0)
Resizes FieldContainer to a rank-1 container with the specified dimension, initialized by 0...
static void validateArguments_setJacobianDetArgs(const ArrayJacDet &jacobianDet, const ArrayJac &jacobian)
Validates arguments to Intrepid::CellTools::setJacobianDet.
Implementation of the default H(grad)-compatible FEM basis of degree 1 on Pyramid cell...
static void matvec(Scalar *matVec, const Scalar *inMat, const Scalar *inVec, const size_t dim)
Matrix-vector left multiply using contiguous data: matVec = inMat * inVec.
static void vecprod(ArrayVecProd &vecProd, const ArrayIn1 &inLeft, const ArrayIn2 &inRight)
Vector product using multidimensional arrays: vecProd = inVecLeft x inVecRight
Implementation of the default H(grad)-compatible FEM basis of degree 1 on Hexahedron cell...
Implementation of an H(grad)-compatible FEM basis of degree 2 on a Pyramid cell.
static void validateArguments_setJacobianInv(const ArrayJacInv &jacobianInv, const ArrayJac &jacobian)
Validates arguments to Intrepid::CellTools::setJacobianInv.
static void validateArguments_mapToPhysicalFrame(const ArrayPhysPoint &physPoints, const ArrayRefPoint &refPoints, const ArrayCell &cellWorkset, const shards::CellTopology &cellTopo, const int &whichCell)
Validates arguments to Intrepid::CellTools::mapToPhysicalFrame.
static void checkPointwiseInclusion(ArrayIncl &inRefCell, const ArrayPoint &points, const shards::CellTopology &cellTopo, const double &threshold=INTREPID_THRESHOLD)
Checks every point in a set for inclusion in a reference cell.
static void validateArguments_setJacobian(const ArrayJac &jacobian, const ArrayPoint &points, const ArrayCell &cellWorkset, const int &whichCell, const shards::CellTopology &cellTopo)
Validates arguments to Intrepid::CellTools::setJacobian.
static void subtract(Scalar *diffArray, const Scalar *inArray1, const Scalar *inArray2, const int size)
Subtracts contiguous data inArray2 from inArray1 of size size: diffArray = inArray1 - inArray2...
static const FieldContainer< double > & getSubcellParametrization(const int subcellDim, const shards::CellTopology &parentCell)
Returns array with the coefficients of the parametrization maps for the edges or faces of a reference...
static void getBarycenter(ArrayCent &barycenter, const ArrayCellCoord &cellCoords)
Compute cell barycenters.
static void getSubCVCoords(ArrayCVCoord &subCVcoords, const ArrayCellCoord &cellCoords, const shards::CellTopology &primaryCell)
Computes coordinates of sub-control volumes in each primary cell.
A stateless class for operations on cell data. Provides methods for:
static void setJacobianDet(ArrayJacDet &jacobianDet, const ArrayJac &jacobian)
Computes the determinant of the Jacobian matrix DF of the reference-to-physical frame map F...
static void getPhysicalFaceTangents(ArrayFaceTangentU &faceTanU, ArrayFaceTangentV &faceTanV, const ArrayJac &worksetJacobians, const int &worksetFaceOrd, const shards::CellTopology &parentCell)
Computes non-normalized tangent vector pairs to physical faces in a face workset ; (see Subcell works...
Implementation of the default H(grad)-compatible FEM basis of degree 2 on Triangle cell...
Implementation of the default H(grad)-compatible FEM basis of degree 1 on Tetrahedron cell...