Intrepid
test_01_kokkos.cpp
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 #include "Intrepid_CellTools.hpp"
52 #include "Teuchos_oblackholestream.hpp"
53 #include "Teuchos_RCP.hpp"
54 #include "Teuchos_GlobalMPISession.hpp"
55 #include "Teuchos_ScalarTraits.hpp"
56 #include <Kokkos_Core.hpp>
57 
58 using namespace std;
59 using namespace Intrepid;
60 
61 
80 void testSubcellParametrizations(int& errorFlag,
81  const shards::CellTopology& parentCell,
82  const Kokkos::View<double**>& subcParamVert_A,
83  const Kokkos::View<double**>& subcParamVert_B,
84  const int subcDim,
85  const Teuchos::RCP<std::ostream>& outStream);
86 
87 
88 int main(int argc, char *argv[]) {
89 
90  Teuchos::GlobalMPISession mpiSession(&argc, &argv);
91 Kokkos::initialize();
93  typedef shards::CellTopology CellTopology;
94 
95  // This little trick lets us print to std::cout only if a (dummy) command-line argument is provided.
96  int iprint = argc - 1;
97 
98  Teuchos::RCP<std::ostream> outStream;
99  Teuchos::oblackholestream bhs; // outputs nothing
100 
101  if (iprint > 0)
102  outStream = Teuchos::rcp(&std::cout, false);
103  else
104  outStream = Teuchos::rcp(&bhs, false);
105 
106  // Save the format state of the original std::cout.
107  Teuchos::oblackholestream oldFormatState;
108  oldFormatState.copyfmt(std::cout);
109 
110  *outStream \
111  << "===============================================================================\n" \
112  << "| |\n" \
113  << "| Unit Test CellTools |\n" \
114  << "| |\n" \
115  << "| 1) Edge parametrizations |\n" \
116  << "| 2) Face parametrizations |\n" \
117  << "| 3) Edge tangents |\n" \
118  << "| 4) Face tangents and normals |\n" \
119  << "| |\n" \
120  << "| Questions? Contact Pavel Bochev (pbboche@sandia.gov) |\n" \
121  << "| Denis Ridzal (dridzal@sandia.gov), or |\n" \
122  << "| Kara Peterson (kjpeter@sandia.gov) |\n" \
123  << "| |\n" \
124  << "| Intrepid's website: http://trilinos.sandia.gov/packages/intrepid |\n" \
125  << "| Trilinos website: http://trilinos.sandia.gov |\n" \
126  << "| |\n" \
127  << "===============================================================================\n";
128 
129  int errorFlag = 0;
130 
131 
132  // Vertices of the parametrization domain for 1-subcells: standard 1-cube [-1,1]
133  Kokkos::View<double**> cube_1("cube_1",2, 1);
134  cube_1(0,0) = -1.0;
135  cube_1(1,0) = 1.0;
136 
137 
138  // Vertices of the parametrization domain for triangular faces: the standard 2-simplex
139  Kokkos::View<double**> simplex_2("simplex_2",3, 2);
140  simplex_2(0, 0) = 0.0; simplex_2(0, 1) = 0.0;
141  simplex_2(1, 0) = 1.0; simplex_2(1, 1) = 0.0;
142  simplex_2(2, 0) = 0.0; simplex_2(2, 1) = 1.0;
143 
144 
145  // Vertices of the parametrization domain for quadrilateral faces: the standard 2-cube
146  Kokkos::View<double**> cube_2("cube_2",4, 2);
147  cube_2(0, 0) = -1.0; cube_2(0, 1) = -1.0;
148  cube_2(1, 0) = 1.0; cube_2(1, 1) = -1.0;
149  cube_2(2, 0) = 1.0; cube_2(2, 1) = 1.0;
150  cube_2(3, 0) = -1.0; cube_2(3, 1) = 1.0;
151 
152 
153  // Pull all available topologies from Shards
154  std::vector<shards::CellTopology> allTopologies;
155  shards::getTopologies(allTopologies);
156 
157 
158  // Set to 1 for edge and 2 for face tests
159  int subcDim;
160 
161  try{
162 
163  *outStream \
164  << "\n"
165  << "===============================================================================\n"\
166  << "| Test 1: edge parametrizations: |\n"\
167  << "===============================================================================\n\n";
168 
169  subcDim = 1;
170 
171  // Loop over the cell topologies
172  for(int topoOrd = 0; topoOrd < (int)allTopologies.size(); topoOrd++){
173 
174  // Test only 2D and 3D topologies that have reference cells, e.g., exclude Line, Pentagon, etc.
175  if(allTopologies[topoOrd].getDimension() > 1 && CellTools::hasReferenceCell(allTopologies[topoOrd]) ){
176  *outStream << " Testing edge parametrization for " << allTopologies[topoOrd].getName() <<"\n";
177  testSubcellParametrizations(errorFlag,
178  allTopologies[topoOrd],
179  cube_1,
180  cube_1,
181  subcDim,
182  outStream);
183  }
184  }
185 
186 
187  *outStream \
188  << "\n"
189  << "===============================================================================\n"\
190  << "| Test 2: face parametrizations: |\n"\
191  << "===============================================================================\n\n";
192 
193  subcDim = 2;
194 
195  // Loop over the cell topologies
196  for(int topoOrd = 0; topoOrd < (int)allTopologies.size(); topoOrd++){
197 
198  // Test only 3D topologies that have reference cells
199  if(allTopologies[topoOrd].getDimension() > 2 && CellTools::hasReferenceCell(allTopologies[topoOrd]) ){
200  *outStream << " Testing face parametrization for cell topology " << allTopologies[topoOrd].getName() <<"\n";
201  testSubcellParametrizations(errorFlag,
202  allTopologies[topoOrd],
203  simplex_2,
204  cube_2,
205  subcDim,
206  outStream);
207  }
208  }
209 
210 
211  /***********************************************************************************************
212  *
213  * Common for test 3 and 4: edge tangents and face normals for standard cells with base topo
214  *
215  **********************************************************************************************/
216 
217  // Allocate storage and extract all standard cells with base topologies
218  std::vector<shards::CellTopology> standardBaseTopologies;
219  shards::getTopologies(standardBaseTopologies, 4, shards::STANDARD_CELL, shards::BASE_TOPOLOGY);
220 
221  // Define topologies for the edge and face parametrization domains. (faces are Tri or Quad)
222  CellTopology paramEdge (shards::getCellTopologyData<shards::Line<2> >() );
223  CellTopology paramTriFace (shards::getCellTopologyData<shards::Triangle<3> >() );
224  CellTopology paramQuadFace(shards::getCellTopologyData<shards::Quadrilateral<4> >() );
225 
226  // Define CubatureFactory:
227  DefaultCubatureFactory<double> cubFactory;
228 
229  *outStream \
230  << "\n"
231  << "===============================================================================\n"\
232  << "| Test 3: edge tangents/normals for stand. cells with base topologies: |\n"\
233  << "===============================================================================\n\n";
234  // This test loops over standard cells with base topologies, creates a set of nodes and tests tangents/normals
235  std::vector<shards::CellTopology>::iterator cti;
236 
237  // Define cubature on the edge parametrization domain:
238  Teuchos::RCP<Cubature<double> > edgeCubature = cubFactory.create(paramEdge, 6);
239  int cubDim = edgeCubature -> getDimension();
240  int numCubPoints = edgeCubature -> getNumPoints();
241 
242  // Allocate storage for cubature points and weights on edge parameter domain and fill with points:
243  FieldContainer<double> paramEdgePoints(numCubPoints, cubDim);
244  FieldContainer<double> paramEdgeWeights(numCubPoints);
245  edgeCubature -> getCubature(paramEdgePoints, paramEdgeWeights);
246 
247 
248  // Loop over admissible topologies
249  for(cti = standardBaseTopologies.begin(); cti !=standardBaseTopologies.end(); ++cti){
250 
251  // Exclude 0D (node), 1D (Line) and Pyramid<5> cells
252  if( ( (*cti).getDimension() >= 2) && ( (*cti).getKey() != shards::Pyramid<5>::key) ){
253 
254  int cellDim = (*cti).getDimension();
255  int vCount = (*cti).getVertexCount();
256  Kokkos::View<double**> refCellVertices("refCellVertices",vCount, cellDim);
257  CellTools::getReferenceSubcellVertices(refCellVertices, cellDim, 0, (*cti) );
258 
259  *outStream << " Testing edge tangents";
260  if(cellDim == 2) { *outStream << " and normals"; }
261  *outStream <<" for cell topology " << (*cti).getName() <<"\n";
262 
263 
264  // Array for physical cell vertices ( must have rank 3 for setJacobians)
265  Kokkos::View<double***> physCellVertices("physCellVertices",1, vCount, cellDim);
266 
267  // Randomize reference cell vertices by moving them up to +/- (1/8) units along their
268  // coordinate axis. Guaranteed to be non-degenerate for standard cells with base topology
269  for(int v = 0; v < vCount; v++){
270  for(int d = 0; d < cellDim; d++){
271  double delta = Teuchos::ScalarTraits<double>::random()/8.0;
272  physCellVertices(0, v, d) = refCellVertices(v, d) + delta;
273  } //for d
274  }// for v
275 
276  // Allocate storage for cub. points on a ref. edge; Jacobians, phys. edge tangents/normals
277  Kokkos::View<double**> refEdgePoints("refEdgePoints",numCubPoints, cellDim);
278  Kokkos::View<double****> edgePointsJacobians("edgePointsJacobians",1, numCubPoints, cellDim, cellDim);
279  Kokkos::View<double***> edgePointTangents("edgePointTangents",1, numCubPoints, cellDim);
280  Kokkos::View<double***> edgePointNormals("edgePointNormals",1, numCubPoints, cellDim);
281 
282  // Loop over edges:
283  for(int edgeOrd = 0; edgeOrd < (int)(*cti).getEdgeCount(); edgeOrd++){
284  /*
285  * Compute tangents on the specified physical edge using CellTools:
286  * 1. Map points from edge parametrization domain to ref. edge with specified ordinal
287  * 2. Compute parent cell Jacobians at ref. edge points
288  * 3. Compute physical edge tangents
289  */
290  CellTools::mapToReferenceSubcell(refEdgePoints, paramEdgePoints, 1, edgeOrd, (*cti) );
291  CellTools::setJacobian(edgePointsJacobians, refEdgePoints, physCellVertices, (*cti) );
292  CellTools::getPhysicalEdgeTangents(edgePointTangents, edgePointsJacobians, edgeOrd, (*cti));
293  /*
294  * Compute tangents directly using parametrization of phys. edge and compare with CellTools tangents.
295  * 1. Get edge vertices
296  * 2. For affine edges tangent coordinates are given by F'(t) = (V1-V0)/2
297  * (for now we only test affine edges, but later we will test edges for cells
298  * with extended topologies.)
299  */
300  int v0ord = (*cti).getNodeMap(1, edgeOrd, 0);
301  int v1ord = (*cti).getNodeMap(1, edgeOrd, 1);
302 
303  for(int pt = 0; pt < numCubPoints; pt++){
304 
305  // Temp storage for directly computed edge tangents
306  Kokkos::View<double*> edgeBenchmarkTangents("edgeBenchmarkTangents",3);
307 
308  for(int d = 0; d < cellDim; d++){
309  edgeBenchmarkTangents(d) = (physCellVertices(0, v1ord, d) - physCellVertices(0, v0ord, d))/2.0;
310 
311  // Compare with d-component of edge tangent by CellTools
312  if( abs(edgeBenchmarkTangents(d) - edgePointTangents(0, pt, d)) > INTREPID_THRESHOLD ){
313  errorFlag++;
314  *outStream
315  << std::setw(70) << "^^^^----FAILURE!" << "\n"
316  << " Edge tangent computation by CellTools failed for: \n"
317  << " Cell Topology = " << (*cti).getName() << "\n"
318  << " Edge ordinal = " << edgeOrd << "\n"
319  << " Edge point number = " << pt << "\n"
320  << " Tangent coordinate = " << d << "\n"
321  << " CellTools value = " << edgePointTangents(0, pt, d) << "\n"
322  << " Benchmark value = " << edgeBenchmarkTangents(d) << "\n\n";
323  }
324  } // for d
325 
326  // Test side normals for 2D cells only: edge normal has coordinates (t1, -t0)
327  if(cellDim == 2) {
328  CellTools::getPhysicalSideNormals(edgePointNormals, edgePointsJacobians, edgeOrd, (*cti));
329  if( abs(edgeBenchmarkTangents(1) - edgePointNormals(0, pt, 0)) > INTREPID_THRESHOLD ){
330  errorFlag++;
331  *outStream
332  << std::setw(70) << "^^^^----FAILURE!" << "\n"
333  << " Edge Normal computation by CellTools failed for: \n"
334  << " Cell Topology = " << (*cti).getName() << "\n"
335  << " Edge ordinal = " << edgeOrd << "\n"
336  << " Edge point number = " << pt << "\n"
337  << " Normal coordinate = " << 0 << "\n"
338  << " CellTools value = " << edgePointNormals(0, pt, 0) << "\n"
339  << " Benchmark value = " << edgeBenchmarkTangents(1) << "\n\n";
340  }
341  if( abs(edgeBenchmarkTangents(0) + edgePointNormals(0, pt, 1)) > INTREPID_THRESHOLD ){
342  errorFlag++;
343  *outStream
344  << std::setw(70) << "^^^^----FAILURE!" << "\n"
345  << " Edge Normal computation by CellTools failed for: \n"
346  << " Cell Topology = " << (*cti).getName() << "\n"
347  << " Edge ordinal = " << edgeOrd << "\n"
348  << " Edge point number = " << pt << "\n"
349  << " Normal coordinate = " << 1 << "\n"
350  << " CellTools value = " << edgePointNormals(0, pt, 1) << "\n"
351  << " Benchmark value = " << -edgeBenchmarkTangents(0) << "\n\n";
352  }
353  } // edge normals
354  } // for pt
355  }// for edgeOrd
356  }// if admissible cell
357  }// for cti
358 
359 
360 
361  *outStream \
362  << "\n"
363  << "===============================================================================\n"\
364  << "| Test 4: face/side normals for stand. 3D cells with base topologies: | |\n"\
365  << "===============================================================================\n\n";
366  // This test loops over standard 3D cells with base topologies, creates a set of nodes and tests normals
367 
368  // Define cubature on the edge parametrization domain:
369  Teuchos::RCP<Cubature<double> > triFaceCubature = cubFactory.create(paramTriFace, 6);
370  Teuchos::RCP<Cubature<double> > quadFaceCubature = cubFactory.create(paramQuadFace, 6);
371 
372  int faceCubDim = triFaceCubature -> getDimension();
373  int numTriFaceCubPoints = triFaceCubature -> getNumPoints();
374  int numQuadFaceCubPoints = quadFaceCubature -> getNumPoints();
375 
376  // Allocate storage for cubature points and weights on face parameter domain and fill with points:
377  FieldContainer<double> paramTriFacePointsFC(numTriFaceCubPoints, faceCubDim);
378  FieldContainer<double> paramTriFaceWeightsFC(numTriFaceCubPoints);
379  FieldContainer<double> paramQuadFacePointsFC(numQuadFaceCubPoints, faceCubDim);
380  FieldContainer<double> paramQuadFaceWeightsFC(numQuadFaceCubPoints);
381 
382  triFaceCubature -> getCubature(paramTriFacePointsFC, paramTriFaceWeightsFC);
383  quadFaceCubature -> getCubature(paramQuadFacePointsFC, paramQuadFaceWeightsFC);
384  Kokkos::View<double**> paramTriFacePoints(&paramTriFacePointsFC[0],paramTriFacePointsFC.dimension(0),paramTriFacePointsFC.dimension(1));
385  Kokkos::View<double*> paramTriFaceWeights(&paramTriFaceWeightsFC[0],paramTriFaceWeightsFC.dimension(0));
386  Kokkos::View<double**> paramQuadFacePoints(&paramQuadFacePointsFC[0],paramQuadFacePointsFC.dimension(0),paramQuadFacePointsFC.dimension(1));
387  Kokkos::View<double*> paramQuadFaceWeights(&paramQuadFaceWeightsFC[0],paramQuadFaceWeightsFC.dimension(0));
388  // Loop over admissible topologies
389  for(cti = standardBaseTopologies.begin(); cti !=standardBaseTopologies.end(); ++cti){
390 
391  // Exclude 2D and Pyramid<5> cells
392  if( ( (*cti).getDimension() == 3) && ( (*cti).getKey() != shards::Pyramid<5>::key) ){
393 
394  int cellDim = (*cti).getDimension();
395  int vCount = (*cti).getVertexCount();
396  Kokkos::View<double**> refCellVertices("refCellVertices",vCount, cellDim);
397  CellTools::getReferenceSubcellVertices(refCellVertices, cellDim, 0, (*cti) );
398 
399  *outStream << " Testing face/side normals for cell topology " << (*cti).getName() <<"\n";
400 
401  // Array for physical cell vertices ( must have rank 3 for setJacobians)
402  Kokkos::View<double***> physCellVertices("physCellVertices",1, vCount, cellDim);
403 
404  // Randomize reference cell vertices by moving them up to +/- (1/8) units along their
405  // coordinate axis. Guaranteed to be non-degenerate for standard cells with base topology
406  for(int v = 0; v < vCount; v++){
407  for(int d = 0; d < cellDim; d++){
408  double delta = Teuchos::ScalarTraits<double>::random()/8.0;
409  physCellVertices(0, v, d) = refCellVertices(v, d) + delta;
410  } //for d
411  }// for v
412 
413  // Allocate storage for cub. points on a ref. face; Jacobians, phys. face normals and
414  // benchmark normals.
415  Kokkos::View<double**> refTriFacePoints("refTriFacePoints",numTriFaceCubPoints, cellDim);
416  Kokkos::View<double**> refQuadFacePoints("refQuadFacePoints",numQuadFaceCubPoints, cellDim);
417  Kokkos::View<double****> triFacePointsJacobians("triFacePointsJacobians",1, numTriFaceCubPoints, cellDim, cellDim);
418  Kokkos::View<double****> quadFacePointsJacobians("quadFacePointsJacobians",1, numQuadFaceCubPoints, cellDim, cellDim);
419  Kokkos::View<double***> triFacePointNormals("triFacePointNormals",1, numTriFaceCubPoints, cellDim);
420  Kokkos::View<double***> triSidePointNormals("triSidePointNormals",1, numTriFaceCubPoints, cellDim);
421  Kokkos::View<double***> quadFacePointNormals("quadFacePointNormals",1, numQuadFaceCubPoints, cellDim);
422  Kokkos::View<double***> quadSidePointNormals("quadSidePointNormals",1, numQuadFaceCubPoints, cellDim);
423 
424 
425  // Loop over faces:
426  for(int faceOrd = 0; faceOrd < (int)(*cti).getSideCount(); faceOrd++){
427 
428  // This test presently includes only Triangle<3> and Quadrilateral<4> faces. Once we support
429  // cells with extended topologies we will add their faces as well.
430  switch( (*cti).getCellTopologyData(2, faceOrd) -> key ) {
431 
432  case shards::Triangle<3>::key:
433  {
434  // Compute face normals using CellTools
435  CellTools::mapToReferenceSubcell(refTriFacePoints, paramTriFacePoints, 2, faceOrd, (*cti) );
436  CellTools::setJacobian(triFacePointsJacobians, refTriFacePoints, physCellVertices, (*cti) );
437  CellTools::getPhysicalFaceNormals(triFacePointNormals, triFacePointsJacobians, faceOrd, (*cti));
438  CellTools::getPhysicalSideNormals(triSidePointNormals, triFacePointsJacobians, faceOrd, (*cti));
439  /*
440  * Compute face normals using direct linear parametrization of the face: the map from
441  * standard 2-simplex to physical Triangle<3> face in 3D is
442  * F(x,y) = V0 + (V1-V0)x + (V2-V0)*y
443  * Face normal is vector product Tx X Ty where Tx = (V1-V0); Ty = (V2-V0)
444  */
445  int v0ord = (*cti).getNodeMap(2, faceOrd, 0);
446  int v1ord = (*cti).getNodeMap(2, faceOrd, 1);
447  int v2ord = (*cti).getNodeMap(2, faceOrd, 2);
448 
449  // Loop over face points: redundant for affine faces, but CellTools gives one vector
450  // per point so need to check all points anyways.
451  for(int pt = 0; pt < numTriFaceCubPoints; pt++){
452  Kokkos::View<double*> tanX("tanX",3), tanY("tanY",3), faceNormal("faceNormal",3);
453  for(int d = 0; d < cellDim; d++){
454  tanX(d) = (physCellVertices(0, v1ord, d) - physCellVertices(0, v0ord, d));
455  tanY(d) = (physCellVertices(0, v2ord, d) - physCellVertices(0, v0ord, d));
456  }// for d
457 
458  RealSpaceTools<double>::vecprod(faceNormal, tanX, tanY);
459 
460  // Compare direct normal with d-component of the face/side normal by CellTools
461  for(int d = 0; d < cellDim; d++){
462 
463  // face normal method
464  if( abs(faceNormal(d) - triFacePointNormals(0, pt, d)) > INTREPID_THRESHOLD ){
465  errorFlag++;
466  *outStream
467  << std::setw(70) << "^^^^----FAILURE!" << "\n"
468  << " Face normal computation by CellTools failed for: \n"
469  << " Cell Topology = " << (*cti).getName() << "\n"
470  << " Face Topology = " << (*cti).getCellTopologyData(2, faceOrd) -> name << "\n"
471  << " Face ordinal = " << faceOrd << "\n"
472  << " Face point number = " << pt << "\n"
473  << " Normal coordinate = " << d << "\n"
474  << " CellTools value = " << triFacePointNormals(0, pt, d)
475  << " Benchmark value = " << faceNormal(d) << "\n\n";
476  }
477  //side normal method
478  if( abs(faceNormal(d) - triSidePointNormals(0, pt, d)) > INTREPID_THRESHOLD ){
479  errorFlag++;
480  *outStream
481  << std::setw(70) << "^^^^----FAILURE!" << "\n"
482  << " Side normal computation by CellTools failed for: \n"
483  << " Cell Topology = " << (*cti).getName() << "\n"
484  << " Side Topology = " << (*cti).getCellTopologyData(2, faceOrd) -> name << "\n"
485  << " Side ordinal = " << faceOrd << "\n"
486  << " Side point number = " << pt << "\n"
487  << " Normal coordinate = " << d << "\n"
488  << " CellTools value = " << triSidePointNormals(0, pt, d)
489  << " Benchmark value = " << faceNormal(d) << "\n\n";
490  }
491  } // for d
492  } // for pt
493  }
494  break;
495 
496  case shards::Quadrilateral<4>::key:
497  {
498  // Compute face normals using CellTools
499  CellTools::mapToReferenceSubcell(refQuadFacePoints, paramQuadFacePoints, 2, faceOrd, (*cti) );
500  CellTools::setJacobian(quadFacePointsJacobians, refQuadFacePoints, physCellVertices, (*cti) );
501  CellTools::getPhysicalFaceNormals(quadFacePointNormals, quadFacePointsJacobians, faceOrd, (*cti));
502  CellTools::getPhysicalSideNormals(quadSidePointNormals, quadFacePointsJacobians, faceOrd, (*cti));
503  /*
504  * Compute face normals using direct bilinear parametrization of the face: the map from
505  * [-1,1]^2 to physical Quadrilateral<4> face in 3D is
506  * F(x,y) = ((V0+V1+V2+V3) + (-V0+V1+V2-V3)*X + (-V0-V1+V2+V3)*Y + (V0-V1+V2-V3)*X*Y)/4
507  * Face normal is vector product Tx X Ty where
508  * Tx = ((-V0+V1+V2-V3) + (V0-V1+V2-V3)*Y)/4
509  * Ty = ((-V0-V1+V2+V3) + (V0-V1+V2-V3)*X)/4
510  */
511  int v0ord = (*cti).getNodeMap(2, faceOrd, 0);
512  int v1ord = (*cti).getNodeMap(2, faceOrd, 1);
513  int v2ord = (*cti).getNodeMap(2, faceOrd, 2);
514  int v3ord = (*cti).getNodeMap(2, faceOrd, 3);
515 
516  // Loop over face points (redundant for affine faces, but needed for later when we handle non-affine ones)
517  for(int pt = 0; pt < numTriFaceCubPoints; pt++){
518  Kokkos::View<double*> tanX("tanX",3), tanY("tanY",3), faceNormal("faceNormal",3);
519  for(int d = 0; d < cellDim; d++){
520  tanX(d) = (physCellVertices(0, v0ord, d)*(-1.0 + paramQuadFacePoints(pt,1) ) +
521  physCellVertices(0, v1ord, d)*( 1.0 - paramQuadFacePoints(pt,1) ) +
522  physCellVertices(0, v2ord, d)*( 1.0 + paramQuadFacePoints(pt,1) ) +
523  physCellVertices(0, v3ord, d)*(-1.0 - paramQuadFacePoints(pt,1) ) )/4.0;
524 
525  tanY(d) = (physCellVertices(0, v0ord, d)*(-1.0 + paramQuadFacePoints(pt,0) ) +
526  physCellVertices(0, v1ord, d)*(-1.0 - paramQuadFacePoints(pt,0) ) +
527  physCellVertices(0, v2ord, d)*( 1.0 + paramQuadFacePoints(pt,0) ) +
528  physCellVertices(0, v3ord, d)*( 1.0 - paramQuadFacePoints(pt,0) ) )/4.0;
529  }// for d
530 
531  RealSpaceTools<double>::vecprod(faceNormal, tanX, tanY);
532  // Compare direct normal with d-component of the face/side normal by CellTools
533  for(int d = 0; d < cellDim; d++){
534 
535  // face normal method
536  if( abs(faceNormal(d) - quadFacePointNormals(0, pt, d)) > INTREPID_THRESHOLD ){
537  errorFlag++;
538  *outStream
539  << std::setw(70) << "^^^^----FAILURE!" << "\n"
540  << " Face normal computation by CellTools failed for: \n"
541  << " Cell Topology = " << (*cti).getName() << "\n"
542  << " Face Topology = " << (*cti).getCellTopologyData(2, faceOrd) -> name << "\n"
543  << " Face ordinal = " << faceOrd << "\n"
544  << " Face point number = " << pt << "\n"
545  << " Normal coordinate = " << d << "\n"
546  << " CellTools value = " << quadFacePointNormals(0, pt, d)
547  << " Benchmark value = " << faceNormal(d) << "\n\n";
548  }
549  //side normal method
550  if( abs(faceNormal(d) - quadSidePointNormals(0, pt, d)) > INTREPID_THRESHOLD ){
551  errorFlag++;
552  *outStream
553  << std::setw(70) << "^^^^----FAILURE!" << "\n"
554  << " Side normal computation by CellTools failed for: \n"
555  << " Cell Topology = " << (*cti).getName() << "\n"
556  << " Side Topology = " << (*cti).getCellTopologyData(2, faceOrd) -> name << "\n"
557  << " Side ordinal = " << faceOrd << "\n"
558  << " Side point number = " << pt << "\n"
559  << " Normal coordinate = " << d << "\n"
560  << " CellTools value = " << quadSidePointNormals(0, pt, d)
561  << " Benchmark value = " << faceNormal(d) << "\n\n";
562  }
563  } // for d
564  }// for pt
565  }// case Quad
566  break;
567  default:
568  errorFlag++;
569  *outStream << " Face normals test failure: face topology not supported \n\n";
570  } // switch
571  }// for faceOrd
572  }// if admissible
573  }// for cti
574  }// try
575 
576  //============================================================================================//
577  // Wrap up test: check if the test broke down unexpectedly due to an exception //
578  //============================================================================================//
579  catch (std::logic_error err) {
580  *outStream << err.what() << "\n";
581  errorFlag = -1000;
582  };
583 
584 
585  if (errorFlag != 0)
586  std::cout << "End Result: TEST FAILED\n";
587  else
588  std::cout << "End Result: TEST PASSED\n";
589 
590  // reset format state of std::cout
591  std::cout.copyfmt(oldFormatState);
592  Kokkos::finalize();
593  return errorFlag;
594 }
595 
596 
597 
598 void testSubcellParametrizations(int& errorFlag,
599  const shards::CellTopology& parentCell,
600  const Kokkos::View<double**>& subcParamVert_A,
601  const Kokkos::View<double**>& subcParamVert_B,
602  const int subcDim,
603  const Teuchos::RCP<std::ostream>& outStream){
604 
605  // Get cell dimension and subcell count
606  int cellDim = parentCell.getDimension();
607  int subcCount = parentCell.getSubcellCount(subcDim);
608 
609 
610  // Loop over subcells of the specified dimension
611  for(int subcOrd = 0; subcOrd < subcCount; subcOrd++){
612  int subcVertexCount = parentCell.getVertexCount(subcDim, subcOrd);
613 
614 
615  // Storage for correct reference subcell vertices and for the images of the parametrization domain points
616  Kokkos::View<double**> refSubcellVertices("refSubcellVertices",subcVertexCount, cellDim);
617  Kokkos::View<double**> mappedParamVertices("mappedParamVertices",subcVertexCount, cellDim);
618 
619 
620  // Retrieve correct reference subcell vertices
621  CellTools<double>::getReferenceSubcellVertices(refSubcellVertices, subcDim, subcOrd, parentCell);
622 
623 
624  // Map vertices of the parametrization domain to 1 or 2-subcell with ordinal subcOrd
625  // For edges parametrization domain is always 1-cube passed as "subcParamVert_A"
626  if(subcDim == 1) {
627  CellTools<double>::mapToReferenceSubcell(mappedParamVertices,
628  subcParamVert_A,
629  subcDim,
630  subcOrd,
631  parentCell);
632  }
633  // For faces need to treat Triangle and Quadrilateral faces separately
634  else if(subcDim == 2) {
635 
636  // domain "subcParamVert_A" is the standard 2-simplex
637  if(subcVertexCount == 3){
638  CellTools<double>::mapToReferenceSubcell(mappedParamVertices,
639  subcParamVert_A,
640  subcDim,
641  subcOrd,
642  parentCell);
643  }
644  // Domain "subcParamVert_B" is the standard 2-cube
645  else if(subcVertexCount == 4){
646  CellTools<double>::mapToReferenceSubcell(mappedParamVertices,
647  subcParamVert_B,
648  subcDim,
649  subcOrd,
650  parentCell);
651  }
652  }
653 
654  // Compare the images of the parametrization domain vertices with the true vertices.
655  for(int subcVertOrd = 0; subcVertOrd < subcVertexCount; subcVertOrd++){
656  for(int dim = 0; dim < cellDim; dim++){
657 
658  if(mappedParamVertices(subcVertOrd, dim) != refSubcellVertices(subcVertOrd, dim) ) {
659  errorFlag++;
660  *outStream
661  << std::setw(70) << "^^^^----FAILURE!" << "\n"
662  << " Cell Topology = " << parentCell.getName() << "\n"
663  << " Parametrization of subcell " << subcOrd << " which is "
664  << parentCell.getName(subcDim,subcOrd) << " failed for vertex " << subcVertOrd << ":\n"
665  << " parametrization map fails to map correctly coordinate " << dim << " of that vertex\n\n";
666 
667  }//if
668  }// for dim
669  }// for subcVertOrd
670  }// for subcOrd
671 
672 }
673 
674 
675 
676 
677 
678 
Implementation of basic linear algebra functionality in Euclidean space.
Header file for the Intrepid::CellTools class.
Header file for utility class to provide multidimensional containers.
Header file for the abstract base class Intrepid::DefaultCubatureFactory.
A factory class that generates specific instances of cubatures.
Teuchos::RCP< Cubature< Scalar, ArrayPoint, ArrayWeight > > create(const shards::CellTopology &cellTopology, const std::vector< int > &degree)
Factory method.
A stateless class for operations on cell data. Provides methods for:
void testSubcellParametrizations(int &errorFlag, const shards::CellTopology &parentCell, const FieldContainer< double > &subcParamVert_A, const FieldContainer< double > &subcParamVert_B, const int subcDim, const Teuchos::RCP< std::ostream > &outStream)
Maps the vertices of the subcell parametrization domain to that subcell.
Definition: test_01.cpp:595