Beispiel #1
0
  int HGRAD_TET_C2_FEM_Test01(const bool verbose) {

    Teuchos::RCP<std::ostream> outStream;
    Teuchos::oblackholestream bhs; // outputs nothing

    if (verbose)
      outStream = Teuchos::rcp(&std::cout, false);
    else
      outStream = Teuchos::rcp(&bhs,       false);

    Teuchos::oblackholestream oldFormatState;
    oldFormatState.copyfmt(std::cout);

    typedef typename
      Kokkos::Impl::is_space<DeviceSpaceType>::host_mirror_space::execution_space HostSpaceType ;

    *outStream << "DeviceSpace::  "; DeviceSpaceType::print_configuration(*outStream, false);
    *outStream << "HostSpace::    ";   HostSpaceType::print_configuration(*outStream, false);
  
  *outStream
    << "\n"
    << "===============================================================================\n"
    << "|                                                                             |\n"
    << "|                 Unit Test (Basis_HGRAD_TET_C2_FEM)                          |\n"
    << "|                                                                             |\n"
    << "|     1) Conversion of Dof tags into Dof ordinals and back                    |\n"
    << "|     2) Basis values for VALUE, GRAD, and Dk operators                       |\n"
    << "|                                                                             |\n"
    << "|  Questions? Contact  Pavel Bochev  ([email protected]),                    |\n"
    << "|                      Denis Ridzal  ([email protected]),                    |\n"
    << "|                      Kara Peterson ([email protected]).                    |\n"
    << "|                      Kyungjoo Kim  ([email protected]).                     |\n"
    << "|                                                                             |\n"
    << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n"
    << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n"
    << "|                                                                             |\n"
    << "===============================================================================\n";

    typedef Kokkos::DynRankView<ValueType,DeviceSpaceType> DynRankView;
    typedef Kokkos::DynRankView<ValueType,HostSpaceType>   DynRankViewHost;
#define ConstructWithLabel(obj, ...) obj(#obj, __VA_ARGS__)

    const ValueType tol = tolerence();
    int errorFlag = 0;
      
    // for virtual function, value and point types are declared in the class
    typedef ValueType outputValueType;
    typedef ValueType pointValueType;
    Basis_HGRAD_TET_C2_FEM<DeviceSpaceType,outputValueType,pointValueType> tetBasis;

  *outStream
    << "\n"
    << "===============================================================================\n"
    << "| TEST 1: Basis creation, exception testing                                   |\n"
    << "===============================================================================\n";
  
  try{
    ordinal_type nthrow = 0, ncatch = 0;
#ifdef HAVE_INTREPID2_DEBUG 

    DynRankView ConstructWithLabel(tetNodes, 10, 3);

    const auto numFields = tetBasis.getCardinality();
    const auto numPoints = tetNodes.dimension(0);
    const auto spaceDim  = tetBasis.getBaseCellTopology().getDimension();

    DynRankView ConstructWithLabel(vals, numFields, numPoints);
    DynRankView ConstructWithLabel(vals_vec, numFields, numPoints, 4);
    {
    // exception #1: CURL cannot be applied to scalar functions
    // resize vals to rank-3 container with dimensions (num. points, num. basis functions, arbitrary)
      INTREPID2_TEST_ERROR_EXPECTED( tetBasis.getValues(vals_vec, tetNodes, OPERATOR_CURL) );
    }
    {
    // exception #2: DIV cannot be applied to scalar functions
    // resize vals to rank-2 container with dimensions (num. points, num. basis functions)
      INTREPID2_TEST_ERROR_EXPECTED( tetBasis.getValues(vals, tetNodes, OPERATOR_DIV) );
    }
        
    // Exceptions 3-7: all bf tags/bf Ids below are wrong and should cause getDofOrdinal() and 
    // getDofTag() to access invalid array elements thereby causing bounds check exception
    {
    // exception #3
      INTREPID2_TEST_ERROR_EXPECTED( tetBasis.getDofOrdinal(3,0,0) );
    // exception #4
      INTREPID2_TEST_ERROR_EXPECTED( tetBasis.getDofOrdinal(1,1,1) );
    // exception #5
      INTREPID2_TEST_ERROR_EXPECTED( tetBasis.getDofOrdinal(0,4,0) );
    // exception #6
      INTREPID2_TEST_ERROR_EXPECTED( tetBasis.getDofTag(10) );
    // exception #7
      INTREPID2_TEST_ERROR_EXPECTED( tetBasis.getDofTag(-1) );
    }
    
    // Exceptions 8-18 test exception handling with incorrectly dimensioned input/output arrays
    {
    // exception #8: input points array must be of rank-2
      DynRankView ConstructWithLabel(badPoints1, 4, 5, 3);
      INTREPID2_TEST_ERROR_EXPECTED( tetBasis.getValues(vals, badPoints1, OPERATOR_VALUE) );
    }
    { 
    // exception #9 dimension 1 in the input point array must equal space dimension of the cell
      DynRankView ConstructWithLabel(badPoints2, 4, spaceDim - 1);
      INTREPID2_TEST_ERROR_EXPECTED( tetBasis.getValues(vals, badPoints2, OPERATOR_VALUE) );
    }
    { 
    // exception #10 output values must be of rank-2 for OPERATOR_VALUE
      DynRankView ConstructWithLabel(badVals1, 4, 3, 1);
      INTREPID2_TEST_ERROR_EXPECTED( tetBasis.getValues(badVals1, tetNodes, OPERATOR_VALUE) );
    }
    { 
    // exception #11 output values must be of rank-3 for OPERATOR_GRAD
      DynRankView ConstructWithLabel(badVals2, 4, 3);
      INTREPID2_TEST_ERROR_EXPECTED( tetBasis.getValues(badVals2, tetNodes, OPERATOR_GRAD) );
    // exception #12 output values must be of rank-3 for OPERATOR_D1
      INTREPID2_TEST_ERROR_EXPECTED( tetBasis.getValues(badVals2, tetNodes, OPERATOR_D1) );
    // exception #13 output values must be of rank-3 for OPERATOR_D2
      INTREPID2_TEST_ERROR_EXPECTED( tetBasis.getValues(badVals2, tetNodes, OPERATOR_D2) );
    }
    {
    // exception #14 incorrect 0th dimension of output array (must equal number of basis functions)
      DynRankView ConstructWithLabel(badVals3, numFields + 1, numPoints);
      INTREPID2_TEST_ERROR_EXPECTED( tetBasis.getValues(badVals3, tetNodes, OPERATOR_VALUE) );
    }
    { 
    // exception #15 incorrect 1st dimension of output array (must equal number of points)
      DynRankView ConstructWithLabel(badVals4, numFields, numPoints + 1);
      INTREPID2_TEST_ERROR_EXPECTED( tetBasis.getValues(badVals4, tetNodes, OPERATOR_VALUE) );
    }
    { 
    // exception #16: incorrect 2nd dimension of output array (must equal the space dimension)
      DynRankView ConstructWithLabel(badVals5, numFields, numPoints, spaceDim + 1);
      INTREPID2_TEST_ERROR_EXPECTED( tetBasis.getValues(badVals5, tetNodes, OPERATOR_GRAD) );
    }
    { 
    // exception #17: incorrect 2nd dimension of output array (must equal D2 cardinality in 2D)
      DynRankView ConstructWithLabel(badVals6, numFields, numPoints, 40);
      INTREPID2_TEST_ERROR_EXPECTED( tetBasis.getValues(badVals6, tetNodes, OPERATOR_D1) );
    // exception #18: incorrect 2nd dimension of output array (must equal D3 cardinality in 2D)
      INTREPID2_TEST_ERROR_EXPECTED( tetBasis.getValues(badVals6, tetNodes, OPERATOR_D2) );
    }
#endif
    // Check if number of thrown exceptions matches the one we expect 
    if (nthrow != ncatch) {
      errorFlag++;
      *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
      *outStream << "# of catch ("<< ncatch << ") is different from # of throw (" << nthrow << ")\n";
    }
  } catch (std::logic_error err) {
    *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
    *outStream << err.what() << '\n';
    *outStream << "-------------------------------------------------------------------------------" << "\n\n";
    errorFlag = -1000;
  };
  
  *outStream
    << "\n"
    << "===============================================================================\n"
    << "| TEST 2: correctness of tag to enum and enum to tag lookups                  |\n"
    << "===============================================================================\n";
  
  try{
    const auto numFields = tetBasis.getCardinality();
    const auto allTags = tetBasis.getAllDofTags();
    
    // Loop over all tags, lookup the associated dof enumeration and then lookup the tag again
    const auto dofTagSize = allTags.dimension(0);
    for (auto i = 0; i < dofTagSize; ++i) {
      const auto bfOrd  = tetBasis.getDofOrdinal(allTags(i,0), allTags(i,1), allTags(i,2));
      
      const auto myTag = tetBasis.getDofTag(bfOrd);
       if( !( (myTag(0) == allTags(i,0)) &&
              (myTag(1) == allTags(i,1)) &&
              (myTag(2) == allTags(i,2)) &&
              (myTag(3) == allTags(i,3)) ) ) {
        errorFlag++;
        *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
        *outStream << " getDofOrdinal( {" 
          << allTags(i,0) << ", " 
          << allTags(i,1) << ", " 
          << allTags(i,2) << ", " 
          << allTags(i,3) << "}) = " << bfOrd <<" but \n";   
        *outStream << " getDofTag(" << bfOrd << ") = { "
          << myTag(0) << ", " 
          << myTag(1) << ", " 
          << myTag(2) << ", " 
          << myTag(3) << "}\n";        
      }
    }
    
    // Now do the same but loop over basis functions
    for( auto bfOrd = 0; bfOrd < numFields; bfOrd++) {
      const auto myTag  = tetBasis.getDofTag(bfOrd);
      const auto myBfOrd = tetBasis.getDofOrdinal(myTag(0), myTag(1), myTag(2));
      if( bfOrd != myBfOrd) {
        errorFlag++;
        *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
        *outStream << " getDofTag(" << bfOrd << ") = { "
          << myTag(0) << ", " 
          << myTag(1) << ", " 
          << myTag(2) << ", " 
          << myTag(3) << "} but getDofOrdinal({" 
          << myTag(0) << ", " 
          << myTag(1) << ", " 
          << myTag(2) << ", " 
          << myTag(3) << "} ) = " << myBfOrd << "\n";
      }
    }
  }
  catch (std::logic_error err){
    *outStream << err.what() << "\n\n";
    errorFlag = -1000;
  };
  
  *outStream
    << "\n"
    << "===============================================================================\n"
    << "| TEST 3: correctness of basis function values                                |\n"
    << "===============================================================================\n";
  
  outStream -> precision(20);
  
  // VALUE: in (F,P) format
  const ValueType basisValues[] = {
    1.00000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00000, 0, 0, 0, 0, 0, 0, 0, \
    0, 0, 0, 1.00000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00000, 0, 0, 0, 0, \
    0, 0, 0, 0, 0, 0, 1.00000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00000, 0, \
    0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
    1.00000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00000, 0, 0, 0, 0, 0, 0, 0, \
    0, 0, 0, 1.00000 };
  
  // GRAD and D1: in (F,P,D) format
  const ValueType basisGrads[] = {
    -3.00000, -3.00000, -3.00000, 1.00000, 1.00000, 1.00000, 1.00000, \
    1.00000, 1.00000, 1.00000, 1.00000, 1.00000, -1.00000, -1.00000, \
    -1.00000, 1.00000, 1.00000, 1.00000, -1.00000, -1.00000, -1.00000, \
    -1.00000, -1.00000, -1.00000, 1.00000, 1.00000, 1.00000, 1.00000, \
    1.00000, 1.00000, -1.00000, 0, 0, 3.00000, 0, 0, -1.00000, 0, 0, \
    -1.00000, 0, 0, 1.00000, 0, 0, 1.00000, 0, 0, -1.00000, 0, 0, \
    -1.00000, 0, 0, 1.00000, 0, 0, -1.00000, 0, 0, 0, -1.00000, 0, 0, \
    -1.00000, 0, 0, 3.00000, 0, 0, -1.00000, 0, 0, -1.00000, 0, 0, \
    1.00000, 0, 0, 1.00000, 0, 0, -1.00000, 0, 0, -1.00000, 0, 0, \
    1.00000, 0, 0, 0, -1.00000, 0, 0, -1.00000, 0, 0, -1.00000, 0, 0, \
    3.00000, 0, 0, -1.00000, 0, 0, -1.00000, 0, 0, -1.00000, 0, 0, \
    1.00000, 0, 0, 1.00000, 0, 0, 1.00000, 4.00000, 0, 0, -4.00000, \
    -4.00000, -4.00000, 0, 0, 0, 0, 0, 0, 0, -2.00000, -2.00000, \
    -2.00000, -2.00000, -2.00000, 2.00000, 0, 0, 2.00000, 0, 0, -2.00000, \
    -2.00000, -2.00000, 0, 0, 0, 0, 0, 0, 0, 4.00000, 0, 4.00000, 0, 0, \
    0, 0, 0, 0, 2.00000, 0, 2.00000, 2.00000, 0, 2.00000, 0, 0, 0, 0, 0, \
    0, 2.00000, 0, 2.00000, 0, 0, 0, 4.00000, 0, 0, 0, 0, -4.00000, \
    -4.00000, -4.00000, 0, 0, 0, 0, 2.00000, 0, -2.00000, -2.00000, \
    -2.00000, -2.00000, 0, -2.00000, 0, 2.00000, 0, 0, 0, 0, -2.00000, \
    -2.00000, -2.00000, 0, 0, 4.00000, 0, 0, 0, 0, 0, 0, -4.00000, \
    -4.00000, -4.00000, 0, 0, 2.00000, 0, 0, 0, 0, 0, 2.00000, -2.00000, \
    -2.00000, 0, -2.00000, -2.00000, -2.00000, -2.00000, -2.00000, \
    -2.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 4.00000, 0, 0, 0, 0, \
    2.00000, 0, 0, 2.00000, 0, 0, 0, 2.00000, 0, 0, 2.00000, 0, 2.00000, \
    2.00000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.00000, 0, 4.00000, 0, 0, 0, \
    0, 0, 0, 2.00000, 0, 0, 2.00000, 0, 2.00000, 0, 0, 2.00000, 0, 0, \
    2.00000, 2.00000};
  
  // D2 values in (F,P, Dk) format
  const ValueType basisD2[]={
    4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, \
    4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, \
    4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, \
    4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, \
    4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, \
    4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, \
    4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, \
    4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, \
    4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 0, 0, 0, 0, 0, 4.00000, \
    0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, \
    4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, \
    0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, \
    0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, \
    4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, \
    0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, \
    0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 0, 0, 4.00000, \
    0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, \
    4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, \
    0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, \
    0, 0, 4.00000, -8.00000, -4.00000, -4.00000, 0, 0, 0, -8.00000, \
    -4.00000, -4.00000, 0, 0, 0, -8.00000, -4.00000, -4.00000, 0, 0, 0, \
    -8.00000, -4.00000, -4.00000, 0, 0, 0, -8.00000, -4.00000, -4.00000, \
    0, 0, 0, -8.00000, -4.00000, -4.00000, 0, 0, 0, -8.00000, -4.00000, \
    -4.00000, 0, 0, 0, -8.00000, -4.00000, -4.00000, 0, 0, 0, -8.00000, \
    -4.00000, -4.00000, 0, 0, 0, -8.00000, -4.00000, -4.00000, 0, 0, 0, \
    0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, \
    0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, \
    0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, \
    0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, -4.00000, 0, -8.00000, -4.00000, \
    0, 0, -4.00000, 0, -8.00000, -4.00000, 0, 0, -4.00000, 0, -8.00000, \
    -4.00000, 0, 0, -4.00000, 0, -8.00000, -4.00000, 0, 0, -4.00000, 0, \
    -8.00000, -4.00000, 0, 0, -4.00000, 0, -8.00000, -4.00000, 0, 0, \
    -4.00000, 0, -8.00000, -4.00000, 0, 0, -4.00000, 0, -8.00000, \
    -4.00000, 0, 0, -4.00000, 0, -8.00000, -4.00000, 0, 0, -4.00000, 0, \
    -8.00000, -4.00000, 0, 0, 0, -4.00000, 0, -4.00000, -8.00000, 0, 0, \
    -4.00000, 0, -4.00000, -8.00000, 0, 0, -4.00000, 0, -4.00000, \
    -8.00000, 0, 0, -4.00000, 0, -4.00000, -8.00000, 0, 0, -4.00000, 0, \
    -4.00000, -8.00000, 0, 0, -4.00000, 0, -4.00000, -8.00000, 0, 0, \
    -4.00000, 0, -4.00000, -8.00000, 0, 0, -4.00000, 0, -4.00000, \
    -8.00000, 0, 0, -4.00000, 0, -4.00000, -8.00000, 0, 0, -4.00000, 0, \
    -4.00000, -8.00000, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, \
    0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, \
    0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, \
    0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 0, 0, \
    4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, \
    0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, \
    0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, \
    0, 0, 0, 4.00000, 0
  };
  
  try{
    ordinal_type nthrow = 0, ncatch = 0;

    DynRankViewHost ConstructWithLabel(tetNodesHost, 10, 3);
    tetNodesHost(0,0) =  0.0;  tetNodesHost(0,1) =  0.0;  tetNodesHost(0,2) =  0.0;  
    tetNodesHost(1,0) =  1.0;  tetNodesHost(1,1) =  0.0;  tetNodesHost(1,2) =  0.0;  
    tetNodesHost(2,0) =  0.0;  tetNodesHost(2,1) =  1.0;  tetNodesHost(2,2) =  0.0;
    tetNodesHost(3,0) =  0.0;  tetNodesHost(3,1) =  0.0;  tetNodesHost(3,2) =  1.0;  
    
    tetNodesHost(4,0) =  0.5;  tetNodesHost(4,1) =  0.0;  tetNodesHost(4,2) =  0.0;
    tetNodesHost(5,0) =  0.5;  tetNodesHost(5,1) =  0.5;  tetNodesHost(5,2) =  0.0;  
    tetNodesHost(6,0) =  0.0;  tetNodesHost(6,1) =  0.5;  tetNodesHost(6,2) =  0.0;  
    tetNodesHost(7,0) =  0.0;  tetNodesHost(7,1) =  0.0;  tetNodesHost(7,2) =  0.5;  
    tetNodesHost(8,0) =  0.5;  tetNodesHost(8,1) =  0.0;  tetNodesHost(8,2) =  0.5;  
    tetNodesHost(9,0) =  0.0;  tetNodesHost(9,1) =  0.5;  tetNodesHost(9,2) =  0.5;  

    auto tetNodes = Kokkos::create_mirror_view(typename DeviceSpaceType::memory_space(), tetNodesHost);
    Kokkos::deep_copy(tetNodes, tetNodesHost);
        
    // Dimensions for the output arrays:
    const auto numFields = tetBasis.getCardinality();
    const auto numPoints = tetNodes.dimension(0);
    const auto spaceDim  = tetBasis.getBaseCellTopology().getDimension();
    const auto D2cardinality = getDkCardinality(OPERATOR_D2, spaceDim);
    
    {
    // Check VALUE of basis functions: resize vals to rank-2 container:
    DynRankView ConstructWithLabel(vals, numFields, numPoints);
    tetBasis.getValues(vals, tetNodes, OPERATOR_VALUE);
    auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
    Kokkos::deep_copy(vals_host, vals);
    for (auto i = 0; i < numFields; ++i) {
      for (auto j = 0; j < numPoints; ++j) {
          const auto l =  i + j * numFields;
           if (std::abs(vals_host(i,j) - basisValues[l]) > tol) {
             errorFlag++;
             *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

             // Output the multi-index of the value where the error is:
             *outStream << " At multi-index { ";
             *outStream << i << " ";*outStream << j << " ";
             *outStream << "}  computed value: " << vals_host(i,j)
               << " but reference value: " << basisValues[l] << "\n";
         }
      }
    }
    }

    {
    // Check GRAD of basis function: resize vals to rank-3 container
    DynRankView ConstructWithLabel(vals, numFields, numPoints, spaceDim);
    tetBasis.getValues(vals, tetNodes, OPERATOR_GRAD);
    auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
    Kokkos::deep_copy(vals_host, vals);
    for (auto i = 0; i < numFields; ++i) {
      for (auto j = 0; j < numPoints; ++j) {
        for (auto k = 0; k < spaceDim; ++k) {
 
          // basisGrads is (F,P,D), compute offset:
          const auto l = k + j * spaceDim + i * spaceDim * numPoints;
           if (std::abs(vals_host(i,j,k) - basisGrads[l]) > tol) {
             errorFlag++;
             *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

             // Output the multi-index of the value where the error is:
             *outStream << " At multi-index { ";
             *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
             *outStream << "}  computed grad component: " << vals_host(i,j,k)
               << " but reference grad component: " << basisGrads[l] << "\n";
            }
         }
      }
    }

    // Check D1 of basis function (do not resize vals because it has the correct size: D1 = GRAD)
    tetBasis.getValues(vals, tetNodes, OPERATOR_D1);
    Kokkos::deep_copy(vals_host, vals);
    for (auto i = 0; i < numFields; ++i) {
      for (auto j = 0; j < numPoints; ++j) {
        for (auto k = 0; k < spaceDim; ++k) {
          
          // basisGrads is (F,P,D), compute offset:
          const auto l = k + j * spaceDim + i * spaceDim * numPoints;
           if (std::abs(vals_host(i,j,k) - basisGrads[l]) > tol) {
             errorFlag++;
             *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

             // Output the multi-index of the value where the error is:
             *outStream << " At multi-index { ";
             *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
             *outStream << "}  computed D1 component: " << vals_host(i,j,k)
               << " but reference D1 component: " << basisGrads[l] << "\n";
            }
         }
      }
    }
    }

    {
    // Check D2 of basis function
    DynRankView ConstructWithLabel(vals, numFields, numPoints, D2cardinality);
    tetBasis.getValues(vals, tetNodes, OPERATOR_D2);
    auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
    Kokkos::deep_copy(vals_host, vals);
    for (auto i = 0; i < numFields; ++i) {
      for (auto j = 0; j < numPoints; ++j) {
        for (auto k = 0; k < D2cardinality; ++k) {
          
          // basisD2 is (F,P,Dk), compute offset:
          const auto l = k + j * D2cardinality + i * D2cardinality * numPoints;
          if (std::abs(vals_host(i,j,k) - basisD2[l]) > tol) {
            errorFlag++;
            *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
            
            // Output the multi-index of the value where the error is:
            *outStream << " At multi-index { ";
            *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
            *outStream << "}  computed D2 component: " << vals_host(i,j,k)
              << " but reference D2 component: " << basisD2[l] << "\n";
          }
        }
      }
    }
    }
    
    {
    // Check all higher derivatives - must be zero. 

      const EOperator ops[] = { OPERATOR_D3,
                                OPERATOR_D4,
                                OPERATOR_D5,
                                OPERATOR_D6,
                                OPERATOR_D7,
                                OPERATOR_D8,
                                OPERATOR_D9,
                                OPERATOR_D10,
                                OPERATOR_MAX };
      for (auto h=0;ops[h]!=OPERATOR_MAX;++h) {
        const auto op = ops[h];
      // The last dimension is the number of kth derivatives and needs to be resized for every Dk
        const auto DkCardin  = getDkCardinality(op, spaceDim);
        DynRankView vals("vals", numFields, numPoints, DkCardin);

        tetBasis.getValues(vals, tetNodes, op);
        auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
        Kokkos::deep_copy(vals_host, vals);

        for (auto i1 = 0; i1 < numFields; ++i1) 
          for (auto i2 = 0; i2 < numPoints; ++i2) 
            for (auto i3 = 0; i3 < DkCardin; ++i3) {
              if (std::abs(vals_host(i1,i2,i3)) > tol) {
                errorFlag++;
                *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
            
                // Get the multi-index of the value where the error is and the operator order
                int ord = Intrepid2::getOperatorOrder(op);
                *outStream << " At multi-index { "<<i1<<" "<<i2 <<" "<<i3;
                *outStream << "}  computed D"<< ord <<" component: " << vals_host(i1,i2,i3) 
                           << " but reference D" << ord << " component:  0 \n";
              }
            }
      }    
    }    
  } catch (std::logic_error err) {
    *outStream << err.what() << "\n\n";
    errorFlag = -1000;
  };

  if (errorFlag != 0)
    std::cout << "End Result: TEST FAILED\n";
  else
    std::cout << "End Result: TEST PASSED\n";
  
  // reset format state of std::cout
  std::cout.copyfmt(oldFormatState);
  return errorFlag;
}
Beispiel #2
0
    int Integration_Test04(const bool verbose) {

      Teuchos::RCP<std::ostream> outStream;
      Teuchos::oblackholestream bhs; // outputs nothing

      if (verbose)
        outStream = Teuchos::rcp(&std::cout, false);
      else
        outStream = Teuchos::rcp(&bhs, false);

      Teuchos::oblackholestream oldFormatState;
      oldFormatState.copyfmt(std::cout);

      typedef typename
        Kokkos::Impl::is_space<DeviceSpaceType>::host_mirror_space::execution_space HostSpaceType ;

      *outStream << "DeviceSpace::  "; DeviceSpaceType::print_configuration(*outStream, false);
      *outStream << "HostSpace::    ";   HostSpaceType::print_configuration(*outStream, false);
 
      *outStream                                                       
        << "===============================================================================\n"
        << "|                                                                             |\n"
        << "|       Unit Test (CubatureDirect,CubatureTensor,DefaultCubatureFactory)      |\n"
        << "|                                                                             |\n"
        << "|     1) Computing integrals of monomials on reference cells in 3D            |\n"
        << "|                                                                             |\n"
        << "|  Questions? Contact  Pavel Bochev ([email protected]) or                   |\n"
        << "|                      Denis Ridzal ([email protected]) or                   |\n"
        << "|                      Kyungjoo Kim ([email protected]).                      |\n"
        << "|                                                                             |\n"
        << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n"
        << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n"
        << "|                                                                             |\n"
        << "===============================================================================\n"
        << "| TEST 1: integrals of monomials in 3D                                        |\n"
        << "===============================================================================\n";
      
      typedef Kokkos::DynRankView<ValueType,DeviceSpaceType> DynRankView;
#define ConstructWithLabel(obj, ...) obj(#obj, __VA_ARGS__)

      typedef ValueType pointValueType;
      typedef ValueType weightValueType;
      typedef CubatureDirectLineGauss<DeviceSpaceType,pointValueType,weightValueType> CubatureLineType;
      typedef CubatureTensor<DeviceSpaceType,pointValueType,weightValueType> CubatureTensorType;
      
      const auto tol = 10.0 * tolerence<ValueType>();

      int errorFlag = 0;

      // get names of files with analytic values
      std::string basedir = "../data";
      std::stringstream namestream;
      std::string filename;
      namestream << basedir << "/HEX_integrals" << ".dat";
      namestream >> filename;
      *outStream << "filename = " << filename << std::endl;
      std::ifstream filecompare(filename);

      // compute and compare integrals
      try {
        // cannot test maxcubature degree edge (20) as max integration point is limited by 1001.
        const auto maxDeg   = 19; //Parameters::MaxCubatureDegreeEdge;
        const auto polySize = (maxDeg+1)*(maxDeg+2)*(maxDeg+3)/6;

        // test inegral values
        DynRankView ConstructWithLabel(testInt, maxDeg+1, polySize);

        // analytic integral values
        const auto analyticMaxDeg = 61;
        const auto analyticPolySize = (analyticMaxDeg+1)*(analyticMaxDeg+2)*(analyticMaxDeg+3)/6;

        DynRankView ConstructWithLabel(analyticInt, analyticPolySize, 1);

        // storage for cubatrue points and weights
        DynRankView ConstructWithLabel(cubPoints,
                                       Parameters::MaxIntegrationPoints,
                                       Parameters::MaxDimension);

        DynRankView ConstructWithLabel(cubWeights,
                                       Parameters::MaxIntegrationPoints);

        // compute integrals
        for (auto cubDeg=0;cubDeg<=maxDeg;++cubDeg) {
          CubatureLineType line(cubDeg);
          CubatureTensorType hexCub( line, line, line );
          *outStream << "Cubature order " << std::setw(2) << std::left << cubDeg << "  Testing\n";
          
          ordinal_type cnt = 0;
          for (auto xDeg=0;xDeg<=cubDeg;++xDeg) 
            for (auto yDeg=0;yDeg<=(cubDeg-xDeg);++yDeg) 
              for (auto zDeg=0;zDeg<=(cubDeg-xDeg-yDeg);++zDeg,++cnt) {
                testInt(cubDeg, cnt) = computeIntegralOfMonomial<ValueType>(hexCub,
                                                                            cubPoints,
                                                                            cubWeights,
                                                                            xDeg,
                                                                            yDeg,
                                                                            zDeg);
              }
        }


        // get analytic values
        if (filecompare.is_open()) {
          getAnalytic(analyticInt, filecompare);
          filecompare.close();
        }

        // perform comparison
        for (auto cubDeg=0;cubDeg<=maxDeg;++cubDeg) {

          const auto y_offs = (analyticMaxDeg - cubDeg);
          const auto x_offs = y_offs*(y_offs + 1)/2;

          ordinal_type offset = 0, cnt = 0;
          const auto oldFlag = errorFlag;
          for (auto xDeg=0;xDeg<=cubDeg;++xDeg,offset += x_offs) 
            for (auto yDeg=0;yDeg<=(cubDeg-xDeg);++yDeg,offset += y_offs) 
              for (auto zDeg=0;zDeg<=(cubDeg-xDeg-yDeg);++zDeg,++cnt) {
                const auto loc = cnt + offset;
                const auto abstol  = ( analyticInt(loc,0) == 0.0 ? tol : std::fabs(tol*analyticInt(loc,0)) );
                const auto absdiff = std::fabs(analyticInt(loc,0) - testInt(cubDeg,cnt));
                if (absdiff > abstol) {
                  *outStream << "Cubature order " << std::setw(2) << std::left << cubDeg << " integrating "
                             << "x^" << std::setw(2) << std::left << xDeg << " * y^" << std::setw(2) << yDeg
                             << " * z^" << std::setw(2) << zDeg << ":" << "   "
                             << std::scientific << std::setprecision(16)
                             << testInt(cubDeg,cnt) << "   " << analyticInt(loc,0) << "   "
                             << std::setprecision(4) << absdiff << "   " << "<?" << "   " << abstol << "\n";
                  errorFlag++;
                  *outStream << std::right << std::setw(118) << "^^^^---FAILURE!\n";
                }
              }
          *outStream << "Cubature order " << std::setw(2) << std::left << cubDeg
                     << (errorFlag == oldFlag ? "  PASSED" : "  FAILED") << std::endl;                         
        }
        *outStream << "\n";
      } catch (std::logic_error err) {
        *outStream << err.what() << "\n";
        errorFlag = -1;
      }
      

      if (errorFlag != 0)
        std::cout << "End Result: TEST FAILED\n";
      else
        std::cout << "End Result: TEST PASSED\n";
      
      // reset format state of std::cout
      std::cout.copyfmt(oldFormatState);
      return errorFlag;
    }
    int HGRAD_TET_COMP12_FEM_Test01(const bool verbose) {
      
      Teuchos::RCP<std::ostream> outStream;
      Teuchos::oblackholestream bhs; // outputs nothing
      
      if (verbose)
        outStream = Teuchos::rcp(&std::cout, false);
      else
        outStream = Teuchos::rcp(&bhs,       false);

      Teuchos::oblackholestream oldFormatState;
      oldFormatState.copyfmt(std::cout);

      typedef typename
        Kokkos::Impl::is_space<DeviceSpaceType>::host_mirror_space::execution_space HostSpaceType ;

      *outStream << "DeviceSpace::  "; DeviceSpaceType::print_configuration(*outStream, false);
      *outStream << "HostSpace::    ";   HostSpaceType::print_configuration(*outStream, false);

      *outStream                                                        
        << "===============================================================================\n"
        << "|                                                                             |\n"
        << "|             Unit Test (Basis_HGRAD_TET_COMP12_FEM)                          |\n"
        << "|                                                                             |\n"
        << "|     1) Evaluation of Basis Function Values                                  |\n"
        << "|                                                                             |\n"
        << "|  Questions? Contact  Pavel Bochev  ([email protected]),                    |\n"
        << "|                      Denis Ridzal  ([email protected]),                    |\n"
        << "|                      Kara Peterson ([email protected]),                    |\n"
        << "|                      Jake Ostien   ([email protected]),                    |\n"
        << "|                      Kyungjoo Kim  ([email protected]).                     |\n"
        << "|                                                                             |\n"
        << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n"
        << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n"
        << "|                                                                             |\n"
        << "===============================================================================\n";

      typedef Kokkos::DynRankView<ValueType,DeviceSpaceType> DynRankView;
      typedef Kokkos::DynRankView<ValueType,HostSpaceType>   DynRankViewHost;
#define ConstructWithLabel(obj, ...) obj(#obj, __VA_ARGS__)

      const ValueType tol = tolerence();
      int errorFlag = 0;

      // for virtual function, value and point types are declared in the class
      typedef ValueType outputValueType;
      typedef ValueType pointValueType;
      Basis_HGRAD_TET_COMP12_FEM<DeviceSpaceType,outputValueType,pointValueType> tetBasis;

      *outStream
        << "\n"
        << "===============================================================================\n"
        << "| TEST 1: correctness of basis function values                                |\n"
        << "===============================================================================\n";
      
      // output precision
      outStream -> precision(20);
      
      // VALUE: Each row gives the 10 correct basis set values at an evaluation point
      const ValueType nodalBasisValues[] = {
        // first 4 vertices
        1.0, 0.0, 0.0, 0.0,  0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
        0.0, 1.0, 0.0, 0.0,  0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
        0.0, 0.0, 1.0, 0.0,  0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
        0.0, 0.0, 0.0, 1.0,  0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
        // second 6 vertices
        0.0, 0.0, 0.0, 0.0,  1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
        0.0, 0.0, 0.0, 0.0,  0.0, 1.0, 0.0, 0.0, 0.0, 0.0,
        0.0, 0.0, 0.0, 0.0,  0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
        0.0, 0.0, 0.0, 0.0,  0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
        0.0, 0.0, 0.0, 0.0,  0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
        0.0, 0.0, 0.0, 0.0,  0.0, 0.0, 0.0, 0.0, 0.0, 1.0
      };

      const ValueType pointBasisValues[] = {
        // pt 0 {0.25, 0.25, 0.25}
        0.0, 0.0, 0.0, 0.0,  1./6., 1./6., 1./6., 1./6., 1./6., 1./6.,
        // pt 1 {0.5, 1/6, 1/6}
        0.0, 0.0, 0.0, 0.0,  1./3., 1./3., 0.0, 0.0, 1./3., 0.0,
        // pt 2 {1/6, 0.5, 0.1/6}
        0.0, 0.0, 0.0, 0.0,  0.0, 1./3., 1./3., 0.0, 0.0, 1./3.,
        // pt 3 {1/6, 1/6, 0.5}
        0.0, 0.0, 0.0, 0.0,  0.0, 0.0, 0.0, 1./3., 1./3., 1./3.,
        // pt 4 {1/6, 1/6, 1/6}
        0.0, 0.0, 0.0, 0.0,  1./3., 0.0, 1./3., 1./3., 0.0, 0.0,
        // pt 5
        0.170820393249936908922752100619382870632, 0.0, 0.0, 0.0, 0.276393202250021030359082633126872376456, 0.0, 0.276393202250021030359082633126872376456, 0.276393202250021030359082633126872376456, 0.0, 0.0,
        // pt 6
        0.0, 0.170820393249936908922752100619382870632, 0.0, 0.0, 0.276393202250021030359082633126872376456, 0.276393202250021030359082633126872376456, 0.0, 0.0, 0.276393202250021030359082633126872376456, 0.0,
        // pt 7
        0.0, 0.0, 0.170820393249936908922752100619382870632, 0.0, 0.0, 0.276393202250021030359082633126872376456, 0.276393202250021030359082633126872376456, 0.0, 0.0, 0.276393202250021030359082633126872376456,
        // pt 8
        0.0, 0.0, 0.0, 0.170820393249936908922752100619382870632, 0.0, 0.0, 0.0, 0.276393202250021030359082633126872376456, 0.276393202250021030359082633126872376456, 0.276393202250021030359082633126872376456,
      };

      // GRAD and D1: each row gives the 3x10 correct values of the gradients of the 10 basis functions
      const ValueType pointBasisGrads[] = {
        // point 0
        -1./4.,   -1./4.,   -1./4.,
        1./4.,      0.0,      0.0, 
        0.0,    1./4.,      0.0,   
        0.0,      0.0,    1./4.,
        0.0,   -3./4.,   -3./4.,
        3./4.,    3./4.,      0.0,
        -3./4.,      0.0,   -3./4.,
        -3./4.,   -3./4.,      0.0,
        3./4.,      0.0,    3./4.,
        0.0,    3./4.,    3./4.,

        // point 1
        -1./24.,  -1./24.,  -1./24.,
        7./8.,      0.0,      0.0,
        0.0,   1./24.,      0.0,
        0.0,      0.0,   1./24.,
        -35./36., -19./12., -19./12.,
        11./18.,  19./12.,      0.0,
        -17./36.,      0.0,   -1./3.,
        -17./36.,   -1./3.,      0.0,
        11./18.,      0.0,  19./12.,
        -5./36.,    1./3.,    1./3.,

        // point 2
        -1./24.,  -1./24.,  -1./24.,
        1./24.,      0.0,      0.0,
        0.0,    7./8.,      0.0,
        0.0,      0.0,   1./24.,
        0.0, -17./36.,   -1./3.,
        19./12.,  11./18.,      0.0,
        -19./12., -35./36., -19./12.,
        -1./3., -17./36.,      0.0,
        1./3.,  -5./36.,    1./3.,
        0.0,  11./18.,  19./12.,

        // point 3
        -1./24.,  -1./24.,  -1./24.,
        1./24.,      0.0,      0.0,
        0.0,   1./24.,      0.0,
        0.0,      0.0,    7./8.,
        0.0,   -1./3., -17./36.,
        1./3.,    1./3.,  -5./36.,
        -1./3.,      0.0, -17./36.,
        -19./12., -19./12., -35./36.,
        19./12.,      0.0,  11./18.,
        0.0,  19./12.,  11./18.,

        // point 4
        -7./8.,   -7./8.,   -7./8.,
        1./24.,      0.0,      0.0,
        0.0,   1./24.,      0.0,
        0.0,      0.0,   1./24.,
        35./36., -11./18., -11./18.,
        17./36.,  17./36.,   5./36.,
        -11./18.,  35./36., -11./18.,
        -11./18., -11./18.,  35./36.,
        17./36.,   5./36.,  17./36.,
        5./36.,  17./36.,  17./36.,

        // point 5
        -1.088525491562421136153440125774228588290, -1.088525491562421136153440125774228588290, -1.088525491562421136153440125774228588290,
        -0.029508497187473712051146708591409529430, 0.0, 0.0,
        0.0, -0.029508497187473712051146708591409529430, 0.0,
        0.0, 0.0, -0.029508497187473712051146708591409529430,
        1.30437298687487732290535130675991113734, -0.563661001875017525299235527605726980380, -0.563661001875017525299235527605726980380,
        0.377322003750035050598471055211453960760, 0.377322003750035050598471055211453960760, 0.186338998124982474700764472394273019620,
        -0.563661001875017525299235527605726980380, 1.30437298687487732290535130675991113734, -0.563661001875017525299235527605726980380,
        -0.563661001875017525299235527605726980380, -0.563661001875017525299235527605726980380, 1.30437298687487732290535130675991113734,
        0.377322003750035050598471055211453960760, 0.186338998124982474700764472394273019620, 0.377322003750035050598471055211453960760,
        0.186338998124982474700764472394273019620, 0.377322003750035050598471055211453960760, 0.377322003750035050598471055211453960760,

        // point 6
        0.029508497187473712051146708591409529430, 0.029508497187473712051146708591409529430, 0.029508497187473712051146708591409529430,
        1.088525491562421136153440125774228588290, 0.0, 0.0,
        0.0, -0.029508497187473712051146708591409529430, 0.0,
        0.0, 0.0, -0.029508497187473712051146708591409529430,
        -1.30437298687487732290535130675991113734, -1.868033988749894848204586834365638117720, -1.868033988749894848204586834365638117720,
        0.563661001875017525299235527605726980380, 1.868033988749894848204586834365638117720, 0.0,
        -0.377322003750035050598471055211453960760, 0.0, -0.190983005625052575897706582817180941140,
        -0.377322003750035050598471055211453960760, -0.190983005625052575897706582817180941140, 0.0,
        0.563661001875017525299235527605726980380, 0.0, 1.868033988749894848204586834365638117720,
        -0.186338998124982474700764472394273019620, 0.190983005625052575897706582817180941140, 0.19098300562505257589770658281718094114,

        // point 7
        0.029508497187473712051146708591409529430, 0.029508497187473712051146708591409529430, 0.029508497187473712051146708591409529430,
        -0.029508497187473712051146708591409529430, 0.0, 0.0,          
        0.0, 1.088525491562421136153440125774228588290, 0.0,           
        0.0, 0.0, -0.029508497187473712051146708591409529430,          
        0.0, -0.377322003750035050598471055211453960760, -0.190983005625052575897706582817180941140,
        1.868033988749894848204586834365638117720, 0.563661001875017525299235527605726980380, 0.0,
        -1.868033988749894848204586834365638117720, -1.30437298687487732290535130675991113734, -1.868033988749894848204586834365638117720,
        -0.190983005625052575897706582817180941140, -0.377322003750035050598471055211453960760, 0.0,
        0.190983005625052575897706582817180941140, -0.186338998124982474700764472394273019620, 0.190983005625052575897706582817180941140,
        0.0, 0.563661001875017525299235527605726980380, 1.868033988749894848204586834365638117720,

        // point 8
        0.029508497187473712051146708591409529430, 0.029508497187473712051146708591409529430, 0.029508497187473712051146708591409529430,
        -0.029508497187473712051146708591409529430, 0.0, 0.0,
        0.0, -0.029508497187473712051146708591409529430, 0.0,
        0.0, 0.0, 1.088525491562421136153440125774228588290,
        0.0, -0.190983005625052575897706582817180941140, -0.377322003750035050598471055211453960760,
        0.190983005625052575897706582817180941140, 0.190983005625052575897706582817180941140, -0.186338998124982474700764472394273019620,
        -0.190983005625052575897706582817180941140, 0.0, -0.377322003750035050598471055211453960760,
        -1.868033988749894848204586834365638117720, -1.868033988749894848204586834365638117720, -1.30437298687487732290535130675991113734,
        1.868033988749894848204586834365638117720, 0.0, 0.563661001875017525299235527605726980380,
        0.0, 1.868033988749894848204586834365638117720, 0.563661001875017525299235527605726980380,
      };
      
      try{
        DynRankViewHost ConstructWithLabel(tetNodesHost, 10, 3);
        
        tetNodesHost(0,0) = 0.0;  tetNodesHost(0,1) = 0.0;  tetNodesHost(0,2) = 0.0;
        tetNodesHost(1,0) = 1.0;  tetNodesHost(1,1) = 0.0;  tetNodesHost(1,2) = 0.0;
        tetNodesHost(2,0) = 0.0;  tetNodesHost(2,1) = 1.0;  tetNodesHost(2,2) = 0.0;
        tetNodesHost(3,0) = 0.0;  tetNodesHost(3,1) = 0.0;  tetNodesHost(3,2) = 1.0;
        tetNodesHost(4,0) = 0.5;  tetNodesHost(4,1) = 0.0;  tetNodesHost(4,2) = 0.0;
        tetNodesHost(5,0) = 0.5;  tetNodesHost(5,1) = 0.5;  tetNodesHost(5,2) = 0.0;
        tetNodesHost(6,0) = 0.0;  tetNodesHost(6,1) = 0.5;  tetNodesHost(6,2) = 0.0;
        tetNodesHost(7,0) = 0.0;  tetNodesHost(7,1) = 0.0;  tetNodesHost(7,2) = 0.5;
        tetNodesHost(8,0) = 0.5;  tetNodesHost(8,1) = 0.0;  tetNodesHost(8,2) = 0.5;
        tetNodesHost(9,0) = 0.0;  tetNodesHost(9,1) = 0.5;  tetNodesHost(9,2) = 0.5;
        
        auto tetNodes = Kokkos::create_mirror_view(typename DeviceSpaceType::memory_space(), tetNodesHost);
        Kokkos::deep_copy(tetNodes, tetNodesHost);

        DynRankViewHost ConstructWithLabel(tetPointsHost, 9, 3);
        
        // from the 5 point integration
        tetPointsHost(0,0) = 0.25;     tetPointsHost(0,1) = 0.25;     tetPointsHost(0,2) = 0.25;
        tetPointsHost(1,0) = 0.5;      tetPointsHost(1,1) = (1./6.);  tetPointsHost(1,2) = (1./6.);
        tetPointsHost(2,0) = (1./6.);  tetPointsHost(2,1) = 0.5;      tetPointsHost(2,2) = (1./6.);
        tetPointsHost(3,0) = (1./6.);  tetPointsHost(3,1) = (1./6.);  tetPointsHost(3,2) = 0.5;
        tetPointsHost(4,0) = (1./6.);  tetPointsHost(4,1) = (1./6.);  tetPointsHost(4,2) = (1./6.);
        
        // from the 4 point integration
        tetPointsHost(5,0) = 0.1381966011250105151795413165634361882280;
        tetPointsHost(5,1) = 0.1381966011250105151795413165634361882280;
        tetPointsHost(5,2) = 0.1381966011250105151795413165634361882280;
        
        tetPointsHost(6,0) = 0.5854101966249684544613760503096914353161;
        tetPointsHost(6,1) = 0.1381966011250105151795413165634361882280;
        tetPointsHost(6,2) = 0.1381966011250105151795413165634361882280;
        
        tetPointsHost(7,0) = 0.1381966011250105151795413165634361882280;
        tetPointsHost(7,1) = 0.5854101966249684544613760503096914353161;
        tetPointsHost(7,2) = 0.1381966011250105151795413165634361882280;
        
        tetPointsHost(8,0) = 0.1381966011250105151795413165634361882280;
        tetPointsHost(8,1) = 0.1381966011250105151795413165634361882280;
        tetPointsHost(8,2) = 0.5854101966249684544613760503096914353161;

        auto tetPoints = Kokkos::create_mirror_view(typename DeviceSpaceType::memory_space(), tetPointsHost);
        Kokkos::deep_copy(tetPoints, tetPointsHost);

        // Dimensions for the output arrays:
        const auto numFields = tetBasis.getCardinality();
        const auto numNodes  = tetNodes.dimension(0);
        const auto spaceDim  = tetBasis.getBaseCellTopology().getDimension();
    
        // Check VALUE of basis functions at nodes: resize vals to rank-2 container:\n";
        {
          *outStream << " check VALUE of basis functions at nodes\n";
          DynRankView vals = DynRankView("vals", numFields, numNodes);
          tetBasis.getValues(vals, tetNodes, OPERATOR_VALUE);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);

          for (auto i=0;i<numFields;++i) {
            for (auto j=0;j<numNodes;++j) {
              const auto l =  i + j * numFields;
              if (std::abs(vals_host(i,j) - nodalBasisValues[l]) > tol) {
                errorFlag++;
                *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                // Output the multi-index of the value where the error is:
                *outStream << " At multi-index { ";
                *outStream << i << " ";*outStream << j << " ";
                *outStream << "}  computed value: " << vals_host(i,j)
                           << " but reference value: " << nodalBasisValues[l] << "\n";
              }
            }
          }
        }

        const auto numPoints = tetPoints.dimension(0);

        // Check VALUE of basis functions at points: resize vals to rank-2 container:\n";
        {
          *outStream << " check VALUE of basis functions at points\n";
          DynRankView vals = DynRankView("vals", numFields, numPoints);
          tetBasis.getValues(vals, tetPoints, OPERATOR_VALUE);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);

          for (auto i=0;i<numFields;++i) {
            for (auto j=0;j<numPoints;++j) {
              const auto l =  i + j * numFields;
              if (std::abs(vals_host(i,j) - pointBasisValues[l]) > tol) {
                errorFlag++;
                *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                // Output the multi-index of the value where the error is:
                *outStream << " At multi-index { ";
                *outStream << i << " ";*outStream << j << " ";
                *outStream << "}  computed value: " << vals_host(i,j)
                           << " but reference value: " << pointBasisValues[l] << "\n";
              }
            }
          }
        }
        
        // Check VALUE of basis functions at random points: resize vals to rank-2 container:\n";
        {
          *outStream << " check VALUE of basis functions at random points\n";
          const auto numRandomPoints = 16384;

          DynRankViewHost tetRandomPointsHost = DynRankViewHost("tetRandomPointsHost", numRandomPoints, 3);
          {
            ordinal_type point = 0;

            std::random_device rd;
            std::mt19937 gen(rd());
            std::uniform_real_distribution<> dis(0, 1);
            while (point < numRandomPoints) {
              const ValueType r = dis(gen), s = dis(gen), t = dis(gen);
              if (r + s + t > 1.0) {
                // do nothing
              } else {
                tetRandomPointsHost(point, 0) = r;
                tetRandomPointsHost(point, 1) = s;
                tetRandomPointsHost(point, 2) = t;
                ++point;
              }
            }
          }
          
          auto tetRandomPoints = Kokkos::create_mirror_view(typename DeviceSpaceType::memory_space(), tetRandomPointsHost);
          Kokkos::deep_copy(tetRandomPoints, tetRandomPointsHost);

          DynRankView vals = DynRankView("vals", numFields, numRandomPoints);
        
          tetBasis.getValues(vals, tetRandomPoints, OPERATOR_VALUE);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);
        
          for (auto j=0;j<numRandomPoints;++j) {
            ValueType sum = 0.0;
            for (auto i=0;i<numFields;++i) 
              sum += vals_host(i,j);

            if (std::abs(sum - 1.0) > tol) {
              errorFlag++;
              *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
              
              // Just indicate something bad happened
              *outStream << " Composite tet basis functions";
              *outStream << " are not summing to 1.0\n";
              *outStream << " sum : " << sum << "\n";
            }
          }
        }
        
    
        // Check GRAD of basis functions at points: resize vals to rank-3 container:\n";
        {
          DynRankView vals = DynRankView("vals", numFields, numPoints, spaceDim);
          tetBasis.getValues(vals, tetPoints, OPERATOR_GRAD);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);
          for (auto i=0;i<numFields;++i) {
            for (auto j=0;j<numPoints;++j) {
              for (auto k=0;k<spaceDim;++k) {
                const auto l = k + i * spaceDim + j * spaceDim * numFields;
                if (std::abs(vals_host(i,j,k) - pointBasisGrads[l]) > tol) {
                  errorFlag++;
                  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
                  
                  // Output the multi-index of the value where the error is:
                  *outStream << " At multi-index { ";
                  *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
                  *outStream << "}  computed grad component: " << vals_host(i,j,k)
                             << " but reference grad component: " << pointBasisGrads[l] << "\n";
                }
              }
            }
          }
        }
      } catch (std::logic_error err) {
        *outStream << err.what() << "\n\n";
        errorFlag = -1000;
      }

      if (errorFlag != 0)
        std::cout << "End Result: TEST FAILED\n";
      else
        std::cout << "End Result: TEST PASSED\n";

      // reset format state of std::cout
      std::cout.copyfmt(oldFormatState);
      return errorFlag;
    }
Beispiel #4
0
    int HGRAD_HEX_C2_FEM_Test01(const bool verbose) {

      Teuchos::RCP<std::ostream> outStream;
      Teuchos::oblackholestream bhs; // outputs nothing

      if (verbose)
        outStream = Teuchos::rcp(&std::cout, false);
      else
        outStream = Teuchos::rcp(&bhs,       false);

      Teuchos::oblackholestream oldFormatState;
      oldFormatState.copyfmt(std::cout);

      typedef typename
        Kokkos::Impl::is_space<DeviceSpaceType>::host_mirror_space::execution_space HostSpaceType ;

      *outStream << "DeviceSpace::  "; DeviceSpaceType::print_configuration(*outStream, false);
      *outStream << "HostSpace::    ";   HostSpaceType::print_configuration(*outStream, false);

      *outStream
        << "\n"
        << "===============================================================================\n"
        << "|                                                                             |\n"
        << "|                 Unit Test (Basis_HGRAD_HEX_C2_FEM)                          |\n"
        << "|                                                                             |\n"
        << "|     1) Conversion of Dof tags into Dof ordinals and back                    |\n"
        << "|     2) Basis values for VALUE, GRAD, and Dk operators                       |\n"
        << "|                                                                             |\n"
        << "|  Questions? Contact  Pavel Bochev  ([email protected]),                    |\n"
        << "|                      Denis Ridzal  ([email protected]),                    |\n"
        << "|                      Kara Peterson ([email protected]).                    |\n"
        << "|                                                                             |\n"
        << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n"
        << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n"
        << "|                                                                             |\n"
        << "===============================================================================\n";


      typedef Kokkos::DynRankView<ValueType,DeviceSpaceType> DynRankView;
      typedef Kokkos::DynRankView<ValueType,HostSpaceType>   DynRankViewHost;
#define ConstructWithLabel(obj, ...) obj(#obj, __VA_ARGS__)

      const ValueType tol = tolerence();
      int errorFlag = 0;

      // for virtual function, value and point types are declared in the class
      typedef ValueType outputValueType;
      typedef ValueType pointValueType;
      Basis_HGRAD_HEX_C2_FEM<DeviceSpaceType,outputValueType,pointValueType> hexBasis;
      //typedef typename decltype(hexBasis)::outputViewType outputViewType;
      //typedef typename decltype(hexBasis)::pointViewType  pointViewType;

      *outStream
        << "\n"
        << "===============================================================================\n"
        << "| TEST 1: Basis creation, exception testing                                   |\n"
        << "===============================================================================\n";

      try{
        ordinal_type nthrow = 0, ncatch = 0;
#ifdef HAVE_INTREPID2_DEBUG

        // Define array containing the 8 vertices of the reference HEX, its center, 12 edge nodes and 6 face centers
        DynRankView ConstructWithLabel( hexNodes, 27, 3);

        // Generic array for the output values; needs to be properly resized depending on the operator type
        const auto numFields = hexBasis.getCardinality();
        const auto numPoints = hexNodes.dimension(0);
        const auto spaceDim  = hexBasis.getBaseCellTopology().getDimension();
        const auto D2Cardin  = getDkCardinality(OPERATOR_D2, spaceDim);

        const auto workSize  = numFields*numPoints*D2Cardin;
        DynRankView ConstructWithLabel(work, workSize);

        DynRankView vals(work.data(), numFields, numPoints);
        {
          // exception #1: CURL cannot be applied to scalar functions in 3D
          // resize vals to rank-3 container with dimensions (num. basis functions, num. points, arbitrary)
          DynRankView tmpvals = DynRankView(work.data(), numFields, numPoints, 4);
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(tmpvals, hexNodes, OPERATOR_CURL) );
        }
        {
          // exception #2: DIV cannot be applied to scalar functions in 3D
          // resize vals to rank-2 container with dimensions (num. basis functions, num. points)
          DynRankView tmpvals = DynRankView(work.data(), numFields, numPoints);
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(tmpvals, hexNodes, OPERATOR_DIV) );
        }
        // Exceptions 3-7: all bf tags/bf Ids below are wrong and should cause getDofOrdinal() and
        // getDofTag() to access invalid array elements thereby causing bounds check exception
        {
          // exception #3
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getDofOrdinal(3,10,0) );
          // exception #4
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getDofOrdinal(1,2,1) );
          // exception #5
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getDofOrdinal(0,4,1) );
          // exception #6
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getDofTag(28) );
          // exception #7
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getDofTag(-1) );
        }
        // Exceptions 8-18 test exception handling with incorrectly dimensioned input/output arrays
        {
          // exception #8: input points array must be of rank-2
          DynRankView ConstructWithLabel(badPoints1, 4, 5, 3);
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(vals, badPoints1, OPERATOR_VALUE) );
        }
        {
          // exception #9 dimension 1 in the input point array must equal space dimension of the cell
          DynRankView ConstructWithLabel(badPoints2, 4, spaceDim - 1);
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(vals, badPoints2, OPERATOR_VALUE) );
        }
        {
          // exception #10 output values must be of rank-2 for OPERATOR_VALUE
          DynRankView ConstructWithLabel(badVals1, 4, 3, 1);
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(badVals1, hexNodes, OPERATOR_VALUE) );
        }
        {
          // exception #11 output values must be of rank-3 for OPERATOR_GRAD
          DynRankView ConstructWithLabel(badVals2, 4, 3);
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(badVals2, hexNodes, OPERATOR_GRAD) );
          // exception #12 output values must be of rank-3 for OPERATOR_D1
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(badVals2, hexNodes, OPERATOR_D1) );
          // exception #13 output values must be of rank-3 for OPERATOR_D2
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(badVals2, hexNodes, OPERATOR_D2) );
        }
        {
          // exception #14 incorrect 0th dimension of output array (must equal number of basis functions)
          DynRankView ConstructWithLabel(badVals3, numFields + 1, numPoints);
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(badVals3, hexNodes, OPERATOR_VALUE) );
        }
        {
          // exception #15 incorrect 1st dimension of output array (must equal number of points)
          DynRankView ConstructWithLabel(badVals4, numFields, numPoints + 1);
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(badVals4, hexNodes, OPERATOR_VALUE) );
        }
        {
          // exception #16: incorrect 2nd dimension of output array (must equal the space dimension)
          DynRankView ConstructWithLabel(badVals5, numFields, numPoints, spaceDim - 1);
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(badVals5, hexNodes, OPERATOR_GRAD) );
        }
        {
          // exception #17: incorrect 2nd dimension of output array (must equal D2 cardinality in 3D)
          DynRankView ConstructWithLabel(badVals6, numFields, numPoints, 40);
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(badVals6, hexNodes, OPERATOR_D2) );
        }
        {
          // exception #18: incorrect 2nd dimension of output array (must equal D3 cardinality in 3D)
          DynRankView ConstructWithLabel(badVals7, numFields, numPoints, 50);
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(badVals7, hexNodes, OPERATOR_D3) );
        }
#endif
        // Check if number of thrown exceptions matches the one we expect
        if (nthrow != ncatch) {
          errorFlag++;
          *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
          *outStream << "# of catch ("<< ncatch << ") is different from # of throw (" << nthrow << ")\n";
        }

      } catch (std::logic_error err) {
        *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
        *outStream << err.what() << '\n';
        *outStream << "-------------------------------------------------------------------------------" << "\n\n";
        errorFlag = -1000;
      };

      *outStream
        << "\n"
        << "===============================================================================\n"
        << "| TEST 2: correctness of tag to enum and enum to tag lookups                  |\n"
        << "===============================================================================\n";

      try{

        const auto numFields = hexBasis.getCardinality();
        const auto allTags = hexBasis.getAllDofTags();

        // Loop over all tags, lookup the associated dof enumeration and then lookup the tag again
        const auto dofTagSize = allTags.dimension(0);
        for (auto i = 0; i < dofTagSize; ++i) {
          const auto bfOrd  = hexBasis.getDofOrdinal(allTags(i,0), allTags(i,1), allTags(i,2));

          const auto myTag = hexBasis.getDofTag(bfOrd);
          if( !( (myTag(0) == allTags(i,0)) &&
                 (myTag(1) == allTags(i,1)) &&
                 (myTag(2) == allTags(i,2)) &&
                 (myTag(3) == allTags(i,3)) ) ) {
            errorFlag++;
            *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
            *outStream << " getDofOrdinal( {"
                       << allTags(i,0) << ", "
                       << allTags(i,1) << ", "
                       << allTags(i,2) << ", "
                       << allTags(i,3) << "}) = " << bfOrd <<" but \n";
            *outStream << " getDofTag(" << bfOrd << ") = { "
                       << myTag(0) << ", "
                       << myTag(1) << ", "
                       << myTag(2) << ", "
                       << myTag(3) << "}\n";
          }
        }

        // Now do the same but loop over basis functions
        for( auto bfOrd = 0; bfOrd < numFields; ++bfOrd) {
          const auto myTag  = hexBasis.getDofTag(bfOrd);
          const auto myBfOrd = hexBasis.getDofOrdinal(myTag(0), myTag(1), myTag(2));
          if( bfOrd != myBfOrd) {
            errorFlag++;
            *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
            *outStream << " getDofTag(" << bfOrd << ") = { "
                       << myTag(0) << ", "
                       << myTag(1) << ", "
                       << myTag(2) << ", "
                       << myTag(3) << "} but getDofOrdinal({"
                       << myTag(0) << ", "
                       << myTag(1) << ", "
                       << myTag(2) << ", "
                       << myTag(3) << "} ) = " << myBfOrd << "\n";
          }
        }
      } catch (std::logic_error err){
        *outStream << err.what() << "\n\n";
        errorFlag = -1000;
      };


      *outStream
        << "\n"
        << "===============================================================================\n"
        << "| TEST 3: correctness of basis function values                                |\n"
        << "===============================================================================\n";

      outStream -> precision(20);

      try{
        // VALUE: Each row gives the 8 correct basis set values at an evaluation point
        const ValueType basisValues[] = {
          1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
          0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, \
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
          0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
          0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, \
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, \
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
          0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
          0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, \
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, \
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
          0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
          0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, \
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, \
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
          0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, \
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
          1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
          0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, \
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
          0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
          0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, \
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000  };


        // GRAD, D1, D2, D3 and D4 test values are stored in files due to their large size
        std::string     fileName;
        std::ifstream   dataFile;

        // GRAD and D1 values are stored in (F,P,D) format in a data file. Read file and do the test
        std::vector<double> basisGrads;           // Flat array for the gradient values.

        fileName = "../testdata/HEX_C2_GradVals.dat";
        dataFile.open(fileName.c_str());
        INTREPID2_TEST_FOR_EXCEPTION( !dataFile.good(), std::logic_error,
                                      ">>> ERROR (HGRAD_HEX_C2/test01): could not open GRAD values data file, test aborted.");
        while (!dataFile.eof() ){
          double temp;
          std::string line;                            // string for one line of input file
          std::getline(dataFile, line);           // get next line from file
          std::stringstream data_line(line);           // convert to stringstream
          while(data_line >> temp){               // extract value from line
            basisGrads.push_back(temp);           // push into vector
          }
        }
        // It turns out that just closing and then opening the ifstream variable does not reset it
        // and subsequent open() command fails. One fix is to explicitely clear the ifstream, or
        // scope the variables.
        dataFile.close();
        dataFile.clear();


        //D2: flat array with the values of D2 applied to basis functions. Multi-index is (F,P,D2cardinality)
        std::vector<double> basisD2;
        fileName = "../testdata/HEX_C2_D2Vals.dat";
        dataFile.open(fileName.c_str());
        INTREPID2_TEST_FOR_EXCEPTION( !dataFile.good(), std::logic_error,
                                      ">>> ERROR (HGRAD_HEX_C2/test01): could not open D2 values data file, test aborted.");
        while (!dataFile.eof() ){
          double temp;
          std::string line;                            // string for one line of input file
          std::getline(dataFile, line);           // get next line from file
          std::stringstream data_line(line);           // convert to stringstream
          while(data_line >> temp){               // extract value from line
            basisD2.push_back(temp);              // push into vector
          }
        }
        dataFile.close();
        dataFile.clear();


        //D3: flat array with the values of D3 applied to basis functions. Multi-index is (F,P,D3cardinality)
        std::vector<double> basisD3;

        fileName = "../testdata/HEX_C2_D3Vals.dat";
        dataFile.open(fileName.c_str());
        INTREPID2_TEST_FOR_EXCEPTION( !dataFile.good(), std::logic_error,
                                      ">>> ERROR (HGRAD_HEX_C2/test01): could not open D3 values data file, test aborted.");

        while (!dataFile.eof() ){
          double temp;
          std::string line;                            // string for one line of input file
          std::getline(dataFile, line);           // get next line from file
          std::stringstream data_line(line);           // convert to stringstream
          while(data_line >> temp){               // extract value from line
            basisD3.push_back(temp);              // push into vector
          }
        }
        dataFile.close();
        dataFile.clear();


        //D4: flat array with the values of D3 applied to basis functions. Multi-index is (F,P,D4cardinality)
        std::vector<double> basisD4;

        fileName = "../testdata/HEX_C2_D4Vals.dat";
        dataFile.open(fileName.c_str());
        INTREPID2_TEST_FOR_EXCEPTION( !dataFile.good(), std::logic_error,
                                      ">>> ERROR (HGRAD_HEX_C2/test01): could not open D4 values data file, test aborted.");

        while (!dataFile.eof() ){
          double temp;
          std::string line;                            // string for one line of input file
          std::getline(dataFile, line);           // get next line from file
          std::stringstream data_line(line);           // convert to stringstream
          while(data_line >> temp){               // extract value from line
            basisD4.push_back(temp);              // push into vector
          }
        }
        dataFile.close();
        dataFile.clear();

        DynRankViewHost ConstructWithLabel(hexNodesHost, 27, 3);

        // vertices
        hexNodesHost(0, 0) = -1.0;  hexNodesHost(0, 1) = -1.0;  hexNodesHost(0, 2) = -1.0;
        hexNodesHost(1, 0) =  1.0;  hexNodesHost(1, 1) = -1.0;  hexNodesHost(1, 2) = -1.0;
        hexNodesHost(2, 0) =  1.0;  hexNodesHost(2, 1) =  1.0;  hexNodesHost(2, 2) = -1.0;
        hexNodesHost(3, 0) = -1.0;  hexNodesHost(3, 1) =  1.0;  hexNodesHost(3, 2) = -1.0;

        hexNodesHost(4, 0) = -1.0;  hexNodesHost(4, 1) = -1.0;  hexNodesHost(4, 2) =  1.0;
        hexNodesHost(5, 0) =  1.0;  hexNodesHost(5, 1) = -1.0;  hexNodesHost(5, 2) =  1.0;
        hexNodesHost(6, 0) =  1.0;  hexNodesHost(6, 1) =  1.0;  hexNodesHost(6, 2) =  1.0;
        hexNodesHost(7, 0) = -1.0;  hexNodesHost(7, 1) =  1.0;  hexNodesHost(7, 2) =  1.0;

        // nodes on edges
        hexNodesHost(8, 0) =  0.0;   hexNodesHost(8, 1) = -1.0;  hexNodesHost(8, 2) = -1.0;
        hexNodesHost(9, 0) =  1.0;   hexNodesHost(9, 1) =  0.0;  hexNodesHost(9, 2) = -1.0;
        hexNodesHost(10,0) =  0.0;   hexNodesHost(10,1) =  1.0;  hexNodesHost(10,2) = -1.0;
        hexNodesHost(11,0) = -1.0;   hexNodesHost(11,1) =  0.0;  hexNodesHost(11,2) = -1.0;
        hexNodesHost(12,0) = -1.0;   hexNodesHost(12,1) = -1.0;  hexNodesHost(12,2) =  0.0;
        hexNodesHost(13,0) =  1.0;   hexNodesHost(13,1) = -1.0;  hexNodesHost(13,2) =  0.0;
        hexNodesHost(14,0) =  1.0;   hexNodesHost(14,1) =  1.0;  hexNodesHost(14,2) =  0.0;
        hexNodesHost(15,0) = -1.0;   hexNodesHost(15,1) =  1.0;  hexNodesHost(15,2) =  0.0;
        hexNodesHost(16,0) =  0.0;   hexNodesHost(16,1) = -1.0;  hexNodesHost(16,2) =  1.0;
        hexNodesHost(17,0) =  1.0;   hexNodesHost(17,1) =  0.0;  hexNodesHost(17,2) =  1.0;
        hexNodesHost(18,0) =  0.0;   hexNodesHost(18,1) =  1.0;  hexNodesHost(18,2) =  1.0;
        hexNodesHost(19,0) = -1.0;   hexNodesHost(19,1) =  0.0;  hexNodesHost(19,2) =  1.0;

        // center
        hexNodesHost(20,0) =  0.0;  hexNodesHost(20,1) =  0.0;   hexNodesHost(20,2) =  0.0;

        // Face nodes
        hexNodesHost(21,0) =  0.0;   hexNodesHost(21,1) =  0.0;  hexNodesHost(21,2) = -1.0;
        hexNodesHost(22,0) =  0.0;   hexNodesHost(22,1) =  0.0;  hexNodesHost(22,2) =  1.0;
        hexNodesHost(23,0) = -1.0;   hexNodesHost(23,1) =  0.0;  hexNodesHost(23,2) =  0.0;
        hexNodesHost(24,0) =  1.0;   hexNodesHost(24,1) =  0.0;  hexNodesHost(24,2) =  0.0;
        hexNodesHost(25,0) =  0.0;   hexNodesHost(25,1) = -1.0;  hexNodesHost(25,2) =  0.0;
        hexNodesHost(26,0) =  0.0;   hexNodesHost(26,1) =  1.0;  hexNodesHost(26,2) =  0.0;

        auto hexNodes = Kokkos::create_mirror_view(typename DeviceSpaceType::memory_space(), hexNodesHost);
        Kokkos::deep_copy(hexNodes, hexNodesHost);

        // Dimensions for the output arrays:
        const auto numFields = hexBasis.getCardinality();
        const auto numPoints = hexNodes.dimension(0);
        const auto spaceDim  = hexBasis.getBaseCellTopology().getDimension();
        const auto D2Cardin  = getDkCardinality(OPERATOR_D2, spaceDim);
        const auto D3Cardin  = getDkCardinality(OPERATOR_D3, spaceDim);
        const auto D4Cardin  = getDkCardinality(OPERATOR_D4, spaceDim);

        {
          // Generic array for values, grads, curls, etc. that will be properly sized before each call
          DynRankView ConstructWithLabel(vals, numFields, numPoints);
          // Check VALUE of basis functions: resize vals to rank-2 container:
          hexBasis.getValues(vals, hexNodes, OPERATOR_VALUE);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);
          for (auto i = 0; i < numFields; ++i) {
            for (auto j = 0; j < numPoints; ++j) {
              const auto l =  i + j * numFields;
              if (std::abs(vals_host(i,j) - basisValues[l]) > tol ) {
                errorFlag++;
                *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                // Output the multi-index of the value where the error is:
                *outStream << " At multi-index { ";
                *outStream << i << " ";*outStream << j << " ";
                *outStream << "}  computed value: " << vals_host(i,j)
                           << " but reference value: " << basisValues[l] << "\n";
              }
            }
          }
        }

        {
          DynRankView ConstructWithLabel(vals, numFields, numPoints, spaceDim);
          // Check GRAD of basis function: resize vals to rank-3 container
          hexBasis.getValues(vals, hexNodes, OPERATOR_GRAD);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);
          for (auto i = 0; i < numFields; ++i) {
            for (auto j = 0; j < numPoints; ++j) {
              for (auto k = 0; k < spaceDim; ++k) {

                // basisGrads is (F,P,D), compute offset:
                const auto l = k + j * spaceDim + i * spaceDim * numPoints;
                if (std::abs(vals_host(i,j,k) - basisGrads[l]) > tol) {
                  errorFlag++;
                  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                  // Output the multi-index of the value where the error is:
                  *outStream << " At multi-index { ";
                  *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
                  *outStream << "}  computed grad component: " << vals_host(i,j,k)
                             << " but reference grad component: " << basisGrads[l] << "\n";
                }
              }
            }
          }

          // Check D1 of basis function (do not resize vals because it has the correct size: D1 = GRAD)
          hexBasis.getValues(vals, hexNodes, OPERATOR_D1);
          Kokkos::deep_copy(vals_host, vals);
          for (auto i = 0; i < numFields; ++i) {
            for (auto j = 0; j < numPoints; ++j) {
              for (auto k = 0; k < spaceDim; ++k) {

                // basisGrads is (F,P,D), compute offset:
                const auto l = k + j * spaceDim + i * spaceDim * numPoints;
                if (std::abs(vals_host(i,j,k) - basisGrads[l]) > tol) {
                  errorFlag++;
                  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                  // Output the multi-index of the value where the error is:
                  *outStream << " At multi-index { ";
                  *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
                  *outStream << "}  computed D1 component: " << vals_host(i,j,k)
                             << " but reference D1 component: " << basisGrads[l] << "\n";
                }
              }
            }
          }
        }

        {
          // Check D2 of basis function
          DynRankView ConstructWithLabel(vals, numFields, numPoints, D2Cardin);
          hexBasis.getValues(vals, hexNodes, OPERATOR_D2);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);
          for (auto i = 0; i < numFields; ++i) {
            for (auto j = 0; j < numPoints; ++j) {
              for (auto k = 0; k < D2Cardin; ++k) {

                // basisD2 is (F,P,Dk), compute offset:
                const auto l = k + j * D2Cardin + i * D2Cardin * numPoints;
                if (std::abs(vals_host(i,j,k) - basisD2[l]) > tol) {
                  errorFlag++;
                  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                  // Output the multi-index of the value where the error is:
                  *outStream << " At multi-index { ";
                  *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
                  *outStream << "}  computed D2 component: " << vals_host(i,j,k)
                             << " but reference D2 component: " << basisD2[l] << "\n";
                }
              }
            }
          }
        }

        {
          // Check D3 of basis function
          DynRankView ConstructWithLabel(vals, numFields, numPoints, D3Cardin);
          hexBasis.getValues(vals, hexNodes, OPERATOR_D3);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);
          for (auto i = 0; i < numFields; ++i) {
            for (auto j = 0; j < numPoints; ++j) {
              for (auto k = 0; k < D3Cardin; ++k) {

                // basisD3 is (F,P,Dk), compute offset:
                const auto l = k + j * D3Cardin + i * D3Cardin * numPoints;
                if (std::abs(vals_host(i,j,k) - basisD3[l]) > tol) {
                  errorFlag++;
                  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                  // Output the multi-index of the value where the error is:
                  *outStream << " At multi-index { ";
                  *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
                  *outStream << "}  computed D3 component: " << vals_host(i,j,k)
                             << " but reference D3 component: " << basisD3[l] << "\n";
                }
              }
            }
          }
        }

        {
          // Check D4 of basis function
          DynRankView ConstructWithLabel(vals, numFields, numPoints, D4Cardin);
          hexBasis.getValues(vals, hexNodes, OPERATOR_D4);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);
          for (auto i = 0; i < numFields; i++) {
            for (auto j = 0; j < numPoints; j++) {
              for (auto k = 0; k < D4Cardin; k++) {

                // basisD4 is (F,P,Dk), compute offset:
                int l = k + j * D4Cardin + i * D4Cardin * numPoints;
                if (std::abs(vals_host(i,j,k) - basisD4[l]) > tol) {
                  errorFlag++;
                  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                  // Output the multi-index of the value where the error is:
                  *outStream << " At multi-index { ";
                  *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
                  *outStream << "}  computed D4 component: " << vals_host(i,j,k)
                             << " but reference D4 component: " << basisD2[l] << "\n"; //D2 same as D4?
                }
              }
            }
          }
        }

        {
          // Check D7 to D10 - must be zero. This basis does not support D5 and D6

          const EOperator ops[] = { OPERATOR_D7,
                                    OPERATOR_D8,
                                    OPERATOR_D9,
                                    OPERATOR_D10,
                                    OPERATOR_MAX };
          for (auto h=0;ops[h]!=OPERATOR_MAX;++h) {
            const auto op = ops[h];
            // The last dimension is the number of kth derivatives and needs to be resized for every Dk
            const auto DkCardin  = getDkCardinality(op, spaceDim);
            DynRankView ConstructWithLabel(vals, numFields, numPoints, DkCardin);
            hexBasis.getValues(vals, hexNodes, op);
            auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
            Kokkos::deep_copy(vals_host, vals);

            for (auto i1 = 0; i1 < numFields; ++i1)
              for (auto i2 = 0; i2 < numPoints; ++i2)
                for (auto i3 = 0; i3 < DkCardin; ++i3) {
                  if (std::abs(vals_host(i1,i2,i3)) > tol) {
                    errorFlag++;
                    *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                    // Get the multi-index of the value where the error is and the operator order
                    const auto ord = Intrepid2::getOperatorOrder(op);
                    *outStream << " At multi-index { "<<i1<<" "<<i2 <<" "<<i3;
                    *outStream << "}  computed D"<< ord <<" component: " << vals_host(i1,i2,i3)
                               << " but reference D" << ord << " component:  0 \n";
                  }
                }
          }
        }
      } catch (std::logic_error err) {
        *outStream << err.what() << "\n\n";
        errorFlag = -1000;
      };

      *outStream
        << "\n"
        << "===============================================================================\n"
        << "| TEST 4: correctness of DoF locations                                        |\n"
        << "===============================================================================\n";

      try{
        const auto numFields = hexBasis.getCardinality();
        const auto spaceDim  = hexBasis.getBaseCellTopology().getDimension();

        // Check exceptions.
        ordinal_type nthrow = 0, ncatch = 0;
#ifdef HAVE_INTREPID2_DEBUG
        {
          DynRankView ConstructWithLabel(badVals, 1, 2, 3);
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getDofCoords(badVals) );
        }
        {
          DynRankView ConstructWithLabel(badVals, 3, 2);
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getDofCoords(badVals) );
        }
        {
          DynRankView ConstructWithLabel(badVals, 27, 2);
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getDofCoords(badVals) );
        }
#endif
        // Check if number of thrown exceptions matches the one we expect
        if (nthrow != ncatch) {
          errorFlag++;
          *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
          *outStream << "# of catch ("<< ncatch << ") is different from # of throw (" << ncatch << ")\n";
        }

        DynRankView ConstructWithLabel(bvals, numFields, numFields);
        DynRankView ConstructWithLabel(cvals, numFields, spaceDim);

        // Check mathematical correctness.
        hexBasis.getDofCoords(cvals);
        hexBasis.getValues(bvals, cvals, OPERATOR_VALUE);
        auto cvals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), cvals);
        Kokkos::deep_copy(cvals_host, cvals);
        auto bvals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), bvals);
        Kokkos::deep_copy(bvals_host, bvals);
        char buffer[120];
        for (auto i=0; i<bvals.dimension(0); ++i) {
          for (auto j=0; j<bvals.dimension(1); ++j) {
            if ((i != j) && (std::abs(bvals_host(i,j) - 0.0) > tol)) {
              errorFlag++;
              sprintf(buffer, "\nValue of basis function %d at (%6.4e, %6.4e, %6.4e) is %6.4e but should be %6.4e!\n", i, cvals_host(i,0), cvals_host(i,1), cvals_host(i,2), bvals_host(i,j), 0.0);
              *outStream << buffer;
            }
            else if ((i == j) && (std::abs(bvals_host(i,j) - 1.0) > tol)) {
              errorFlag++;
              sprintf(buffer, "\nValue of basis function %d at (%6.4e, %6.4e, %6.4e) is %6.4e but should be %6.4e!\n", i, cvals_host(i,0), cvals_host(i,1), cvals_host(i,2), bvals_host(i,j), 1.0);
              *outStream << buffer;
            }
          }
        }

      } catch (std::logic_error err){
        *outStream << err.what() << "\n\n";
        errorFlag = -1000;
      };

      if (errorFlag != 0)
        std::cout << "End Result: TEST FAILED\n";
      else
        std::cout << "End Result: TEST PASSED\n";

      // reset format state of std::cout
      std::cout.copyfmt(oldFormatState);
      return errorFlag;
    }
Beispiel #5
0
    int HGRAD_PYR_C1_FEM_Test01(const bool verbose) {

      Teuchos::RCP<std::ostream> outStream;
      Teuchos::oblackholestream bhs; // outputs nothing

      if (verbose)
        outStream = Teuchos::rcp(&std::cout, false);
      else
        outStream = Teuchos::rcp(&bhs,       false);

      Teuchos::oblackholestream oldFormatState;
      oldFormatState.copyfmt(std::cout);

      typedef typename
        Kokkos::Impl::is_space<DeviceSpaceType>::host_mirror_space::execution_space HostSpaceType ;

      *outStream << "DeviceSpace::  "; DeviceSpaceType::print_configuration(*outStream, false);
      *outStream << "HostSpace::    ";   HostSpaceType::print_configuration(*outStream, false);

      *outStream
        << "===============================================================================\n"
        << "|                                                                             |\n"
        << "|                 Unit Test (Basis_HGRAD_PYR_C1_FEM)                          |\n"
        << "|                                                                             |\n"
        << "|     1) Conversion of Dof tags into Dof ordinals and back                    |\n"
        << "|     2) Basis values for VALUE, GRAD, CURL, and Dk operators                 |\n"
        << "|                                                                             |\n"
        << "|  Questions? Contact  Pavel Bochev  ([email protected]),                    |\n"
        << "|                      Denis Ridzal  ([email protected]),                    |\n"
        << "|                      Kara Peterson ([email protected]).                    |\n"
        << "|                      Kyungjoo Kim  ([email protected]).                     |\n"
        << "|                                                                             |\n"
        << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n"
        << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n"
        << "|                                                                             |\n"
        << "===============================================================================\n";

      typedef Kokkos::DynRankView<ValueType,DeviceSpaceType> DynRankView;
      typedef Kokkos::DynRankView<ValueType,HostSpaceType>   DynRankViewHost;
#define ConstructWithLabel(obj, ...) obj(#obj, __VA_ARGS__)

      const ValueType tol = tolerence();
      int errorFlag = 0;

      // for virtual function, value and point types are declared in the class
      typedef ValueType outputValueType;
      typedef ValueType pointValueType;
      Basis_HGRAD_PYR_C1_FEM<DeviceSpaceType,outputValueType,pointValueType> pyrBasis;

     *outStream
       << "\n"
       << "===============================================================================\n"
       << "| TEST 1: constructors and exceptions                                         |\n"
       << "===============================================================================\n";

     try {
       ordinal_type nthrow = 0, ncatch = 0;
#ifdef HAVE_INTREPID2_DEBUG
       // Define array containing the 4 vertices of the reference PYR and its center.
       DynRankView ConstructWithLabel(pyrNodes, 10, 3);

       // Generic array for the output values; needs to be properly resized depending on the operator type
       const auto numFields = pyrBasis.getCardinality();
       const auto numPoints = pyrNodes.dimension(0);
       const auto spaceDim  = pyrBasis.getBaseCellTopology().getDimension();

       DynRankView vals("vals", numFields, numPoints);
       DynRankView vals_vec("vals", numFields, numPoints, spaceDim);

       {
         // exception #1: CURL cannot be applied to scalar functions
         INTREPID2_TEST_ERROR_EXPECTED( pyrBasis.getValues(vals_vec, pyrNodes, OPERATOR_CURL) );
         // exception #2: DIV cannot be applied to scalar functions
         INTREPID2_TEST_ERROR_EXPECTED( pyrBasis.getValues(vals_vec, pyrNodes, OPERATOR_DIV) );
       }

       // Exceptions 3-7: all bf tags/bf Ids below are wrong and should cause getDofOrdinal() and
       // getDofTag() to access invalid array elements thereby causing bounds check exception
       {
         // exception #3
         INTREPID2_TEST_ERROR_EXPECTED( pyrBasis.getDofOrdinal(3,0,0) );
         // exception #4
         INTREPID2_TEST_ERROR_EXPECTED( pyrBasis.getDofOrdinal(1,1,1) );
         // exception #5
         INTREPID2_TEST_ERROR_EXPECTED( pyrBasis.getDofOrdinal(0,6,0) );
         // exception #6
         INTREPID2_TEST_ERROR_EXPECTED( pyrBasis.getDofTag(7) );
         // exception #7
         INTREPID2_TEST_ERROR_EXPECTED( pyrBasis.getDofTag(-1) );
       }

       // Exceptions 8-18 test exception handling with incorrectly dimensioned input/output arrays
       {
         // exception #8: input points array must be of rank-2
         DynRankView ConstructWithLabel(badPoints1, 4, 5, 3);
         INTREPID2_TEST_ERROR_EXPECTED( pyrBasis.getValues(vals, badPoints1, OPERATOR_VALUE) );
       }
       {
         // exception #9 dimension 1 in the input point array must equal space dimension of the cell
         DynRankView ConstructWithLabel(badPoints2, 4, 2);
         INTREPID2_TEST_ERROR_EXPECTED( pyrBasis.getValues(vals, badPoints2, OPERATOR_VALUE) );
       }
       {
         // exception #10 output values must be of rank-2 for OPERATOR_VALUE
         DynRankView ConstructWithLabel(badVals1, 4, 3, 1);
         INTREPID2_TEST_ERROR_EXPECTED( pyrBasis.getValues(badVals1, pyrNodes, OPERATOR_VALUE) );
       }
       {
         // exception #11 output values must be of rank-3 for OPERATOR_GRAD
         DynRankView ConstructWithLabel(badVals2, 4, 3);
         INTREPID2_TEST_ERROR_EXPECTED( pyrBasis.getValues(badVals2, pyrNodes, OPERATOR_GRAD) );

         // exception #12 output values must be of rank-3 for OPERATOR_D1
         INTREPID2_TEST_ERROR_EXPECTED( pyrBasis.getValues(badVals2, pyrNodes, OPERATOR_D1) );

         // exception #13 output values must be of rank-3 for OPERATOR_D2
         INTREPID2_TEST_ERROR_EXPECTED( pyrBasis.getValues(badVals2, pyrNodes, OPERATOR_D2) );
       }
       {
         // exception #14 incorrect 0th dimension of output array (must equal number of basis functions)
         DynRankView ConstructWithLabel(badVals3, numFields + 1, numPoints);
         INTREPID2_TEST_ERROR_EXPECTED( pyrBasis.getValues(badVals3, pyrNodes, OPERATOR_VALUE) );
       }
       {
         // exception #15 incorrect 1st dimension of output array (must equal number of points)
         DynRankView ConstructWithLabel(badVals4, numFields, numPoints + 1);
         INTREPID2_TEST_ERROR_EXPECTED( pyrBasis.getValues(badVals4, pyrNodes, OPERATOR_VALUE) );
       }
       {
         // exception #16: incorrect 2nd dimension of output array (must equal the space dimension)
         DynRankView ConstructWithLabel(badVals5, numFields, numPoints, 4);
         INTREPID2_TEST_ERROR_EXPECTED( pyrBasis.getValues(badVals5, pyrNodes, OPERATOR_GRAD) );
       }
       {
         // exception #17: incorrect 2nd dimension of output array (must equal D2 cardinality in 3D)
         DynRankView ConstructWithLabel(badVals6, numFields, numPoints, 40);
         INTREPID2_TEST_ERROR_EXPECTED( pyrBasis.getValues(badVals6, pyrNodes, OPERATOR_D2) );
         //exception #18: incorrect 2nd dimension of output array (must equal D3 cardinality in 3D)
         INTREPID2_TEST_ERROR_EXPECTED( pyrBasis.getValues(badVals6, pyrNodes, OPERATOR_D3) );
       }
#endif
       if (nthrow != ncatch) {
         errorFlag++;
         *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
         *outStream << "# of catch ("<< ncatch << ") is different from # of throw (" << nthrow << ")\n";
       }
     } catch (std::logic_error err) {
       *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
       *outStream << err.what() << '\n';
       *outStream << "-------------------------------------------------------------------------------" << "\n\n";
       errorFlag = -1000;
     }

     *outStream                                 \
       << "\n"
       << "===============================================================================\n" \
       << "| TEST 2: correctness of tag to enum and enum to tag lookups                  |\n" \
       << "===============================================================================\n";

     try {
       const auto numFields = pyrBasis.getCardinality();
       const auto allTags = pyrBasis.getAllDofTags();

       // Loop over all tags, lookup the associated dof enumeration and then lookup the tag again
       const auto dofTagSize = allTags.dimension(0);
       for (auto i=0;i<dofTagSize;++i) {
         const auto bfOrd = pyrBasis.getDofOrdinal(allTags(i,0), allTags(i,1), allTags(i,2));

         const auto myTag = pyrBasis.getDofTag(bfOrd);
         if( !( (myTag(0) == allTags(i,0)) &&
                (myTag(1) == allTags(i,1)) &&
                (myTag(2) == allTags(i,2)) &&
                (myTag(3) == allTags(i,3)) ) ) {
           errorFlag++;
           *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
           *outStream << " getDofOrdinal( {"
                      << allTags(i,0) << ", "
                      << allTags(i,1) << ", "
                      << allTags(i,2) << ", "
                      << allTags(i,3) << "}) = " << bfOrd <<" but \n";
           *outStream << " getDofTag(" << bfOrd << ") = { "
                      << myTag(0) << ", "
                      << myTag(1) << ", "
                      << myTag(2) << ", "
                      << myTag(3) << "}\n";
         }
       }
       // Now do the same but loop over basis functions
       for (auto bfOrd=0;bfOrd<numFields;++bfOrd) {
         const auto myTag = pyrBasis.getDofTag(bfOrd);

         const auto myBfOrd = pyrBasis.getDofOrdinal(myTag(0), myTag(1), myTag(2));
         if( bfOrd != myBfOrd) {
           errorFlag++;
           *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
           *outStream << " getDofTag(" << bfOrd << ") = { "
                      << myTag(0) << ", "
                      << myTag(1) << ", "
                      << myTag(2) << ", "
                      << myTag(3) << "} but getDofOrdinal({"
                      << myTag(0) << ", "
                      << myTag(1) << ", "
                      << myTag(2) << ", "
                      << myTag(3) << "} ) = " << myBfOrd << "\n";
         }
       }
     } catch (std::logic_error err) {
       *outStream << err.what() << "\n\n";
       errorFlag = -1000;
     }

     *outStream                                 \
       << "\n"
       << "===============================================================================\n" \
       << "| TEST 3: correctness of basis function values                                |\n" \
       << "===============================================================================\n";

     outStream -> precision(20);

     // VALUE: Each row gives the 4 correct basis set values at an evaluation point
     const ValueType basisValues[] = {
       1.0, 0.0, 0.0, 0.0, 0.0,
       0.0, 1.0, 0.0, 0.0, 0.0,
       0.0, 0.0, 1.0, 0.0, 0.0,
       0.0, 0.0, 0.0, 1.0, 0.0,
       0.0, 0.0, 0.0, 0.0, 1.0,
       //
       0.0515625,   0.0984375,  0.4265625,  0.2234375,  0.2,
       0.2,         0,          0.,         0.5,        0.3,
       0.025,       0.025,      0.,         0,          0.95,
       0.18,        0.045,      0.005,      0.02,       0.75,
       0.035,       0.015,      0.285,      0.665,      0.,
     };

     // GRAD and D1: each row gives the 3 x 5 correct values of the gradients of the 5 basis functions
     const ValueType basisGrads[] = {
       -0.5, -0.5,  0.0,  0.5,  0.0, -0.5,  0.0,  0.0,  0.0,  0.0,  0.5, -0.5,  0.0,  0.0,  1.0, \
       -0.5,  0.0, -0.5,  0.5, -0.5,  0.0,  0.0,  0.5, -0.5,  0.0,  0.0,  0.0,  0.0,  0.0,  1.0, \
       0.0,  0.0,  0.0,  0.0, -0.5, -0.5,  0.5,  0.5,  0.0, -0.5,  0.0, -0.5,  0.0,  0.0,  1.0, \
       0.0, -0.5, -0.5,  0.0,  0.0,  0.0,  0.5,  0.0, -0.5, -0.5,  0.5,  0.0,  0.0,  0.0,  1.0, \
       -0.25,-0.25,-0.25, 0.25,-0.25,-0.25, 0.25, 0.25,-0.25,-0.25, 0.25,-0.25, 0.0,  0.0,  1.0, \
       -0.09375, -0.171875, -0.201171875,  0.09375, -0.328125, -0.298828125, 0.40625,  0.328125, -0.201171875, -0.40625,  0.171875, -0.298828125,  0.0,  0.0,  1.0, \
       -0.1428571428571429, -0.5, -0.3571428571428571,  0.1428571428571429,  0.0, -0.1428571428571429,  0.3571428571428571, 0.0, -0.3571428571428571, -0.3571428571428571,  0.5, -0.1428571428571429,  0.0,  0.0,  1.0, \
       -0.5, -0.25, -0.25,  0.5, -0.25, -0.25,  0.0,  0.25, -0.25,  0.,  0.25, -0.25, 0.0,  0.0,  1.0, \
       -0.45, -0.4, -0.13,  0.45, -0.1, -0.37,  0.05,  0.1, -0.13, -0.05,  0.4, -0.37,  0.0,  0.0,  1.0, \
       -0.025, -0.35, -0.34,  0.025, -0.15, -0.16,  0.475,  0.15, -0.34, -0.475,  0.35, -0.16,  0.0,  0.0,  1.0
     };


     //D2: flat array with the values of D2 applied to basis functions. Multi-index is (P,F,K)
     const auto eps = epsilon();
     const ValueType basisD2[] = {
       0, 0.25,-0.25, 0,-0.25, 0.5, 0,-0.25, 0.25, 0, 0.25,-0.5, 0, 0.25,-0.25, 0,-0.25, 0.5, 0,-0.25, 0.25, 0, 0.25,-0.5, 0, 0, 0, 0, 0, 0, \
       0, 0.25,-0.25, 0, 0.25,-0.5, 0,-0.25, 0.25, 0,-0.25, 0.5, 0, 0.25,-0.25, 0, 0.25,-0.5, 0,-0.25, 0.25, 0,-0.25, 0.5, 0, 0, 0, 0, 0, 0, \
       0, 0.25, 0.25, 0, 0.25, 0.5, 0,-0.25,-0.25, 0,-0.25,-0.5, 0, 0.25, 0.25, 0, 0.25, 0.5, 0,-0.25,-0.25, 0,-0.25,-0.5, 0, 0, 0, 0, 0, 0, \
       0, 0.25, 0.25, 0,-0.25,-0.5, 0,-0.25,-0.25, 0, 0.25, 0.5, 0, 0.25, 0.25, 0,-0.25,-0.5, 0,-0.25,-0.25, 0, 0.25, 0.5, 0, 0, 0, 0, 0, 0, \
       0, 0.25/eps, 0, 0, 0, 0, 0,-0.25/eps, 0, 0, 0, 0, 0, 0.25/eps, 0, 0, 0, 0, 0,-0.25/eps, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, \
       0, 0.3125, 0.1953125, 0, 0.09765625, 0.1220703125, 0,-0.3125,-0.1953125, 0,-0.09765625,-0.1220703125, 0, 0.3125, 0.1953125, 0, 0.09765625, 0.1220703125, 0,-0.3125,-0.1953125, 0,-0.09765625,-0.1220703125, 0, 0, 0, 0, 0, 0, \
       0, 0.3571428571428571, 0.1530612244897959, 0,-0.3571428571428571,-0.306122448979592, 0,-0.3571428571428572,-0.1530612244897959, 0, 0.3571428571428571, 0.306122448979592, 0, 0.3571428571428571, 0.1530612244897959, 0,-0.3571428571428571,-0.306122448979592, 0,-0.3571428571428571,-0.1530612244897959, 0, 0.3571428571428571, 0.306122448979592, 0, 0, 0, 0, 0, 0, \
       0, 5,-5, 0, 0, 0, 0,-5, 5, 0, 0, 0, 0, 5,-5, 0, 0, 0, 0, -5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
       0, 1,-0.8, 0,-0.6, 0.96, 0, -1, 0.8, 0, 0.6,-0.96, 0,1,-0.8, 0, -0.6, 0.96, 0, -1, 0.8, 0, 0.6, -0.96, 0, 0, 0, 0, 0, 0, \
       0, 0.25, 0.225, 0,-0.1,-0.18, 0,-0.25,-0.225, 0, 0.1, 0.18, 0, 0.25, 0.225, 0,-0.1,-0.18, 0,-0.25,-0.225,0,0.1,0.18, 0, 0, 0, 0, 0, 0
     };

     try {
       DynRankViewHost ConstructWithLabel(pyrNodesHost, 10, 3);

       pyrNodesHost(0,0) = -1.0;  pyrNodesHost(0,1) = -1.0;  pyrNodesHost(0,2) =  0;
       pyrNodesHost(1,0) =  1.0;  pyrNodesHost(1,1) = -1.0;  pyrNodesHost(1,2) =  0;
       pyrNodesHost(2,0) =  1.0;  pyrNodesHost(2,1) =  1.0;  pyrNodesHost(2,2) =  0;
       pyrNodesHost(3,0) = -1.0;  pyrNodesHost(3,1) =  1.0;  pyrNodesHost(3,2) =  0;
       pyrNodesHost(4,0) =  0.0;  pyrNodesHost(4,1) =  0.0;  pyrNodesHost(4,2) =  1.0;

       pyrNodesHost(5,0) =  0.25; pyrNodesHost(5,1) =  0.5;  pyrNodesHost(5,2) = 0.2;
       pyrNodesHost(6,0) = -0.7 ; pyrNodesHost(6,1) =  0.3;  pyrNodesHost(6,2) = 0.3;
       pyrNodesHost(7,0) =  0.;   pyrNodesHost(7,1) = -0.05; pyrNodesHost(7,2) = 0.95;
       pyrNodesHost(8,0) = -0.15; pyrNodesHost(8,1) = -0.2;  pyrNodesHost(8,2) = 0.75;
       pyrNodesHost(9,0) = -0.4;  pyrNodesHost(9,1) =  0.9;  pyrNodesHost(9,2) = 0.0;

       auto pyrNodes = Kokkos::create_mirror_view(typename DeviceSpaceType::memory_space(), pyrNodesHost);
       Kokkos::deep_copy(pyrNodes, pyrNodesHost);

       // Dimensions for the output arrays:
       const auto numFields = pyrBasis.getCardinality();
       const auto numPoints = pyrNodes.dimension(0);
       const auto spaceDim  = pyrBasis.getBaseCellTopology().getDimension();
       const auto D2Cardin  = getDkCardinality(OPERATOR_D2, spaceDim);

       // Check VALUE of basis functions: resize vals to rank-2 container:
       {
         DynRankView vals = DynRankView("vals", numFields, numPoints);
         pyrBasis.getValues(vals, pyrNodes, OPERATOR_VALUE);
         auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
         Kokkos::deep_copy(vals_host, vals);
         for (auto i=0;i<numFields;++i) {
           for (auto j=0;j<numPoints;++j) {
             const auto l =  i + j * numFields;
             if (std::abs(vals_host(i,j) - basisValues[l]) > tol) {
               errorFlag++;
               *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

               // Output the multi-index of the value where the error is:
               *outStream << " At multi-index { ";
               *outStream << i << " ";*outStream << j << " ";
               *outStream << "}  computed value: " << vals_host(i,j)
                          << " but reference value: " << basisValues[l] << "\n";
             }
           }
         }
       }

       // Check GRAD of basis function: resize vals to rank-3 container
       {
         DynRankView vals = DynRankView("vals", numFields, numPoints, spaceDim);
         pyrBasis.getValues(vals, pyrNodes, OPERATOR_GRAD);
         auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
         Kokkos::deep_copy(vals_host, vals);
         for (auto i=0;i<numFields;++i) {
           for (auto j=0;j<numPoints;++j) {
             for (auto k=0;k<spaceDim;++k) {
               const auto l = k + i * spaceDim + j * spaceDim * numFields;
               if (std::abs(vals_host(i,j,k) - basisGrads[l]) > tol) {
                 errorFlag++;
                 *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                 // Output the multi-index of the value where the error is:
                 *outStream << " At multi-index { ";
                 *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
                 *outStream << "}  computed grad component: " << vals_host(i,j,k)
                            << " but reference grad component: " << basisGrads[l] << "\n";
               }
             }
           }
         }
       }

       // Check D1 of basis function
       {
         DynRankView vals = DynRankView("vals", numFields, numPoints, spaceDim);
         pyrBasis.getValues(vals, pyrNodes, OPERATOR_D1);
         auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
         Kokkos::deep_copy(vals_host, vals);
         for (auto i=0;i<numFields;++i) {
           for (auto j=0;j<numPoints;++j) {
             for (auto k=0;k<spaceDim;++k) {
               const auto l = k + i * spaceDim + j * spaceDim * numFields;
               if (std::abs(vals_host(i,j,k) - basisGrads[l]) > tol) {
                 errorFlag++;
                 *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                 // Output the multi-index of the value where the error is:
                 *outStream << " At multi-index { ";
                 *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
                 *outStream << "}  computed D1 component: " << vals_host(i,j,k)
                            << " but reference D1 component: " << basisGrads[l] << "\n";
               }
             }
           }
         }
       }

       // Check D2 of basis function
       {
         DynRankView vals = DynRankView("vals", numFields, numPoints, D2Cardin);
         pyrBasis.getValues(vals, pyrNodes, OPERATOR_D2);
         auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
         Kokkos::deep_copy(vals_host, vals);
         for (auto i=0;i<numFields;++i) {
           for (auto j=0;j<numPoints;++j) {
             // derivatives are singular when z = 1; using the same eps, it can be comparable
             //if (j == 4) continue; 
             for (auto k=0;k<D2Cardin;++k) {
               const auto l = k + i * D2Cardin + j * D2Cardin * numFields;
               if (std::abs(vals_host(i,j,k) - basisD2[l]) > tol) {
                 errorFlag++;
                 *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                 // Output the multi-index of the value where the error is:
                 *outStream << " At multi-index { ";
                 *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
                 *outStream << "}  computed D2 component: " << vals_host(i,j,k)
                            << " but reference D2 component: " << basisD2[l] << "\n";
               }
             }
           }
         }
       }

       // Check all higher derivatives - must be zero.
       {
         const EOperator ops[] = { OPERATOR_D3,
                                   OPERATOR_D4,
                                   OPERATOR_D5,
                                   OPERATOR_D6,
                                   OPERATOR_D7,
                                   OPERATOR_D8,
                                   OPERATOR_D9,
                                   OPERATOR_D10,
                                   OPERATOR_MAX };
         for (auto h=0;ops[h]!=OPERATOR_MAX;++h) {
           const auto op = ops[h];
           const auto DkCardin  = getDkCardinality(op, spaceDim);
           DynRankView vals("vals", numFields, numPoints, DkCardin);

           pyrBasis.getValues(vals, pyrNodes, op);
           auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
           Kokkos::deep_copy(vals_host, vals);
           for (auto i1=0;i1<numFields; i1++)
             for (auto i2=0;i2<numPoints; i2++)
               for (auto i3=0;i3<DkCardin; i3++) {
                 if (std::abs(vals_host(i1,i2,i3)) > tol) {
                   errorFlag++;
                   *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                   // Get the multi-index of the value where the error is and the operator order
                   const auto ord = Intrepid2::getOperatorOrder(op);
                   *outStream << " At multi-index { "<<i1<<" "<<i2 <<" "<<i3;
                   *outStream << "}  computed D"<< ord <<" component: " << vals(i1,i2,i3)
                              << " but reference D" << ord << " component:  0 \n";
                 }
               }
         }
       }
     } catch (std::logic_error err) {
       *outStream << err.what() << "\n\n";
       errorFlag = -1000;
     }

     if (errorFlag != 0)
       std::cout << "End Result: TEST FAILED\n";
     else
       std::cout << "End Result: TEST PASSED\n";

     // reset format state of std::cout
     std::cout.copyfmt(oldFormatState);

     return errorFlag;
    }
Beispiel #6
0
    int FunctionSpaceTools_Test03(const bool verbose) {

      Teuchos::RCP<std::ostream> outStream;
      Teuchos::oblackholestream bhs; // outputs nothing

      if (verbose)
        outStream = Teuchos::rcp(&std::cout, false);
      else
        outStream = Teuchos::rcp(&bhs, false);

      Teuchos::oblackholestream oldFormatState;
      oldFormatState.copyfmt(std::cout);

      typedef typename
        Kokkos::Impl::is_space<DeviceSpaceType>::host_mirror_space::execution_space HostSpaceType ;

      *outStream << "DeviceSpace::  "; DeviceSpaceType::print_configuration(*outStream, false);
      *outStream << "HostSpace::    ";   HostSpaceType::print_configuration(*outStream, false);
      
      *outStream
        << "===============================================================================\n"
        << "|                                                                             |\n"
        << "|                      Unit Test (FunctionSpaceTools)                         |\n"
        << "|                                                                             |\n"
        << "|     1) Basic operator transformations and integration in HDIV:              |\n"
        << "|                                                                             |\n"
        << "|  Questions? Contact  Pavel Bochev ([email protected]) or                   |\n"
        << "|                      Denis Ridzal ([email protected]) or                   |\n"
        << "|                      Kyungjoo Kim ([email protected]).                      |\n"
        << "|                                                                             |\n"
        << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n"
        << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n"
        << "|                                                                             |\n"
        << "===============================================================================\n";

      typedef CellTools<DeviceSpaceType> ct;      
      typedef FunctionSpaceTools<DeviceSpaceType> fst;      
      typedef Kokkos::DynRankView<ValueType,DeviceSpaceType> DynRankView;

      int errorFlag = 0;

      *outStream
        << "\n"
        << "===============================================================================\n"
        << "| TEST 1: correctness of math operations                                      |\n"
        << "===============================================================================\n";
      
      outStream->precision(20);
      
      try {
        DefaultCubatureFactory cub_factory;                            

        shards::CellTopology cell_topo = shards::getCellTopologyData< shards::Hexahedron<8> >();    

        const auto cub_degree = 20;                                                               
        auto cub = cub_factory.create<DeviceSpaceType,ValueType,ValueType>(cell_topo, cub_degree); 

        const auto space_dim = cub->getDimension();                                              
        const auto num_cub_points = cub->getNumPoints();                                          

        Basis_HDIV_HEX_I1_FEM<DeviceSpaceType> basis;                        
        const auto num_fields = basis.getCardinality();                                       
        
        /* Cell geometries and orientations. */
        const auto num_cells = 4;
        const auto num_nodes = 8;
        
        const ValueType hexnodes[] = {
          // hex 0  -- affine
          -1.0, -1.0, -1.0,
          1.0, -1.0, -1.0,
          1.0, 1.0, -1.0,
          -1.0, 1.0, -1.0,
          -1.0, -1.0, 1.0,
          1.0, -1.0, 1.0,
          1.0, 1.0, 1.0,
          -1.0, 1.0, 1.0,
          // hex 1  -- affine
          -3.0, -3.0, 1.0,
          6.0, 3.0, 1.0,
          7.0, 8.0, 0.0,
          -2.0, 2.0, 0.0,
          -3.0, -3.0, 4.0,
          6.0, 3.0, 4.0,
          7.0, 8.0, 3.0,
          -2.0, 2.0, 3.0,
          // hex 2  -- affine
          -3.0, -3.0, 0.0,
          9.0, 3.0, 0.0,
          15.0, 6.1, 0.0,
          3.0, 0.1, 0.0,
          9.0, 3.0, 0.1,
          21.0, 9.0, 0.1,
          27.0, 12.1, 0.1,
          15.0, 6.1, 0.1,
          // hex 3  -- nonaffine
          -2.0, -2.0, 0.0,
          2.0, -1.0, 0.0,
          1.0, 6.0, 0.0,
          -1.0, 1.0, 0.0,
          0.0, 0.0, 1.0,
          1.0, 0.0, 1.0,
          1.0, 1.0, 1.0,
          0.0, 1.0, 1.0
        };
        
        const ValueType facesigns[] = {
          1, 1, 1, 1, 1, 1,
          1, -1, 1, -1, 1, -1,
          -1, -1, 1, 1, -1, 1,
          -1, -1, 1, 1, -1, -1
        };
        
        /* Computational arrays. */
        DynRankView ConstructWithLabel( cub_points,  num_cub_points, space_dim);
        DynRankView ConstructWithLabel( cub_weights, num_cub_points);

        DynRankView ConstructWithLabel( cell_nodes,       num_cells, num_nodes, space_dim);
        DynRankView ConstructWithLabel( field_signs,      num_cells, num_fields);

        DynRankView ConstructWithLabel( jacobian,         num_cells, num_cub_points, space_dim, space_dim);
        DynRankView ConstructWithLabel( jacobian_det,     num_cells, num_cub_points);
        DynRankView ConstructWithLabel( weighted_measure, num_cells, num_cub_points);
        
        DynRankView ConstructWithLabel( div_of_basis_at_cub_points,                                 num_fields, num_cub_points);
        DynRankView ConstructWithLabel( transformed_div_of_basis_at_cub_points,          num_cells, num_fields, num_cub_points);
        DynRankView ConstructWithLabel( weighted_transformed_div_of_basis_at_cub_points, num_cells, num_fields, num_cub_points);
        DynRankView ConstructWithLabel( stiffness_matrices,                              num_cells, num_fields, num_fields);
        
        DynRankView ConstructWithLabel( value_of_basis_at_cub_points,                                 num_fields, num_cub_points, space_dim);
        DynRankView ConstructWithLabel( transformed_value_of_basis_at_cub_points,          num_cells, num_fields, num_cub_points, space_dim);
        DynRankView ConstructWithLabel( weighted_transformed_value_of_basis_at_cub_points, num_cells, num_fields, num_cub_points, space_dim);
        DynRankView ConstructWithLabel( mass_matrices,                                     num_cells, num_fields, num_fields);

        /******************* START COMPUTATION ***********************/

        // get cubature points and weights
        cub->getCubature(cub_points, cub_weights);

        const Kokkos::DynRankView<const ValueType,Kokkos::LayoutRight,Kokkos::HostSpace> cell_nodes_host (&hexnodes[0],  num_cells, num_nodes, space_dim); 
        const Kokkos::DynRankView<const ValueType,Kokkos::LayoutRight,Kokkos::HostSpace> field_signs_host(&facesigns[0], num_cells, num_fields); 
        
        Kokkos::deep_copy( cell_nodes,  cell_nodes_host  );
        Kokkos::deep_copy( field_signs, field_signs_host );
        
        // compute geometric cell information
        ct::setJacobian(jacobian, cub_points, cell_nodes, cell_topo);
        ct::setJacobianDet(jacobian_det, jacobian);

        // compute weighted measure
        fst::computeCellMeasure(weighted_measure, jacobian_det, cub_weights);

        // **Computing stiffness matrices:
        basis.getValues(div_of_basis_at_cub_points, cub_points, OPERATOR_DIV);
        
        // transform divergences of basis functions
        fst::HDIVtransformDIV(transformed_div_of_basis_at_cub_points,
                              jacobian_det,
                              div_of_basis_at_cub_points);
        
        // multiply with weighted measure
        fst::multiplyMeasure(weighted_transformed_div_of_basis_at_cub_points,
                             weighted_measure,
                             transformed_div_of_basis_at_cub_points);
        
        // we can apply the field signs to the basis function arrays, or after the fact, see below
        fst::applyFieldSigns(transformed_div_of_basis_at_cub_points, field_signs);
        fst::applyFieldSigns(weighted_transformed_div_of_basis_at_cub_points, field_signs);
        
        // compute stiffness matrices
        fst::integrate(stiffness_matrices,
                       transformed_div_of_basis_at_cub_points,
                       weighted_transformed_div_of_basis_at_cub_points);
        

        // **Computing mass matrices:
        basis.getValues(value_of_basis_at_cub_points, cub_points, OPERATOR_VALUE);

            
        
        // transform values of basis functions
        fst::HDIVtransformVALUE(transformed_value_of_basis_at_cub_points,
                                jacobian,
                                jacobian_det,
                                value_of_basis_at_cub_points);

        // multiply with weighted measure
        fst::multiplyMeasure(weighted_transformed_value_of_basis_at_cub_points,
                             weighted_measure,
                             transformed_value_of_basis_at_cub_points);
        
        // compute mass matrices
        fst::integrate(mass_matrices,
                       transformed_value_of_basis_at_cub_points,
                       weighted_transformed_value_of_basis_at_cub_points);
        
        // apply field signs
        fst::applyLeftFieldSigns(mass_matrices, field_signs);
        fst::applyRightFieldSigns(mass_matrices, field_signs);
        
        /*******************  STOP COMPUTATION ***********************/
        
        
        /******************* START COMPARISON ***********************/
        std::string basedir = "../testdata";
        for (auto cid=0;cid<num_cells-1;++cid) {
          std::stringstream namestream;
          std::string filename;
          namestream <<  basedir << "/mass_HDIV_HEX_I1_FEM" << "_" << "0" << cid+1 << ".dat";
          namestream >> filename;

          *outStream << "\nCell ID : " << cid << "  mass matrix comparing with " << filename << "\n\n";
          
          std::ifstream massfile(&filename[0]);
          if (massfile.is_open()) {
            const auto mass_matrix_cell = Kokkos::subdynrankview(mass_matrices, cid, Kokkos::ALL(), Kokkos::ALL());
            errorFlag += compareToAnalytic(massfile, 
                                           mass_matrix_cell, 
                                           1e-10,
                                           verbose);
            massfile.close();
          } else {
            errorFlag = -1;
            INTREPID2_TEST_FOR_EXCEPTION( true, std::runtime_error,
                                          "Failed to open a file" );
          }
          
          namestream.clear();
          namestream << basedir << "/stiff_HDIV_HEX_I1_FEM" << "_" << "0" << cid+1 << ".dat";
          namestream >> filename;

          *outStream << "\nCell ID : " << cid << "  stiffness matrix comparing with " << filename << "\n\n";
          
          std::ifstream stifffile(&filename[0]);
          if (stifffile.is_open()) {
            const auto stiffness_matrix_cell = Kokkos::subdynrankview(stiffness_matrices, cid, Kokkos::ALL(), Kokkos::ALL());
            errorFlag += compareToAnalytic(stifffile,
                                           stiffness_matrix_cell,
                                           1e-10,
                                           verbose);
            stifffile.close();
          } else {
            errorFlag = -1;
            INTREPID2_TEST_FOR_EXCEPTION( true, std::runtime_error,
                                          "Failed to open a file" );
          }
        }

        for (auto cid=3;cid<num_cells;++cid) {
          std::stringstream namestream;
          std::string filename;
          namestream <<  basedir << "/mass_fp_HDIV_HEX_I1_FEM" << "_" << "0" << cid+1 << ".dat";
          namestream >> filename;

          *outStream << "\nCell ID : " << cid << "  mass matrix comparing with " << filename << "\n\n";
          
          std::ifstream massfile(&filename[0]);
          if (massfile.is_open()) {
            const auto mass_matrix_cell = Kokkos::subdynrankview(mass_matrices, cid, Kokkos::ALL(), Kokkos::ALL());
            errorFlag += compareToAnalytic(massfile, 
                                           mass_matrix_cell, 
                                           1e-4, 
                                           verbose,
                                           INTREPID2_UTILS_SCALAR);
            massfile.close();
          } else {
            errorFlag = -1;
            INTREPID2_TEST_FOR_EXCEPTION( true, std::runtime_error,
                                          "Failed to open a file" );
          }
          
          namestream.clear();
          namestream << basedir << "/stiff_fp_HDIV_HEX_I1_FEM" << "_" << "0" << cid+1 << ".dat";
          namestream >> filename;
          
          *outStream << "\nCell ID : " << cid << "  stiffness matrix comparing with " << filename << "\n\n";

          std::ifstream stifffile(&filename[0]);
          if (stifffile.is_open()) {
            const auto stiffness_matrix_cell = Kokkos::subdynrankview(stiffness_matrices, cid, Kokkos::ALL(), Kokkos::ALL());
            errorFlag += compareToAnalytic(stifffile,
                                           stiffness_matrix_cell,
                                           1e-4, 
                                           verbose,
                                           INTREPID2_UTILS_SCALAR);
            stifffile.close();
          } else {
            errorFlag = -1;
            INTREPID2_TEST_FOR_EXCEPTION( true, std::runtime_error,
                                          "Failed to open a file" );
          }
        }
        /******************* STOP COMPARISON ***********************/

        *outStream << "\n";
      } catch (std::logic_error err) {
        *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
        *outStream << err.what() << '\n';
        *outStream << "-------------------------------------------------------------------------------" << "\n\n";
        errorFlag = -1000;
      }

      if (errorFlag != 0)
        std::cout << "End Result: TEST FAILED\n";
      else
        std::cout << "End Result: TEST PASSED\n";
      
      // reset format state of std::cout
      std::cout.copyfmt(oldFormatState);

      return errorFlag;
    }
Beispiel #7
0
    int PointTools_Test01(const bool verbose) {
      Teuchos::RCP<std::ostream> outStream;
      Teuchos::oblackholestream bhs; // outputs nothing

      if (verbose)
        outStream = Teuchos::rcp(&std::cout, false);
      else
        outStream = Teuchos::rcp(&bhs,       false);

      Teuchos::oblackholestream oldFormatState;
      oldFormatState.copyfmt(std::cout);

      typedef typename
        Kokkos::Impl::is_space<DeviceSpaceType>::host_mirror_space::execution_space HostSpaceType ;

      *outStream << "DeviceSpace::  "; DeviceSpaceType::print_configuration(*outStream, false);
      *outStream << "HostSpace::    ";   HostSpaceType::print_configuration(*outStream, false);

      *outStream
        << "===============================================================================\n"
        << "|                                                                             |\n"
        << "|                       Unit Test (PointTools)                                |\n"
        << "|                                                                             |\n"
        << "|     1) Construction of equispaced and warped lattices on simplices          |\n"
        << "|                                                                             |\n"
        << "|  Questions? Contact  Pavel Bochev ([email protected]) or                   |\n"
        << "|                      Denis Ridzal ([email protected]) or                   |\n"
        << "|                      Robert Kirby ([email protected]) or               |\n"
        << "|                      Kyungjoo Kim ([email protected])                       |\n"
        << "|                                                                             |\n"
        << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n"
        << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n"
        << "|                                                                             |\n"
        << "===============================================================================\n";
      typedef PointTools pts;
      typedef Kokkos::DynRankView<ValueType,DeviceSpaceType> DynRankView;
#define ConstructWithLabel(obj, ...) obj(#obj, __VA_ARGS__)
      
      int errorFlag = 0;     
      
      *outStream 
        << "\n"
        << "===============================================================================\n" 
        << "| TEST 1: size of lattices                                                    |\n" 
        << "===============================================================================\n";

      try {
        const shards::CellTopology line( shards::getCellTopologyData< shards::Line<2> >() );      
        const ordinal_type order[2] = { 4, 3 }, offset[2] = { 0, 1 }, val[2] = { 5, 2}; 
        for (auto i=0;i<2;++i) {
          const auto lsize = pts::getLatticeSize( line, order[i], offset[i] );
          if (lsize != val[i]) {
            errorFlag++;
            *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
            *outStream << "  lattice size of line (order,offset,exact): " 
                       << order[i] << ", " << offset[i] << ", " << val[i] << ":: computed val = " 
                       << lsize << "\n";
          }
        }

      } catch (std::exception &err) {
        *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
        *outStream << err.what() << '\n';
        *outStream << "-------------------------------------------------------------------------------" << "\n\n";
        errorFlag = -1000;
      };
      
      *outStream
        << "\n"
        << "===============================================================================\n" 
        << "| TEST 2: check for unsupported cell types                                     \n" 
        << "===============================================================================\n";
#ifdef HAVE_INTREPID2_DEBUG
      try {
        ordinal_type nthrow = 0, ncatch = 0;

        INTREPID2_TEST_ERROR_EXPECTED( pts::getLatticeSize(shards::getCellTopologyData<shards::Quadrilateral<4> >(), 3, 0) );
        INTREPID2_TEST_ERROR_EXPECTED( pts::getLatticeSize(shards::getCellTopologyData<shards::Hexahedron<8> >(), 3, 0 ) );

        if (nthrow != ncatch) {
          errorFlag++;
          *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
          *outStream << "# of catch ("<< ncatch << ") is different from # of throw (" << ncatch << ")\n";
        }
      } catch (std::exception &err) {
        *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
        *outStream << err.what() << '\n';
        *outStream << "-------------------------------------------------------------------------------" << "\n\n";
        errorFlag = -1000;
      };
#endif

      *outStream                                
        << "\n"
        << "===============================================================================\n" 
        << "| TEST 2: malformed point arrays                                               \n" 
        << "===============================================================================\n";
#ifdef HAVE_INTREPID2_DEBUG
      try {
        const shards::CellTopology line( shards::getCellTopologyData< shards::Line<2> >() );      
        ordinal_type nthrow = 0, ncatch = 0;
        {
          DynRankView ConstructWithLabel(points, 3, 1);
          INTREPID2_TEST_ERROR_EXPECTED( PointTools::getLattice( points, line , 5 , 0 ) );
        }
        {
          DynRankView ConstructWithLabel(points, 6, 2);
          INTREPID2_TEST_ERROR_EXPECTED( PointTools::getLattice( points, line , 5 , 0 ) );
        }
        if (nthrow != ncatch) {
          errorFlag++;
          *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
          *outStream << "# of catch ("<< ncatch << ") is different from # of throw (" << ncatch << ")\n";
        }
      } catch (std::exception &err) {
        *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
        *outStream << err.what() << '\n';
        *outStream << "-------------------------------------------------------------------------------" << "\n\n";
        errorFlag = -1000;
      };       
#endif
      
      if (errorFlag != 0)
        std::cout << "End Result: TEST FAILED\n";
      else
        std::cout << "End Result: TEST PASSED\n";
      
      return errorFlag;
    }
Beispiel #8
0
    int CellTools_Test02(const bool verbose) {
      typedef ValueType value_type;

      Teuchos::RCP<std::ostream> outStream;
      Teuchos::oblackholestream bhs; // outputs nothing

      if (verbose)
        outStream = Teuchos::rcp(&std::cout, false);
      else
        outStream = Teuchos::rcp(&bhs,       false);

      Teuchos::oblackholestream oldFormatState;
      oldFormatState.copyfmt(std::cout);

      typedef typename
        Kokkos::Impl::is_space<DeviceSpaceType>::host_mirror_space::execution_space HostSpaceType ;

      *outStream << "DeviceSpace::  "; DeviceSpaceType::print_configuration(*outStream, false);
      *outStream << "HostSpace::    ";   HostSpaceType::print_configuration(*outStream, false);
      
      *outStream
        << "===============================================================================\n"
        << "|                                                                             |\n"
        << "|                              Unit Test CellTools                            |\n"
        << "|                                                                             |\n"
        << "|     1) Edge parametrizations                                                |\n"
        << "|     2) Face parametrizations                                                |\n"
        << "|     3) Edge tangents                                                        |\n"
        << "|     4) Face tangents and normals                                            |\n"
        << "|                                                                             |\n"
        << "|  Questions? Contact  Pavel Bochev ([email protected])                      |\n"
        << "|                      Denis Ridzal ([email protected]), or                  |\n"
        << "|                      Kara Peterson([email protected]), or                  |\n"
        << "|                      Kyungjoo Kim ([email protected])                       |\n"
        << "|                                                                             |\n"
        << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n"
        << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n"
        << "|                                                                             |\n"
        << "===============================================================================\n";
  
      typedef CellTools<DeviceSpaceType> ct;
      typedef Kokkos::DynRankView<value_type,DeviceSpaceType> DynRankView;
#define ConstructWithLabel(obj, ...) obj(#obj, __VA_ARGS__)

      int errorFlag = 0;

      
      // Vertices of the parametrization domain for 1-subcells: standard 1-cube [-1,1]
      DynRankView ConstructWithLabel(cube_1, 2, 1);
      cube_1(0,0) = -1.0; 
      cube_1(1,0) = 1.0;
      
  
      // Vertices of the parametrization domain for triangular faces: the standard 2-simplex
      DynRankView ConstructWithLabel(simplex_2, 3, 2);
      simplex_2(0, 0) = 0.0;   simplex_2(0, 1) = 0.0;
      simplex_2(1, 0) = 1.0;   simplex_2(1, 1) = 0.0;
      simplex_2(2, 0) = 0.0;   simplex_2(2, 1) = 1.0;
      
      
      // Vertices of the parametrization domain for quadrilateral faces: the standard 2-cube
      DynRankView ConstructWithLabel(cube_2, 4, 2);
      cube_2(0, 0) =  -1.0;    cube_2(0, 1) =  -1.0;
      cube_2(1, 0) =   1.0;    cube_2(1, 1) =  -1.0;
      cube_2(2, 0) =   1.0;    cube_2(2, 1) =   1.0;
      cube_2(3, 0) =  -1.0;    cube_2(3, 1) =   1.0;
      
  
      try {
        // // Pull all available topologies from Shards
        // std::vector<shards::CellTopology> allTopologies;
        // shards::getTopologies(allTopologies);
        
        // const auto topoSize = allTopologies.size();

        // /***********************************************************************************************
        //  *
        //  * Common for test 3 and 4: edge tangents and face normals for standard cells with base topo
        //  *
        //  **********************************************************************************************/
        
        // // Allocate storage and extract all standard cells with base topologies
        // std::vector<shards::CellTopology> standardBaseTopologies;    
        // shards::getTopologies(standardBaseTopologies, 4, shards::STANDARD_CELL, shards::BASE_TOPOLOGY);
        
        // // Define topologies for the edge and face parametrization domains. (faces are Tri or Quad)
        // CellTopology paramEdge    (shards::getCellTopologyData<shards::Line<2> >() );
        // CellTopology paramTriFace (shards::getCellTopologyData<shards::Triangle<3> >() );
        // CellTopology paramQuadFace(shards::getCellTopologyData<shards::Quadrilateral<4> >() );
        
        // // Define CubatureFactory:
        // DefaultCubatureFactory<DeviceSpaceType>  cubFactory;   
        
        // *outStream 
        //   << "\n"
        //   << "===============================================================================\n" 
        //   << "| Test 4: face/side normals for stand. 3D cells with base topologies:         |\n" 
        //   << "===============================================================================\n\n";

        // // This test loops over standard 3D cells with base topologies, creates a set of nodes and tests normals 
        // {
        //   // Define cubature on the edge parametrization domain:
        //   const auto triFaceCubature  = cubFactory.create(paramTriFace, 6); 
        //   const auto quadFaceCubature = cubFactory.create(paramQuadFace, 6); 
          
        //   const auto faceCubDim           = triFaceCubature->getDimension();
        //   const auto numTriFaceCubPoints  = triFaceCubature->getNumPoints();
        //   const auto numQuadFaceCubPoints = quadFaceCubature->getNumPoints();    
          
        //   // Allocate storage for cubature points and weights on face parameter domain and fill with points:
        //   DynRankView ConstructWithLabel(paramTriFacePoints, numTriFaceCubPoints, faceCubDim);
        //   DynRankView ConstructWithLabel(paramTriFaceWeights, numTriFaceCubPoints);
        //   DynRankView ConstructWithLabel(paramQuadFacePoints, numQuadFaceCubPoints, faceCubDim);
        //   DynRankView ConstructWithLabel(paramQuadFaceWeights, numQuadFaceCubPoints);
          
        //   triFaceCubature->getCubature(paramTriFacePoints, paramTriFaceWeights);
        //   quadFaceCubature->getCubature(paramQuadFacePoints, paramQuadFaceWeights);
    
        //   // Loop over admissible topologies 
        //   for(cti = standardBaseTopologies.begin(); cti !=standardBaseTopologies.end(); ++cti){
            
        //     // Exclude 2D and Pyramid<5> cells
        //     if( ( (*cti).getDimension() == 3) && ( (*cti).getKey() != shards::Pyramid<5>::key) ){ 
              
        //       int cellDim = (*cti).getDimension();
        //       int vCount  = (*cti).getVertexCount();
        //       DynRankView ConstructWithLabel refCellVertices(vCount, cellDim);
        //       CellTools::getReferenceSubcellVertices(refCellVertices, cellDim, 0, (*cti) );
              
        //       *outStream << " Testing face/side normals for cell topology " <<  (*cti).getName() <<"\n";
              
        //       // Array for physical cell vertices ( must have rank 3 for setJacobians)
        //       DynRankView ConstructWithLabel physCellVertices(1, vCount, cellDim);
              
        //       // Randomize reference cell vertices by moving them up to +/- (1/8) units along their
        //       // coordinate axis. Guaranteed to be non-degenerate for standard cells with base topology 
        //       for(int v = 0; v < vCount; v++){
        //         for(int d = 0; d < cellDim; d++){
        //           double delta = Teuchos::ScalarTraits<double>::random()/8.0;
        //           physCellVertices(0, v, d) = refCellVertices(v, d) + delta;
        //         } //for d
        //       }// for v     
              
        //       // Allocate storage for cub. points on a ref. face; Jacobians, phys. face normals and 
        //       // benchmark normals.
        //       DynRankView ConstructWithLabel refTriFacePoints(numTriFaceCubPoints, cellDim);        
        //       DynRankView ConstructWithLabel refQuadFacePoints(numQuadFaceCubPoints, cellDim);        
        //       DynRankView ConstructWithLabel triFacePointsJacobians(1, numTriFaceCubPoints, cellDim, cellDim);
        //       DynRankView ConstructWithLabel quadFacePointsJacobians(1, numQuadFaceCubPoints, cellDim, cellDim);
        //       DynRankView ConstructWithLabel triFacePointNormals(1, numTriFaceCubPoints, cellDim);
        //       DynRankView ConstructWithLabel triSidePointNormals(1, numTriFaceCubPoints, cellDim);
        //       DynRankView ConstructWithLabel quadFacePointNormals(1, numQuadFaceCubPoints, cellDim);
        //       DynRankView ConstructWithLabel quadSidePointNormals(1, numQuadFaceCubPoints, cellDim);
              
              
        //       // Loop over faces:
        //       for(int faceOrd = 0; faceOrd < (int)(*cti).getSideCount(); faceOrd++){
                
        //         // This test presently includes only Triangle<3> and Quadrilateral<4> faces. Once we support
        //         // cells with extended topologies we will add their faces as well.
        //         switch( (*cti).getCellTopologyData(2, faceOrd) -> key ) {
                  
        //         case shards::Triangle<3>::key: 
        //           {
        //             // Compute face normals using CellTools
        //             CellTools::mapToReferenceSubcell(refTriFacePoints, paramTriFacePoints, 2, faceOrd, (*cti) );
        //             CellTools::setJacobian(triFacePointsJacobians, refTriFacePoints, physCellVertices, (*cti) );
        //             CellTools::getPhysicalFaceNormals(triFacePointNormals, triFacePointsJacobians, faceOrd, (*cti));               
        //             CellTools::getPhysicalSideNormals(triSidePointNormals, triFacePointsJacobians, faceOrd, (*cti));               
        //             /* 
        //              * Compute face normals using direct linear parametrization of the face: the map from
        //              * standard 2-simplex to physical Triangle<3> face in 3D is 
        //              * F(x,y) = V0 + (V1-V0)x + (V2-V0)*y 
        //              * Face normal is vector product Tx X Ty where Tx = (V1-V0); Ty = (V2-V0)
        //              */
        //             int v0ord = (*cti).getNodeMap(2, faceOrd, 0);
        //             int v1ord = (*cti).getNodeMap(2, faceOrd, 1);
        //             int v2ord = (*cti).getNodeMap(2, faceOrd, 2);
                    
        //             // Loop over face points: redundant for affine faces, but CellTools gives one vector 
        //             // per point so need to check all points anyways.
        //             for(int pt = 0; pt < numTriFaceCubPoints; pt++){
        //               DynRankView ConstructWithLabel tanX(3), tanY(3), faceNormal(3);
        //               for(int d = 0; d < cellDim; d++){
        //                 tanX(d) = (physCellVertices(0, v1ord, d) - physCellVertices(0, v0ord, d));
        //                 tanY(d) = (physCellVertices(0, v2ord, d) - physCellVertices(0, v0ord, d));
        //               }// for d
                      
        //               RealSpaceTools<double>::vecprod(faceNormal, tanX, tanY); 
                      
        //               // Compare direct normal with d-component of the face/side normal by CellTools
        //               for(int d = 0; d < cellDim; d++){
                        
        //                 // face normal method
        //                 if( abs(faceNormal(d) - triFacePointNormals(0, pt, d)) > INTREPID2_THRESHOLD ){
        //                   errorFlag++;
        //                   *outStream
        //                     << std::setw(70) << "^^^^----FAILURE!" << "\n"
        //                     << " Face normal computation by CellTools failed for: \n"
        //                     << "       Cell Topology = " << (*cti).getName() << "\n"
        //                     << "       Face Topology = " << (*cti).getCellTopologyData(2, faceOrd) -> name << "\n"
        //                     << "        Face ordinal = " << faceOrd << "\n"
        //                     << "   Face point number = " << pt << "\n"
        //                     << "   Normal coordinate = " << d  << "\n"
        //                     << "     CellTools value = " <<  triFacePointNormals(0, pt, d)
        //                     << "     Benchmark value = " <<  faceNormal(d) << "\n\n";
        //                 }
        //                 //side normal method
        //                 if( abs(faceNormal(d) - triSidePointNormals(0, pt, d)) > INTREPID2_THRESHOLD ){
        //                   errorFlag++;
        //                   *outStream
        //                     << std::setw(70) << "^^^^----FAILURE!" << "\n"
        //                     << " Side normal computation by CellTools failed for: \n"
        //                     << "       Cell Topology = " << (*cti).getName() << "\n"
        //                     << "       Side Topology = " << (*cti).getCellTopologyData(2, faceOrd) -> name << "\n"
        //                     << "        Side ordinal = " << faceOrd << "\n"
        //                     << "   Side point number = " << pt << "\n"
        //                     << "   Normal coordinate = " << d  << "\n"
        //                     << "     CellTools value = " <<  triSidePointNormals(0, pt, d)
        //                     << "     Benchmark value = " <<  faceNormal(d) << "\n\n";
        //                 }
        //               } // for d
        //             } // for pt
        //           }
        //           break;
                  
        //         case shards::Quadrilateral<4>::key:
        //           {
        //             // Compute face normals using CellTools
        //             CellTools::mapToReferenceSubcell(refQuadFacePoints, paramQuadFacePoints, 2, faceOrd, (*cti) );
        //             CellTools::setJacobian(quadFacePointsJacobians, refQuadFacePoints, physCellVertices, (*cti) );
        //             CellTools::getPhysicalFaceNormals(quadFacePointNormals, quadFacePointsJacobians, faceOrd, (*cti));               
        //             CellTools::getPhysicalSideNormals(quadSidePointNormals, quadFacePointsJacobians, faceOrd, (*cti)); 
        //             /*
        //              * Compute face normals using direct bilinear parametrization of the face: the map from
        //              * [-1,1]^2 to physical Quadrilateral<4> face in 3D is 
        //              * F(x,y) = ((V0+V1+V2+V3) + (-V0+V1+V2-V3)*X + (-V0-V1+V2+V3)*Y + (V0-V1+V2-V3)*X*Y)/4 
        //              * Face normal is vector product Tx X Ty where
        //              *          Tx = ((-V0+V1+V2-V3) + (V0-V1+V2-V3)*Y)/4
        //              *          Ty = ((-V0-V1+V2+V3) + (V0-V1+V2-V3)*X)/4
        //              */
        //             int v0ord = (*cti).getNodeMap(2, faceOrd, 0);
        //             int v1ord = (*cti).getNodeMap(2, faceOrd, 1);
        //             int v2ord = (*cti).getNodeMap(2, faceOrd, 2);
        //             int v3ord = (*cti).getNodeMap(2, faceOrd, 3);
                    
        //             // Loop over face points (redundant for affine faces, but needed for later when we handle non-affine ones)
        //             for(int pt = 0; pt < numTriFaceCubPoints; pt++){
        //               DynRankView ConstructWithLabel tanX(3), tanY(3), faceNormal(3);
        //               for(int d = 0; d < cellDim; d++){
        //                 tanX(d) = (physCellVertices(0, v0ord, d)*(-1.0 + paramQuadFacePoints(pt,1) )  +
        //                            physCellVertices(0, v1ord, d)*( 1.0 - paramQuadFacePoints(pt,1) ) + 
        //                            physCellVertices(0, v2ord, d)*( 1.0 + paramQuadFacePoints(pt,1) ) + 
        //                            physCellVertices(0, v3ord, d)*(-1.0 - paramQuadFacePoints(pt,1) ) )/4.0;
                        
        //                 tanY(d) = (physCellVertices(0, v0ord, d)*(-1.0 + paramQuadFacePoints(pt,0) ) +
        //                            physCellVertices(0, v1ord, d)*(-1.0 - paramQuadFacePoints(pt,0) ) + 
        //                            physCellVertices(0, v2ord, d)*( 1.0 + paramQuadFacePoints(pt,0) ) + 
        //                            physCellVertices(0, v3ord, d)*( 1.0 - paramQuadFacePoints(pt,0) ) )/4.0;
        //               }// for d
                      
        //               RealSpaceTools<double>::vecprod(faceNormal, tanX, tanY); 
        //               // Compare direct normal with d-component of the face/side normal by CellTools
        //               for(int d = 0; d < cellDim; d++){
                        
        //                 // face normal method
        //                 if( abs(faceNormal(d) - quadFacePointNormals(0, pt, d)) > INTREPID2_THRESHOLD ){
        //                   errorFlag++;
        //                   *outStream
        //                     << std::setw(70) << "^^^^----FAILURE!" << "\n"
        //                     << " Face normal computation by CellTools failed for: \n"
        //                     << "       Cell Topology = " << (*cti).getName() << "\n"
        //                     << "       Face Topology = " << (*cti).getCellTopologyData(2, faceOrd) -> name << "\n"
        //                     << "        Face ordinal = " << faceOrd << "\n"
        //                     << "   Face point number = " << pt << "\n"
        //                     << "   Normal coordinate = " << d  << "\n"
        //                     << "     CellTools value = " <<  quadFacePointNormals(0, pt, d)
        //                     << "     Benchmark value = " <<  faceNormal(d) << "\n\n";
        //                 }
        //                 //side normal method
        //                 if( abs(faceNormal(d) - quadSidePointNormals(0, pt, d)) > INTREPID2_THRESHOLD ){
        //                   errorFlag++;
        //                   *outStream
        //                     << std::setw(70) << "^^^^----FAILURE!" << "\n"
        //                     << " Side normal computation by CellTools failed for: \n"
        //                     << "       Cell Topology = " << (*cti).getName() << "\n"
        //                     << "       Side Topology = " << (*cti).getCellTopologyData(2, faceOrd) -> name << "\n"
        //                     << "        Side ordinal = " << faceOrd << "\n"
        //                     << "   Side point number = " << pt << "\n"
        //                     << "   Normal coordinate = " << d  << "\n"
        //                     << "     CellTools value = " <<  quadSidePointNormals(0, pt, d)
        //                     << "     Benchmark value = " <<  faceNormal(d) << "\n\n";
        //                 }
        //               } // for d
        //             }// for pt
        //           }// case Quad
        //           break;
        //         default:
        //           errorFlag++;
        //           *outStream << " Face normals test failure: face topology not supported \n\n";
        //         } // switch 
        //       }// for faceOrd
        //     }// if admissible
        //   }// for cti
      } catch (std::logic_error err) {
        //============================================================================================//
        // Wrap up test: check if the test broke down unexpectedly due to an exception                //
        //============================================================================================//
        *outStream << err.what() << "\n";
        errorFlag = -1000;
      }
      
      if (errorFlag != 0)
        std::cout << "End Result: TEST FAILED\n";
      else
        std::cout << "End Result: TEST PASSED\n";
      
      // reset format state of std::cout
      std::cout.copyfmt(oldFormatState);

      return errorFlag;
    }
Beispiel #9
0
    int HGRAD_TRI_C1_FEM_Test01(const bool verbose) {

      Teuchos::RCP<std::ostream> outStream;
      Teuchos::oblackholestream bhs; // outputs nothing

      if (verbose)
        outStream = Teuchos::rcp(&std::cout, false);
      else
        outStream = Teuchos::rcp(&bhs,       false);

      Teuchos::oblackholestream oldFormatState;
      oldFormatState.copyfmt(std::cout);

      typedef typename
        Kokkos::Impl::is_space<DeviceSpaceType>::host_mirror_space::execution_space HostSpaceType ;

      *outStream << "DeviceSpace::  "; DeviceSpaceType::print_configuration(*outStream, false);
      *outStream << "HostSpace::    ";   HostSpaceType::print_configuration(*outStream, false);

      *outStream
        << "===============================================================================\n"
        << "|                                                                             |\n"
        << "|                 Unit Test (Basis_HGRAD_TRI_C1_FEM)                          |\n"
        << "|                                                                             |\n"
        << "|     1) Conversion of Dof tags into Dof ordinals and back                    |\n"
        << "|     2) Basis values for VALUE, GRAD, CURL, and Dk operators                 |\n"
        << "|                                                                             |\n"
        << "|  Questions? Contact  Pavel Bochev  ([email protected]),                    |\n"
        << "|                      Denis Ridzal  ([email protected]),                    |\n"
        << "|                      Kara Peterson ([email protected]),                    |\n"
        << "|                      Kyungjoo Kim  ([email protected]).                     |\n"
        << "|                                                                             |\n"
        << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n"
        << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n"
        << "|                                                                             |\n"
        << "===============================================================================\n";

      typedef Kokkos::DynRankView<ValueType,DeviceSpaceType> DynRankView;
#define ConstructWithLabel(obj, ...) obj(#obj, __VA_ARGS__)

      const ValueType tol = Parameters::Tolerence;
      int errorFlag = 0;

      // for virtual function, value and point types are declared in the class
      typedef ValueType outputValueType;
      typedef ValueType pointValueType;
      Basis_HGRAD_TRI_C1_FEM<DeviceSpaceType,outputValueType,pointValueType> triBasis;
      //typedef typename decltype(triBasis)::outputViewType outputViewType;
      //typedef typename decltype(triBasis)::pointViewType  pointViewType;

      *outStream
        << "\n"
        << "===============================================================================\n"
        << "| TEST 1: Basis creation, exceptions tests                                    |\n"
        << "===============================================================================\n";

      try {
        ordinal_type nthrow = 0, ncatch = 0;
#ifdef HAVE_INTREPID2_DEBUG

        // Define array containing the 3 vertices of the reference Triangle, its center and another point
        DynRankView ConstructWithLabel(triNodes, 5, 2);

        // Generic array for the output values; needs to be properly resized depending on the operator type
        const auto numFields = triBasis.getCardinality();
        const auto numPoints = triNodes.dimension(0);
        const auto spaceDim  = triBasis.getBaseCellTopology().getDimension();

        DynRankView vals;
        vals = DynRankView("vals", numFields, numPoints);

        {
          // exception #1: DIV cannot be applied to scalar functions
          INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(vals, triNodes, OPERATOR_DIV) );
        }
        // Exceptions 2-6: all bf tags/bf Ids below are wrong and should cause getDofOrdinal() and
        // getDofTag() to access invalid array elements thereby causing bounds check exception
        {
          // exception #2
          INTREPID2_TEST_ERROR_EXPECTED( triBasis.getDofOrdinal(2,0,0) );
          // exception #3
          INTREPID2_TEST_ERROR_EXPECTED( triBasis.getDofOrdinal(1,1,1) );
          // exception #4
          INTREPID2_TEST_ERROR_EXPECTED( triBasis.getDofOrdinal(0,4,0) );
          // exception #5
          INTREPID2_TEST_ERROR_EXPECTED( triBasis.getDofTag(5) );
          // exception #6
          INTREPID2_TEST_ERROR_EXPECTED( triBasis.getDofTag(-1) );
        }

        // Exceptions 7-17 test exception handling with incorrectly dimensioned input/output arrays
        // exception #7: input points array must be of rank-2
        {
          DynRankView ConstructWithLabel( badPoints1, 4, 5, 3);
          INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(vals, badPoints1, OPERATOR_VALUE) );
        }
        {
          // exception #8 dimension 1 in the input point array must equal space dimension of the cell
          DynRankView ConstructWithLabel( badPoints2, 4, 3);
          INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(vals, badPoints2, OPERATOR_VALUE) );
        }
        {
          // exception #9 output values must be of rank-2 for OPERATOR_VALUE
          DynRankView ConstructWithLabel( badVals1, 4, 3, 1);
          INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(badVals1, triNodes, OPERATOR_VALUE) );
        }
        {
          // exception #10 output values must be of rank-3 for OPERATOR_GRAD
          DynRankView ConstructWithLabel( badVals2, 4, 3);
          INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(badVals2, triNodes, OPERATOR_GRAD) );
          // exception #11 output values must be of rank-3 for OPERATOR_CURL
          INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(badVals2, triNodes, OPERATOR_CURL) );
          // exception #12 output values must be of rank-3 for OPERATOR_D2
          INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(badVals2, triNodes, OPERATOR_D2) );
        }
        {
          // exception #13 incorrect 1st dimension of output array (must equal number of basis functions)
          DynRankView ConstructWithLabel( badVals3, numFields + 1, numPoints);
          INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(badVals3, triNodes, OPERATOR_VALUE) );
        }
        {
          // exception #14 incorrect 0th dimension of output array (must equal number of points)
          DynRankView ConstructWithLabel( badVals4, numFields, numPoints + 1);
          INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(badVals4, triNodes, OPERATOR_VALUE) );
        }
        {
          // exception #15: incorrect 2nd dimension of output array (must equal the space dimension)
          DynRankView ConstructWithLabel( badVals5, numFields, numPoints, spaceDim + 1);
          INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(badVals5, triNodes, OPERATOR_GRAD) );
        }
        {
          // exception #16: incorrect 2nd dimension of output array (must equal D2 cardinality in 2D)
          DynRankView ConstructWithLabel( badVals6, numFields, numPoints, 40);
          INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(badVals6, triNodes, OPERATOR_D2) );
        }
#endif
        if (nthrow != ncatch) {
          errorFlag++;
          *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
          *outStream << "# of catch ("<< ncatch << ") is different from # of throw (" << ncatch << ")\n";
        }
      } catch (std::logic_error err) {
        *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
        *outStream << err.what() << '\n';
        *outStream << "-------------------------------------------------------------------------------" << "\n\n";
        errorFlag = -1000;
      }

      *outStream
        << "\n"
        << "===============================================================================\n"
        << "| TEST 2: correctness of tag to enum and enum to tag lookups                  |\n"
        << "===============================================================================\n";
      // all tags are on host space
      try {
        const auto numFields = triBasis.getCardinality();
        const auto allTags = triBasis.getAllDofTags();

        // Loop over all tags, lookup the associated dof enumeration and then lookup the tag again
        const auto dofTagSize = allTags.dimension(0);
        for (auto i=0;i<dofTagSize;++i) {
          const auto bfOrd  = triBasis.getDofOrdinal(allTags(i,0), allTags(i,1), allTags(i,2));

          const auto myTag = triBasis.getDofTag(bfOrd);
          if( !( (myTag(0) == allTags(i,0)) &&
                 (myTag(1) == allTags(i,1)) &&
                 (myTag(2) == allTags(i,2)) &&
                 (myTag(3) == allTags(i,3)) ) ) {
            errorFlag++;
            *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
            *outStream << " getDofOrdinal( {"
                       << allTags(i,0) << ", "
                       << allTags(i,1) << ", "
                       << allTags(i,2) << ", "
                       << allTags(i,3) << "}) = " << bfOrd <<" but \n";
            *outStream << " getDofTag(" << bfOrd << ") = { "
                       << myTag(0) << ", "
                       << myTag(1) << ", "
                       << myTag(2) << ", "
                       << myTag(3) << "}\n";
          }
        }

        // Now do the same but loop over basis functions
        for (auto bfOrd=0;bfOrd<numFields;++bfOrd) {
          const auto myTag = triBasis.getDofTag(bfOrd);

          const auto myBfOrd = triBasis.getDofOrdinal(myTag(0), myTag(1), myTag(2));
          if ( bfOrd != myBfOrd) {
            errorFlag++;
            *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
            *outStream << " getDofTag(" << bfOrd << ") = { "
                       << myTag(0) << ", "
                       << myTag(1) << ", "
                       << myTag(2) << ", "
                       << myTag(3) << "} but getDofOrdinal({"
                       << myTag(0) << ", "
                       << myTag(1) << ", "
                       << myTag(2) << ", "
                       << myTag(3) << "} ) = " << myBfOrd << "\n";
          }
        }
      } catch (std::logic_error err) {
        *outStream << err.what() << "\n\n";
        errorFlag = -1000;
      }

      *outStream \
        << "\n"
        << "===============================================================================\n"\
        << "| TEST 3: correctness of basis function values                                |\n"\
        << "===============================================================================\n";

      outStream -> precision(20);

      // VALUE: Each row gives the 3 correct basis set values at an evaluation point
      const ValueType basisValues[] = {
        1.0, 0.0, 0.0,
        0.0, 1.0, 0.0,
        0.0, 0.0, 1.0,
        0.0, 0.5, 0.5,
        0.25,0.0, 0.75
      };

      // GRAD and D1: each row gives the 6 correct values of the gradients of the 3 basis functions
      const ValueType basisGrads[] = {
        -1.0, -1.0,    1.0,  0.0,    0.0,  1.0,
        -1.0, -1.0,    1.0,  0.0,    0.0,  1.0,
        -1.0, -1.0,    1.0,  0.0,    0.0,  1.0,
        -1.0, -1.0,    1.0,  0.0,    0.0,  1.0,
        -1.0, -1.0,    1.0,  0.0,    0.0,  1.0,
      };

      // CURL: each row gives the 6 correct values of the curls of the 3 basis functions
      const ValueType basisCurls[] = {
        -1.0,  1.0,    0.0, -1.0,    1.0,  0.0,
        -1.0,  1.0,    0.0, -1.0,    1.0,  0.0,
        -1.0,  1.0,    0.0, -1.0,    1.0,  0.0,
        -1.0,  1.0,    0.0, -1.0,    1.0,  0.0,
        -1.0,  1.0,    0.0, -1.0,    1.0,  0.0
      };

      try{
        DynRankView ConstructWithLabel(triNodesHost, 5, 2);

        triNodesHost(0,0) =  0.0;  triNodesHost(0,1) =  0.0;
        triNodesHost(1,0) =  1.0;  triNodesHost(1,1) =  0.0;
        triNodesHost(2,0) =  0.0;  triNodesHost(2,1) =  1.0;
        triNodesHost(3,0) =  0.5;  triNodesHost(3,1) =  0.5;
        triNodesHost(4,0) =  0.0;  triNodesHost(4,1) =  0.75;

        auto triNodes = Kokkos::create_mirror_view(typename DeviceSpaceType::memory_space(), triNodesHost);
        Kokkos::deep_copy(triNodes, triNodesHost);

        // Dimensions for the output arrays:
        const auto numFields = triBasis.getCardinality();
        const auto numPoints = triNodes.dimension(0);
        const auto spaceDim  = triBasis.getBaseCellTopology().getDimension();

        // Check VALUE of basis functions: resize vals to rank-2 container:
        {
          DynRankView vals = DynRankView("vals", numFields, numPoints);
          triBasis.getValues(vals, triNodes, OPERATOR_VALUE);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);
          for (auto i=0;i<numFields;++i) {
            for (auto j=0;j<numPoints;++j) {
              const auto l =  i + j * numFields;
              if (std::abs(vals_host(i,j) - basisValues[l]) > tol) {
                errorFlag++;
                *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                // Output the multi-index of the value where the error is:
                *outStream << " At multi-index { ";
                *outStream << i << " ";*outStream << j << " ";
                *outStream << "}  computed value: " << vals_host(i,j)
                           << " but reference value: " << basisValues[l] << "\n";
              }
            }
          }
        }

        // Check GRAD of basis
        {
          DynRankView vals = DynRankView("vals", numFields, numPoints, spaceDim);
          triBasis.getValues(vals, triNodes, OPERATOR_GRAD);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);          
          for (auto i=0;i<numFields;++i) {
            for (auto j=0;j<numPoints;++j) {
              for (auto k=0;k<spaceDim;++k) {
                auto l = k + i * spaceDim + j * spaceDim * numFields;
                if (std::abs(vals_host(i,j,k) - basisGrads[l]) > tol) {
                  errorFlag++;
                  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                  // Output the multi-index of the value where the error is:
                  *outStream << " At multi-index { ";
                  *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
                  *outStream << "}  computed grad component: " << vals_host(i,j,k)
                             << " but reference grad component: " << basisGrads[l] << "\n";
                }
              }
            }
          }
        }

        // Check D1 of basis
        {
          DynRankView vals = DynRankView("vals", numFields, numPoints, spaceDim);
          triBasis.getValues(vals, triNodes, OPERATOR_D1);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);
          for (auto i=0;i<numFields;++i) {
            for (auto j=0;j<numPoints;++j) {
              for (auto k=0;k<spaceDim;++k) {
                auto l = k + i * spaceDim + j * spaceDim * numFields;
                if (std::abs(vals_host(i,j,k) - basisGrads[l]) > tol) {
                  errorFlag++;
                  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                  // Output the multi-index of the value where the error is:
                  *outStream << " At multi-index { ";
                  *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
                  *outStream << "}  computed D1 component: " << vals_host(i,j,k)
                             << " but reference D1 component: " << basisGrads[l] << "\n";
                }
              }
            }
          }
        }

        // Check CURL of basis function
        {
          DynRankView vals = DynRankView("vals", numFields, numPoints, spaceDim);
          triBasis.getValues(vals, triNodes, OPERATOR_CURL);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);
          for (auto i=0;i<numFields;++i) {
            for (auto j=0;j<numPoints;++j) {
              for (auto k=0;k<spaceDim;++k) {
                auto l = k + i * spaceDim + j * spaceDim * numFields;
                if (std::abs(vals_host(i,j,k) - basisCurls[l]) > tol) {
                  errorFlag++;
                  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                  // Output the multi-index of the value where the error is:
                  *outStream << " At multi-index { ";
                  *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
                  *outStream << "}  computed curl component: " << vals_host(i,j,k)
                             << " but reference curl component: " << basisCurls[l] << "\n";
                }
              }
            }
          }
        }

        // Check all higher derivatives - must be zero.
        {
          const EOperator ops[] = { OPERATOR_D2,
                                    OPERATOR_D3,
                                    OPERATOR_D4,
                                    OPERATOR_D5,
                                    OPERATOR_D6,
                                    OPERATOR_D7,
                                    OPERATOR_D8,
                                    OPERATOR_D9,
                                    OPERATOR_D10,
                                    OPERATOR_MAX };
          for (auto h=0;ops[h]!=OPERATOR_MAX;++h) {
            const auto op = ops[h];
            const auto DkCardin  = getDkCardinality(op, spaceDim);
            DynRankView vals("vals", numFields, numPoints, DkCardin);

            triBasis.getValues(vals, triNodes, op);
            auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
            Kokkos::deep_copy(vals_host, vals);
            for (auto i1=0;i1<numFields; i1++)
              for (auto i2=0;i2<numPoints; i2++)
                for (auto i3=0;i3<DkCardin; i3++) {
                  if (std::abs(vals_host(i1,i2,i3)) > tol) {
                    errorFlag++;
                    *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                    // Get the multi-index of the value where the error is and the operator order
                    const auto ord = Intrepid2::getOperatorOrder(op);
                    *outStream << " At multi-index { "<<i1<<" "<<i2 <<" "<<i3;
                    *outStream << "}  computed D"<< ord <<" component: " << vals_host(i1,i2,i3)
                               << " but reference D" << ord << " component:  0 \n";
                  }
                }
          }
        }
      } catch (std::logic_error err) {
        *outStream << err.what() << "\n\n";
        errorFlag = -1000;
      }

      *outStream
        << "\n"
        << "===============================================================================\n"
        << "| TEST 4: correctness of DoF locations                                        |\n"
        << "===============================================================================\n";

      try {
        const auto numFields = triBasis.getCardinality();
        const auto spaceDim  = triBasis.getBaseCellTopology().getDimension();

        // Check exceptions.
        ordinal_type nthrow = 0, ncatch = 0;
#ifdef HAVE_INTREPID2_DEBUG
        {
          DynRankView ConstructWithLabel(badVals, 1,2,3);
          INTREPID2_TEST_ERROR_EXPECTED( triBasis.getDofCoords(badVals) );
        }
        {
          DynRankView ConstructWithLabel(badVals, 4,2);
          INTREPID2_TEST_ERROR_EXPECTED( triBasis.getDofCoords(badVals) );
        }
        {
          DynRankView ConstructWithLabel(badVals, 4,3);
          INTREPID2_TEST_ERROR_EXPECTED( triBasis.getDofCoords(badVals) );
        }
#endif
        if (nthrow != ncatch) {
          errorFlag++;
          *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
          *outStream << "# of catch ("<< ncatch << ") is different from # of throw (" << ncatch << ")\n";
        }

        DynRankView ConstructWithLabel(bvals, numFields, numFields);
        DynRankView ConstructWithLabel(cvals, numFields, spaceDim);

        // Check mathematical correctness.
        triBasis.getDofCoords(cvals);
        triBasis.getValues(bvals, cvals, OPERATOR_VALUE);

        auto cvals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), cvals);
        Kokkos::deep_copy(cvals_host, cvals);

        auto bvals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), bvals);
        Kokkos::deep_copy(bvals_host, bvals);

        for (auto i=0;i<numFields;++i) {
          for (auto j=0;j<numFields;++j) {
            const ValueType expected_value = (i == j);
            const ValueType value = bvals_host(i,j);
            if (std::abs(value - expected_value) > tol) {
              errorFlag++;
              std::stringstream ss;
              ss << "\nValue of basis function " << i << " at (" << cvals_host(i,0) << ", " << cvals_host(i,1)<< ") is " << value << " but should be " << expected_value << "\n";
              *outStream << ss.str();
            }
          }
        }
      } catch (std::logic_error err) {
        *outStream << err.what() << "\n\n";
        errorFlag = -1000;
      };

      if (errorFlag != 0)
        std::cout << "End Result: TEST FAILED\n";
      else
        std::cout << "End Result: TEST PASSED\n";

      // reset format state of std::cout
      std::cout.copyfmt(oldFormatState);

      return errorFlag;
    }
Beispiel #10
0
    int FunctionSpaceTools_Test04(const bool verbose) {

      Teuchos::RCP<std::ostream> outStream;
      Teuchos::oblackholestream bhs; // outputs nothing

      if (verbose)
        outStream = Teuchos::rcp(&std::cout, false);
      else
        outStream = Teuchos::rcp(&bhs, false);

      Teuchos::oblackholestream oldFormatState;
      oldFormatState.copyfmt(std::cout);

      typedef typename
        Kokkos::Impl::is_space<DeviceSpaceType>::host_mirror_space::execution_space HostSpaceType ;

      *outStream << "DeviceSpace::  "; DeviceSpaceType::print_configuration(*outStream, false);
      *outStream << "HostSpace::    ";   HostSpaceType::print_configuration(*outStream, false);

      *outStream                                                       
        << "===============================================================================\n"
        << "|                                                                             |\n"
        << "|                      Unit Test (FunctionSpaceTools)                         |\n"
        << "|                                                                             |\n"
        << "|     1) volume integration on tetrahedra, testing dataIntegral               |\n"
        << "|                                                                             |\n"
        << "|  Questions? Contact  Pavel Bochev ([email protected]) or                   |\n"
        << "|                      Denis Ridzal ([email protected]) or                   |\n"
        << "|                      Kyungjoo Kim ([email protected]).                      |\n"
        << "|                                                                             |\n"
        << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n"
        << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n"
        << "|                                                                             |\n"
        << "===============================================================================\n";

      typedef CellTools<DeviceSpaceType> ct;
      typedef FunctionSpaceTools<DeviceSpaceType> fst;
      typedef Kokkos::DynRankView<ValueType,DeviceSpaceType> DynRankView;

      const auto tol = tolerence<ValueType>();

      int errorFlag = 0;

      *outStream
        << "\n"
        << "===============================================================================\n"
        << "| TEST 1: correctness of cell volumes                                         |\n"
        << "===============================================================================\n";

      outStream->precision(20);

      try {
        DefaultCubatureFactory cub_factory;

        shards::CellTopology cell_topo = shards::getCellTopologyData< shards::Tetrahedron<4> >();

        const auto cub_degree = 0;
        auto cub = cub_factory.create<DeviceSpaceType,ValueType,ValueType>(cell_topo, cub_degree);

        const auto space_dim = cub->getDimension();
        const auto num_cub_points = cub->getNumPoints();

        /* Cell geometries. */
        const auto num_cells = 4;
        const auto num_nodes = 4;

        const ValueType tetnodes[] = {
          // tet 0
          0.0, 0.0, 0.0,
          1.0, 0.0, 0.0,
          0.0, 1.0, 0.0,
          0.0, 0.0, 1.0,
          // tet 1
          4.0, 5.0, 1.0,
          -6.0, 2.0, 0.0,
          4.0, -3.0, -1.0,
          0.0, 2.0, 5.0,
          // tet 2
          -6.0, -3.0, 1.0,
          9.0, 2.0, 1.0,
          8.9, 2.1, 0.9,
          8.9, 2.1, 1.1,
          // tet 3
          -6.0, -3.0, 1.0,
          12.0, 3.0, 1.0,
          2.9, 0.1, 0.9,
          2.9, 0.1, 1.1
        };
        
        /* Analytic volumes. */
        const ValueType tetvols[] = {1.0/6.0, 194.0/3.0, 1.0/15.0, 2.0/25.0};

      /* Computational arrays. */
        DynRankView ConstructWithLabel( cub_points,  num_cub_points, space_dim);
        DynRankView ConstructWithLabel( cub_weights, num_cub_points);

        DynRankView ConstructWithLabel( cell_nodes,       num_cells, num_nodes, space_dim);

        DynRankView ConstructWithLabel( jacobian,         num_cells, num_cub_points, space_dim, space_dim);
        DynRankView ConstructWithLabel( jacobian_det,     num_cells, num_cub_points);
        DynRankView ConstructWithLabel( weighted_measure, num_cells, num_cub_points);

        DynRankView ConstructWithLabel( data_one, num_cells, num_cub_points);
        DynRankView ConstructWithLabel( volumes, num_cells);

        /******************* START COMPUTATION ***********************/

        // get cubature points and weights
        cub->getCubature(cub_points, cub_weights);

        const Kokkos::DynRankView<const ValueType,Kokkos::LayoutRight,HostSpaceType> cell_nodes_host (&tetnodes[0],  num_cells, num_nodes, space_dim);
        Kokkos::deep_copy( cell_nodes,  cell_nodes_host  );
        
        // compute geometric cell information
        ct::setJacobian(jacobian, cub_points, cell_nodes, cell_topo);
        ct::setJacobianDet(jacobian_det, jacobian);

        // compute weighted measure
        fst::computeCellMeasure(weighted_measure, jacobian_det, cub_weights);

        Kokkos::deep_copy(data_one, 1.0);

        // compute volumes
        fst::integrate(volumes, data_one, weighted_measure);
        
        /******************* STOP COMPUTATION ***********************/
        
        // memcpy do implicit sync
        const auto volumes_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), volumes);
        Kokkos::deep_copy(volumes_host, volumes);

        /******************* START COMPARISON ***********************/
        for (auto cid=0;cid<num_cells-1;++cid) {
          *outStream << "Volume of cell " << cid 
                     << " = " << std::setw(24) << volumes_host(cid) 
                     << "    vs.    Analytic value =  " << std::setw(24) << tetvols[cid] << "\n";
          errorFlag += (std::fabs(volumes_host(cid)-tetvols[cid]) > tol);
          
        }
        /******************* STOP COMPARISON ***********************/
        
        *outStream << "\n";
      } catch (std::logic_error err) {
        *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
        *outStream << err.what() << '\n';
        *outStream << "-------------------------------------------------------------------------------" << "\n\n";
        errorFlag = -1000;
      }

      if (errorFlag != 0)
        std::cout << "End Result: TEST FAILED\n";
      else
        std::cout << "End Result: TEST PASSED\n";

      // reset format state of std::cout
      std::cout.copyfmt(oldFormatState);

      return errorFlag;
    }
Beispiel #11
0
    int HGRAD_LINE_Cn_FEM_Test01(const bool verbose) {

      Teuchos::RCP<std::ostream> outStream;
      Teuchos::oblackholestream bhs; // outputs nothing

      if (verbose)
        outStream = Teuchos::rcp(&std::cout, false);
      else
        outStream = Teuchos::rcp(&bhs,       false);

      Teuchos::oblackholestream oldFormatState;
      oldFormatState.copyfmt(std::cout);

      typedef typename
        Kokkos::Impl::is_space<DeviceSpaceType>::host_mirror_space::execution_space HostSpaceType ;

      *outStream << "DeviceSpace::  "; DeviceSpaceType::print_configuration(*outStream, false);
      *outStream << "HostSpace::    ";   HostSpaceType::print_configuration(*outStream, false);

      *outStream
        << "===============================================================================\n"
        << "|                                                                             |\n"
        << "|               Unit Test (Basis_HGRAD_LINE_Cn_FEM_JACOBI)                    |\n"
        << "|                                                                             |\n"
        << "|     1) Conversion of Dof tags into Dof ordinals and back                    |\n"
        << "|     2) Basis values for VALUE, GRAD, CURL, and Dk operators                 |\n"
        << "|                                                                             |\n"
        << "|  Questions? Contact  Pavel Bochev  ([email protected]),                    |\n"
        << "|                      Denis Ridzal  ([email protected]),                    |\n"
        << "|                      Kara Peterson ([email protected]),                    |\n"
        << "|                      Kyungjoo Kim  ([email protected]).                     |\n"
        << "|                                                                             |\n"
        << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n"
        << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n"
        << "|                                                                             |\n"
        << "===============================================================================\n";

      typedef Kokkos::DynRankView<ValueType,DeviceSpaceType> DynRankView;
      //typedef Kokkos::DynRankView<ValueType,HostSpaceType>   DynRankViewHost;
#define ConstructWithLabel(obj, ...) obj(#obj, __VA_ARGS__)

      const ValueType tol = tolerence();
      int errorFlag = 0;

      // for virtual function, value and point types are declared in the class
      typedef ValueType outputValueType;
      typedef ValueType pointValueType;
      //typedef ValueType weightValueType;

      typedef Basis_HGRAD_LINE_Cn_FEM<DeviceSpaceType,outputValueType,pointValueType> LineBasisType;
      //typedef CubatureDirectLineGauss<DeviceSpaceType,pointValueType,weightValueType> CubatureLineType;
      //typedef FunctionSpaceTools<DeviceSpaceType> fst;

      *outStream
        << "\n"
        << "===============================================================================\n"
        << "| TEST 1: Basis creation, exceptions tests                                    |\n"
        << "===============================================================================\n";

      try{

        ordinal_type nthrow = 0, ncatch = 0;
#ifdef HAVE_INTREPID2_DEBUG
        const ordinal_type order = 5;

        LineBasisType lineBasis(order);

        // Define array containing array of nodes to evaluate
        DynRankView ConstructWithLabel(lineNodes, 10, 1);

        // Generic array for the output values; needs to be properly resized depending on the operator type
        const auto numFields = lineBasis.getCardinality();
        const auto numPoints = lineNodes.dimension(0);
        //const auto spaceDim  = lineBasis.getBaseCellTopology().getDimension();


        // Exceptions 1-5: all bf tags/bf Ids below are wrong and should cause getDofOrdinal() and
        // getDofTag() to access invalid array elements thereby causing bounds check exception
        {
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getDofOrdinal(2,0,0) );
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getDofOrdinal(1,1,1) );
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getDofOrdinal(1,0,7) );
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getDofTag(numFields) );
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getDofTag(-1) );

          // no exception; if happens, it is unexpected;
          lineBasis.getDofOrdinal(1,0,3);
          lineBasis.getDofTag(5);
        }

        // Exceptions 6-16 test exception handling with incorrectly dimensioned input/output arrays
        {
          DynRankView ConstructWithLabel(vals, numFields, numPoints);
          {
            // exception #6: input points array must be of rank-2
            DynRankView ConstructWithLabel(badPoints, 4, 5, 3);
            INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getValues(vals, badPoints, OPERATOR_VALUE) );
          }
          {
            // exception #7: dimension 1 in the input point array must equal space dimension of the cell
            DynRankView ConstructWithLabel(badPoints, 4, 3);
            INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getValues(vals, badPoints, OPERATOR_VALUE) );
          }
          {
            // exception #8: output values must be of rank-2 for OPERATOR_VALUE
            DynRankView ConstructWithLabel(badVals, 4, 3, 1);
            INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getValues(badVals, lineNodes, OPERATOR_VALUE) );
          }
          lineBasis.getValues(vals, lineNodes, OPERATOR_VALUE);
        }
        {
          // exception #9: output values must be of rank-3 for OPERATOR_GRAD
          DynRankView ConstructWithLabel(badVals, 4, 3);
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getValues(badVals, lineNodes, OPERATOR_GRAD) );

          // exception #10: output values must be of rank-3 for OPERATOR_CURL
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getValues(badVals, lineNodes, OPERATOR_CURL) );

          // exception #11: output values must be of rank-2 for OPERATOR_DIV
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getValues(badVals, lineNodes, OPERATOR_DIV) );

          // exception #12: output values must be of rank-2 for OPERATOR_D1
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getValues(badVals, lineNodes, OPERATOR_D1) );
        }
        {
          // exception #13: incorrect 0th dimension of output array (must equal number of basis functions)
          DynRankView ConstructWithLabel(badVals, lineBasis.getCardinality() + 1, lineNodes.dimension(0));
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getValues(badVals, lineNodes, OPERATOR_VALUE) );
        }
        {
          // exception #14: incorrect 1st dimension of output array (must equal number of points)
          DynRankView ConstructWithLabel(badVals, lineBasis.getCardinality(), lineNodes.dimension(0) + 1);
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getValues(badVals, lineNodes, OPERATOR_VALUE) );
        }
        {
          // exception #15: incorrect 2nd dimension of output array (must equal spatial dimension)
          DynRankView ConstructWithLabel(badVals, lineBasis.getCardinality(), lineNodes.dimension(0), 2);
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getValues(badVals, lineNodes, OPERATOR_GRAD) );
        }
#endif
        if (nthrow != ncatch) {
          errorFlag++;
          *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
          *outStream << "# of catch ("<< ncatch << ") is different from # of throw (" << nthrow << ")\n";
        }
      } catch (std::exception err) {
        *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
        *outStream << err.what() << '\n';
        *outStream << "-------------------------------------------------------------------------------" << "\n\n";
        errorFlag = -1000;
      };
      
      *outStream
        << "\n"
        << "===============================================================================\n"
        << "| TEST 2: correctness of basis function values                                |\n"
        << "===============================================================================\n";
      outStream->precision(20);

      // check Kronecker property for Lagrange polynomials.      
      try {
        const auto maxp = Parameters::MaxOrder;
        
        const EPointType pts[3] = { POINTTYPE_EQUISPACED, POINTTYPE_WARPBLEND, POINTTYPE_GAUSS };
        for (auto idx=0;idx<3;++idx) {
          *outStream << " -- Testing " << EPointTypeToString(pts[idx]) << " -- \n";
          for (auto ip=1;ip<maxp;++ip) {

            LineBasisType lineBasis(ip, pts[idx]);

            const auto numDofs   = lineBasis.getCardinality();
            const auto numPoints = lineBasis.getCardinality();
            const auto spaceDim  = lineBasis.getBaseCellTopology().getDimension();
            
            DynRankView ConstructWithLabel(dofCoords, numPoints, spaceDim);
            lineBasis.getDofCoords(dofCoords);

            DynRankView ConstructWithLabel(vals, numDofs, numPoints);
            lineBasis.getValues(vals, dofCoords, OPERATOR_VALUE);

            // host mirror for comparison
            auto valsHost = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
            Kokkos::deep_copy(valsHost, vals);
            
            for (auto i=0;i<numDofs;++i) 
              for (int j=0;j<numPoints;++j) {
                const ValueType exactVal = (i == j);
                const auto val = valsHost(i,j);
                if (std::isnan(val) || std::abs(val-exactVal) > tol) {
                  errorFlag++;
                  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
                  *outStream << " Basis function at i= " << i << ", j=" << j << ": "
                             << val << " != " << exactVal << "\n\n";
                }
              }
          }
        }
      } catch (std::exception err) {
        *outStream << err.what() << "\n\n";
        errorFlag = -1000;
      };

      if (errorFlag != 0)
        std::cout << "End Result: TEST FAILED\n";
      else
        std::cout << "End Result: TEST PASSED\n";
      
      std::cout.copyfmt(oldFormatState);

      return errorFlag;
    }
Beispiel #12
0
    int HCURL_TRI_I1_FEM_Test01(const bool verbose) {
      
      Teuchos::RCP<std::ostream> outStream;
      Teuchos::oblackholestream bhs; // outputs nothing

      if (verbose)
        outStream = Teuchos::rcp(&std::cout, false);
      else
        outStream = Teuchos::rcp(&bhs, false);
      
      Teuchos::oblackholestream oldFormatState;
      oldFormatState.copyfmt(std::cout);
      
      typedef typename
        Kokkos::Impl::is_space<DeviceSpaceType>::host_mirror_space::execution_space HostSpaceType ;
      
      *outStream << "DeviceSpace::  "; DeviceSpaceType::print_configuration(*outStream, false);
      *outStream << "HostSpace::    ";   HostSpaceType::print_configuration(*outStream, false);
  
  *outStream 
    << "===============================================================================\n" 
    << "|                                                                             |\n" 
    << "|                 Unit Test (Basis_HCURL_TRI_I1_FEM)                          |\n" 
    << "|                                                                             |\n" 
    << "|     1) Conversion of Dof tags into Dof ordinals and back                    |\n" 
    << "|     2) Basis values for VALUE and CURL operators                            |\n" 
    << "|                                                                             |\n" 
    << "|  Questions? Contact  Pavel Bochev  ([email protected]),                    |\n" 
    << "|                      Denis Ridzal  ([email protected]),                    |\n" 
    << "|                      Kara Peterson ([email protected]).                    |\n" 
    << "|                      Kyungjoo Kim  ([email protected]).                     |\n"
    << "|                                                                             |\n" 
    << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n" 
    << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n" 
    << "|                                                                             |\n" 
    << "===============================================================================\n";

      typedef Kokkos::DynRankView<ValueType,DeviceSpaceType> DynRankView;
      typedef Kokkos::DynRankView<ValueType,HostSpaceType> DynRankViewHost;
#define ConstructWithLabel(obj, ...) obj(#obj, __VA_ARGS__)
      const ValueType tol = tolerence();

      int errorFlag = 0;

      // for virtual function, value and point types are declared in the class
      typedef ValueType outputValueType;
      typedef ValueType pointValueType;
      Basis_HCURL_TRI_I1_FEM<DeviceSpaceType,outputValueType,pointValueType> triBasis;

    *outStream
    << "\n"
    << "===============================================================================\n"
    << "| TEST 1: Basis creation, exception testing                                   |\n"
    << "===============================================================================\n";

  try{
    ordinal_type nthrow = 0, ncatch = 0;
#ifdef HAVE_INTREPID2_DEBUG

    // Define array containing the 3 vertices of the reference TRI and its 3 edge midpoints.
    DynRankView ConstructWithLabel(triNodes, 7, 2);

    // Generic array for the output values; needs to be properly resized depending on the operator type
    const ordinal_type cardinality = triBasis.getCardinality();
    const ordinal_type numPoints = triNodes.extent(0);

    DynRankView vals;
    vals = DynRankView("vals", cardinality, numPoints);

    {
    // exception #1: GRAD cannot be applied to HCURL functions 
      INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(vals, triNodes, OPERATOR_GRAD) );
    }
    {
    // exception #2: DIV cannot be applied to HCURL functions
      INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(vals, triNodes, OPERATOR_DIV) );
    }
    // Exceptions 3-7: all bf tags/bf Ids below are wrong and should cause getDofOrdinal() and 
    // getDofTag() to access invalid array elements thereby causing bounds check exception
    {
    // exception #3
      INTREPID2_TEST_ERROR_EXPECTED( triBasis.getDofOrdinal(3,0,0) );
    // exception #4
      INTREPID2_TEST_ERROR_EXPECTED( triBasis.getDofOrdinal(1,1,1) );
    // exception #5
      INTREPID2_TEST_ERROR_EXPECTED( triBasis.getDofOrdinal(0,4,1) );
    // exception #6
      INTREPID2_TEST_ERROR_EXPECTED( triBasis.getDofTag(cardinality) );
    // exception #7
      INTREPID2_TEST_ERROR_EXPECTED( triBasis.getDofTag(-1) );
    }
    // Exceptions 8-15 test exception handling with incorrectly dimensioned input/output arrays
    {
    // exception #8: input points array must be of rank-2
      DynRankView ConstructWithLabel(badPoints1, 4, 5, 3);
      INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(vals, badPoints1, OPERATOR_VALUE) );
    }
    // exception #9 dimension 1 in the input point array must equal space dimension of the cell
    {
      DynRankView ConstructWithLabel(badPoints2, 4, triBasis.getBaseCellTopology().getDimension() + 1);
      INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(vals, badPoints2, OPERATOR_VALUE) ); 
    }
    {
    // exception #10 output values must be of rank-3 for OPERATOR_VALUE in 2D
      DynRankView ConstructWithLabel(badVals1, 4, 3);
      INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(badVals1, triNodes, OPERATOR_VALUE) ); 
    }
    {
    // exception #11 output values must be of rank-2 for OPERATOR_CURL
      DynRankView ConstructWithLabel(badCurls1,4,3,2);
      INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(badCurls1, triNodes, OPERATOR_CURL) ); 
    }
    {
    // exception #12 incorrect 0th dimension of output array (must equal number of basis functions)
      DynRankView ConstructWithLabel(badVals2, triBasis.getCardinality() + 1, triNodes.extent(0), triBasis.getBaseCellTopology().getDimension());
      INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(badVals2, triNodes, OPERATOR_VALUE) ) ;
    }
    {
    // exception #13 incorrect 1st  dimension of output array (must equal number of points)
      DynRankView ConstructWithLabel(badVals3, triBasis.getCardinality(), triNodes.extent(0) + 1, triBasis.getBaseCellTopology().getDimension() );
      INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(badVals3, triNodes, OPERATOR_VALUE) ) ;
    }
    {
    // exception #14: incorrect 2nd dimension of output array for VALUE (must equal the space dimension)
      DynRankView ConstructWithLabel(badVals4, triBasis.getCardinality(), triNodes.extent(0), triBasis.getBaseCellTopology().getDimension() - 1);
      INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(badVals4, triNodes, OPERATOR_VALUE) ) ;
    } 
    // exception #15: D2 cannot be applied to HCURL functions 
    // resize vals to rank-3 container with dimensions (num. basis functions, num. points, arbitrary)
//    vals.resize(triBasis.getCardinality(), 
//                triNodes.extent(0),  
//                Intrepid2::getDkCardinality(OPERATOR_D2, triBasis.getBaseCellTopology().getDimension()));
//    INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(vals, triNodes, OPERATOR_D2) ); 
#endif
  // Check if number of thrown exceptions matches the one we expect
    if (nthrow != ncatch) {
      errorFlag++;
      *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
      *outStream << "# of catch ("<< ncatch << ") is different from # of throw (" << nthrow << ")\n";
    }
  } catch (std::logic_error err) {
    *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
    *outStream << err.what() << '\n';
    *outStream << "-------------------------------------------------------------------------------" << "\n\n";
    errorFlag = -1000;
  }
  
  *outStream
    << "\n"
    << "===============================================================================\n"
    << "| TEST 2: correctness of tag to enum and enum to tag lookups                  |\n"
    << "===============================================================================\n";
  
  // all tags are on host space
  try{
    const auto allTags = triBasis.getAllDofTags();
    
    // Loop over all tags, lookup the associated dof enumeration and then lookup the tag again
    const ordinal_type dofTagSize = allTags.extent(0);
    for (ordinal_type i = 0; i < dofTagSize; ++i) {
      const auto bfOrd  = triBasis.getDofOrdinal(allTags(i,0), allTags(i,1), allTags(i,2));
      
      const auto myTag = triBasis.getDofTag(bfOrd);
       if( !( (myTag(0) == allTags(i,0)) &&
              (myTag(1) == allTags(i,1)) &&
              (myTag(2) == allTags(i,2)) &&
              (myTag(3) == allTags(i,3)) ) ) {
        errorFlag++;
        *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
        *outStream << " getDofOrdinal( {" 
          << allTags(i,0) << ", " 
          << allTags(i,1) << ", " 
          << allTags(i,2) << ", " 
          << allTags(i,3) << "}) = " << bfOrd <<" but \n";   
        *outStream << " getDofTag(" << bfOrd << ") = { "
          << myTag(0) << ", " 
          << myTag(1) << ", " 
          << myTag(2) << ", " 
          << myTag(3) << "}\n";        
      }
    }
    
    // Now do the same but loop over basis functions
    for( ordinal_type bfOrd = 0; bfOrd < triBasis.getCardinality(); bfOrd++) {
      const auto myTag  = triBasis.getDofTag(bfOrd);
      const auto myBfOrd = triBasis.getDofOrdinal(myTag(0), myTag(1), myTag(2));
      if( bfOrd != myBfOrd) {
        errorFlag++;
        *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
        *outStream << " getDofTag(" << bfOrd << ") = { "
          << myTag(0) << ", " 
          << myTag(1) << ", " 
          << myTag(2) << ", " 
          << myTag(3) << "} but getDofOrdinal({" 
          << myTag(0) << ", " 
          << myTag(1) << ", " 
          << myTag(2) << ", " 
          << myTag(3) << "} ) = " << myBfOrd << "\n";
      }
    }
  }
  catch (std::logic_error err){
    *outStream << err.what() << "\n\n";
    errorFlag = -1000;
  };
  
  *outStream
    << "\n"
    << "===============================================================================\n"
    << "| TEST 3: correctness of basis function values                                |\n"
    << "===============================================================================\n";
  
  outStream -> precision(20);
  
  // VALUE: correct values in (P,F,D) layout
  const ValueType basisValues[] = {
    1.000, 0, 0, 0, 0, -1.000, 1.000, 1.000, 0, 1.000, 0, 0, 0, 0, \
    -1.000, 0, -1.000, -1.000, 1.000, 0.5000, 0, 0.5000, 0, -0.5000, \
    0.5000, 0.5000, -0.5000, 0.5000, -0.5000, -0.5000, 0.5000, 0, \
    -0.5000, 0, -0.5000, -1.000, 0.7500, 0.2500, -0.2500, 0.2500, \
    -0.2500, -0.7500};
  
  // CURL: correct values in (P,F) layout
  const ValueType basisCurls[] = {   
    2.0,  2.0,  2.0,  
    2.0,  2.0,  2.0,  
    2.0,  2.0,  2.0,  
    2.0,  2.0,  2.0,  
    2.0,  2.0,  2.0,  
    2.0,  2.0,  2.0,  
    2.0,  2.0,  2.0  
  };
  
  try{
    DynRankViewHost ConstructWithLabel(triNodesHost, 7, 2);
    triNodesHost(0,0) =  0.0;  triNodesHost(0,1) =  0.0;  
    triNodesHost(1,0) =  1.0;  triNodesHost(1,1) =  0.0;  
    triNodesHost(2,0) =  0.0;  triNodesHost(2,1) =  1.0;  
    // edge midpoints
    triNodesHost(3,0) =  0.5;  triNodesHost(3,1) =  0.0;  
    triNodesHost(4,0) =  0.5;  triNodesHost(4,1) =  0.5;  
    triNodesHost(5,0) =  0.0;  triNodesHost(5,1) =  0.5;  
    // Inside Triangle
    triNodesHost(6,0) =  0.25; triNodesHost(6,1) =  0.25;  

    auto triNodes = Kokkos::create_mirror_view(typename DeviceSpaceType::memory_space(), triNodesHost);
    Kokkos::deep_copy(triNodes, triNodesHost);

    // Dimensions for the output arrays:
    const ordinal_type cardinality = triBasis.getCardinality();
    const ordinal_type numPoints = triNodes.extent(0);
    const ordinal_type spaceDim  = triBasis.getBaseCellTopology().getDimension();
    
    {
    // Check VALUE of basis functions: resize vals to rank-3 container:
    DynRankView ConstructWithLabel(vals, cardinality, numPoints, spaceDim);
    triBasis.getValues(vals, triNodes, OPERATOR_VALUE);
    auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
    Kokkos::deep_copy(vals_host, vals);
    for (ordinal_type i = 0; i < cardinality; ++i) {
      for (ordinal_type j = 0; j < numPoints; ++j) {
        for (ordinal_type k = 0; k < spaceDim; ++k) {
          
          // compute offset for (P,F,D) data layout: indices are P->j, F->i, D->k
           ordinal_type l = k + i * spaceDim + j * spaceDim * cardinality;
           if (std::abs(vals_host(i,j,k) - basisValues[l]) > tol) {
             errorFlag++;
             *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

             // Output the multi-index of the value where the error is:
             *outStream << " At multi-index { ";
             *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
             *outStream << "}  computed value: " << vals_host(i,j,k)
               << " but reference value: " << basisValues[l] << "\n";
            }
         }
      }
    }
    } 
    
    {
    // Check CURL of basis function: resize vals to rank-2 container
    DynRankView ConstructWithLabel(vals, cardinality, numPoints);
    triBasis.getValues(vals, triNodes, OPERATOR_CURL);
    auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
    Kokkos::deep_copy(vals_host, vals);
    for (ordinal_type i = 0; i < cardinality; ++i) {
      for (ordinal_type j = 0; j < numPoints; ++j) {
        ordinal_type l =  i + j * cardinality;
        if (std::abs(vals_host(i,j) - basisCurls[l]) > tol) {
          errorFlag++;
          *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
          
          // Output the multi-index of the value where the error is:
          *outStream << " At multi-index { ";
          *outStream << i << " ";*outStream << j << " ";
          *outStream << "}  computed curl component: " << vals_host(i,j)
            << " but reference curl component: " << basisCurls[l] << "\n";
        }
      }
    }  
    }
  } //end try
   
  // Catch unexpected errors
  catch (std::logic_error err) {
    *outStream << err.what() << "\n\n";
    errorFlag = -1000;
  };
 
  *outStream 
    << "\n"
    << "===============================================================================\n"
    << "| TEST 4: correctness of DoF locations                                        |\n"
    << "===============================================================================\n";

  try{
    const ordinal_type cardinality = triBasis.getCardinality();
    const ordinal_type spaceDim  = triBasis.getBaseCellTopology().getDimension();

    // Check exceptions.
    ordinal_type nthrow = 0, ncatch = 0;
#ifdef HAVE_INTREPID2_DEBUG
    {
      DynRankView ConstructWithLabel(badVals, 1, 2, 3);
      INTREPID2_TEST_ERROR_EXPECTED( triBasis.getDofCoords(badVals) );
    }
    {
      DynRankView ConstructWithLabel(badVals, 4, 2);
      INTREPID2_TEST_ERROR_EXPECTED( triBasis.getDofCoords(badVals) );
    }
    {
      DynRankView ConstructWithLabel(badVals, 4, 3);
      INTREPID2_TEST_ERROR_EXPECTED( triBasis.getDofCoords(badVals) );
    }
#endif
    // Check if number of thrown exceptions matches the one we expect
    if (nthrow != ncatch) {
      errorFlag++;
      *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
      *outStream << "# of catch ("<< ncatch << ") is different from # of throw (" << ncatch << ")\n";
    }

    // Check mathematical correctness
    DynRankView ConstructWithLabel(bvals, cardinality, cardinality, spaceDim);
    DynRankView ConstructWithLabel(cvals, cardinality, spaceDim);
    DynRankView ConstructWithLabel(dofCoeffs, cardinality, spaceDim);
    triBasis.getDofCoeffs(dofCoeffs);
    triBasis.getDofCoords(cvals);
    triBasis.getValues(bvals, cvals, OPERATOR_VALUE);

    auto cvals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), cvals);
    Kokkos::deep_copy(cvals_host, cvals);
    auto dofCoeffs_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), dofCoeffs);
    Kokkos::deep_copy(dofCoeffs_host, dofCoeffs);
    auto bvals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), bvals);
    Kokkos::deep_copy(bvals_host, bvals);

    char buffer[120];
    for (ordinal_type i=0; i<cardinality; ++i) {
      for (ordinal_type j=0; j<cardinality; ++j) {

        double dofValue = 0.0;
        for(ordinal_type d=0;d<spaceDim;++d)
          dofValue += bvals_host(i,j,d)*dofCoeffs_host(j,d);

        if ((i != j) && (std::abs(dofValue - 0.0) > tol )) {
          errorFlag++;
          sprintf(buffer, "\nValue of basis function %d at (%6.4e, %6.4e) is %6.4e but should be %6.4e!\n", i, cvals_host(i,0), cvals_host(i,1), dofValue, 0.0);
          *outStream << buffer;
        }
        else if ((i == j) && (std::abs(dofValue - 1.0) > tol )) {
          errorFlag++;
          sprintf(buffer, "\nValue of basis function %d at (%6.4e, %6.4e) is %6.4e but should be %6.4e!\n", i, cvals_host(i,0), cvals_host(i,1), dofValue, 1.0);
          *outStream << buffer;
        }
      }
    }

  }
  catch (std::logic_error err){
    *outStream << err.what() << "\n\n";
    errorFlag = -1000;
  };

  if (errorFlag != 0)
    std::cout << "End Result: TEST FAILED\n";
  else
    std::cout << "End Result: TEST PASSED\n";
 
  // reset format state of std::cout
  std::cout.copyfmt(oldFormatState);
  return errorFlag;
}
Beispiel #13
0
    int HGRAD_HEX_Cn_FEM_Test01(const bool verbose) {

      Teuchos::RCP<std::ostream> outStream;
      Teuchos::oblackholestream bhs; // outputs nothing

      if (verbose)
        outStream = Teuchos::rcp(&std::cout, false);
      else
        outStream = Teuchos::rcp(&bhs,       false);

      Teuchos::oblackholestream oldFormatState;
      oldFormatState.copyfmt(std::cout);

      typedef typename
        Kokkos::Impl::is_space<DeviceSpaceType>::host_mirror_space::execution_space HostSpaceType ;

      *outStream << "DeviceSpace::  "; DeviceSpaceType::print_configuration(*outStream, false);
      *outStream << "HostSpace::    ";   HostSpaceType::print_configuration(*outStream, false);
  
      *outStream                                                       
        << "===============================================================================\n"
        << "|                                                                             |\n"
        << "|                 Unit Test (Basis_HGRAD_HEX_C2_FEM)                          |\n"
        << "|                                                                             |\n"
        << "|     1) Conversion of Dof tags into Dof ordinals and back                    |\n"
        << "|     2) Basis values for VALUE, GRAD, and Dk operators                       |\n"
        << "|                                                                             |\n"
        << "|  Questions? Contact  Pavel Bochev  ([email protected]),                    |\n"
        << "|                      Robert Kirby  ([email protected]),                |\n"
        << "|                      Denis Ridzal  ([email protected]),                    |\n"
        << "|                      Kara Peterson ([email protected]).                    |\n"
        << "|                      Kyungjoo Kim  ([email protected]).                     |\n"
        << "|                                                                             |\n"
        << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n"
        << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n"
        << "|                                                                             |\n"
        << "===============================================================================\n";
        
      typedef Kokkos::DynRankView<ValueType,DeviceSpaceType> DynRankView;
      typedef Kokkos::DynRankView<ValueType,HostSpaceType>   DynRankViewHost;
#define ConstructWithLabel(obj, ...) obj(#obj, __VA_ARGS__)
      
      const ValueType tol = tolerence();
      int errorFlag = 0;
      
      // for virtual function, value and point types are declared in the class
      typedef ValueType outputValueType;
      typedef ValueType pointValueType;
      
      typedef Basis_HGRAD_HEX_Cn_FEM<DeviceSpaceType,outputValueType,pointValueType> HexBasisType;
      
      *outStream
        << "\n"
        << "===============================================================================\n"
        << "| TEST 1: Basis creation, exceptions tests                                    |\n"
        << "===============================================================================\n";

      try {

        ordinal_type nthrow = 0, ncatch = 0;
#ifdef HAVE_INTREPID2_DEBUG
        const ordinal_type order = 3;
        HexBasisType hexBasis(order);

        // Define array containing array of nodes to evaluate
        DynRankView ConstructWithLabel(hexNodes, 27, 3);

        // Generic array for the output values; needs to be properly resized depending on the operator type
        const ordinal_type numFields = hexBasis.getCardinality();
        const ordinal_type numPoints = hexNodes.dimension(0);
        //const ordinal_type spaceDim  = hexBasis.getBaseCellTopology().getDimension();

        // exception 1 - 2: CURL and DIV is not supported. 
        {
          DynRankView ConstructWithLabel(vals, numFields, numPoints, 3);
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(vals, hexNodes, OPERATOR_CURL) );
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(vals, hexNodes, OPERATOR_DIV) );
        }

        // Exceptions 3-7: all bf tags/bf Ids below are wrong and should cause getDofOrdinal() and 
        // getDofTag() to access invalid array elements thereby causing bounds check exception
        {
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getDofOrdinal(3,10,0) );
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getDofOrdinal(1,2,3) );
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getDofOrdinal(0,4,1) );
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getDofTag(numFields) );
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getDofTag(-1) );
        }

        // Exceptions 8-18 test exception handling with incorrectly dimensioned input/output arrays
        // exception #8: input points array must be of rank-2
        {          
          DynRankView ConstructWithLabel(vals, numFields, numPoints);
          {
            // exception #8: input points array must be of rank-2
            DynRankView ConstructWithLabel(badPoints, 4, 5, 3);
            INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(vals, badPoints, OPERATOR_VALUE) );
          }
          {
            // exception #9: dimension 1 in the input point array must equal space dimension of the cell
            DynRankView ConstructWithLabel(badPoints, 4, 4);
            INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(vals, badPoints, OPERATOR_VALUE) );
          }
          {
            // exception #10: output values must be of rank-2 for OPERATOR_VALUE
            DynRankView ConstructWithLabel(badVals, 4, 3, 1);
            INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(badVals, hexNodes, OPERATOR_VALUE) );
          }
          {
            DynRankView ConstructWithLabel(badVals, 4, 3);

            // exception #11: output values must be of rank-3 for OPERATOR_GRAD
            INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(badVals, hexNodes, OPERATOR_GRAD) );

            // exception #12: output values must be of rank-3 for OPERATOR_CURL
            INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(badVals, hexNodes, OPERATOR_D1) );

            // exception #13: output values must be of rank-3 for OPERATOR_D2
            INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(badVals, hexNodes, OPERATOR_D2) );
          }
        }
        {
          // exception #14: incorrect 0th dimension of output array (must equal number of basis functions)
          DynRankView ConstructWithLabel(badVals, hexBasis.getCardinality() + 1, hexNodes.dimension(0));
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(badVals, hexNodes, OPERATOR_VALUE) );
        }
        {
          // exception #15: incorrect 1st dimension of output array (must equal number of points)
          DynRankView ConstructWithLabel(badVals, hexBasis.getCardinality(), hexNodes.dimension(0) + 1);
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(badVals, hexNodes, OPERATOR_VALUE) );
        }
        {
          // exception #16: incorrect 2nd dimension of output array (must equal spatial dimension)
          DynRankView ConstructWithLabel(badVals, hexBasis.getCardinality(), hexNodes.dimension(0), 2);
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(badVals, hexNodes, OPERATOR_GRAD) );
        }
        {
          DynRankView ConstructWithLabel(badVals, hexBasis.getCardinality(), hexNodes.dimension(0), 40);

          // exception #17: incorrect 2nd dimension of output array (must equal spatial dimension)
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(badVals, hexNodes, OPERATOR_D2) );

          // exception #18: incorrect 2nd dimension of output array (must equal spatial dimension)
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(badVals, hexNodes, OPERATOR_D3) );
        }
#endif
        if (nthrow != ncatch) {
          errorFlag++;
          *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
          *outStream << "# of catch ("<< ncatch << ") is different from # of throw (" << nthrow << ")\n";
        }
      } catch (std::exception err) {
        *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
        *outStream << err.what() << '\n';
        *outStream << "-------------------------------------------------------------------------------" << "\n\n";
        errorFlag = -1000;
      };

      *outStream                                
        << "\n"
        << "===============================================================================\n" 
        << "| TEST 2: correctness of tag to enum and enum to tag lookups                  |\n" 
        << "===============================================================================\n";
      
      try {

        const ordinal_type order = 5;
        HexBasisType hexBasis(order);

        const ordinal_type numFields = hexBasis.getCardinality();
        const auto allTags = hexBasis.getAllDofTags();

        // Loop over all tags, lookup the associated dof enumeration and then lookup the tag again
        const ordinal_type dofTagSize = allTags.dimension(0);
        for (ordinal_type i=0;i<dofTagSize;++i) {
          const auto bfOrd = hexBasis.getDofOrdinal(allTags(i,0), allTags(i,1), allTags(i,2));

          const auto myTag = hexBasis.getDofTag(bfOrd);
          if( !( (myTag(0) == allTags(i,0)) &&
                 (myTag(1) == allTags(i,1)) &&
                 (myTag(2) == allTags(i,2)) &&
                 (myTag(3) == allTags(i,3)) ) ) {
            errorFlag++;
            *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
            *outStream << " getDofOrdinal( {"
                       << allTags(i,0) << ", "
                       << allTags(i,1) << ", "
                       << allTags(i,2) << ", "
                       << allTags(i,3) << "}) = " << bfOrd <<" but \n";
            *outStream << " getDofTag(" << bfOrd << ") = { "
                       << myTag(0) << ", "
                       << myTag(1) << ", "
                       << myTag(2) << ", "
                       << myTag(3) << "}\n";
          }
        }
        // Now do the same but loop over basis functions
        for(ordinal_type bfOrd=0;bfOrd<numFields;++bfOrd) {
          const auto myTag  = hexBasis.getDofTag(bfOrd);
          const auto myBfOrd = hexBasis.getDofOrdinal(myTag(0), myTag(1), myTag(2));
          if( bfOrd != myBfOrd) {
            errorFlag++;
            *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
            *outStream << " getDofTag(" << bfOrd << ") = { "
                       << myTag(0) << ", "
                       << myTag(1) << ", "
                       << myTag(2) << ", "
                       << myTag(3) << "} but getDofOrdinal({"
                       << myTag(0) << ", "
                       << myTag(1) << ", "
                       << myTag(2) << ", "
                       << myTag(3) << "} ) = " << myBfOrd << "\n";
          }
        }
      } catch (std::exception err) {
        *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
        *outStream << err.what() << '\n';
        *outStream << "-------------------------------------------------------------------------------" << "\n\n";
        errorFlag = -1000;
      };
      
      *outStream      
        << "\n"
        << "===============================================================================\n"
        << "| TEST 3: correctness of basis function values                                |\n"
        << "===============================================================================\n";
      
      outStream -> precision(20);
      
      // VALUE: Each row gives the 27 correct basis set values at an evaluation point
      const ValueType basisValues[] = {
        1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.000  };

      // GRAD, D1, D2, D3 and D4 test values are stored in files due to their large size
      std::string     fileName;
      std::ifstream   dataFile;
      
      // GRAD and D1 values are stored in (F,P,D) format in a data file. Read file and do the test
      std::vector<ValueType> basisGrads;           // Flat array for the gradient values.
      {
        fileName = "../testdata/HEX_C2_GradVals.dat";
        dataFile.open(fileName.c_str());
        INTREPID2_TEST_FOR_EXCEPTION( !dataFile.good(), std::logic_error,
                                      ">>> ERROR (HGRAD_HEX_C2/test01): could not open GRAD values data file, test aborted.");
        while (!dataFile.eof() ){
          double temp;
          std::string line;                       // string for one line of input file
          std::getline(dataFile, line);           // get next line from file
          std::stringstream data_line(line);      // convert to stringstream
          while(data_line >> temp){               // extract value from line
            basisGrads.push_back(temp);           // push into vector
          }
        }
        dataFile.close();
        dataFile.clear();
      }

      //D2: flat array with the values of D2 applied to basis functions. Multi-index is (F,P,D2cardinality)
      std::vector<ValueType> basisD2; 
      {
        fileName = "../testdata/HEX_C2_D2Vals.dat";  
        dataFile.open(fileName.c_str());
        INTREPID2_TEST_FOR_EXCEPTION( !dataFile.good(), std::logic_error,
                                      ">>> ERROR (HGRAD_HEX_C2/test01): could not open D2 values data file, test aborted.");
        while (!dataFile.eof() ){
          double temp;
          std::string line;                       // string for one line of input file
          std::getline(dataFile, line);           // get next line from file
          std::stringstream data_line(line);      // convert to stringstream
          while(data_line >> temp){               // extract value from line
            basisD2.push_back(temp);              // push into vector
          }
        }
        dataFile.close();
        dataFile.clear();
      }

      //D3: flat array with the values of D3 applied to basis functions. Multi-index is (F,P,D3cardinality)
      std::vector<ValueType> basisD3;
      {
        fileName = "../testdata/HEX_C2_D3Vals.dat";  
        dataFile.open(fileName.c_str());
        TEUCHOS_TEST_FOR_EXCEPTION( !dataFile.good(), std::logic_error,
                                    ">>> ERROR (HGRAD_HEX_C2/test01): could not open D3 values data file, test aborted.");
  
        while (!dataFile.eof() ){
          double temp;
          std::string line;                            // string for one line of input file
          std::getline(dataFile, line);           // get next line from file
          std::stringstream data_line(line);           // convert to stringstream
          while(data_line >> temp){               // extract value from line
            basisD3.push_back(temp);              // push into vector
          }
        }
        dataFile.close();
        dataFile.clear();
      }
  
      //D4: flat array with the values of D applied to basis functions. Multi-index is (F,P,D4cardinality)
      std::vector<double> basisD4;
      {
        fileName = "../testdata/HEX_C2_D4Vals.dat";
        dataFile.open(fileName.c_str());
        TEUCHOS_TEST_FOR_EXCEPTION( !dataFile.good(), std::logic_error,
                                    ">>> ERROR (HGRAD_HEX_C2/test01): could not open D4 values data file, test aborted.");
        
        while (!dataFile.eof() ){
          double temp;
          std::string line;                            // string for one line of input file
          std::getline(dataFile, line);           // get next line from file
          std::stringstream data_line(line);           // convert to stringstream
          while(data_line >> temp){               // extract value from line
            basisD4.push_back(temp);              // push into vector
          }
        }
        dataFile.close();
        dataFile.clear();
      }

      try{
        const ordinal_type order = 2;
        HexBasisType hexBasis(order);

        DynRankViewHost ConstructWithLabel(hexNodesHost, 27, 3);

        // do it lexicographically as a lattice
        hexNodesHost(0, 0) = -1.0;   hexNodesHost(0, 1) = -1.0;  hexNodesHost(0, 2) = -1.0;
        hexNodesHost(1, 0) =  0.0;   hexNodesHost(1, 1) = -1.0;  hexNodesHost(1, 2) = -1.0;
        hexNodesHost(2, 0) =  1.0;   hexNodesHost(2, 1) = -1.0;  hexNodesHost(2, 2) = -1.0;
        hexNodesHost(3, 0) = -1.0;   hexNodesHost(3, 1) =  0.0;  hexNodesHost(3, 2) = -1.0;
        hexNodesHost(4, 0) =  0.0;   hexNodesHost(4, 1) =  0.0;  hexNodesHost(4, 2) = -1.0;
        hexNodesHost(5, 0) =  1.0;   hexNodesHost(5, 1) =  0.0;  hexNodesHost(5, 2) = -1.0;
        hexNodesHost(6, 0) = -1.0;   hexNodesHost(6, 1) =  1.0;  hexNodesHost(6, 2) = -1.0;
        hexNodesHost(7, 0) = 0.0;    hexNodesHost(7, 1) =  1.0;  hexNodesHost(7, 2) = -1.0;
        hexNodesHost(8, 0) = 1.0;    hexNodesHost(8, 1) =  1.0;  hexNodesHost(8, 2) = -1.0;
        hexNodesHost(9, 0) = -1.0;   hexNodesHost(9, 1) = -1.0;  hexNodesHost(9, 2) = 0.0;
        hexNodesHost(10, 0) =  0.0;   hexNodesHost(10, 1) = -1.0;  hexNodesHost(10, 2) = 0.0;
        hexNodesHost(11, 0) =  1.0;   hexNodesHost(11, 1) = -1.0;  hexNodesHost(11, 2) = 0.0;
        hexNodesHost(12, 0) = -1.0;   hexNodesHost(12, 1) =  0.0;  hexNodesHost(12, 2) = 0.0;
        hexNodesHost(13, 0) =  0.0;   hexNodesHost(13, 1) =  0.0;  hexNodesHost(13, 2) = 0.0;
        hexNodesHost(14, 0) =  1.0;   hexNodesHost(14, 1) =  0.0;  hexNodesHost(14, 2) = 0.0;
        hexNodesHost(15, 0) = -1.0;   hexNodesHost(15, 1) =  1.0;  hexNodesHost(15, 2) = 0.0;
        hexNodesHost(16, 0) = 0.0;    hexNodesHost(16, 1) =  1.0;  hexNodesHost(16, 2) = 0.0;
        hexNodesHost(17, 0) = 1.0;    hexNodesHost(17, 1) =  1.0;  hexNodesHost(17, 2) = 0.0;
        hexNodesHost(18, 0) = -1.0;   hexNodesHost(18, 1) = -1.0;  hexNodesHost(18, 2) = 1.0;
        hexNodesHost(19, 0) =  0.0;   hexNodesHost(19, 1) = -1.0;  hexNodesHost(19, 2) = 1.0;
        hexNodesHost(20, 0) =  1.0;   hexNodesHost(20, 1) = -1.0;  hexNodesHost(20, 2) = 1.0;
        hexNodesHost(21, 0) = -1.0;   hexNodesHost(21, 1) =  0.0;  hexNodesHost(21, 2) = 1.0;
        hexNodesHost(22, 0) =  0.0;   hexNodesHost(22, 1) =  0.0;  hexNodesHost(22, 2) = 1.0;
        hexNodesHost(23, 0) =  1.0;   hexNodesHost(23, 1) =  0.0;  hexNodesHost(23, 2) = 1.0;
        hexNodesHost(24, 0) = -1.0;   hexNodesHost(24, 1) =  1.0;  hexNodesHost(24, 2) = 1.0;
        hexNodesHost(25, 0) = 0.0;    hexNodesHost(25, 1) =  1.0;  hexNodesHost(25, 2) = 1.0;
        hexNodesHost(26, 0) = 1.0;    hexNodesHost(26, 1) =  1.0;  hexNodesHost(26, 2) = 1.0;
        
        auto hexNodes = Kokkos::create_mirror_view(typename DeviceSpaceType::memory_space(), hexNodesHost);
        Kokkos::deep_copy(hexNodes, hexNodesHost);

        // Dimensions for the output arrays:
        const ordinal_type numFields = hexBasis.getCardinality();
        const ordinal_type numPoints = hexNodes.dimension(0);
        const ordinal_type spaceDim  = hexBasis.getBaseCellTopology().getDimension();
        const ordinal_type D2Cardin  = getDkCardinality(OPERATOR_D2, spaceDim);
        const ordinal_type D3Cardin  = getDkCardinality(OPERATOR_D3, spaceDim);
        const ordinal_type D4Cardin  = getDkCardinality(OPERATOR_D4, spaceDim);

        *outStream << " -- Testing OPERATOR_VALUE \n";
        {
          // Check VALUE of basis functions: resize vals to rank-2 container:
          DynRankView ConstructWithLabel(vals, numFields, numPoints);
          hexBasis.getValues(vals, hexNodes, OPERATOR_VALUE);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);
          for (ordinal_type i = 0; i < numFields; ++i) {
            for (ordinal_type j = 0; j < numPoints; ++j) {

              // Compute offset for (F,P) container
              const ordinal_type l = j + i * numPoints;
              if (std::abs(vals_host(i,j) - basisValues[l]) > tol) {
                errorFlag++;
                *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                // Output the multi-index of the value where the error is:
                *outStream << " At multi-index { ";
                *outStream << i << " ";*outStream << j << " ";
                *outStream << "}  computed value: " << vals_host(i,j)
                           << " but reference value: " << basisValues[l] << "\n";
              }
            }
          }
        }
    
        *outStream << " -- Testing OPERATOR_GRAD \n";
        {
          // Check GRAD of basis function: resize vals to rank-3 container
          DynRankView ConstructWithLabel(vals, numFields, numPoints, spaceDim);
          hexBasis.getValues(vals, hexNodes, OPERATOR_GRAD);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);
          for (ordinal_type i = 0; i < numFields; ++i) {
            for (ordinal_type j = 0; j < numPoints; ++j) {
              for (ordinal_type k = 0; k < spaceDim; ++k) {

                // basisGrads is (F,P,D), compute offset:
                const ordinal_type l = k + j * spaceDim + i * spaceDim * numPoints;
                if (std::abs(vals_host(i,j,k) - basisGrads[l]) > tol) {
                  errorFlag++;
                  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                  // Output the multi-index of the value where the error is:
                  *outStream << " At multi-index { ";
                  *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
                  *outStream << "}  computed grad component: " << vals_host(i,j,k)
                             << " but reference grad component: " << basisGrads[l] << "\n";
                }
              }
            }
          }
        }

        *outStream << " -- Testing OPERATOR_D1 \n";
        {
          // Check GRAD of basis function: resize vals to rank-3 container
          DynRankView ConstructWithLabel(vals, numFields, numPoints, spaceDim);
          hexBasis.getValues(vals, hexNodes, OPERATOR_D1);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);
          for (ordinal_type i = 0; i < numFields; ++i) {
            for (ordinal_type j = 0; j < numPoints; ++j) {
              for (ordinal_type k = 0; k < spaceDim; ++k) {

                // basisGrads is (F,P,D), compute offset:
                const ordinal_type l = k + j * spaceDim + i * spaceDim * numPoints;
                if (std::abs(vals_host(i,j,k) - basisGrads[l]) > tol) {
                  errorFlag++;
                  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                  // Output the multi-index of the value where the error is:
                  *outStream << " At multi-index { ";
                  *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
                  *outStream << "}  computed grad component: " << vals_host(i,j,k)
                             << " but reference grad component: " << basisGrads[l] << "\n";
                }
              }
            }
          }
        }

        *outStream << " -- Testing OPERATOR_D2 \n";
        {
          // Check GRAD of basis function: resize vals to rank-3 container
          DynRankView ConstructWithLabel(vals, numFields, numPoints, D2Cardin);
          hexBasis.getValues(vals, hexNodes, OPERATOR_D2);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);
          for (ordinal_type i = 0; i < numFields; ++i) {
            for (ordinal_type j = 0; j < numPoints; ++j) {
              for (ordinal_type k = 0; k < D2Cardin; ++k) {

                // basisGrads is (F,P,D), compute offset:
                const ordinal_type l = k + j * D2Cardin + i * D2Cardin * numPoints;
                if (std::abs(vals_host(i,j,k) - basisD2[l]) > tol) {
                  errorFlag++;
                  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                  // Output the multi-index of the value where the error is:
                  *outStream << " At multi-index { ";
                  *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
                  *outStream << "}  computed grad component: " << vals_host(i,j,k)
                             << " but reference grad component: " << basisD2[l] << "\n";
                }
              }
            }
          }
        }
    
        *outStream << " -- Testing OPERATOR_D3 \n";
        {
          // Check GRAD of basis function: resize vals to rank-3 container
          DynRankView ConstructWithLabel(vals, numFields, numPoints, D3Cardin);
          hexBasis.getValues(vals, hexNodes, OPERATOR_D3);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);
          for (ordinal_type i = 0; i < numFields; ++i) {
            for (ordinal_type j = 0; j < numPoints; ++j) {
              for (ordinal_type k = 0; k < D3Cardin; ++k) {

                // basisGrads is (F,P,D), compute offset:
                const ordinal_type l = k + j * D3Cardin + i * D3Cardin * numPoints;
                if (std::abs(vals_host(i,j,k) - basisD3[l]) > tol) {
                  errorFlag++;
                  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                  // Output the multi-index of the value where the error is:
                  *outStream << " At multi-index { ";
                  *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
                  *outStream << "}  computed grad component: " << vals_host(i,j,k)
                             << " but reference grad component: " << basisD3[l] << "\n";
                }
              }
            }
          }
        }
    
        *outStream << " -- Testing OPERATOR_D4 \n";
        {
          // Check GRAD of basis function: resize vals to rank-3 container
          DynRankView ConstructWithLabel(vals, numFields, numPoints, D4Cardin);
          hexBasis.getValues(vals, hexNodes, OPERATOR_D4);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);
          for (ordinal_type i = 0; i < numFields; ++i) {
            for (ordinal_type j = 0; j < numPoints; ++j) {
              for (ordinal_type k = 0; k < D4Cardin; ++k) {

                // basisGrads is (F,P,D), compute offset:
                const ordinal_type l = k + j * D4Cardin + i * D4Cardin * numPoints;
                if (std::abs(vals_host(i,j,k) - basisD4[l]) > tol) {
                  errorFlag++;
                  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                  // Output the multi-index of the value where the error is:
                  *outStream << " At multi-index { ";
                  *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
                  *outStream << "}  computed grad component: " << vals_host(i,j,k)
                             << " but reference grad component: " << basisD4[l] << "\n";
                }
              }
            }
          }
        }

        // // Check D7 to D10 - must be zero. This basis does not cover D5 and D6
        const EOperator ops[4] = { OPERATOR_D7,
                                   OPERATOR_D8,
                                   OPERATOR_D9,
                                   OPERATOR_D10 };
        
        for (ordinal_type oid=0;oid<4;++oid) {
          *outStream << " -- Testing OPERATOR_D" << (oid+7) << "\n";
          const auto op = ops[oid];
          const ordinal_type DkCardin = Intrepid2::getDkCardinality(op, spaceDim);
          
          DynRankView ConstructWithLabel(vals, numFields, numPoints, DkCardin);
          hexBasis.getValues(vals, hexNodes, op);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);
          for (ordinal_type i = 0; i < numFields; ++i) {
            for (ordinal_type j = 0; j < numPoints; ++j) {
              for (ordinal_type k = 0; k < DkCardin; ++k) {
                // basisGrads is (F,P,D), compute offset:
                if (std::abs(vals_host(i,j,k)) > tol) {
                  errorFlag++;
                  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
                  
                  // Output the multi-index of the value where the error is:
                  *outStream << " At multi-index { ";
                  *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
                  *outStream << "}  computed grad component: " << vals_host(i,j,k)
                             << " but reference grad component: 0.0\n";
                }
              }
            }
          }
        }
      } catch (std::exception err) {
        *outStream << err.what() << "\n\n";
        errorFlag = -1000;
      };

      if (errorFlag != 0)
        std::cout << "End Result: TEST FAILED\n";
      else
        std::cout << "End Result: TEST PASSED\n";
      
      // reset format state of std::cout
      std::cout.copyfmt(oldFormatState);

      return errorFlag;
    }
Beispiel #14
0
    int HGRAD_WEDGE_C2_FEM_Test01(const bool verbose) {
      
      Teuchos::RCP<std::ostream> outStream;
      Teuchos::oblackholestream bhs; // outputs nothing
      
      if (verbose)
        outStream = Teuchos::rcp(&std::cout, false);
      else
        outStream = Teuchos::rcp(&bhs,       false);

      Teuchos::oblackholestream oldFormatState;
      oldFormatState.copyfmt(std::cout);

      typedef typename
        Kokkos::Impl::is_space<DeviceSpaceType>::host_mirror_space::execution_space HostSpaceType ;

      *outStream << "DeviceSpace::  "; DeviceSpaceType::print_configuration(*outStream, false);
      *outStream << "HostSpace::    ";   HostSpaceType::print_configuration(*outStream, false);

      *outStream                                                       
        << "===============================================================================\n"
        << "|                                                                             |\n"
        << "|                 Unit Test (Basis_HGRAD_WEDGE_C2_FEM)                        |\n"
        << "|                                                                             |\n"
        << "|     1) Conversion of Dof tags into Dof ordinals and back                    |\n"
        << "|     2) Basis values for VALUE, GRAD, and Dk operators                       |\n"
        << "|                                                                             |\n"
        << "|  Questions? Contact  Pavel Bochev  ([email protected]),                    |\n"
        << "|                      Denis Ridzal  ([email protected]),                    |\n"
        << "|                      Kara Peterson ([email protected]),                    |\n"
        << "|                      Kyungjoo Kim  ([email protected]).                     |\n"
        << "|                                                                             |\n"
        << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n"
        << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n"
        << "|                                                                             |\n"
        << "===============================================================================\n";

      typedef Kokkos::DynRankView<ValueType,DeviceSpaceType> DynRankView;
      typedef Kokkos::DynRankView<ValueType,HostSpaceType>   DynRankViewHost;
#define ConstructWithLabel(obj, ...) obj(#obj, __VA_ARGS__)

      const ValueType tol = tolerence();
      int errorFlag = 0;

      // for virtual function, value and point types are declared in the class
      typedef ValueType outputValueType;
      typedef ValueType pointValueType;
      Basis_HGRAD_WEDGE_C2_FEM<DeviceSpaceType,outputValueType,pointValueType> wedgeBasis;

      *outStream
        << "\n"
        << "===============================================================================\n"
        << "| TEST 1: constructors and exceptions                                         |\n"
        << "===============================================================================\n";


      try {
        ordinal_type nthrow = 0, ncatch = 0;
#ifdef HAVE_INTREPID2_DEBUG

        // Define array containing the 4 vertices of the reference WEDGE and its center.
        DynRankView ConstructWithLabel(wedgeNodes, 18, 3);

        // Generic array for the output values; needs to be properly resized depending on the operator type
        const ordinal_type numFields = wedgeBasis.getCardinality();
        const ordinal_type numPoints = wedgeNodes.extent(0);
        const ordinal_type spaceDim  = wedgeBasis.getBaseCellTopology().getDimension();

        DynRankView vals("vals", numFields, numPoints);
        DynRankView vals_vec("vals", numFields, numPoints, spaceDim);

        {
          // exception #1: CURL cannot be applied to scalar functions
          INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(vals_vec, wedgeNodes, OPERATOR_DIV) );

          // exception #2: DIV cannot be applied to scalar functions
          INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(vals_vec, wedgeNodes, OPERATOR_DIV) );
        }

        // Exceptions 3-7: all bf tags/bf Ids below are wrong and should cause getDofOrdinal() and 
        // getDofTag() to access invalid array elements thereby causing bounds check exception
        {
          // exception #3
          INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getDofOrdinal(3,0,0) );
          // exception #4
          INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getDofOrdinal(1,1,1) );
          // exception #5
          INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getDofOrdinal(0,9,0) );
          // exception #6
          INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getDofTag(numFields) );
          // exception #7
          INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getDofTag(-1) );
        }
        // Exceptions 8-18 test exception handling with incorrectly dimensioned input/output arrays
        {
          // exception #8: input points array must be of rank-2
          DynRankView ConstructWithLabel( badPoints1, 4, 5, 3);
          INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(vals, badPoints1, OPERATOR_VALUE) );
        }
        {
          // exception #9 dimension 1 in the input point array must equal space dimension of the cell
          DynRankView ConstructWithLabel( badPoints2, 4, spaceDim + 1);
          INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(vals, badPoints2, OPERATOR_VALUE) );
        }
        {
          // exception #10 output values must be of rank-2 for OPERATOR_VALUE
          DynRankView ConstructWithLabel( badVals1, 4, 3, 1);
          INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(badVals1, wedgeNodes, OPERATOR_VALUE) );
        }
        {
          // exception #11 output values must be of rank-3 for OPERATOR_GRAD
          DynRankView ConstructWithLabel( badVals2, 4, 3);
          INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(badVals2, wedgeNodes, OPERATOR_GRAD) );

          // exception #12 output values must be of rank-3 for OPERATOR_D1
          INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(badVals2, wedgeNodes, OPERATOR_D1) );
    
          // exception #13 output values must be of rank-3 for OPERATOR_D2
          INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(badVals2, wedgeNodes, OPERATOR_D2) );
        }
        {
          // exception #14 incorrect 0th dimension of output array (must equal number of basis functions)
          DynRankView ConstructWithLabel( badVals3, numFields + 1, numPoints);
          INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(badVals3, wedgeNodes, OPERATOR_VALUE) );
        }
        {
          // exception #15 incorrect 1st dimension of output array (must equal number of points)
          DynRankView ConstructWithLabel( badVals4, numFields, numPoints + 1);
          INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(badVals4, wedgeNodes, OPERATOR_VALUE) );
        }
        {
          // exception #16: incorrect 2nd dimension of output array (must equal the space dimension)
          DynRankView ConstructWithLabel( badVals5, numFields, numPoints, spaceDim - 1);
          INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(badVals5, wedgeNodes, OPERATOR_GRAD) );
        }
        {
          // exception #17: incorrect 2nd dimension of output array (must equal D2 cardinality in 3D)
          DynRankView ConstructWithLabel( badVals6, numFields, numPoints, 40);
          INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(badVals6, wedgeNodes, OPERATOR_D2) );
          // exception #18: incorrect 2nd dimension of output array (must equal D3 cardinality in 3D)
          INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(badVals6, wedgeNodes, OPERATOR_D3) );
        }
#endif
        if (nthrow != ncatch) {
          errorFlag++;
          *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
          *outStream << "# of catch ("<< ncatch << ") is different from # of throw (" << ncatch << ")\n";
        }
      } catch (std::exception err) {
        *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
        *outStream << err.what() << '\n';
        *outStream << "-------------------------------------------------------------------------------" << "\n\n";
        errorFlag = -1000;
      }
      
      *outStream
        << "\n"
        << "===============================================================================\n"
        << "| TEST 2: correctness of tag to enum and enum to tag lookups                  |\n"
        << "===============================================================================\n";
  
      try {
        const ordinal_type numFields = wedgeBasis.getCardinality();
        const auto allTags = wedgeBasis.getAllDofTags();

        // Loop over all tags, lookup the associated dof enumeration and then lookup the tag again
        const ordinal_type dofTagSize = allTags.extent(0);
        for (ordinal_type i=0;i<dofTagSize;++i) {
          const auto bfOrd = wedgeBasis.getDofOrdinal(allTags(i,0), allTags(i,1), allTags(i,2));
          
          const auto myTag = wedgeBasis.getDofTag(bfOrd);
          if( !( (myTag(0) == allTags(i,0)) &&
                 (myTag(1) == allTags(i,1)) &&
                 (myTag(2) == allTags(i,2)) &&
                 (myTag(3) == allTags(i,3)) ) ) {
            errorFlag++;
            *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
            *outStream << " getDofOrdinal( {"
                       << allTags(i,0) << ", "
                       << allTags(i,1) << ", "
                       << allTags(i,2) << ", "
                       << allTags(i,3) << "}) = " << bfOrd <<" but \n";
            *outStream << " getDofTag(" << bfOrd << ") = { "
                       << myTag(0) << ", "
                       << myTag(1) << ", "
                       << myTag(2) << ", "
                       << myTag(3) << "}\n";
          }
        }
        
        // Now do the same but loop over basis functions
        for (ordinal_type bfOrd=0;bfOrd<numFields;++bfOrd) {
          const auto myTag = wedgeBasis.getDofTag(bfOrd);
          
          const auto myBfOrd = wedgeBasis.getDofOrdinal(myTag(0), myTag(1), myTag(2));
          if( bfOrd != myBfOrd) {
            errorFlag++;
            *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
            *outStream << " getDofTag(" << bfOrd << ") = { "
                       << myTag(0) << ", "
                       << myTag(1) << ", "
                       << myTag(2) << ", "
                       << myTag(3) << "} but getDofOrdinal({"
                       << myTag(0) << ", "
                       << myTag(1) << ", "
                       << myTag(2) << ", "
                       << myTag(3) << "} ) = " << myBfOrd << "\n";
          }
        }
      } catch (std::logic_error err) {
        *outStream << err.what() << "\n\n";
        errorFlag = -1000;
      }

      *outStream
        << "\n"
        << "===============================================================================\n"
        << "| TEST 3: correctness of basis function values                                |\n"
        << "===============================================================================\n";
      
      outStream -> precision(20);
  
      // VALUE: correct basis function values in (F,P) format
      const ValueType basisValues[] = {
        1.00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00, 0, \
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00, 0, 0, 0, 0, \
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00, 0, 0, 0, 0, 0, 0, 0, \
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
        0, 0, 0, 0, 0, 0, 0, 0, 1.00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
        0, 0, 0, 0, 0, 1.00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
        0, 0, 1.00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
        1.00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00, 0, \
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00, 0, 0, 0, 0, \
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00, 0, 0, 0, 0, 0, 0, 0, \
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
        0, 0, 0, 0, 0, 0, 0, 0, 1.00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
        0, 0, 0, 0, 0, 1.00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
        0, 0, 1.00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
        1.00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00  };

      // GRAD and D1 values are stored in (F,P,D) format in a data file. Read file and do the test     
      std::vector<ValueType> basisGrads;           // Flat array for the gradient values.
      { 
        std::ifstream dataFile("../testdata/WEDGE_C2_GradVals.dat");
        
        INTREPID2_TEST_FOR_EXCEPTION( !dataFile.good(), std::logic_error,
                                      ">>> ERROR (HGRAD_WEDGE_C2/test01): could not open GRAD values data file, test aborted.");
        while (!dataFile.eof() ){
          ValueType temp;
          std::string line;                            // string for one line of input file
          std::getline(dataFile, line);           // get next line from file
          std::stringstream data_line(line);           // convert to stringstream
          while (data_line >> temp)               // extract value from line
            basisGrads.push_back(temp);           // push into vector
        }
      }
  
      //D2: flat array with the values of D2 applied to basis functions. Multi-index is (F,P,D2cardinality)
      std::vector<ValueType> basisD2;
      { 
        std::ifstream dataFile("../testdata/WEDGE_C2_D2Vals.dat");
        
        INTREPID2_TEST_FOR_EXCEPTION( !dataFile.good(), std::logic_error,
                                      ">>> ERROR (HGRAD_WEDGE_C2/test01): could not open D2 values data file, test aborted.");
        while (!dataFile.eof() ){
          ValueType temp;
          std::string line;                            // string for one line of input file
          std::getline(dataFile, line);           // get next line from file
          std::stringstream data_line(line);           // convert to stringstream
          while (data_line >> temp)               // extract value from line
            basisD2.push_back(temp);           // push into vector
        }
      }

      //D3: flat array with the values of D3 applied to basis functions. Multi-index is (F,P,D3cardinality)
      std::vector<ValueType> basisD3;
      { 
        std::ifstream dataFile("../testdata/WEDGE_C2_D3Vals.dat");
        
        INTREPID2_TEST_FOR_EXCEPTION( !dataFile.good(), std::logic_error,
                                      ">>> ERROR (HGRAD_WEDGE_C2/test01): could not open D3 values data file, test aborted.");
        while (!dataFile.eof() ){
          ValueType temp;
          std::string line;                            // string for one line of input file
          std::getline(dataFile, line);           // get next line from file
          std::stringstream data_line(line);           // convert to stringstream
          while (data_line >> temp)               // extract value from line
            basisD3.push_back(temp);           // push into vector
        }
      }
  
      //D4: flat array with the values of D3 applied to basis functions. Multi-index is (F,P,D4cardinality)
      std::vector<ValueType> basisD4;
      { 
        std::ifstream dataFile("../testdata/WEDGE_C2_D4Vals.dat");
        
        INTREPID2_TEST_FOR_EXCEPTION( !dataFile.good(), std::logic_error,
                                      ">>> ERROR (HGRAD_WEDGE_C2/test01): could not open D4 values data file, test aborted.");
        while (!dataFile.eof() ){
          ValueType temp;
          std::string line;                            // string for one line of input file
          std::getline(dataFile, line);           // get next line from file
          std::stringstream data_line(line);           // convert to stringstream
          while (data_line >> temp)               // extract value from line
            basisD4.push_back(temp);           // push into vector
        }
      }
      
      try {
        DynRankViewHost ConstructWithLabel(wedgeNodesHost, 18, 3);

        wedgeNodesHost(0,0) =  0.0;  wedgeNodesHost(0,1) =  0.0;  wedgeNodesHost(0,2) = -1.0;  
        wedgeNodesHost(1,0) =  1.0;  wedgeNodesHost(1,1) =  0.0;  wedgeNodesHost(1,2) = -1.0;  
        wedgeNodesHost(2,0) =  0.0;  wedgeNodesHost(2,1) =  1.0;  wedgeNodesHost(2,2) = -1.0;
        wedgeNodesHost(3,0) =  0.0;  wedgeNodesHost(3,1) =  0.0;  wedgeNodesHost(3,2) =  1.0;  
        wedgeNodesHost(4,0) =  1.0;  wedgeNodesHost(4,1) =  0.0;  wedgeNodesHost(4,2) =  1.0;  
        wedgeNodesHost(5,0) =  0.0;  wedgeNodesHost(5,1) =  1.0;  wedgeNodesHost(5,2) =  1.0;
        
        wedgeNodesHost(6,0) =  0.5;  wedgeNodesHost(6,1) =  0.0;  wedgeNodesHost(6,2) = -1.0;  
        wedgeNodesHost(7,0) =  0.5;  wedgeNodesHost(7,1) =  0.5;  wedgeNodesHost(7,2) = -1.0;  
        wedgeNodesHost(8,0) =  0.0;  wedgeNodesHost(8,1) =  0.5;  wedgeNodesHost(8,2) = -1.0;
        wedgeNodesHost(9,0) =  0.0;  wedgeNodesHost(9,1) =  0.0;  wedgeNodesHost(9,2) =  0.0;
        wedgeNodesHost(10,0)=  1.0;  wedgeNodesHost(10,1)=  0.0;  wedgeNodesHost(10,2)=  0.0;  
        wedgeNodesHost(11,0)=  0.0;  wedgeNodesHost(11,1)=  1.0;  wedgeNodesHost(11,2)=  0.0;  
        
        wedgeNodesHost(12,0)=  0.5;  wedgeNodesHost(12,1)=  0.0;  wedgeNodesHost(12,2)=  1.0;  
        wedgeNodesHost(13,0)=  0.5;  wedgeNodesHost(13,1)=  0.5;  wedgeNodesHost(13,2)=  1.0;  
        wedgeNodesHost(14,0)=  0.0;  wedgeNodesHost(14,1)=  0.5;  wedgeNodesHost(14,2)=  1.0;  
        wedgeNodesHost(15,0)=  0.5;  wedgeNodesHost(15,1)=  0.0;  wedgeNodesHost(15,2)=  0.0;  
        wedgeNodesHost(16,0)=  0.5;  wedgeNodesHost(16,1)=  0.5;  wedgeNodesHost(16,2)=  0.0;  
        wedgeNodesHost(17,0)=  0.0;  wedgeNodesHost(17,1)=  0.5;  wedgeNodesHost(17,2)=  0.0;  
        
        auto wedgeNodes = Kokkos::create_mirror_view(typename DeviceSpaceType::memory_space(), wedgeNodesHost);
        Kokkos::deep_copy(wedgeNodes, wedgeNodesHost);

        // Dimensions for the output arrays:
        const ordinal_type numFields = wedgeBasis.getCardinality();
        const ordinal_type numPoints = wedgeNodes.extent(0);
        const ordinal_type spaceDim  = wedgeBasis.getBaseCellTopology().getDimension();
        const ordinal_type D2Cardin  = getDkCardinality(OPERATOR_D2, spaceDim);
        const ordinal_type D3Cardin  = getDkCardinality(OPERATOR_D3, spaceDim);
        const ordinal_type D4Cardin  = getDkCardinality(OPERATOR_D4, spaceDim);

        // Check VALUE of basis functions: resize vals to rank-2 container:
        {
          DynRankView vals = DynRankView("vals", numFields, numPoints);
          wedgeBasis.getValues(vals, wedgeNodes, OPERATOR_VALUE);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);
          for (ordinal_type i = 0; i < numFields; ++i) {
            for (ordinal_type j = 0; j < numPoints; ++j) {
              const ordinal_type l =  i + j * numFields;
              if (std::abs(vals_host(i,j) - basisValues[l]) > tol) {
                errorFlag++;
                *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
                
                // Output the multi-index of the value where the error is:
                *outStream << " At multi-index { ";
                *outStream << i << " ";*outStream << j << " ";
                *outStream << "}  computed value: " << vals_host(i,j)
                           << " but reference value: " << basisValues[l] << "\n";
              }
            }
          }
        }
    
    
        // Check GRAD of basis function: resize vals to rank-3 container
        {
          DynRankView vals = DynRankView("vals", numFields, numPoints, spaceDim);
          wedgeBasis.getValues(vals, wedgeNodes, OPERATOR_GRAD);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);
          for (ordinal_type i = 0; i < numFields; ++i) {
            for (ordinal_type j = 0; j < numPoints; ++j) {
              for (ordinal_type k = 0; k < spaceDim; ++k) {
                
                // basisGrads is (F,P,D), compute offset:
                const ordinal_type l = k + j * spaceDim + i * spaceDim * numPoints;
                if (std::abs(vals_host(i,j,k) - basisGrads[l]) > tol) {
                  errorFlag++;
                  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
                  
                  // Output the multi-index of the value where the error is:
                  *outStream << " At multi-index { ";
                  *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
                  *outStream << "}  computed grad component: " << vals_host(i,j,k)
                             << " but reference grad component: " << basisGrads[l] << "\n";
                }
              }
            }
          }
        }

        // Check D1 of basis function (do not resize vals because it has the correct size: D1 = GRAD)
        {
          DynRankView vals = DynRankView("vals", numFields, numPoints, spaceDim);
          wedgeBasis.getValues(vals, wedgeNodes, OPERATOR_D1);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);
          for (ordinal_type i = 0; i < numFields; ++i) {
            for (ordinal_type j = 0; j < numPoints; ++j) {
              for (ordinal_type k = 0; k < spaceDim; ++k) {

                // basisGrads is (F,P,D), compute offset:
                const ordinal_type l = k + j * spaceDim + i * spaceDim * numPoints;
                if (std::abs(vals_host(i,j,k) - basisGrads[l]) > tol) {
                  errorFlag++;
                  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                  // Output the multi-index of the value where the error is:
                  *outStream << " At multi-index { ";
                  *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
                  *outStream << "}  computed D1 component: " << vals_host(i,j,k)
                             << " but reference D1 component: " << basisGrads[l] << "\n";
                }
              }
            }
          }
        }

        
        // Check D2 of basis function
        {
          DynRankView vals = DynRankView("vals", numFields, numPoints, D2Cardin);
          wedgeBasis.getValues(vals, wedgeNodes, OPERATOR_D2);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);
          for (ordinal_type i = 0; i < numFields; ++i) {
            for (ordinal_type j = 0; j < numPoints; ++j) {
              for (ordinal_type k = 0; k < D2Cardin; ++k) {

                // basisGrads is (F,P,D), compute offset:
                const ordinal_type l = k + j * D2Cardin + i * D2Cardin * numPoints;
                if (std::abs(vals_host(i,j,k) - basisD2[l]) > tol) {
                  errorFlag++;
                  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                  // Output the multi-index of the value where the error is:
                  *outStream << " At multi-index { ";
                  *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
                  *outStream << "}  computed D2 component: " << vals_host(i,j,k)
                             << " but reference D2 component: " << basisGrads[l] << "\n";
                }
              }
            }
          }
        }

        // Check D3 of basis function
        {
          DynRankView vals = DynRankView("vals", numFields, numPoints, D3Cardin);
          wedgeBasis.getValues(vals, wedgeNodes, OPERATOR_D3);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);
          for (ordinal_type i = 0; i < numFields; ++i) {
            for (ordinal_type j = 0; j < numPoints; ++j) {
              for (ordinal_type k = 0; k < D3Cardin; ++k) {

                // basisGrads is (F,P,D), compute offset:
                const ordinal_type l = k + j * D3Cardin + i * D3Cardin * numPoints;
                if (std::abs(vals_host(i,j,k) - basisD3[l]) > tol) {
                  errorFlag++;
                  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                  // Output the multi-index of the value where the error is:
                  *outStream << " At multi-index { ";
                  *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
                  *outStream << "}  computed D3 component: " << vals_host(i,j,k)
                             << " but reference D3 component: " << basisD3[l] << "\n";
                }
              }
            }
          }
        }

        // Check D4 of basis function
        {
          DynRankView vals = DynRankView("vals", numFields, numPoints, D4Cardin);
          wedgeBasis.getValues(vals, wedgeNodes, OPERATOR_D4);
          auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);
          for (ordinal_type i = 0; i < numFields; ++i) {
            for (ordinal_type j = 0; j < numPoints; ++j) {
              for (ordinal_type k = 0; k < D4Cardin; ++k) {

                // basisGrads is (F,P,D), compute offset:
                const ordinal_type l = k + j * D4Cardin + i * D4Cardin * numPoints;
                if (std::abs(vals_host(i,j,k) - basisD4[l]) > tol) {
                  errorFlag++;
                  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                  // Output the multi-index of the value where the error is:
                  *outStream << " At multi-index { ";
                  *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
                  *outStream << "}  computed D4 component: " << vals_host(i,j,k)
                             << " but reference D4 component: " << basisD4[l] << "\n";
                }
              }
            }
          }
        }

        // Check all higher derivatives - must be zero.
        {
          const EOperator ops[] = { OPERATOR_D5,
                                    OPERATOR_D6,
                                    OPERATOR_D7,
                                    OPERATOR_D8,
                                    OPERATOR_D9,
                                    OPERATOR_D10,
                                    OPERATOR_MAX };
          for (auto h=0;ops[h]!=OPERATOR_MAX;++h) {
            const auto op = ops[h];
            const ordinal_type DkCardin  = getDkCardinality(op, spaceDim);
            DynRankView vals("vals", numFields, numPoints, DkCardin);

            wedgeBasis.getValues(vals, wedgeNodes, op);
            auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
            Kokkos::deep_copy(vals_host, vals);
            for (ordinal_type i1=0;i1<numFields; i1++)
              for (ordinal_type i2=0;i2<numPoints; i2++)
                for (ordinal_type i3=0;i3<DkCardin; i3++) {
                  if (std::abs(vals_host(i1,i2,i3)) > tol) {
                    errorFlag++;
                    *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
                    
                    // Get the multi-index of the value where the error is and the operator order
                    const auto ord = Intrepid2::getOperatorOrder(op);
                    *outStream << " At multi-index { "<<i1<<" "<<i2 <<" "<<i3;
                    *outStream << "}  computed D"<< ord <<" component: " << vals_host(i1,i2,i3)
                               << " but reference D" << ord << " component:  0 \n";
                  }
                }
          }
        }
      } catch (std::exception err) {
        *outStream << err.what() << "\n\n";
        errorFlag = -1000;
      }

      if (errorFlag != 0)
        std::cout << "End Result: TEST FAILED\n";
      else
        std::cout << "End Result: TEST PASSED\n";
      
      // reset format state of std::cout
      std::cout.copyfmt(oldFormatState);

      return errorFlag;
    }
Beispiel #15
0
    int HDIV_WEDGE_I1_FEM_Test01(const bool verbose) {

      Teuchos::RCP<std::ostream> outStream;
      Teuchos::oblackholestream bhs; // outputs nothing

      if (1)// (verbose)
        outStream = Teuchos::rcp(&std::cout, false);
      else
        outStream = Teuchos::rcp(&bhs,       false);

      Teuchos::oblackholestream oldFormatState;
      oldFormatState.copyfmt(std::cout);

      typedef typename
        Kokkos::Impl::is_space<DeviceSpaceType>::host_mirror_space::execution_space HostSpaceType ;

      *outStream << "DeviceSpace::  "; DeviceSpaceType::print_configuration(*outStream, false);
      *outStream << "HostSpace::    ";   HostSpaceType::print_configuration(*outStream, false);
      
      *outStream  
        << "===============================================================================\n"
        << "|                                                                             |\n"
        << "|                 Unit Test (Basis_HDIV_WEDGE_I1_FEM)                         |\n"
        << "|                                                                             |\n"
        << "|     1) Conversion of Dof tags into Dof ordinals and back                    |\n"
        << "|     2) Basis values for VALUE and DIV operators                             |\n"
        << "|                                                                             |\n"
        << "|  Questions? Contact  Pavel Bochev  ([email protected]),                    |\n"
        << "|                      Denis Ridzal  ([email protected]),                    |\n"
        << "|                      Kara Peterson ([email protected]).                    |\n"
        << "|                                                                             |\n"
        << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n"
        << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n"
        << "|                                                                             |\n"
        << "===============================================================================\n";

      typedef Kokkos::DynRankView<ValueType,DeviceSpaceType> DynRankView;
      typedef Kokkos::DynRankView<ValueType,HostSpaceType> DynRankViewHost;
#define ConstructWithLabel(obj, ...) obj(#obj, __VA_ARGS__)

      const ValueType tol = tolerence();
      int errorFlag = 0;

      // for virtual function, value and point types are declared in the class
      typedef ValueType outputValueType;
      typedef ValueType pointValueType;
      Basis_HDIV_WEDGE_I1_FEM<DeviceSpaceType,outputValueType,pointValueType> wedgeBasis;

      *outStream
        << "\n"
        << "===============================================================================\n"
        << "| TEST 1: constructors and exceptions                                         |\n"
        << "===============================================================================\n";

      try {
        ordinal_type nthrow = 0, ncatch = 0;
#ifdef HAVE_INTREPID2_DEBUG
  // Define array containing the 6 vertices of the reference WEDGE and 6 other points.
  DynRankView ConstructWithLabel(wedgeNodes, 12, 3);

        // Generic array for the output values; needs to be properly resized depending on the operator type
        const auto numFields = wedgeBasis.getCardinality();
        const auto numPoints = wedgeNodes.dimension(0);
        const auto spaceDim  = wedgeBasis.getBaseCellTopology().getDimension();
        
    // exception #1: GRAD cannot be applied to HDIV functions 
    DynRankView ConstructWithLabel(vals, numFields, numPoints, spaceDim );
    INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(vals, wedgeNodes, OPERATOR_GRAD));

    // exception #2: CURL cannot be applied to HDIV functions
    INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(vals, wedgeNodes, OPERATOR_CURL));
        
    // Exceptions 3-7: all bf tags/bf Ids below are wrong and should cause getDofOrdinal() and 
    // getDofTag() to access invalid array elements thereby causing bounds check exception
    // exception #3
    INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getDofOrdinal(3,0,0));
    // exception #4
    INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getDofOrdinal(1,1,1));
    // exception #5
    INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getDofOrdinal(0,4,1));
    // exception #6
    INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getDofTag(11));
    // exception #7
    INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getDofTag(-1));

    // Exceptions 8-15 test exception handling with incorrectly dimensioned input/output arrays
    // exception #8: input points array must be of rank-2
    DynRankView ConstructWithLabel(badPoints1, 4, 5, 3);
    INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(vals, badPoints1, OPERATOR_VALUE));

    // exception #9 dimension 1 in the input point array must equal space dimension of the cell
    DynRankView ConstructWithLabel(badPoints2, 4, 2);
    INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(vals, badPoints2, OPERATOR_VALUE));
    
    // exception #10 output values must be of rank-3 for OPERATOR_VALUE
    DynRankView ConstructWithLabel(badVals1, 4, 3);
    INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(badVals1, wedgeNodes, OPERATOR_VALUE));
 
    // exception #11 output values must be of rank-2 for OPERATOR_DIV
    DynRankView ConstructWithLabel(badVals2, 4, 3, 1);
    INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(badVals2, wedgeNodes, OPERATOR_DIV));
    
    // exception #12 incorrect 0th dimension of output array (must equal number of basis functions)
    DynRankView ConstructWithLabel(badVals3, wedgeBasis.getCardinality() + 1, wedgeNodes.dimension(0), 3);
    INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(badVals3, wedgeNodes, OPERATOR_VALUE));

    // exception #13 incorrect 0th dimension of output array (must equal number of basis functions)
    DynRankView ConstructWithLabel(badVals4, wedgeBasis.getCardinality() + 1, wedgeNodes.dimension(0));
    INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(badVals4, wedgeNodes, OPERATOR_DIV));

    // exception #14 incorrect 1st dimension of output array (must equal number of points)
    DynRankView ConstructWithLabel(badVals5, wedgeBasis.getCardinality(), wedgeNodes.dimension(0) + 1, 3);
    INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(badVals5, wedgeNodes, OPERATOR_VALUE));

    // exception #15 incorrect 1st dimension of output array (must equal number of points)
    DynRankView ConstructWithLabel(badVals6, wedgeBasis.getCardinality(), wedgeNodes.dimension(0) + 1);
    INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(badVals6, wedgeNodes, OPERATOR_DIV));

    // exception #16: incorrect 2nd dimension of output array (must equal the space dimension)
    DynRankView ConstructWithLabel(badVals7, wedgeBasis.getCardinality(), wedgeNodes.dimension(0), 4);
    INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(badVals7, wedgeNodes, OPERATOR_VALUE));
#endif
    
      } catch (std::logic_error err) {
        *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
        *outStream << err.what() << '\n';
        *outStream << "-------------------------------------------------------------------------------" << "\n\n";
        errorFlag = -1000;
      }
  
      *outStream
        << "\n"
        << "===============================================================================\n"
        << "| TEST 2: correctness of tag to enum and enum to tag lookups                  |\n"
        << "===============================================================================\n";
  
      try{
        const auto numFields = wedgeBasis.getCardinality();
        const auto allTags = wedgeBasis.getAllDofTags();

        // Loop over all tags, lookup the associated dof enumeration and then lookup the tag again
        const auto dofTagSize = allTags.dimension(0);
    
    // Loop over all tags, lookup the associated dof enumeration and then lookup the tag again
    for (size_type i = 0; i < dofTagSize; i++) {
      const auto bfOrd  = wedgeBasis.getDofOrdinal(allTags(i, 0), allTags(i, 1), allTags(i, 2));
      
      const auto myTag = wedgeBasis.getDofTag(bfOrd);
       if( !( (myTag(0) == allTags(i, 0)) &&
              (myTag(1) == allTags(i, 1)) &&
              (myTag(2) == allTags(i, 2)) &&
              (myTag(3) == allTags(i, 3)) ) ) {
        errorFlag++;
        *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
        *outStream << " getDofOrdinal( {" 
          << allTags(i, 0) << ", "
          << allTags(i, 1) << ", "
          << allTags(i, 2) << ", "
          << allTags(i, 3) << "}) = " << bfOrd <<" but \n";
        *outStream << " getDofTag(" << bfOrd << ") = { "
          << myTag(0) << ", "
          << myTag(1) << ", "
          << myTag(2) << ", "
          << myTag(3) << "}\n";
      }
    }
    
    // Now do the same but loop over basis functions
    for( int bfOrd = 0; bfOrd <numFields; bfOrd++) {
      const auto myTag  = wedgeBasis.getDofTag(bfOrd);
      const auto myBfOrd = wedgeBasis.getDofOrdinal(myTag(0), myTag(1), myTag(2));
      if( bfOrd != myBfOrd) {
        errorFlag++;
        *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
        *outStream << " getDofTag(" << bfOrd << ") = { "
          << myTag(0) << ", "
          << myTag(1) << ", "
          << myTag(2) << ", "
          << myTag(3) << "} but getDofOrdinal({"
          << myTag(0) << ", "
          << myTag(1) << ", "
          << myTag(2) << ", "
          << myTag(3) << "} ) = " << myBfOrd << "\n";
      }
    }
  }
  catch (std::logic_error err){
    *outStream << err.what() << "\n\n";
    errorFlag = -1000;
  };
  
  *outStream \
    << "\n"
    << "===============================================================================\n"\
    << "| TEST 3: correctness of basis function values                                |\n"\
    << "===============================================================================\n";
  
  outStream -> precision(20);
  
  // VALUE: Each row pair gives the 5x3 correct basis set values at an evaluation point
  double basisValues[] = {
    0, -0.500000, 0, 0, 0, 0, -0.500000, 0, 0, 0, 0, -2.00000, 0, 0, 0, \
    0.500000, -0.500000, 0, 0.500000, 0, 0, 0, 0, 0, 0, 0, -2.00000, 0, \
    0, 0, 0, 0, 0, 0, 0.500000, 0, -0.500000, 0.500000, 0, 0, 0, \
    -2.00000, 0, 0, 0, 0, -0.500000, 0, 0, 0, 0, -0.500000, 0, 0, 0, 0, \
    0, 0, 0, 2.00000, 0.500000, -0.500000, 0, 0.500000, 0, 0, 0, 0, 0, 0, \
    0, 0, 0, 0, 2.00000, 0, 0, 0, 0, 0.500000, 0, -0.500000, 0.500000, 0, \
    0, 0, 0, 0, 0, 2.00000, 0.125000, -0.250000, 0, 0.125000, 0.250000, \
    0, -0.375000, 0.250000, 0, 0, 0, -2.00000, 0, 0, 0, 0.250000, \
    -0.375000, 0, 0.250000, 0.125000, 0, -0.250000, 0.125000, 0, 0, 0, \
    -1.00000, 0, 0, 1.00000, 0.125000, -0.375000, 0, 0.125000, 0.125000, \
    0, -0.375000, 0.125000, 0, 0, 0, 0, 0, 0, 2.00000, 0.125000, \
    -0.500000, 0, 0.125000, 0, 0, -0.375000, 0, 0, 0, 0, -0.250000, 0, 0, \
    1.75000, 0, -0.250000, 0, 0, 0.250000, 0, -0.500000, 0.250000, 0, 0, \
    0, -1.25000, 0, 0, 0.750000, 0.250000, -0.250000, 0, 0.250000, \
    0.250000, 0, -0.250000, 0.250000, 0, 0, 0, -1.00000, 0, 0, 1.00000};
  
  // DIV: each row pair gives the 5 correct values of the divergence of the 5 basis functions
  double basisDivs[] = {   
    // 6 vertices
    1.0, 1.0, 1.0, 1.0, 1.0,
    1.0, 1.0, 1.0, 1.0, 1.0,
    1.0, 1.0, 1.0, 1.0, 1.0,
    1.0, 1.0, 1.0, 1.0, 1.0,
    1.0, 1.0, 1.0, 1.0, 1.0,
    1.0, 1.0, 1.0, 1.0, 1.0,
    // 6 other points
    1.0, 1.0, 1.0, 1.0, 1.0,
    1.0, 1.0, 1.0, 1.0, 1.0,
    1.0, 1.0, 1.0, 1.0, 1.0,
    1.0, 1.0, 1.0, 1.0, 1.0,
    1.0, 1.0, 1.0, 1.0, 1.0,
    1.0, 1.0, 1.0, 1.0, 1.0
  };
  
  try{

    DynRankViewHost ConstructWithLabel(wedgeNodesHost, 12, 3);
    wedgeNodesHost(0,0) =  0.0;  wedgeNodesHost(0,1) =  0.0;  wedgeNodesHost(0,2) = -1.0;
    wedgeNodesHost(1,0) =  1.0;  wedgeNodesHost(1,1) =  0.0;  wedgeNodesHost(1,2) = -1.0;
    wedgeNodesHost(2,0) =  0.0;  wedgeNodesHost(2,1) =  1.0;  wedgeNodesHost(2,2) = -1.0;
    wedgeNodesHost(3,0) =  0.0;  wedgeNodesHost(3,1) =  0.0;  wedgeNodesHost(3,2) =  1.0;
    wedgeNodesHost(4,0) =  1.0;  wedgeNodesHost(4,1) =  0.0;  wedgeNodesHost(4,2) =  1.0;
    wedgeNodesHost(5,0) =  0.0;  wedgeNodesHost(5,1) =  1.0;  wedgeNodesHost(5,2) =  1.0;

    wedgeNodesHost(6,0) =  0.25; wedgeNodesHost(6,1) =  0.5;  wedgeNodesHost(6,2) = -1.0;
    wedgeNodesHost(7,0) =  0.5;  wedgeNodesHost(7,1) =  0.25; wedgeNodesHost(7,2) =  0.0;
    wedgeNodesHost(8,0) =  0.25; wedgeNodesHost(8,1) =  0.25; wedgeNodesHost(8,2) =  1.0;
    wedgeNodesHost(9,0) =  0.25; wedgeNodesHost(9,1) =  0.0;  wedgeNodesHost(9,2) =  0.75;
    wedgeNodesHost(10,0)=  0.0;  wedgeNodesHost(10,1)=  0.5;  wedgeNodesHost(10,2)= -0.25;
    wedgeNodesHost(11,0)=  0.5;  wedgeNodesHost(11,1)=  0.5;  wedgeNodesHost(11,2)=  0.0;
        
        const auto wedgeNodes = Kokkos::create_mirror_view(typename DeviceSpaceType::memory_space(), wedgeNodesHost);
        Kokkos::deep_copy(wedgeNodes, wedgeNodesHost);

        // Dimensions for the output arrays:
        const auto numFields = wedgeBasis.getCardinality();
        const auto numPoints = wedgeNodes.dimension(0);
        const auto spaceDim  = wedgeBasis.getBaseCellTopology().getDimension();

    
    // Check VALUE of basis functions: resize vals to rank-3 container:
    {
    DynRankView ConstructWithLabel(vals, numFields, numPoints, spaceDim);
    wedgeBasis.getValues(vals, wedgeNodes, OPERATOR_VALUE);
    const auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
    Kokkos::deep_copy(vals_host, vals);
    for (int i = 0; i < numFields; i++) {
      for (size_type j = 0; j < numPoints; j++) {
        for (size_type k = 0; k < spaceDim; k++) {
           int l = k + i * spaceDim + j * spaceDim * numFields;
           if (std::abs(vals_host(i,j,k) - basisValues[l]) > tol) {
             errorFlag++;
             *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

             // Output the multi-index of the value where the error is:
             *outStream << " At multi-index { ";
             *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
             *outStream << "}  computed value: " << vals_host(i,j,k)
               << " but reference value: " << basisValues[l] << "\n";
            }
         }
      }
    }
    }

    
    // Check DIV of basis function: resize vals to rank-2 container
    {
    DynRankView ConstructWithLabel(vals, numFields, numPoints);
    wedgeBasis.getValues(vals, wedgeNodes, OPERATOR_DIV);
    const auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
    Kokkos::deep_copy(vals_host, vals);
    for (int i = 0; i < numFields; i++) {
      for (size_type j = 0; j < numPoints; j++) {
          int l =  i + j * numFields;
           if (std::abs(vals_host(i,j) - basisDivs[l]) > tol) {
             errorFlag++;
             *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

             // Output the multi-index of the value where the error is:
             *outStream << " At multi-index { ";
             *outStream << i << " ";*outStream << j << " ";
             *outStream << "}  computed divergence component: " << vals_host(i,j)
               << " but reference divergence component: " << basisDivs[l] << "\n";
         }
      }
    }
    }
          } catch (std::logic_error err) {
        *outStream << err.what() << "\n\n";
        errorFlag = -1000;
      }

      *outStream
        << "\n"
        << "===============================================================================\n"
        << "| TEST 4: correctness of DoF locations                                        |\n"
        << "===============================================================================\n";

      try {
        const auto numFields = wedgeBasis.getCardinality();
        const auto spaceDim  = wedgeBasis.getBaseCellTopology().getDimension();

        // Check exceptions.
        ordinal_type nthrow = 0, ncatch = 0;
#ifdef HAVE_INTREPID2_DEBUG
        {
          DynRankView ConstructWithLabel(badVals, 1,2,3);
          INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getDofCoords(badVals) );
        }
        {
          DynRankView ConstructWithLabel(badVals, 4,3);
          INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getDofCoords(badVals) );
        }
        {
          DynRankView ConstructWithLabel(badVals, 5,2);
          INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getDofCoords(badVals) );
        }
#endif
        if (nthrow != ncatch) {
          errorFlag++;
          *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
          *outStream << "# of catch ("<< ncatch << ") is different from # of throw (" << ncatch << ")\n";
        }
       
        DynRankView ConstructWithLabel(bvals, numFields, numFields, spaceDim);
        DynRankView ConstructWithLabel(cvals, numFields, spaceDim);
       
        // Check mathematical correctness.
        wedgeBasis.getDofCoords(cvals);
        wedgeBasis.getValues(bvals, cvals, OPERATOR_VALUE);

        // Check mathematical correctness
        DynRankViewHost ConstructWithLabel(normals, numFields,spaceDim); // normals at each point basis point
        normals(0,0)  =  0.0; normals(0,1)  = -2.0; normals(0,2)  =  0.0;
        normals(1,0)  =  2.0; normals(1,1)  =  2.0; normals(1,2)  =  0.0;
        normals(2,0)  = -2.0; normals(2,1)  =  0.0; normals(2,2)  =  0.0;
        normals(3,0)  =  0.0; normals(3,1)  =  0.0; normals(3,2)  = -0.5;
        normals(4,0)  =  0.0; normals(4,1)  =  0.0; normals(4,2)  =  0.5;
    
        auto cvals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), cvals);
        Kokkos::deep_copy(cvals_host, cvals);

        auto bvals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), bvals);
        Kokkos::deep_copy(bvals_host, bvals);
    
        for (ordinal_type i=0;i<numFields;++i) {
          for (ordinal_type j=0;j<numFields;++j) {

            ValueType normal = 0.0;
            for(size_type d=0;d<spaceDim;++d) {
               normal += bvals_host(i,j,d)*normals(j,d);
            }

            const ValueType expected_normal = (i == j);
            if (std::abs(normal - expected_normal) > tol || isnan(normal)) {
              errorFlag++;
              std::stringstream ss;
              ss << "\nNormal component of basis function " << i << " at (" << cvals_host(j,0) << ", " << cvals_host(j,1)<< ", " << cvals_host(j,2) << ") is " << normal << " but should be " << expected_normal << "\n";
              *outStream << ss.str();
            }
          }
        }
      } catch (std::logic_error err) {
        *outStream << err.what() << "\n\n";
        errorFlag = -1000;
      }
  
      if (errorFlag != 0)
        std::cout << "End Result: TEST FAILED\n";
      else
        std::cout << "End Result: TEST PASSED\n";
           
      // reset format state of std::cout
      std::cout.copyfmt(oldFormatState);

      return errorFlag;
    }
Beispiel #16
0
    int HDIV_TRI_I1_FEM_Test01(const bool verbose) {

      Teuchos::RCP<std::ostream> outStream;
      Teuchos::oblackholestream bhs; // outputs nothing

      if (verbose)
        outStream = Teuchos::rcp(&std::cout, false);
      else
        outStream = Teuchos::rcp(&bhs,       false);

      Teuchos::oblackholestream oldFormatState;
      oldFormatState.copyfmt(std::cout);

      typedef typename
        Kokkos::Impl::is_space<DeviceSpaceType>::host_mirror_space::execution_space HostSpaceType ;

      *outStream << "DeviceSpace::  "; DeviceSpaceType::print_configuration(*outStream, false);
      *outStream << "HostSpace::    ";   HostSpaceType::print_configuration(*outStream, false);

      *outStream
        << "===============================================================================\n"
        << "|                                                                             |\n"
        << "|                 Unit Test (Basis_HDIV_TRI_I1_FEM)                           |\n"
        << "|                                                                             |\n"
        << "|     1) Conversion of Dof tags into Dof ordinals and back                    |\n"
        << "|     2) Basis values for VALUE and DIV operators                             |\n"
        << "|                                                                             |\n"
        << "|  Questions? Contact  Pavel Bochev  ([email protected]),                    |\n"
        << "|                      Denis Ridzal  ([email protected]),                    |\n"
        << "|                      Kara Peterson ([email protected]).                    |\n"
        << "|                                                                             |\n"
        << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n"
        << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n"
        << "|                                                                             |\n"
        << "===============================================================================\n";

      typedef Kokkos::DynRankView<ValueType,DeviceSpaceType> DynRankView;
      typedef Kokkos::DynRankView<ValueType,HostSpaceType> DynRankViewHost;
#define ConstructWithLabel(obj, ...) obj(#obj, __VA_ARGS__)

      const ValueType tol = tolerence();
      int errorFlag = 0;

      // for virtual function, value and point types are declared in the class
      typedef ValueType outputValueType;
      typedef ValueType pointValueType;
      Basis_HDIV_TRI_I1_FEM<DeviceSpaceType,outputValueType,pointValueType> triBasis;
      //typedef typename decltype(triBasis)::outputViewType outputViewType;
      //typedef typename decltype(triBasis)::pointViewType  pointViewType;

      *outStream
        << "\n"
        << "===============================================================================\n"
        << "| TEST 1: Basis creation, exceptions tests                                    |\n"
        << "===============================================================================\n";

      try {
        ordinal_type nthrow = 0, ncatch = 0;
#ifdef HAVE_INTREPID2_DEBUG

        // Define array containing the 3 vertices of the reference TRI and its 3 edge midpoints.
        DynRankView ConstructWithLabel(triNodes, 6, 2);

        // Generic array for the output values; needs to be properly resized depending on the operator type
        const ordinal_type numFields = triBasis.getCardinality();
        const ordinal_type numPoints = triNodes.dimension(0);

        DynRankView vals;
        vals = DynRankView("vals", numFields, numPoints);


        // exception #1: GRAD cannot be applied to HDIV functions
        // resize vals to rank-3 container with dimensions (num. basis functions, num. points, arbitrary)
        INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(vals, triNodes, OPERATOR_GRAD) );

        // exception #2: CURL cannot be applied to HDIV functions
        INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(vals, triNodes, OPERATOR_CURL) );

        // Exceptions 3-7: all bf tags/bf Ids below are wrong and should cause getDofOrdinal() and
        // getDofTag() to access invalid array elements thereby causing bounds check exception
        // exception #3
        INTREPID2_TEST_ERROR_EXPECTED( triBasis.getDofOrdinal(3,0,0) );
        // exception #4
        INTREPID2_TEST_ERROR_EXPECTED( triBasis.getDofOrdinal(1,1,1) );
        // exception #5
        INTREPID2_TEST_ERROR_EXPECTED( triBasis.getDofOrdinal(0,2,1) );
        // exception #6
        INTREPID2_TEST_ERROR_EXPECTED( triBasis.getDofTag(numFields) );
        // exception #7
        INTREPID2_TEST_ERROR_EXPECTED( triBasis.getDofTag(-1) );
        // exception #8
        INTREPID2_TEST_ERROR_EXPECTED( triBasis.getDofOrdinal(2,0,0) );

        // Exceptions 9-16 test exception handling with incorrectly dimensioned input/output arrays
        // exception #9: input points array must be of rank-2
        DynRankView ConstructWithLabel(badPoints1, 4, 5, 3);
        INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(vals, badPoints1, OPERATOR_VALUE) );

        // exception #10 dimension 1 in the input point array must equal space dimension of the cell
        DynRankView ConstructWithLabel(badPoints2, 4, triBasis.getBaseCellTopology().getDimension() + 1);
        INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(vals, badPoints2, OPERATOR_VALUE) );
        
        // exception #11 output values must be of rank-3 for OPERATOR_VALUE
        DynRankView ConstructWithLabel(badVals1, 4, 3);
        INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(badVals1, triNodes, OPERATOR_VALUE) );

        // exception #12 output values must be of rank-2 for OPERATOR_DIV
        DynRankView ConstructWithLabel(badVals2, 4, 3, 1);
        INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(badVals2, triNodes, OPERATOR_VALUE) );

        // exception #13 incorrect 0th dimension of output array for OPERATOR_VALUE (must equal number of basis functions)
        DynRankView ConstructWithLabel(badVals3, triBasis.getCardinality() + 1, triNodes.dimension(0), triBasis.getBaseCellTopology().getDimension());
        INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(badVals3, triNodes, OPERATOR_VALUE) );

        // exception #14 incorrect 0th dimension of output array for OPERATOR_DIV (must equal number of basis functions)
        DynRankView ConstructWithLabel(badVals4, triBasis.getCardinality() + 1, triNodes.dimension(0));
        INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(badVals4, triNodes, OPERATOR_DIV) );

        // exception #15 incorrect 1st dimension of output array (must equal number of points)
        DynRankView ConstructWithLabel(badVals5, triBasis.getCardinality(), triNodes.dimension(0) + 1, triBasis.getBaseCellTopology().getDimension());
        INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(badVals5, triNodes, OPERATOR_VALUE) );
    
        // exception #16 incorrect 1st dimension of output array (must equal number of points)
        DynRankView ConstructWithLabel(badVals6, triBasis.getCardinality(), triNodes.dimension(0) + 1);
        INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(badVals6, triNodes, OPERATOR_DIV) );
    
        // exception #17: incorrect 2nd dimension of output array (must equal the space dimension)
        DynRankView ConstructWithLabel(badVals7, triBasis.getCardinality(), triNodes.dimension(0), triBasis.getBaseCellTopology().getDimension() + 1);
        INTREPID2_TEST_ERROR_EXPECTED( triBasis.getValues(badVals7, triNodes, OPERATOR_VALUE) );
    
#endif
        if (nthrow != ncatch) {
          errorFlag++;
          *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
          *outStream << "# of catch ("<< ncatch << ") is different from # of throw (" << nthrow << ")\n";
        }
      } catch (std::logic_error err) {
        *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
        *outStream << err.what() << '\n';
        *outStream << "-------------------------------------------------------------------------------" << "\n\n";
        errorFlag = -1000;
      }

      *outStream
        << "\n"
        << "===============================================================================\n"
        << "| TEST 2: correctness of tag to enum and enum to tag lookups                  |\n"
        << "===============================================================================\n";

      // all tags are on host space
      try {
        const ordinal_type numFields = triBasis.getCardinality();
        const auto allTags = triBasis.getAllDofTags();
   
        // Loop over all tags, lookup the associated dof enumeration and then lookup the tag again
        const ordinal_type dofTagSize = allTags.dimension(0);
        
        // Loop over all tags, lookup the associated dof enumeration and then lookup the tag again
        for (ordinal_type i = 0; i < dofTagSize; i++) {
          const auto bfOrd  = triBasis.getDofOrdinal(allTags(i,0), allTags(i,1), allTags(i,2));

          const auto myTag = triBasis.getDofTag(bfOrd);
          if( !( (myTag(0) == allTags(i, 0)) &&
                  (myTag(1) == allTags(i, 1)) &&
                  (myTag(2) == allTags(i, 2)) &&
                  (myTag(3) == allTags(i, 3)) ) ) {
            errorFlag++;
            *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
            *outStream << " getDofOrdinal( {"
              << allTags(i, 0) << ", "
              << allTags(i, 1) << ", "
              << allTags(i, 2) << ", "
              << allTags(i, 3) << "}) = " << bfOrd <<" but \n";
            *outStream << " getDofTag(" << bfOrd << ") = { "
              << myTag(0) << ", "
              << myTag(1) << ", "
              << myTag(2) << ", "
              << myTag(3) << "}\n";
          }
        }
    
        // Now do the same but loop over basis functions
        for( ordinal_type bfOrd = 0; bfOrd < numFields; bfOrd++) {
          auto myTag  = triBasis.getDofTag(bfOrd);
          auto myBfOrd = triBasis.getDofOrdinal(myTag[0], myTag[1], myTag[2]);
          if( bfOrd != myBfOrd) {
            errorFlag++;
            *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
            *outStream << " getDofTag(" << bfOrd << ") = { "
              << myTag(0) << ", "
              << myTag(1) << ", "
              << myTag(2) << ", "
              << myTag(3) << "} but getDofOrdinal({"
              << myTag(0) << ", "
              << myTag(1) << ", "
              << myTag(2) << ", "
              << myTag(3) << "} ) = " << myBfOrd << "\n";
          }
        }
      } catch (std::logic_error err) {
        *outStream << err.what() << "\n\n";
        errorFlag = -1000;
      }

      *outStream \
        << "\n"
        << "===============================================================================\n"\
        << "| TEST 3: correctness of basis function values                                |\n"\
        << "===============================================================================\n";

      outStream -> precision(20);

      // VALUE: Correct basis values in (F,P,D) format: each group of two rows gives basis function
      // values at vertices followed by midpoints. This is the same array format as the output from getValues.
      double basisValues[] = {
        // basis function 0 at 3 vertices followed by 3 midpoints
        0.0,-1.0,                  1.0,-1.0,                               0.0, 0.0,
        0.5,-1.0,                  0.5,-0.5,                               0.0,-0.5,
        // basis function 1 at 3 vertices followed by 3 midpoints
        0.0, 0.0,                  1.0, 0.0,                0.0, 1.0,
        0.5, 0.0,                  0.5, 0.5,                0.0, 0.5,
        // basis function 2 at 3 vertices followed by 3 midpoints
        -1.0, 0.0,                 0.0, 0.0,                              -1.0, 1.0,
        -0.5, 0.0,                -0.5, 0.5,                              -1.0, 0.5
      };

      // DIV: each row gives the 3 correct values of the divergence of the 3 basis functions
      double basisDivs[] = {
        // 3 vertices
        2.0,  2.0,   2.0,
        2.0,  2.0,   2.0,
        2.0,  2.0,   2.0,
        // 3 edge centers
        2.0,  2.0,   2.0,
        2.0,  2.0,   2.0,
        2.0,  2.0,   2.0,
      };



      try{

        DynRankViewHost ConstructWithLabel(triNodesHost, 6, 2);

        triNodesHost(0,0) =  0.0;  triNodesHost(0,1) =  0.0;
        triNodesHost(1,0) =  1.0;  triNodesHost(1,1) =  0.0;
        triNodesHost(2,0) =  0.0;  triNodesHost(2,1) =  1.0;
        // edge midpoints
        triNodesHost(3,0) =  0.5;  triNodesHost(3,1) =  0.0;
        triNodesHost(4,0) =  0.5;  triNodesHost(4,1) =  0.5;
        triNodesHost(5,0) =  0.0;  triNodesHost(5,1) =  0.5;

        auto triNodes = Kokkos::create_mirror_view(typename DeviceSpaceType::memory_space(), triNodesHost);
        Kokkos::deep_copy(triNodes, triNodesHost);
        
        // Dimensions for the output arrays:
        const ordinal_type numFields = triBasis.getCardinality();
        const ordinal_type numPoints = triNodes.dimension(0);
        const ordinal_type spaceDim  = triBasis.getBaseCellTopology().getDimension();
    
        {
          // Check VALUE of basis functions: resize vals to rank-3 container:
          DynRankView vals = DynRankView("vals", numFields, numPoints, spaceDim);
          triBasis.getValues(vals, triNodes, OPERATOR_VALUE);
          const auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);
          for (ordinal_type i = 0; i < numFields; i++) {
            for (ordinal_type j = 0; j < numPoints; j++) {
              for (ordinal_type k = 0; k < spaceDim; k++) {
                // basisValues are in (F,P,D) format and the multiindex is (i,j,k), here's the offset:
                 ordinal_type l = k + j * spaceDim + i * spaceDim * numPoints;

                 if (std::abs(vals_host(i,j,k) - basisValues[l]) > tol) {
                   errorFlag++;
                   *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                   // Output the multi-index of the value where the error is:
                   *outStream << " address =  "<< l <<"\n";
                   *outStream << " At multi-index { ";
                   *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
                   *outStream << "}  computed value: " << vals_host(i,j,k)
                     << " but reference value: " << basisValues[l] << "\n";
                  }
               }
            }
          }
        }

        {
          // Check DIV of basis function: resize vals to rank-2 container
          DynRankView vals = DynRankView("vals", numFields, numPoints);
          triBasis.getValues(vals, triNodes, OPERATOR_DIV);
          const auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
          Kokkos::deep_copy(vals_host, vals);
          for (ordinal_type i = 0; i < numFields; i++) {
            for (ordinal_type j = 0; j < numPoints; j++) {
              ordinal_type l =  i + j * numFields;
              if (std::abs(vals_host(i,j) - basisDivs[l]) > tol) {
                errorFlag++;
                *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                // Output the multi-index of the value where the error is:
                *outStream << " At (Field,Point,Dim) multi-index { ";
                *outStream << i << " ";*outStream << j << " ";
                *outStream << "}  computed divergence component: " << vals_host(i,j)
                  << " but reference divergence component: " << basisDivs[l] << "\n";
              }
            }
          }
        }
      } catch (std::logic_error err) {
        *outStream << err.what() << "\n\n";
        errorFlag = -1000;
      }

     *outStream
       << "\n"
       << "===============================================================================\n"
       << "| TEST 4: DOF correctness (Kronecker property)                                |\n"
       << "===============================================================================\n";

      try {
        const ordinal_type numFields = triBasis.getCardinality();
        const ordinal_type spaceDim  = triBasis.getBaseCellTopology().getDimension();

         // Check exceptions.
         ordinal_type nthrow = 0, ncatch = 0;
 #ifdef HAVE_INTREPID2_DEBUG
         {
           DynRankView ConstructWithLabel(badVals, 1,2,3);
           INTREPID2_TEST_ERROR_EXPECTED( triBasis.getDofCoords(badVals));
         }
         {
           DynRankView ConstructWithLabel(badVals, 4,2);
           INTREPID2_TEST_ERROR_EXPECTED( triBasis.getDofCoords(badVals));
         }
         {
           DynRankView ConstructWithLabel(badVals, 3,3);
           INTREPID2_TEST_ERROR_EXPECTED( triBasis.getDofCoords(badVals));
         }
 #endif
         if (nthrow != ncatch) {
           errorFlag++;
           *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
           *outStream << "# of catch ("<< ncatch << ") is different from # of throw (" << ncatch << ")\n";
         }

         DynRankView ConstructWithLabel(bvals, numFields, numFields, spaceDim);
         DynRankView ConstructWithLabel(cvals, numFields, spaceDim); 
         DynRankView ConstructWithLabel(dofCoeffs, numFields, spaceDim);

         // Check mathematical correctness.
         triBasis.getDofCoords(cvals);
         triBasis.getValues(bvals, cvals, OPERATOR_VALUE);
         triBasis.getDofCoeffs(dofCoeffs);


         auto cvals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), cvals);
         Kokkos::deep_copy(cvals_host, cvals);

         auto bvals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), bvals);
         Kokkos::deep_copy(bvals_host, bvals);
         
         auto dofCoeffs_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), dofCoeffs);
         Kokkos::deep_copy(dofCoeffs_host, dofCoeffs);

         for (ordinal_type i=0;i<numFields;++i) {
           for (ordinal_type j=0;j<numFields;++j) {

             ValueType dofValue = 0.0;
             for(ordinal_type d=0;d<spaceDim;++d) {
                dofValue += bvals_host(i,j,d)*dofCoeffs_host(j,d);
             }

             const ValueType expected_dofValue = (i == j);
             if (std::abs(dofValue - expected_dofValue) > tol || std::isnan(dofValue)) {
               errorFlag++;
               std::stringstream ss;
               ss << "\nDegree of freedom " << j << " of basis function " << i << " at (" << cvals_host(j,0) << ", " << cvals_host(j,1)<< ", " << cvals_host(j,2) << ") is " << dofValue << " but should be " << expected_dofValue << "\n";
               *outStream << ss.str();
             }
           }
         }
       } catch (std::logic_error err){
         *outStream << err.what() << "\n\n";
         errorFlag = -1000;
       };

      if (errorFlag != 0)
        std::cout << "End Result: TEST FAILED\n";
      else
        std::cout << "End Result: TEST PASSED\n";

      // reset format state of std::cout
      std::cout.copyfmt(oldFormatState);
      return errorFlag;
     }
Beispiel #17
0
  int HCURL_WEDGE_I1_FEM_Test01(const bool verbose) {
      
    Teuchos::RCP<std::ostream> outStream;
    Teuchos::oblackholestream bhs; // outputs nothing

    if (verbose)
      outStream = Teuchos::rcp(&std::cout, false);
    else
      outStream = Teuchos::rcp(&bhs, false);
      
    Teuchos::oblackholestream oldFormatState;
    oldFormatState.copyfmt(std::cout);
      
    typedef typename
      Kokkos::Impl::is_space<DeviceSpaceType>::host_mirror_space::execution_space HostSpaceType ;
      
    *outStream << "DeviceSpace::  "; DeviceSpaceType::print_configuration(*outStream, false);
    *outStream << "HostSpace::    ";   HostSpaceType::print_configuration(*outStream, false);

  *outStream 
    << "\n"
    << "===============================================================================\n" 
    << "|                                                                             |\n" 
    << "|                 Unit Test (Basis_HCURL_WEDGE_I1_FEM)                        |\n" 
    << "|                                                                             |\n" 
    << "|     1) Conversion of Dof tags into Dof ordinals and back                    |\n" 
    << "|     2) Basis values for VALUE and CURL operators                            |\n" 
    << "|                                                                             |\n" 
    << "|  Questions? Contact  Pavel Bochev  ([email protected]),                    |\n" 
    << "|                      Denis Ridzal  ([email protected]),                    |\n" 
    << "|                      Kara Peterson ([email protected]).                    |\n" 
    << "|                      Kyungjoo Kim  ([email protected]).                     |\n"
    << "|                                                                             |\n" 
    << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n" 
    << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n" 
    << "|                                                                             |\n" 
    << "===============================================================================\n";

      typedef Kokkos::DynRankView<ValueType,DeviceSpaceType> DynRankView;
      typedef Kokkos::DynRankView<ValueType,HostSpaceType> DynRankViewHost;
#define ConstructWithLabel(obj, ...) obj(#obj, __VA_ARGS__)
      const ValueType tol = tolerence();

      int errorFlag = 0;

      // for virtual function, value and point types are declared in the class
      typedef ValueType outputValueType;
      typedef ValueType pointValueType;
      Basis_HCURL_WEDGE_I1_FEM<DeviceSpaceType,outputValueType,pointValueType> wedgeBasis;

  *outStream 
    << "\n"
    << "===============================================================================\n"
    << "| TEST 1: Basis creation, exception testing                                   |\n"
    << "===============================================================================\n";

  try{
    ordinal_type nthrow = 0, ncatch = 0;
#ifdef HAVE_INTREPID2_DEBUG
    // Define array containing the 4 vertices of the reference WEDGE and its center.
    DynRankView ConstructWithLabel(wedgeNodes, 12, 3);

    // Generic array for the output values; needs to be properly resized depending on the operator type
    const ordinal_type numFields = wedgeBasis.getCardinality();
    const ordinal_type numPoints = wedgeNodes.dimension(0);
    const ordinal_type spaceDim  = wedgeBasis.getBaseCellTopology().getDimension();

    DynRankView vals ("vals", numFields, numPoints);
    DynRankView vals_vec ("vals", numFields, numPoints, spaceDim);

    {
    // exception #1: GRAD cannot be applied to HCURL functions 
    // resize vals to rank-3 container with dimensions (num. basis functions, num. points, arbitrary)
      INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(vals_vec, wedgeNodes, OPERATOR_GRAD) );

    // exception #2: DIV cannot be applied to HCURL functions
    // resize vals to rank-2 container with dimensions (num. basis functions, num. points)
      INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(vals, wedgeNodes, OPERATOR_DIV) );
    }   
    // Exceptions 3-7: all bf tags/bf Ids below are wrong and should cause getDofOrdinal() and 
    // getDofTag() to access invalid array elements thereby causing bounds check exception
    {
    // exception #3
      INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getDofOrdinal(3,0,0) );
    // exception #4
      INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getDofOrdinal(1,1,1) );
    // exception #5
      INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getDofOrdinal(0,4,1) );
    // exception #6
      INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getDofTag(numFields) );
    // exception #7
      INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getDofTag(-1) );
    }

    // Exceptions 8- test exception handling with incorrectly dimensioned input/output arrays
    {
    // exception #8: input points array must be of rank-2
      DynRankView ConstructWithLabel(badPoints1, 4, 5, 3);
      INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(vals, badPoints1, OPERATOR_VALUE) );
    } 
    {
    // exception #9 dimension 1 in the input point array must equal space dimension of the cell
      DynRankView ConstructWithLabel(badPoints2, 4, 2);
      INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(vals, badPoints2, OPERATOR_VALUE) );
    }
    {
    // exception #10 output values must be of rank-3 for OPERATOR_VALUE
      DynRankView ConstructWithLabel(badVals1, 4, 3);
      INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(badVals1, wedgeNodes, OPERATOR_VALUE) );
    // exception #11 output values must be of rank-3 for OPERATOR_CURL
      INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(badVals1, wedgeNodes, OPERATOR_CURL) );
    }
    { 
    // exception #12 incorrect 0th dimension of output array (must equal number of basis functions)
      DynRankView ConstructWithLabel(badVals2, numFields + 1, numPoints, 3);
      INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(badVals2, wedgeNodes, OPERATOR_VALUE) );
    }
    {
    // exception #13 incorrect 1st dimension of output array (must equal number of points)
      DynRankView ConstructWithLabel(badVals3, numFields, numPoints + 1, 3);
      INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(badVals3, wedgeNodes, OPERATOR_VALUE) );
    }
    {
    // exception #14: incorrect 2nd dimension of output array (must equal the space dimension)
      DynRankView ConstructWithLabel(badVals4, numFields, numPoints, 4);
      INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(badVals4, wedgeNodes, OPERATOR_VALUE) );
    
    // exception #15: incorrect 2nd dimension of output array (must equal the space dimension)
      INTREPID2_TEST_ERROR_EXPECTED( wedgeBasis.getValues(badVals4, wedgeNodes, OPERATOR_CURL) );
    }
#endif
  // Check if number of thrown exceptions matches the one we expect 
    if (nthrow != ncatch) {
      errorFlag++;
      *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
      *outStream << "# of catch ("<< ncatch << ") is different from # of throw (" << nthrow << ")\n";
    }
  } catch (std::logic_error err) {
    *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
    *outStream << err.what() << '\n';
    *outStream << "-------------------------------------------------------------------------------" << "\n\n";
    errorFlag = -1000;
  };

  *outStream 
    << "\n"
    << "===============================================================================\n"
    << "| TEST 2: correctness of tag to enum and enum to tag lookups                  |\n"
    << "===============================================================================\n";
  
  try{
    const ordinal_type numFields = wedgeBasis.getCardinality();
    const auto allTags = wedgeBasis.getAllDofTags();

    // Loop over all tags, lookup the associated dof enumeration and then lookup the tag again
    const ordinal_type dofTagSize = allTags.dimension(0);
    for (ordinal_type i = 0; i < dofTagSize; ++i) {
      auto bfOrd  = wedgeBasis.getDofOrdinal(allTags(i,0), allTags(i,1), allTags(i,2));
      
      const auto myTag = wedgeBasis.getDofTag(bfOrd);
       if( !( (myTag(0) == allTags(i,0)) &&
              (myTag(1) == allTags(i,1)) &&
              (myTag(2) == allTags(i,2)) &&
              (myTag(3) == allTags(i,3)) ) ) {
        errorFlag++;
        *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
        *outStream << " getDofOrdinal( {" 
          << allTags(i,0) << ", " 
          << allTags(i,1) << ", " 
          << allTags(i,2) << ", " 
          << allTags(i,3) << "}) = " << bfOrd <<" but \n";   
        *outStream << " getDofTag(" << bfOrd << ") = { "
          << myTag(0) << ", " 
          << myTag(1) << ", " 
          << myTag(2) << ", " 
          << myTag(3) << "}\n";        
      }
    }
    
    // Now do the same but loop over basis functions
    for( ordinal_type bfOrd = 0; bfOrd < numFields; ++bfOrd) {
      const auto  myTag  = wedgeBasis.getDofTag(bfOrd);
      const auto myBfOrd = wedgeBasis.getDofOrdinal(myTag(0), myTag(1), myTag(2));
      if( bfOrd != myBfOrd) {
        errorFlag++;
        *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
        *outStream << " getDofTag(" << bfOrd << ") = { "
          << myTag(0) << ", " 
          << myTag(1) << ", " 
          << myTag(2) << ", " 
          << myTag(3) << "} but getDofOrdinal({" 
          << myTag(0) << ", " 
          << myTag(1) << ", " 
          << myTag(2) << ", " 
          << myTag(3) << "} ) = " << myBfOrd << "\n";
      }
    }
  } catch (std::logic_error err){
    *outStream << err.what() << "\n\n";
    errorFlag = -1000;
  };
  
  *outStream
    << "\n"
    << "===============================================================================\n"
    << "| TEST 3: correctness of basis function values                                |\n"
    << "===============================================================================\n";
  
  outStream -> precision(20);
  
  // VALUE: Each row pair gives the 9x3 correct basis set values at an evaluation point: (P,F,D) layout
  const ValueType basisValues[] = {
    1.00000, 0, 0, 0, 0, 0, 0, -1.00000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
    0, 0.500000, 0, 0, 0, 0, 0, 0, 1.00000, 1.00000, 0, 0, 1.00000, 0, 0, \
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.500000, 0, 0, 0, 0, \
    0, 0, -1.00000, 0, 0, -1.00000, -1.00000, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0.500000, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
    1.00000, 0, 0, 0, 0, 0, 0, -1.00000, 0, 0, 0, 0.500000, 0, 0, 0, 0, \
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00000, 1.00000, 0, 0, 1.00000, 0, \
    0, 0, 0, 0, 0, 0, 0, 0, 0.500000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
    0, 0, 0, -1.00000, 0, 0, -1.00000, -1.00000, 0, 0, 0, 0, 0, 0, 0, 0, \
    0, 0.500000, 0.500000, 0.250000, 0, -0.500000, 0.250000, 0, \
    -0.500000, -0.750000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.125000, \
    0, 0, 0.125000, 0, 0, 0.250000, 0.375000, 0.250000, 0, -0.125000, \
    0.250000, 0, -0.125000, -0.250000, 0, 0.375000, 0.250000, 0, \
    -0.125000, 0.250000, 0, -0.125000, -0.250000, 0, 0, 0, 0.125000, 0, \
    0, 0.250000, 0, 0, 0.125000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.750000, \
    0.250000, 0, -0.250000, 0.250000, 0, -0.250000, -0.750000, 0, 0, 0, \
    0.250000, 0, 0, 0.125000, 0, 0, 0.125000, 0.125000, 0.0312500, 0, 0, \
    0.0312500, 0, 0, -0.0937500, 0, 0.875000, 0.218750, 0, 0, 0.218750, \
    0, 0, -0.656250, 0, 0, 0, 0.375000, 0, 0, 0.125000, 0, 0, 0, \
    0.312500, 0, 0, -0.312500, 0, 0, -0.312500, -0.625000, 0, 0.187500, \
    0, 0, -0.187500, 0, 0, -0.187500, -0.375000, 0, 0, 0, 0.250000, 0, 0, \
    0, 0, 0, 0.250000, 0.250000, 0.250000, 0, -0.250000, 0.250000, 0, \
    -0.250000, -0.250000, 0, 0.250000, 0.250000, 0, -0.250000, 0.250000, \
    0, -0.250000, -0.250000, 0, 0, 0, 0, 0, 0, 0.250000, 0, 0, 0.250000    
  };
  
  // CURL: each row pair gives the 9x3 correct values of the curls of the 9 basis functions: (P,F,D) layout
  const ValueType basisCurls[] = {  
    0, -0.500000, 2.00000, 0, 0, 2.00000, -0.500000, 0, 2.00000, 0, \
    0.500000, 0, 0, 0, 0, 0.500000, 0, 0, -0.500000, 0.500000, 0, 0, \
    -0.500000, 0, 0.500000, 0, 0, 0.500000, -0.500000, 2.00000, 0.500000, \
    0, 2.00000, 0, 0, 2.00000, -0.500000, 0.500000, 0, -0.500000, 0, 0, \
    0, 0, 0, -0.500000, 0.500000, 0, 0, -0.500000, 0, 0.500000, 0, 0, 0, \
    0, 2.00000, 0, 0.500000, 2.00000, -0.500000, 0.500000, 2.00000, 0, 0, \
    0, 0, -0.500000, 0, 0.500000, -0.500000, 0, -0.500000, 0.500000, 0, \
    0, -0.500000, 0, 0.500000, 0, 0, 0, -0.500000, 0, 0, 0, 0, -0.500000, \
    0, 0, 0, 0.500000, 2.00000, 0, 0, 2.00000, 0.500000, 0, 2.00000, \
    -0.500000, 0.500000, 0, 0, -0.500000, 0, 0.500000, 0, 0, 0.500000, \
    -0.500000, 0, 0.500000, 0, 0, 0, 0, 0, -0.500000, 0.500000, 2.00000, \
    -0.500000, 0, 2.00000, 0, 0, 2.00000, -0.500000, 0.500000, 0, 0, \
    -0.500000, 0, 0.500000, 0, 0, 0, 0, 0, 0, 0.500000, 0, -0.500000, \
    0.500000, 0, 0, 0, 2.00000, 0, -0.500000, 2.00000, 0.500000, \
    -0.500000, 2.00000, -0.500000, 0.500000, 0, 0, -0.500000, 0, \
    0.500000, 0, 0, 0.125000, -0.250000, 2.00000, 0.125000, 0.250000, \
    2.00000, -0.375000, 0.250000, 2.00000, -0.125000, 0.250000, 0, \
    -0.125000, -0.250000, 0, 0.375000, -0.250000, 0, -0.500000, 0.500000, \
    0, 0, -0.500000, 0, 0.500000, 0, 0, 0.250000, -0.375000, 1.00000, \
    0.250000, 0.125000, 1.00000, -0.250000, 0.125000, 1.00000, -0.250000, \
    0.375000, 1.00000, -0.250000, -0.125000, 1.00000, 0.250000, \
    -0.125000, 1.00000, -0.500000, 0.500000, 0, 0, -0.500000, 0, \
    0.500000, 0, 0, 0.125000, -0.375000, 0, 0.125000, 0.125000, 0, \
    -0.375000, 0.125000, 0, -0.125000, 0.375000, 2.00000, -0.125000, \
    -0.125000, 2.00000, 0.375000, -0.125000, 2.00000, -0.500000, \
    0.500000, 0, 0, -0.500000, 0, 0.500000, 0, 0, 0.125000, -0.500000, \
    0.250000, 0.125000, 0, 0.250000, -0.375000, 0, 0.250000, -0.125000, \
    0.500000, 1.75000, -0.125000, 0, 1.75000, 0.375000, 0, 1.75000, \
    -0.500000, 0.500000, 0, 0, -0.500000, 0, 0.500000, 0, 0, 0, \
    -0.250000, 1.25000, 0, 0.250000, 1.25000, -0.500000, 0.250000, \
    1.25000, 0, 0.250000, 0.750000, 0, -0.250000, 0.750000, 0.500000, \
    -0.250000, 0.750000, -0.500000, 0.500000, 0, 0, -0.500000, 0, \
    0.500000, 0, 0, 0.250000, -0.250000, 1.00000, 0.250000, 0.250000, \
    1.00000, -0.250000, 0.250000, 1.00000, -0.250000, 0.250000, 1.00000, \
    -0.250000, -0.250000, 1.00000, 0.250000, -0.250000, 1.00000, \
    -0.500000, 0.500000, 0, 0, -0.500000, 0, 0.500000, 0, 0
  };
  
  try{
    
    DynRankViewHost ConstructWithLabel(wedgeNodesHost, 12, 3);
    wedgeNodesHost(0,0) =  0.0;  wedgeNodesHost(0,1) =  0.0;  wedgeNodesHost(0,2) = -1.0;
    wedgeNodesHost(1,0) =  1.0;  wedgeNodesHost(1,1) =  0.0;  wedgeNodesHost(1,2) = -1.0;
    wedgeNodesHost(2,0) =  0.0;  wedgeNodesHost(2,1) =  1.0;  wedgeNodesHost(2,2) = -1.0;
    wedgeNodesHost(3,0) =  0.0;  wedgeNodesHost(3,1) =  0.0;  wedgeNodesHost(3,2) =  1.0;
    wedgeNodesHost(4,0) =  1.0;  wedgeNodesHost(4,1) =  0.0;  wedgeNodesHost(4,2) =  1.0;
    wedgeNodesHost(5,0) =  0.0;  wedgeNodesHost(5,1) =  1.0;  wedgeNodesHost(5,2) =  1.0;
  
    wedgeNodesHost(6,0) =  0.25; wedgeNodesHost(6,1) =  0.5;  wedgeNodesHost(6,2) = -1.0;
    wedgeNodesHost(7,0) =  0.5;  wedgeNodesHost(7,1) =  0.25; wedgeNodesHost(7,2) =  0.0;
    wedgeNodesHost(8,0) =  0.25; wedgeNodesHost(8,1) =  0.25; wedgeNodesHost(8,2) =  1.0;
    wedgeNodesHost(9,0) =  0.25; wedgeNodesHost(9,1) =  0.0;  wedgeNodesHost(9,2) =  0.75;
    wedgeNodesHost(10,0)=  0.0;  wedgeNodesHost(10,1)=  0.5;  wedgeNodesHost(10,2)= -0.25;
    wedgeNodesHost(11,0)=  0.5;  wedgeNodesHost(11,1)=  0.5;  wedgeNodesHost(11,2)=  0.0;

    const auto wedgeNodes = Kokkos::create_mirror_view(typename DeviceSpaceType::memory_space(), wedgeNodesHost);
    Kokkos::deep_copy(wedgeNodes, wedgeNodesHost);
        
    // Dimensions for the output arrays:
    const ordinal_type numFields = wedgeBasis.getCardinality();
    const ordinal_type numPoints = wedgeNodes.dimension(0);
    const ordinal_type spaceDim  = wedgeBasis.getBaseCellTopology().getDimension();
    
    {
    // Check VALUE of basis functions: resize vals to rank-3 container:
    DynRankView ConstructWithLabel(vals, numFields, numPoints, spaceDim);
    wedgeBasis.getValues(vals, wedgeNodes, OPERATOR_VALUE);
    auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
    Kokkos::deep_copy(vals_host, vals);
    for (ordinal_type i = 0; i < numFields; ++i) {
      for (ordinal_type j = 0; j < numPoints; ++j) {
        for (ordinal_type k = 0; k < spaceDim; ++k) {
          
          // compute offset for (P,F,D) data layout: indices are P->j, F->i, D->k
           const ordinal_type l = k + i * spaceDim + j * spaceDim * numFields;
           if (std::abs(vals_host(i,j,k) - basisValues[l]) > tol) {
             errorFlag++;
             *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

             // Output the multi-index of the value where the error is:
             *outStream << " At multi-index { ";
             *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
             *outStream << "}  computed value: " << vals_host(i,j,k)
               << " but reference value: " << basisValues[l] << "\n";
            }
         }
      }
    }
    }

    {
    // Check CURL of basis function: resize vals to rank-3 container
    DynRankView ConstructWithLabel(vals, numFields, numPoints, spaceDim);
    wedgeBasis.getValues(vals, wedgeNodes, OPERATOR_CURL);
    auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals);
    Kokkos::deep_copy(vals_host, vals);
    for (ordinal_type i = 0; i < numFields; ++i) {
      for (ordinal_type j = 0; j < numPoints; ++j) {
        for (ordinal_type k = 0; k < spaceDim; ++k) {
          
          // compute offset for (P,F,D) data layout: indices are P->j, F->i, D->k
           const ordinal_type l = k + i * spaceDim + j * spaceDim * numFields;
           if (std::abs(vals_host(i,j,k) - basisCurls[l]) > tol) {
             errorFlag++;
             *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

             // Output the multi-index of the value where the error is:
             *outStream << " At multi-index { ";
             *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
             *outStream << "}  computed curl component: " << vals_host(i,j,k)
               << " but reference curl component: " << basisCurls[l] << "\n";
            }
         }
      }
    }
    }
    
   }    
  
  // Catch unexpected errors
  catch (std::logic_error err) {
    *outStream << err.what() << "\n\n";
    errorFlag = -1000;
  };

  if (errorFlag != 0)
    std::cout << "End Result: TEST FAILED\n";
  else
    std::cout << "End Result: TEST PASSED\n";
  
  // reset format state of std::cout
  std::cout.copyfmt(oldFormatState);
  return errorFlag;
}
Beispiel #18
0
    int Integration_Test01(const bool verbose) {

      Teuchos::RCP<std::ostream> outStream;
      Teuchos::oblackholestream bhs; // outputs nothing

      if (verbose)
        outStream = Teuchos::rcp(&std::cout, false);
      else
        outStream = Teuchos::rcp(&bhs, false);

      Teuchos::oblackholestream oldFormatState;
      oldFormatState.copyfmt(std::cout);

      typedef typename
        Kokkos::Impl::is_space<DeviceSpaceType>::host_mirror_space::execution_space HostSpaceType ;

      *outStream << "DeviceSpace::  "; DeviceSpaceType::print_configuration(*outStream, false);
      *outStream << "HostSpace::    ";   HostSpaceType::print_configuration(*outStream, false);

      *outStream
        << "===============================================================================\n"
        << "|                                                                             |\n"
        << "|                  Unit Test (CubatureDirect,CubatureTensor)                  |\n"
        << "|                                                                             |\n"
        << "|     1) Computing volumes of reference cells                                 |\n"
        << "|                                                                             |\n"
        << "|  Questions? Contact  Pavel Bochev ([email protected]) or                   |\n"
        << "|                      Denis Ridzal ([email protected]) or                   |\n"
        << "|                      Kyungjoo Kim ([email protected]).                      |\n"
        << "|                                                                             |\n"
        << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n"
        << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n"
        << "|                                                                             |\n"
        << "===============================================================================\n";

      typedef Kokkos::DynRankView<ValueType,DeviceSpaceType> DynRankView;
#define ConstructWithLabel(obj, ...) obj(#obj, __VA_ARGS__)

      typedef ValueType pointValueType;
      typedef ValueType weightValueType;
      typedef CubatureDirectLineGauss        <DeviceSpaceType,pointValueType,weightValueType> CubatureLineType;
      typedef CubatureDirectLineGaussJacobi20<DeviceSpaceType,pointValueType,weightValueType> CubatureLineJacobiType;
      typedef CubatureDirectTriDefault       <DeviceSpaceType,pointValueType,weightValueType> CubatureTriType;
      typedef CubatureDirectTetDefault       <DeviceSpaceType,pointValueType,weightValueType> CubatureTetType;
      typedef CubatureTensor                 <DeviceSpaceType,pointValueType,weightValueType> CubatureTensorType;
      typedef CubatureTensorPyr              <DeviceSpaceType,pointValueType,weightValueType> CubatureTensorPyrType;

      const auto tol = 100.0 * tolerence();

      int errorFlag  = 0;

      *outStream
        << "\n"
        << "===============================================================================\n"
        << "| TEST 1: exception                                                           |\n"
        << "===============================================================================\n";

      try {
        ordinal_type nthrow = 0, ncatch = 0;
#ifdef HAVE_INTREPID2_DEBUG
        *outStream << "-> Line testing\n\n";
        {
          INTREPID2_TEST_ERROR_EXPECTED( CubatureLineType(-1) );
          INTREPID2_TEST_ERROR_EXPECTED( CubatureLineType(Parameters::MaxCubatureDegreeEdge+1) );
        }

        *outStream << "-> Triangle testing\n\n";
        {
          INTREPID2_TEST_ERROR_EXPECTED( CubatureTriType triCub(-1) );
          INTREPID2_TEST_ERROR_EXPECTED( CubatureTriType triCub(Parameters::MaxCubatureDegreeTri+1) );
        }

        *outStream << "-> Tetrahedron testing\n\n";
        {
          INTREPID2_TEST_ERROR_EXPECTED( CubatureTetType tetCub(-1) );
          INTREPID2_TEST_ERROR_EXPECTED( CubatureTetType tetCub(Parameters::MaxCubatureDegreeTet+1) );
        }
#endif
        if (nthrow != ncatch) {
          errorFlag++;
          *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
          *outStream << "# of catch ("<< ncatch << ") is different from # of throw (" << ncatch << ")\n";
        }

      } catch (std::logic_error err) {
        *outStream << err.what() << "\n";
        errorFlag = -1000;
      };


      *outStream
        << "\n"
        << "===============================================================================\n"
        << "| TEST 2: basic functionalities                                               |\n"
        << "===============================================================================\n";

      try {

        *outStream << "-> Line testing\n\n";
        {
          CubatureLineType lineCub(4);
          INTREPID2_TEST_FOR_EXCEPTION( lineCub.getDimension() != 1, std::logic_error,
                                        ">>> ERROR (Integration::Test01): line cubature must have 1 dimension.");
          INTREPID2_TEST_FOR_EXCEPTION( lineCub.getAccuracy() != 4, std::logic_error,
                                        ">>> ERROR (Integration::Test01): line cubature reports wrong accuracy.");
        }

        *outStream << "-> Triangle testing\n\n";
        {
          CubatureTriType triCub(17);
          INTREPID2_TEST_FOR_EXCEPTION( triCub.getNumPoints() != 61, std::logic_error,
                                        ">>> ERROR (Integration::Test01): triangle cubature reports a wrong number of points.");
          INTREPID2_TEST_FOR_EXCEPTION( triCub.getDimension() != 2, std::logic_error,
                                        ">>> ERROR (Integration::Test01): triangle cubature reports a wrong dimension.");
        }

        *outStream << "-> Tetrahedron testing\n\n";
        {
          CubatureTetType tetCub(17);
          INTREPID2_TEST_FOR_EXCEPTION( tetCub.getNumPoints() != 495, std::logic_error,
                                        ">>> ERROR (Integration::Test01): tetrahedron cubature reports a wrong number of points.");
          INTREPID2_TEST_FOR_EXCEPTION( tetCub.getDimension() != 3, std::logic_error,
                                        ">>> ERROR (Integration::Test01): tetrahedron cubature reports a wrong dimension.");
        }

        *outStream << "-> Quad testing\n\n";
        {
          CubatureTensorType quadCub( CubatureLineType(3), CubatureLineType(7) );

          INTREPID2_TEST_FOR_EXCEPTION( quadCub.getDimension() != 2, std::logic_error,
                                        ">>> ERROR (Integration::Test01): quad cubature must have 2 dimension.");

          ordinal_type accuracy[Parameters::MaxDimension];
          quadCub.getAccuracy( accuracy );
          INTREPID2_TEST_FOR_EXCEPTION( accuracy[0] != 3 || accuracy[1] != 7, std::logic_error,
                                        ">>> ERROR (Integration::Test01): quad cubature reports wrong accuracy.");

        }

        *outStream << "-> Hex testing\n\n";
        {
          CubatureTensorType hexCub( CubatureLineType(1), CubatureLineType(4), CubatureLineType(2) );

          INTREPID2_TEST_FOR_EXCEPTION( hexCub.getDimension() != 3, std::logic_error,
                                        ">>> ERROR (Integration::Test01): hex cubature must have 3 dimension.");

          ordinal_type accuracy[Parameters::MaxDimension];
          hexCub.getAccuracy( accuracy );
          INTREPID2_TEST_FOR_EXCEPTION( accuracy[0] != 1 || accuracy[1] != 4 || accuracy[2] != 2, std::logic_error,
                                        ">>> ERROR (Integration::Test01): hex cubature reports wrong accuracy.");
        }

        *outStream << "-> Prism testing\n\n";
        {
          CubatureTensorType prismCub( CubatureTriType(4), CubatureLineType(3) );

          INTREPID2_TEST_FOR_EXCEPTION( prismCub.getDimension() != 3, std::logic_error,
                                        ">>> ERROR (Integration::Test01): prism cubature must have 3 dimension.");

          ordinal_type accuracy[Parameters::MaxDimension];
          prismCub.getAccuracy( accuracy );
          INTREPID2_TEST_FOR_EXCEPTION( accuracy[0] != 4 || accuracy[1] != 3, std::logic_error,
                                        ">>> ERROR (Integration::Test01): prism cubature reports wrong accuracy.");
        }

      } catch (std::logic_error err) {
        *outStream << err.what() << "\n";
        errorFlag = -1000;
      };

      *outStream
        << "===============================================================================\n"
        << "| TEST 3: volume computations                                                 |\n"
        << "===============================================================================\n";

      try {

        DynRankView ConstructWithLabel(cubPoints,  Parameters::MaxIntegrationPoints, Parameters::MaxDimension);
        DynRankView ConstructWithLabel(cubWeights, Parameters::MaxIntegrationPoints);

        *outStream << "-> Line testing\n\n";
        {
          for (ordinal_type deg=0;deg<=Parameters::MaxCubatureDegreeEdge;++deg) {
            CubatureLineType cub(deg);
            cub.getCubature(cubPoints, cubWeights);
            const auto npts = cub.getNumPoints();

            const auto testVol = computeRefVolume(npts, cubWeights);
            const auto refVol  = 2.0;
            if (std::abs(testVol - refVol) > tol) {
              *outStream << std::setw(30) << "Line volume --> " << std::setw(10) << std::scientific << testVol <<
                std::setw(10) << "diff = " << std::setw(10) << std::scientific << std::abs(testVol - refVol) << "\n";
              ++errorFlag;
              *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
            }
          }
        }

        *outStream << "-> Triangle testing\n\n";
        {
          for (auto deg=0;deg<=Parameters::MaxCubatureDegreeTri;++deg) {
            CubatureTriType cub(deg);
            cub.getCubature(cubPoints, cubWeights);
            const auto npts = cub.getNumPoints();

            const auto testVol = computeRefVolume(npts, cubWeights);
            const auto refVol  = 0.5;
            if (std::abs(testVol - refVol) > tol) {
              *outStream << std::setw(30) << "Triangle volume --> " << std::setw(10) << std::scientific << testVol <<
                std::setw(10) << "diff = " << std::setw(10) << std::scientific << std::abs(testVol - refVol) << "\n";
              ++errorFlag;
              *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
            }
          }
        }

        *outStream << "-> Quad testing\n\n";
        {
          for (ordinal_type y_deg=0;y_deg<=Parameters::MaxCubatureDegreeEdge;++y_deg)
            for (ordinal_type x_deg=0;x_deg<=Parameters::MaxCubatureDegreeEdge;++x_deg) {
              const auto x_line = CubatureLineType(x_deg);
              const auto y_line = CubatureLineType(y_deg);
              CubatureTensorType cub( x_line, y_line );

              cub.getCubature(cubPoints, cubWeights);
              const auto npts = cub.getNumPoints();

              const auto testVol = computeRefVolume(npts, cubWeights);
              const auto refVol  = 4.0;
              if (std::abs(testVol - refVol) > tol) {
                *outStream << std::setw(30) << "Quadrilateral volume --> " << std::setw(10) << std::scientific << testVol <<
                  std::setw(10) << "diff = " << std::setw(10) << std::scientific << std::abs(testVol - refVol) << "\n";

                ++errorFlag;
                *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
              }
            }
        }
        
        *outStream << "-> Tetrahedron testing\n\n";
        {
          for (auto deg=0;deg<=Parameters::MaxCubatureDegreeTet;++deg) {
            CubatureTetType cub(deg);
            
            cub.getCubature(cubPoints, cubWeights);
            const auto npts = cub.getNumPoints();
            
            const auto testVol = computeRefVolume(npts, cubWeights);
            const auto refVol  = 1.0/6.0;
            if (std::abs(testVol - refVol) > tol) {
              *outStream << std::setw(30) << "Tetrahedron volume --> " << std::setw(10) << std::scientific << testVol <<
                std::setw(10) << "diff = " << std::setw(10) << std::scientific << std::abs(testVol - refVol) << "\n";
              
              ++errorFlag;
              *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
            }
          }
        }
        
        *outStream << "-> Hexahedron testing\n\n";
        {
          // when hex is tested with max cubature degree edge, it exceeds max integration points 1001
          for (ordinal_type z_deg=0;z_deg<Parameters::MaxCubatureDegreeEdge;++z_deg)
            for (ordinal_type y_deg=0;y_deg<Parameters::MaxCubatureDegreeEdge;++y_deg)
              for (ordinal_type x_deg=0;x_deg<Parameters::MaxCubatureDegreeEdge;++x_deg) {
                const auto x_line = CubatureLineType(x_deg);
                const auto y_line = CubatureLineType(y_deg);
                const auto z_line = CubatureLineType(z_deg);
                CubatureTensorType cub( x_line, y_line, z_line );

                cub.getCubature(cubPoints, cubWeights);
                const auto npts = cub.getNumPoints();

                const auto testVol = computeRefVolume(npts, cubWeights);
                const auto refVol  = 8.0;
                if (std::abs(testVol - refVol) > tol) {
                  *outStream << std::setw(30) << "Hexahedron volume --> " << std::setw(10) << std::scientific << testVol <<
                    std::setw(10) << "diff = " << std::setw(10) << std::scientific << std::abs(testVol - refVol) << "\n";

                  ++errorFlag;
                  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
                }
              }
        }

        *outStream << "-> Prism testing\n\n";
        {
          for (auto z_deg=0;z_deg<Parameters::MaxCubatureDegreeEdge;++z_deg)
            for (auto xy_deg=0;xy_deg<Parameters::MaxCubatureDegreeTri;++xy_deg) {
              const auto xy_tri = CubatureTriType(xy_deg);
              const auto z_line = CubatureLineType(z_deg);
              CubatureTensorType cub( xy_tri, z_line );
              
              cub.getCubature(cubPoints, cubWeights);
              const auto npts = cub.getNumPoints();
              
              const auto testVol = computeRefVolume(npts, cubWeights);
              const auto refVol  = 1.0;
              if (std::abs(testVol - refVol) > tol) {
                *outStream << std::setw(30) << "Wedge volume --> " << std::setw(10) << std::scientific << testVol <<
                  std::setw(10) << "diff = " << std::setw(10) << std::scientific << std::abs(testVol - refVol) << "\n";
                ++errorFlag;
                *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
              }
            }
        }
        
        *outStream << "-> Pyramid testing: over-integration by 2 (due to duffy transformation) \n\n";
        {
          for (auto deg=0;deg<=Parameters::MaxCubatureDegreePyr;++deg) {
            const auto xy_line = CubatureLineType(deg);
            const auto z_line  = CubatureLineJacobiType(deg);
            CubatureTensorPyrType cub( xy_line, xy_line, z_line );
            cub.getCubature(cubPoints, cubWeights);
            const auto npts = cub.getNumPoints();
            
            const auto testVol = computeRefVolume(npts, cubWeights);
            const auto refVol  = 4.0/3.0;
            if (std::abs(testVol - refVol) > tol) {              
              *outStream << std::setw(30) << "Pyramid volume --> " << std::setw(10) << std::scientific << testVol <<
                std::setw(10) << "diff = " << std::setw(10) << std::scientific << std::abs(testVol - refVol) << "\n";
              
              ++errorFlag;
              *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
            }
          }
        }

        *outStream << "-> Hypercube testing\n\n";
        // later.... refVol = 32
        // for (int deg=0; deg<=20; deg++) {
        //   Teuchos::RCP<CubatureLineType > lineCub = Teuchos::rcp(new CubatureLineType(deg));
        //   CubatureTensorType hypercubeCub(lineCub, 5);
        //   int numCubPoints = hypercubeCub.getNumPoints();
        //   FieldContainer<DeviceSpaceType> cubPoints( numCubPoints, hypercubeCub.getDimension() );
        //   FieldContainer<DeviceSpaceType> cubWeights( numCubPoints );
        //   hypercubeCub.getCubature(cubPoints, cubWeights);
        //   testVol = 0;
        //   for (int i=0; i<numCubPoints; i++)
        //     testVol += cubWeights(i);
        //   *outStream << std::setw(30) << "5-D Hypercube volume --> " << std::setw(10) << std::scientific << testVol <<
        //     std::setw(10) << "diff = " << std::setw(10) << std::scientific << std::abs(testVol - volumeList[8]) << "\n";
        //   if (std::abs(testVol - volumeList[8])/std::abs(testVol) > tol) {
        //     errorFlag = 1;
        //     *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
        //   }
        // }
      }  catch (std::logic_error err) {
        *outStream << err.what() << "\n";
        errorFlag = -1;
      };


      if (errorFlag != 0)
        std::cout << "End Result: TEST FAILED\n";
      else
        std::cout << "End Result: TEST PASSED\n";

      // reset format state of std::cout
      std::cout.copyfmt(oldFormatState);
      Kokkos::finalize();
      return errorFlag;
    }
Beispiel #19
0
    int Integration_Test10(const bool verbose) {

      Teuchos::RCP<std::ostream> outStream;
      Teuchos::oblackholestream bhs; // outputs nothing

      if (verbose)
        outStream = Teuchos::rcp(&std::cout, false);
      else
        outStream = Teuchos::rcp(&bhs, false);

      Teuchos::oblackholestream oldFormatState;
      oldFormatState.copyfmt(std::cout);

      typedef typename
        Kokkos::Impl::is_space<DeviceSpaceType>::host_mirror_space::execution_space HostSpaceType ;

      *outStream << "DeviceSpace::  "; DeviceSpaceType::print_configuration(*outStream, false);
      *outStream << "HostSpace::    ";   HostSpaceType::print_configuration(*outStream, false);
 
      *outStream
        << "===============================================================================\n"
        << "|                                                                             |\n"
        << "|                 Unit Test (CubaturePolylib)                                 |\n"
        << "|                                                                             |\n"
        << "|     1) Computing integrals of monomials on reference cells in 1D            |\n"
        << "|                                                                             |\n"
        << "|  Questions? Contact  Pavel Bochev ([email protected]) or                   |\n"
        << "|                      Denis Ridzal ([email protected]) or                   |\n"
        << "|                      Kyungjoo Kim ([email protected]).                      |\n"
        << "|                                                                             |\n"
        << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n"
        << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n"
        << "|                                                                             |\n"
        << "===============================================================================\n"
        << "| TEST 1: integrals of monomials in 1D                                        |\n"
        << "===============================================================================\n";

      typedef Kokkos::DynRankView<ValueType,DeviceSpaceType> DynRankView;
#define ConstructWithLabel(obj, ...) obj(#obj, __VA_ARGS__)

      typedef ValueType pointValueType;
      typedef ValueType weightValueType;
      typedef CubaturePolylib<DeviceSpaceType,pointValueType,weightValueType> CubatureLineType;

      const auto tol = 10.0 * tolerence();

      int errorFlag = 0;

      // open file with analytic values
      std::string basedir = "../data";
      std::stringstream namestream;
      std::string filename;
      namestream <<  basedir << "/EDGE_integrals" << ".dat";
      namestream >> filename;
      *outStream << "filename = "  << filename << std::endl;
      std::ifstream filecompare(filename);

      *outStream << "\n-> Integrals of monomials on a reference line (edge):\n";

      // compute and compare integrals
      try {
        const auto maxDeg   = Parameters::MaxCubatureDegreeEdge;
        const auto polySize = maxDeg + 1;

        // test inegral values
        DynRankView ConstructWithLabel(testInt, maxDeg+1, polySize);
        
        // analytic integral values
        DynRankView ConstructWithLabel(analyticInt, maxDeg+1, polySize);

        // get analytic values
        if (filecompare.is_open()) {
          getAnalytic(analyticInt, filecompare);
          filecompare.close();
        } else {
          INTREPID2_TEST_FOR_EXCEPTION( true, std::runtime_error,
                                        ">>> ERROR (Integration::Test02): Cannot open analytic solution file" );
        }
        
        // storage for cubatrue points and weights
        DynRankView ConstructWithLabel(cubPoints, 
                                       Parameters::MaxIntegrationPoints, 
                                       Parameters::MaxDimension);

        DynRankView ConstructWithLabel(cubWeights, 
                                       Parameters::MaxIntegrationPoints);
        
        // compute integrals
        EPolyType polyType[4] = { POLYTYPE_GAUSS,
                                  POLYTYPE_GAUSS_RADAU_LEFT,
                                  POLYTYPE_GAUSS_RADAU_RIGHT,
                                  POLYTYPE_GAUSS_LOBATTO };
        for (size_type pid=0;pid<4;++pid) {
          const auto ptype = polyType[pid];
          *outStream << "\n  -> Testing poly type " << EPolyTypeToString(ptype) << "\n";

          for (size_type cubDeg=0;cubDeg<=maxDeg;++cubDeg) {
            CubatureLineType lineCub(cubDeg, ptype);
            for (auto polyDeg=0;polyDeg<=cubDeg;++polyDeg) 
              testInt(cubDeg, polyDeg) = computeIntegralOfMonomial<ValueType>(lineCub,
                                                                              cubPoints,
                                                                              cubWeights,
                                                                              polyDeg);
          }
                    
          // perform comparison
          for (size_type cubDeg=0;cubDeg<=maxDeg;++cubDeg) {
            for (auto polyDeg=0;polyDeg<=cubDeg;++polyDeg) {
              const auto abstol  = ( analyticInt(polyDeg,0) == 0 ? tol : std::fabs(tol*analyticInt(polyDeg,0)) );
              const auto absdiff = std::fabs(analyticInt(polyDeg,0) - testInt(cubDeg,polyDeg));
              *outStream << "Cubature order " << std::setw(2) << std::left << cubDeg << " integrating "
                         << "x^" << std::setw(2) << std::left << polyDeg <<  ":" << "   "
                         << std::scientific << std::setprecision(16) << testInt(cubDeg,polyDeg) << "   " << analyticInt(polyDeg,0) << "   "
                         << std::setprecision(4) << absdiff << "   " << "<?" << "   " << abstol << "\n";
              if (absdiff > abstol) {
                errorFlag++;
                *outStream << std::right << std::setw(104) << "^^^^---FAILURE!\n";
              }
            }
            *outStream << "\n";
          }
        } 
      } catch (std::logic_error err) {
        *outStream << err.what() << "\n";
        errorFlag = -1;
      }
      
      
      if (errorFlag != 0)
        std::cout << "End Result: TEST FAILED\n";
      else
        std::cout << "End Result: TEST PASSED\n";

      // reset format state of std::cout
      std::cout.copyfmt(oldFormatState);

      return errorFlag;
    }
Beispiel #20
0
    int HGRAD_LINE_C1_FEM_Test01(const bool verbose) {

      typedef ValueType value_type;

      Teuchos::RCP<std::ostream> outStream;
      Teuchos::oblackholestream bhs; // outputs nothing

      if (verbose)
        outStream = Teuchos::rcp(&std::cout, false);
      else
        outStream = Teuchos::rcp(&bhs,       false);

      Teuchos::oblackholestream oldFormatState;
      oldFormatState.copyfmt(std::cout);

      typedef typename
        Kokkos::Impl::is_space<DeviceSpaceType>::host_mirror_space::execution_space HostSpaceType ;

      *outStream << "DeviceSpace::  "; DeviceSpaceType::print_configuration(*outStream, false);
      *outStream << "HostSpace::    ";   HostSpaceType::print_configuration(*outStream, false);

      *outStream
        << "===============================================================================n"
        << "|                                                                             |\n"
        << "|                 Unit Test (Basis_HGRAD_LINE_C1_FEM)                         |\n"
        << "|                                                                             |\n"
        << "|     1) Conversion of Dof tags into Dof ordinals and back                    |\n"
        << "|     2) Basis values for VALUE, GRAD, CURL, DIV, and Dk operators            |\n"
        << "|                                                                             |\n"
        << "|  Questions? Contact  Pavel Bochev  ([email protected]),                    |\n"
        << "|                      Denis Ridzal  ([email protected]),                    |\n"
        << "|                      Kara Peterson ([email protected]).                    |\n"
        << "|                                                                             |\n"
        << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n"
        << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n"
        << "|                                                                             |\n"
        << "===============================================================================\n";

      typedef Kokkos::DynRankView<value_type,DeviceSpaceType> DynRankView;
#define ConstructWithLabel(obj, ...) obj(#obj, __VA_ARGS__)

      const value_type tol = Parameters::Tolerence;
      int errorFlag = 0;

      *outStream
        << "\n"
        << "===============================================================================\n"
        << "| TEST 1: Basis creation, exceptions tests                                    |\n"
        << "===============================================================================\n";


      try{
        ordinal_type nthrow = 0, ncatch = 0;
#ifdef HAVE_INTREPID2_DEBUG
        Basis_HGRAD_LINE_C1_FEM<DeviceSpaceType> lineBasis;

        // Define array containing the 2 vertices of the reference Line, its center and another point
        DynRankView ConstructWithLabel(lineNodes, 4, 1);

        // Generic array for the output values; needs to be properly resized depending on the operator type
        const auto numFields = lineBasis.getCardinality();
        const auto numPoints = lineNodes.dimension(0);
        const auto spaceDim  = lineBasis.getBaseCellTopology().getDimension();

        const auto workSize  = numFields*numPoints*spaceDim;
        DynRankView ConstructWithLabel(work, workSize);

        // resize vals to rank-2 container with dimensions
        DynRankView vals = DynRankView(work.data(), numFields, numPoints);

        // Exceptions 1-5: all bf tags/bf Ids below are wrong and should cause getDofOrdinal() and
        // getDofTag() to access invalid array elements thereby causing bounds check exception
        {
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getDofOrdinal(2,0,0), nthrow, ncatch );  // #1
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getDofOrdinal(1,1,1), nthrow, ncatch );  // #2
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getDofOrdinal(0,4,0), nthrow, ncatch );  // #3
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getDofTag(5),         nthrow, ncatch );  // #4
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getDofTag(-1),        nthrow, ncatch );  // #5
        }

        // Exceptions 6-17 test exception handling with incorrectly dimensioned input/output arrays
        {
          // exception #6: input points array must be of rank-2
          DynRankView ConstructWithLabel(badPoints, 4, 5, 3);
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getValues(vals, badPoints, OPERATOR_VALUE), nthrow, ncatch );
        }
        {
          // exception #7 dimension 1 in the input point array must equal space dimension of the cell
          DynRankView ConstructWithLabel(badPoints, 4, 2);
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getValues(vals, badPoints, OPERATOR_VALUE), nthrow, ncatch );
        }
        {
          // exception #8 output values must be of rank-2 for OPERATOR_VALUE
          DynRankView ConstructWithLabel(badVals, 4, 3, 1);
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getValues(badVals, lineNodes, OPERATOR_VALUE), nthrow, ncatch );
        }
        {
          // exception #9 output values must be of rank-3 for OPERATOR_GRAD
          DynRankView ConstructWithLabel(badVals, 4, 3);
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getValues(badVals, lineNodes, OPERATOR_GRAD), nthrow, ncatch );

          // exception #10 output values must be of rank-3 for OPERATOR_DIV
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getValues(badVals, lineNodes, OPERATOR_DIV), nthrow, ncatch );

          // exception #11 output values must be of rank-3 for OPERATOR_CURL
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getValues(badVals, lineNodes, OPERATOR_CURL), nthrow, ncatch );

          // exception #12 output values must be of rank-3 for OPERATOR_D2
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getValues(badVals, lineNodes, OPERATOR_D2), nthrow, ncatch );
        }
        {
          // exception #13 incorrect 1st dimension of output array (must equal number of basis functions)
          DynRankView ConstructWithLabel(badVals, numFields + 1, numPoints);
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getValues(badVals, lineNodes, OPERATOR_VALUE), nthrow, ncatch );
        }
        {
          // exception #14 incorrect 0th dimension of output array (must equal number of points)
          DynRankView ConstructWithLabel(badVals, numFields, numPoints + 1);
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getValues(badVals, lineNodes, OPERATOR_VALUE), nthrow, ncatch );
        }
        {
          // exception #15: incorrect 2nd dimension of output array (must equal the space dimension)
          DynRankView ConstructWithLabel(badVals, numFields, numPoints, 2);
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getValues(badVals, lineNodes, OPERATOR_GRAD), nthrow, ncatch );
        }
        {
          // exception #16: incorrect 2nd dimension of output array (must equal D2 cardinality in 1D)
          DynRankView ConstructWithLabel(badVals, numFields, numPoints, 40);
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getValues(badVals, lineNodes, OPERATOR_D2), nthrow, ncatch );

          // exception #17: incorrect 2nd dimension of output array (must equal D3 cardinality in 1D)
          INTREPID2_TEST_ERROR_EXPECTED( lineBasis.getValues(badVals, lineNodes, OPERATOR_D3), nthrow, ncatch );
        }
#endif
        // Check if number of thrown exceptions matches the one we expect
        if (nthrow != ncatch) {
          errorFlag++;
          *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
          *outStream << "# of catch ("<< ncatch << ") is different from # of throw (" << ncatch << ")\n";
        }


      } catch (std::logic_error err) {
        *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
        *outStream << err.what() << '\n';
        *outStream << "-------------------------------------------------------------------------------" << "\n\n";
        errorFlag = -1000;
      }

      *outStream
        << "\n"
        << "===============================================================================\n"
        << "| TEST 2: correctness of tag to enum and enum to tag lookups                  |\n"
        << "===============================================================================\n";

      try{
        Basis_HGRAD_LINE_C1_FEM<DeviceSpaceType> lineBasis;

        const auto numFields = lineBasis.getCardinality();
        const auto allTags = lineBasis.getAllDofTags();

        // Loop over all tags, lookup the associated dof enumeration and then lookup the tag again
        const auto dofTagSize = allTags.dimension(0);
        for (auto i=0;i<dofTagSize;++i) {
          const auto bfOrd  = lineBasis.getDofOrdinal(allTags(i,0), allTags(i,1), allTags(i,2));

          const auto myTag = lineBasis.getDofTag(bfOrd);
          if( !( (myTag(0) == allTags(i,0)) &&
                 (myTag(1) == allTags(i,1)) &&
                 (myTag(2) == allTags(i,2)) &&
                 (myTag(3) == allTags(i,3)) ) ) {
            errorFlag++;
            *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
            *outStream << " getDofOrdinal( {"
                       << allTags(i,0) << ", "
                       << allTags(i,1) << ", "
                       << allTags(i,2) << ", "
                       << allTags(i,3) << "}) = " << bfOrd <<" but \n";
            *outStream << " getDofTag(" << bfOrd << ") = { "
                       << myTag(0) << ", "
                       << myTag(1) << ", "
                       << myTag(2) << ", "
                       << myTag(3) << "}\n";
          }
        }

        // Now do the same but loop over basis functions
        for(auto bfOrd=0;bfOrd<numFields;++bfOrd) {
          const auto myTag = lineBasis.getDofTag(bfOrd);
          const auto myBfOrd = lineBasis.getDofOrdinal(myTag(0), myTag(1), myTag(2));
          if( bfOrd != myBfOrd) {
            errorFlag++;
            *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
            *outStream << " getDofTag(" << bfOrd << ") = { "
                       << myTag(0) << ", "
                       << myTag(1) << ", "
                       << myTag(2) << ", "
                       << myTag(3) << "} but getDofOrdinal({"
                       << myTag(0) << ", "
                       << myTag(1) << ", "
                       << myTag(2) << ", "
                       << myTag(3) << "} ) = " << myBfOrd << "\n";
          }
        }
      } catch (std::logic_error err) {
        *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
        *outStream << err.what() << '\n';
        *outStream << "-------------------------------------------------------------------------------" << "\n\n";
        errorFlag = -1000;
      }

      *outStream                                  \
        << "\n"
        << "===============================================================================\n" \
        << "| TEST 3: correctness of basis function values                                |\n" \
        << "===============================================================================\n";

      outStream->precision(20);

      try{
        // VALUE: Each row gives the 2 correct basis set values at an evaluation point
        const value_type basisValues[][2] = {
          { 1.0, 0.0 },
          { 0.0, 1.0 },
          { 0.5, 0.5 },
          { 0.25, 0.75 }
        };

        // GRAD, DIV, CURL and D1: each row gives the 2 correct values of the gradients of the 2 basis functions
        const value_type basisDerivs[][2][1] = {
          { {-0.5}, {0.5} },
          { {-0.5}, {0.5} },
          { {-0.5}, {0.5} },
          { {-0.5}, {0.5} }
        };

        Basis_HGRAD_LINE_C1_FEM<DeviceSpaceType> lineBasis;

        // Define array containing the 2 vertices of the reference Line, its center and another point
        DynRankView ConstructWithLabel(lineNodes, 4, 1);
        lineNodes(0,0) =  -1.0;
        lineNodes(1,0) =   1.0;
        lineNodes(2,0) =   0.0;
        lineNodes(3,0) =   0.5;

        // Generic array for the output values; needs to be properly resized depending on the operator type
        const auto numFields = lineBasis.getCardinality();
        const auto numPoints = lineNodes.dimension(0);
        const auto spaceDim  = lineBasis.getBaseCellTopology().getDimension();

        const auto workSize  = numFields*numPoints*spaceDim;
        DynRankView ConstructWithLabel(work, workSize);

        // Check VALUE of basis functions: resize vals to rank-2 container:
        {
          DynRankView vals = DynRankView(work.data(), numFields, numPoints);
          lineBasis.getValues(vals, lineNodes, OPERATOR_VALUE);
          for (auto i=0;i<numFields;++i)
            for (auto j=0;j<numPoints;++j)
              if (std::abs(vals(i,j) - basisValues[j][i]) > tol) {
                errorFlag++;
                *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                // Output the multi-index of the value where the error is:
                *outStream << " At multi-index { ";
                *outStream << i << " ";*outStream << j << " ";
                *outStream << "}  computed value: " << vals(i,j)
                           << " but reference value: " << basisValues[j][i] << "\n";
              }
        }

        // Check derivatives of basis function: resize vals to rank-3 container
        {
          DynRankView vals = DynRankView(work.data(), numFields, numPoints, spaceDim);
          const EOperator ops[] = { OPERATOR_GRAD, 
                                    OPERATOR_DIV, 
                                    OPERATOR_CURL, 
                                    OPERATOR_D1, 
                                    OPERATOR_MAX };
          for (auto h=0;ops[h]!=OPERATOR_MAX;++h) {
            const auto op = ops[h];
            lineBasis.getValues(vals, lineNodes, op);
            for (auto i=0;i<numFields;++i)
              for (auto j=0;j<numPoints;++j)
                for (auto k=0;k<spaceDim;++k)
                  if (std::abs(vals(i,j,k) - basisDerivs[j][i][k]) > tol) {
                    errorFlag++;
                    *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                    // Output the multi-index of the value where the error is:
                    *outStream << " At multi-index { ";
                    *outStream << i << " ";*outStream << j << " ";*outStream << k << " ";
                    *outStream << "}  computed grad component: " << vals(i,j,k)
                               << " but reference grad component: " << basisDerivs[j][i][k] << "\n";
                  }
          }
        }

        // Check all higher derivatives - must be zero.
        {
          const EOperator ops[] = { OPERATOR_D2,
                                    OPERATOR_D3,
                                    OPERATOR_D4,
                                    OPERATOR_D5,
                                    OPERATOR_D6,
                                    OPERATOR_D7,
                                    OPERATOR_D8,
                                    OPERATOR_D9,
                                    OPERATOR_D10,
                                    OPERATOR_MAX };
          for (auto h=0;ops[h]!=OPERATOR_MAX;++h) {
            const auto op = ops[h];
            const auto DkCardin  = getDkCardinality(op, spaceDim);
            DynRankView vals = DynRankView(work.data(), numFields, numPoints, DkCardin);

            lineBasis.getValues(vals, lineNodes, op);
            for (auto i1=0;i1<numFields;++i1)
              for (auto i2=0;i2<numPoints;++i2)
                for (auto i3=0;i3<DkCardin;++i3)
                  if (std::abs(vals(i1,i2,i3)) > tol) {
                    errorFlag++;
                    *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";

                    // Get the multi-index of the value where the error is and the operator order
                    const auto ord = Intrepid2::getOperatorOrder(op);
                    *outStream << " At multi-index { "<<i1<<" "<<i2 <<" "<<i3;
                    *outStream << "}  computed D"<< ord <<" component: " << vals(i1,i2,i3)
                               << " but reference D" << ord << " component:  0 \n";
                  }
          }
        }

      } catch (std::logic_error err) {
        *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
        *outStream << err.what() << '\n';
        *outStream << "-------------------------------------------------------------------------------" << "\n\n";
        errorFlag = -1000;
      };

      if (errorFlag != 0)
        std::cout << "End Result: TEST FAILED\n";
      else
        std::cout << "End Result: TEST PASSED\n";

      // reset format state of std::cout
      std::cout.copyfmt(oldFormatState);

      return errorFlag;
    }