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