Exemplo n.º 1
0
void getDkMultiplicities(Teuchos::Array<int>&  partialMult,
                         const int             derivativeEnum,
                         const EOperator       operatorType,
                         const int             spaceDim) {
  
  /* Hash table to convert enumeration of partial derivative to multiplicities of dx,dy,dz in 3D.
  Multiplicities {mx,my,mz} are arranged lexicographically in bins numbered from 0 to 10. 
  The size of bins is an arithmetic progression, i.e., 1,2,3,4,5,...,11. Conversion formula is:
  \verbatim
    mx = derivativeOrder - binNumber
    mz = derivativeEnum  - binBegin
    my = derivativeOrder - mx - mz = binNumber + binBegin - derivativeEnum
  \endverbatim
  where binBegin is the enumeration of the first element in the bin. Bin numbers and binBegin 
  values are stored in hash tables for quick access by derivative enumeration value. 
  */ 
  
  // Returns the bin number for the specified derivative enumeration
  static const int binNumber[66] = { 
    0,
    1, 1,
    2, 2, 2,
    3, 3, 3, 3,
    4, 4, 4, 4, 4,
    5, 5, 5, 5, 5, 5,
    6, 6, 6, 6, 6, 6, 6,
    7, 7, 7, 7, 7, 7, 7, 7,
    8, 8, 8, 8, 8, 8, 8, 8, 8,
    9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
    10,10,10,10,10,10,10,10,10,10,10
  };
  
  // Returns the binBegin value for the specified derivative enumeration 
  static const int binBegin[66] ={ 
    0,
    1, 1,
    3, 3 ,3,
    6, 6, 6, 6,
    10,10,10,10,10,
    15,15,15,15,15,15,
    21,21,21,21,21,21,21,
    28,28,28,28,28,28,28,28,
    36,36,36,36,36,36,36,36,36,
    45,45,45,45,45,45,45,45,45,45,
    55,55,55,55,55,55,55,55,55,55,55
  };
    
#ifdef HAVE_INTREPID_DEBUG
  // Enumeration value must be between 0 and the cardinality of the derivative set
  TEUCHOS_TEST_FOR_EXCEPTION( !( (0 <= derivativeEnum) && (derivativeEnum < getDkCardinality(operatorType,spaceDim) ) ),
                      std::invalid_argument,
                      ">>> ERROR (Intrepid::getDkMultiplicities): Invalid derivative enumeration value for this order and space dimension");
#endif
  
  // This method should only be called for Dk operators
  int derivativeOrder;
  switch(operatorType){
    
    case OPERATOR_D1:
    case OPERATOR_D2:
    case OPERATOR_D3:
    case OPERATOR_D4:
    case OPERATOR_D5:
    case OPERATOR_D6:
    case OPERATOR_D7:
    case OPERATOR_D8:
    case OPERATOR_D9:
    case OPERATOR_D10:
      derivativeOrder = Intrepid::getOperatorOrder(operatorType);
      break;
      
    default:
      TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
                         ">>> ERROR (Intrepid::getDkMultiplicities): operator type Dk required for this method");
  }// switch
  
  switch(spaceDim) {
    
    case 1:
      
      // Resize return array for multiplicity of {dx}
      partialMult.resize(1);
      
      // Multiplicity of dx equals derivativeOrder
      partialMult[0] = derivativeOrder;
      break;
      
    case 2:
      
      // Resize array for multiplicities of {dx,dy}
      partialMult.resize(2);
      
      // Multiplicity of dy equals the enumeration of the derivative; of dx - the complement
      partialMult[1] = derivativeEnum;
      partialMult[0] = derivativeOrder - derivativeEnum;
      break;
      
    case 3:
      
      // Resize array for multiplicities of {dx,dy,dz}
      partialMult.resize(3);
      
      // Recover multiplicities
      partialMult[0] = derivativeOrder - binNumber[derivativeEnum];
      partialMult[1] = binNumber[derivativeEnum] + binBegin[derivativeEnum] - derivativeEnum;
      partialMult[2] = derivativeEnum  -  binBegin[derivativeEnum];
      break;
      
    default:
      TEUCHOS_TEST_FOR_EXCEPTION( !( (0 < spaceDim ) && (spaceDim < 4) ), std::invalid_argument,
                          ">>> ERROR (Intrepid::getDkMultiplicities): Invalid space dimension");          
  }
}
  void Basis_HGRAD_HEX_Cn_FEM<Scalar,ArrayScalar>::getValues( ArrayScalar &outputValues ,
							       const ArrayScalar &inputPoints ,
							       const EOperator operatorType ) const 
  {
#ifdef HAVE_INTREPID2_DEBUG
    Intrepid2::getValues_HGRAD_Args<Scalar, ArrayScalar>(outputValues,
							inputPoints,
							operatorType,
							this -> getBaseCellTopology(),
							this -> getCardinality() );
#endif
    
    Basis<Scalar,ArrayScalar> &xBasis_ = *this->bases_[0][0];
    Basis<Scalar,ArrayScalar> &yBasis_ = *this->bases_[0][1];
    Basis<Scalar,ArrayScalar> &zBasis_ = *this->bases_[0][2];


    ArrayScalar xInputPoints(inputPoints.dimension(0),1);
    ArrayScalar yInputPoints(inputPoints.dimension(0),1);
    ArrayScalar zInputPoints(inputPoints.dimension(0),1);

    for (int i=0;i<inputPoints.dimension(0);i++) {
      xInputPoints(i,0) = inputPoints(i,0);
      yInputPoints(i,0) = inputPoints(i,1);
      zInputPoints(i,0) = inputPoints(i,2);
    }

    switch (operatorType) {
    case OPERATOR_VALUE:
      {
	ArrayScalar xBasisValues(xBasis_.getCardinality(),xInputPoints.dimension(0));
	ArrayScalar yBasisValues(yBasis_.getCardinality(),yInputPoints.dimension(0));
	ArrayScalar zBasisValues(zBasis_.getCardinality(),zInputPoints.dimension(0));

	xBasis_.getValues(xBasisValues,xInputPoints,OPERATOR_VALUE);
	yBasis_.getValues(yBasisValues,yInputPoints,OPERATOR_VALUE);
	zBasis_.getValues(zBasisValues,zInputPoints,OPERATOR_VALUE);

	int bfcur = 0;
	for (int k=0;k<zBasis_.getCardinality();k++) {
	  for (int j=0;j<yBasis_.getCardinality();j++) {
	    for (int i=0;i<xBasis_.getCardinality();i++) {
	      for (int l=0;l<inputPoints.dimension(0);l++) {
		outputValues(bfcur,l) = xBasisValues(i,l) * yBasisValues(j,l) * zBasisValues(k,l);
	      }
	      bfcur++;
	    }
	  }
	}
      }
      break;
    case OPERATOR_D1:
    case OPERATOR_GRAD:
      {
        ArrayScalar xBasisValues(xBasis_.getCardinality(),xInputPoints.dimension(0));
        ArrayScalar yBasisValues(yBasis_.getCardinality(),yInputPoints.dimension(0));
        ArrayScalar zBasisValues(zBasis_.getCardinality(),zInputPoints.dimension(0));
        ArrayScalar xBasisDerivs(xBasis_.getCardinality(),xInputPoints.dimension(0),1);
        ArrayScalar yBasisDerivs(yBasis_.getCardinality(),yInputPoints.dimension(0),1);
        ArrayScalar zBasisDerivs(zBasis_.getCardinality(),zInputPoints.dimension(0),1);

        xBasis_.getValues(xBasisValues,xInputPoints,OPERATOR_VALUE);
        yBasis_.getValues(yBasisValues,yInputPoints,OPERATOR_VALUE);
        zBasis_.getValues(zBasisValues,zInputPoints,OPERATOR_VALUE);
        xBasis_.getValues(xBasisDerivs,xInputPoints,OPERATOR_D1);
        yBasis_.getValues(yBasisDerivs,yInputPoints,OPERATOR_D1);    	
        zBasis_.getValues(zBasisDerivs,zInputPoints,OPERATOR_D1);    	

	int bfcur = 0;
	for (int k=0;k<zBasis_.getCardinality();k++) {
	  for (int j=0;j<yBasis_.getCardinality();j++) {
	    for (int i=0;i<xBasis_.getCardinality();i++) {
	      for (int l=0;l<inputPoints.dimension(0);l++) {
		outputValues(bfcur,l,0) = xBasisDerivs(i,l,0) * yBasisValues(j,l) * zBasisValues(k,l);
		outputValues(bfcur,l,1) = xBasisValues(i,l) * yBasisDerivs(j,l,0) * zBasisValues(k,l);
		outputValues(bfcur,l,2) = xBasisValues(i,l) * yBasisValues(j,l) * zBasisDerivs(k,l,0);
	      }
	      bfcur++;
	    }
	  }
	}
      }
      break;
    case OPERATOR_D2:
    case OPERATOR_D3:
    case OPERATOR_D4:
    case OPERATOR_D5: 
    case OPERATOR_D6:
    case OPERATOR_D7:
    case OPERATOR_D8:
    case OPERATOR_D9:
    case OPERATOR_D10:
      {
        ArrayScalar xBasisValues(xBasis_.getCardinality(),xInputPoints.dimension(0));
        ArrayScalar yBasisValues(yBasis_.getCardinality(),yInputPoints.dimension(0));
        ArrayScalar zBasisValues(yBasis_.getCardinality(),zInputPoints.dimension(0));

        Teuchos::Array<int> partialMult;
	
        for (int d=0;d<getDkCardinality(operatorType,3);d++) {
          getDkMultiplicities( partialMult , d , operatorType , 3 );
          if (partialMult[0] == 0) {
            xBasisValues.resize(xBasis_.getCardinality(),xInputPoints.dimension(0));
            xBasis_.getValues( xBasisValues , xInputPoints, OPERATOR_VALUE );
          }
          else {
            xBasisValues.resize(xBasis_.getCardinality(),xInputPoints.dimension(0),1);
            EOperator xop = (EOperator) ( (int) OPERATOR_D1 + partialMult[0] - 1 );
            xBasis_.getValues( xBasisValues , xInputPoints, xop );
            xBasisValues.resize(xBasis_.getCardinality(),xInputPoints.dimension(0));
          }
          if (partialMult[1] == 0) {
            yBasisValues.resize(yBasis_.getCardinality(),yInputPoints.dimension(0));
            yBasis_.getValues( yBasisValues , yInputPoints, OPERATOR_VALUE );
          }
          else {
            yBasisValues.resize(yBasis_.getCardinality(),yInputPoints.dimension(0),1);
            EOperator yop = (EOperator) ( (int) OPERATOR_D1 + partialMult[1] - 1 );
            yBasis_.getValues( yBasisValues , yInputPoints, yop );
            yBasisValues.resize(yBasis_.getCardinality(),yInputPoints.dimension(0));
          }
          if (partialMult[2] == 0) {
            zBasisValues.resize(zBasis_.getCardinality(),zInputPoints.dimension(0));
            zBasis_.getValues( zBasisValues , zInputPoints, OPERATOR_VALUE );
          }
          else {
            zBasisValues.resize(zBasis_.getCardinality(),zInputPoints.dimension(0),1);
            EOperator zop = (EOperator) ( (int) OPERATOR_D1 + partialMult[2] - 1 );
            zBasis_.getValues( zBasisValues , zInputPoints, zop );
            zBasisValues.resize(zBasis_.getCardinality(),zInputPoints.dimension(0));
          }


          int bfcur = 0;
	  for (int k=0;k<zBasis_.getCardinality();k++) {
	    for (int j=0;j<yBasis_.getCardinality();j++) {
	      for (int i=0;i<xBasis_.getCardinality();i++) {
		for (int l=0;l<inputPoints.dimension(0);l++) {
		  outputValues(bfcur,l,d) = xBasisValues(i,l) * yBasisValues(j,l) * zBasisValues(k,l);
		}
		bfcur++;
	      }
	    }
	  }
	}
      }
      break;
    default:
        TEUCHOS_TEST_FOR_EXCEPTION( true , std::invalid_argument,
                            ">>> ERROR (Basis_HGRAD_HEX_Cn_FEM): Operator type not implemented");
        break;
    }
  }
Exemplo n.º 3
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;
}
  void Basis_HGRAD_LINE_Cn_FEM<Scalar, ArrayScalar>::getValues(ArrayScalar &        outputValues,
                                                              const ArrayScalar &  inputPoints,
                                                              const EOperator      operatorType) const {
  
    // Verify arguments
#ifdef HAVE_INTREPID2_DEBUG
    Intrepid2::getValues_HGRAD_Args<Scalar, ArrayScalar>(outputValues,
                                                        inputPoints,
                                                        operatorType,
                                                        this -> getBaseCellTopology(),
                                                        this -> getCardinality() );
#endif
    const int numPts = inputPoints.dimension(0);
    const int numBf = this->getCardinality();

    try {
      switch (operatorType) {
      case OPERATOR_VALUE:
        {
          ArrayScalar phisCur( numBf , numPts );
          Phis_.getValues( phisCur , inputPoints , operatorType );
          for (int i=0;i<outputValues.dimension(0);i++) {
            for (int j=0;j<outputValues.dimension(1);j++) {
              outputValues(i,j) = 0.0;
              for (int k=0;k<this->getCardinality();k++) {
                outputValues(i,j) += this->Vinv_(k,i) * phisCur(k,j);
              }
            }
          }
        }
        break;
      case OPERATOR_GRAD:
      case OPERATOR_D1:
      case OPERATOR_D2:
      case OPERATOR_D3:
      case OPERATOR_D4:
      case OPERATOR_D5:
      case OPERATOR_D6:
      case OPERATOR_D7:
      case OPERATOR_D8:
      case OPERATOR_D9:
      case OPERATOR_D10:
        {
          const int dkcard = 
            (operatorType == OPERATOR_GRAD)? getDkCardinality(OPERATOR_D1,1): getDkCardinality(operatorType,1);
          
          ArrayScalar phisCur( numBf , numPts , dkcard );
          Phis_.getValues( phisCur , inputPoints , operatorType );

          for (int i=0;i<outputValues.dimension(0);i++) {
            for (int j=0;j<outputValues.dimension(1);j++) {
              for (int k=0;k<outputValues.dimension(2);k++) {
                outputValues(i,j,k) = 0.0;
                for (int l=0;l<this->getCardinality();l++) {
                  outputValues(i,j,k) += this->Vinv_(l,i) * phisCur(l,j,k);
                }
              }
            }
          }
        }
        break;
      default:
        TEUCHOS_TEST_FOR_EXCEPTION( true , std::invalid_argument,
                            ">>> ERROR (Basis_HGRAD_LINE_Cn_FEM): Operator type not implemented" );
        break;
      }
    }
    catch (std::invalid_argument &exception){
      TEUCHOS_TEST_FOR_EXCEPTION( true , std::invalid_argument,
                          ">>> ERROR (Basis_HGRAD_LINE_Cn_FEM): Operator failed");    
    }

  }
  void Basis_HGRAD_QUAD_Cn_FEM<Scalar,ArrayScalar>::getValues( ArrayScalar &outputValues ,
							       const ArrayScalar &inputPoints ,
							       const EOperator operatorType ) const 
  {
#ifdef HAVE_INTREPID2_DEBUG
    getValues_HGRAD_Args<Scalar, ArrayScalar>(outputValues,
					      inputPoints,
					      operatorType,
					      this -> getBaseCellTopology(),
					      this -> getCardinality() );
#endif

    ArrayScalar xInputPoints(inputPoints.dimension(0),1);
    ArrayScalar yInputPoints(inputPoints.dimension(0),1);

    const Basis<Scalar,ArrayScalar> &xBasis_ = *this->bases_[0][0];
    const Basis<Scalar,ArrayScalar> &yBasis_ = *this->bases_[0][1];

    for (int i=0;i<inputPoints.dimension(0);i++) {
      xInputPoints(i,0) = inputPoints(i,0);
      yInputPoints(i,0) = inputPoints(i,1);
    }

    switch (operatorType) {
    case OPERATOR_VALUE:
      {
	ArrayScalar xBasisValues(xBasis_.getCardinality(),xInputPoints.dimension(0));
	ArrayScalar yBasisValues(yBasis_.getCardinality(),yInputPoints.dimension(0));

	xBasis_.getValues(xBasisValues,xInputPoints,OPERATOR_VALUE);
	yBasis_.getValues(yBasisValues,yInputPoints,OPERATOR_VALUE);

	int bfcur = 0;
	for (int j=0;j<yBasis_.getCardinality();j++) {
	  for (int i=0;i<xBasis_.getCardinality();i++) {
	    for (int k=0;k<inputPoints.dimension(0);k++) {
	      outputValues(bfcur,k) = xBasisValues(i,k) * yBasisValues(j,k);
	    }
	    bfcur++;
	  }
	}
      }
      break;
    case OPERATOR_GRAD:
    case OPERATOR_D1:
      {
	ArrayScalar xBasisValues(xBasis_.getCardinality(),xInputPoints.dimension(0));
	ArrayScalar yBasisValues(yBasis_.getCardinality(),yInputPoints.dimension(0));
	ArrayScalar xBasisDerivs(xBasis_.getCardinality(),xInputPoints.dimension(0),1);
	ArrayScalar yBasisDerivs(yBasis_.getCardinality(),yInputPoints.dimension(0),1);

	xBasis_.getValues(xBasisValues,xInputPoints,OPERATOR_VALUE);
	yBasis_.getValues(yBasisValues,yInputPoints,OPERATOR_VALUE);
	xBasis_.getValues(xBasisDerivs,xInputPoints,OPERATOR_D1);
	yBasis_.getValues(yBasisDerivs,yInputPoints,OPERATOR_D1);	

	// there are two multiindices: I need the (1,0) and (0,1) derivatives
	int bfcur = 0;

	for (int j=0;j<yBasis_.getCardinality();j++) {
	  for (int i=0;i<xBasis_.getCardinality();i++) {
	    for (int k=0;k<inputPoints.dimension(0);k++) {
	      outputValues(bfcur,k,0) = xBasisDerivs(i,k,0) * yBasisValues(j,k);
	      outputValues(bfcur,k,1) = xBasisValues(i,k) * yBasisDerivs(j,k,0);
	    }
	    bfcur++;
	  }
	}
      }
      break;
    case OPERATOR_D2:
    case OPERATOR_D3:
    case OPERATOR_D4:
    case OPERATOR_D5: 
    case OPERATOR_D6:
    case OPERATOR_D7:
    case OPERATOR_D8:
    case OPERATOR_D9:
    case OPERATOR_D10:
      {
	ArrayScalar xBasisValues(xBasis_.getCardinality(),xInputPoints.dimension(0));
	ArrayScalar yBasisValues(yBasis_.getCardinality(),yInputPoints.dimension(0));

	Teuchos::Array<int> partialMult;

	for (int d=0;d<getDkCardinality(operatorType,2);d++) {
	  getDkMultiplicities( partialMult , d , operatorType , 2 );
	  if (partialMult[0] == 0) {
	    xBasisValues.resize(xBasis_.getCardinality(),xInputPoints.dimension(0));
	    xBasis_.getValues( xBasisValues , xInputPoints, OPERATOR_VALUE );
	  }
	  else {
	    xBasisValues.resize(xBasis_.getCardinality(),xInputPoints.dimension(0),1);
	    EOperator xop = (EOperator) ( (int) OPERATOR_D1 + partialMult[0] - 1 );
	    xBasis_.getValues( xBasisValues , xInputPoints, xop );
	    xBasisValues.resize(xBasis_.getCardinality(),xInputPoints.dimension(0));
	  }
	  if (partialMult[1] == 0) {
	    yBasisValues.resize(yBasis_.getCardinality(),yInputPoints.dimension(0));
	    yBasis_.getValues( yBasisValues , yInputPoints, OPERATOR_VALUE );
	  }
	  else {
	    yBasisValues.resize(yBasis_.getCardinality(),yInputPoints.dimension(0),1);
	    EOperator yop = (EOperator) ( (int) OPERATOR_D1 + partialMult[1] - 1 );
	    yBasis_.getValues( yBasisValues , yInputPoints, yop );
	    yBasisValues.resize(yBasis_.getCardinality(),yInputPoints.dimension(0));
	  }


	  int bfcur = 0;
	  for (int j=0;j<yBasis_.getCardinality();j++) {
	    for (int i=0;i<xBasis_.getCardinality();i++) {
	      for (int k=0;k<inputPoints.dimension(0);k++) {
		outputValues(bfcur,k,d) = xBasisValues(i,k) * yBasisValues(j,k);
	      }
	      bfcur++;
	    }
	  }
	}
      }
      break;
    case OPERATOR_CURL:
      {
	ArrayScalar xBasisValues(xBasis_.getCardinality(),xInputPoints.dimension(0));
	ArrayScalar yBasisValues(yBasis_.getCardinality(),yInputPoints.dimension(0));
	ArrayScalar xBasisDerivs(xBasis_.getCardinality(),xInputPoints.dimension(0),1);
	ArrayScalar yBasisDerivs(yBasis_.getCardinality(),yInputPoints.dimension(0),1);

	xBasis_.getValues(xBasisValues,xInputPoints,OPERATOR_VALUE);
	yBasis_.getValues(yBasisValues,yInputPoints,OPERATOR_VALUE);
	xBasis_.getValues(xBasisDerivs,xInputPoints,OPERATOR_D1);
	yBasis_.getValues(yBasisDerivs,yInputPoints,OPERATOR_D1);	

	// there are two multiindices: I need the (1,0) and (0,1) derivatives
	int bfcur = 0;

	for (int j=0;j<yBasis_.getCardinality();j++) {
	  for (int i=0;i<xBasis_.getCardinality();i++) {
	    for (int k=0;k<inputPoints.dimension(0);k++) {
	      outputValues(bfcur,k,0) = xBasisValues(i,k) * yBasisDerivs(j,k,0);
	      outputValues(bfcur,k,1) = -xBasisDerivs(i,k,0) * yBasisValues(j,k);
	    }
	    bfcur++;
	  }
	}
      }
      break;      
    default:
        TEUCHOS_TEST_FOR_EXCEPTION( true , std::invalid_argument,
                            ">>> ERROR (Basis_HGRAD_QUAD_Cn_FEM): Operator type not implemented");
        break;
    }
  }
Exemplo n.º 6
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_Cn_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"
  << "|                      Mauro Perego  ([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<PointValueType,DeviceSpaceType> DynRankViewPointValueType;
  typedef Kokkos::DynRankView<OutValueType,DeviceSpaceType> DynRankViewOutValueType;
  typedef typename ScalarTraits<OutValueType>::scalar_type scalar_type;
  typedef Kokkos::DynRankView<scalar_type, DeviceSpaceType> DynRankViewScalarValueType;      
  typedef Kokkos::DynRankView<scalar_type, HostSpaceType> DynRankViewHostScalarValueType;      

#define ConstructWithLabelScalar(obj, ...) obj(#obj, __VA_ARGS__)

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

  typedef Basis_HGRAD_HEX_Cn_FEM<DeviceSpaceType,OutValueType,PointValueType> HexBasisType;
  constexpr ordinal_type maxOrder = Parameters::MaxOrder;


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

  try {

#ifdef HAVE_INTREPID2_DEBUG
    ordinal_type nthrow = 0, ncatch = 0;
    constexpr ordinal_type order = 3;
    if(order < maxOrder) {
      HexBasisType hexBasis(order);

      // Define array containing array of nodes to evaluate
      DynRankViewPointValueType ConstructWithLabelPointView(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.extent(0);
      //const ordinal_type spaceDim  = hexBasis.getBaseCellTopology().getDimension();

      // exception 1 - 2: CURL and DIV is not supported.
      {
        DynRankViewOutValueType ConstructWithLabelOutView(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
      {
        DynRankViewOutValueType ConstructWithLabelOutView(vals, numFields, numPoints);
        {
          // exception #8: input points array must be of rank-2
          DynRankViewPointValueType ConstructWithLabelPointView(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
          DynRankViewPointValueType ConstructWithLabelPointView(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
          DynRankViewOutValueType ConstructWithLabelOutView(badVals, 4, 3, 1);
          INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(badVals, hexNodes, OPERATOR_VALUE) );
        }
        {
          DynRankViewOutValueType ConstructWithLabelOutView(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)
        DynRankViewOutValueType ConstructWithLabelOutView(badVals, hexBasis.getCardinality() + 1, hexNodes.extent(0));
        INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(badVals, hexNodes, OPERATOR_VALUE) );
      }
      {
        // exception #15: incorrect 1st dimension of output array (must equal number of points)
        DynRankViewOutValueType ConstructWithLabelOutView(badVals, hexBasis.getCardinality(), hexNodes.extent(0) + 1);
        INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(badVals, hexNodes, OPERATOR_VALUE) );
      }
      {
        // exception #16: incorrect 2nd dimension of output array (must equal spatial dimension)
        DynRankViewOutValueType ConstructWithLabelOutView(badVals, hexBasis.getCardinality(), hexNodes.extent(0), 2);
        INTREPID2_TEST_ERROR_EXPECTED( hexBasis.getValues(badVals, hexNodes, OPERATOR_GRAD) );
      }
      {
        DynRankViewOutValueType ConstructWithLabelOutView(badVals, hexBasis.getCardinality(), hexNodes.extent(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) );
      }
    }
    if (nthrow != ncatch) {
      errorFlag++;
      *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
      *outStream << "# of catch ("<< ncatch << ") is different from # of throw (" << nthrow << ")\n";
    }
#endif
  } 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 = std::min(5, maxOrder);
    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.extent(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;
  };

  try {

    *outStream
    << "\n"
    << "===============================================================================\n"
    << "| TEST 3: Testing Kronecker property of basis functions                                              |\n"
    << "===============================================================================\n";


    const ordinal_type order = std::min(3,maxOrder);
    HexBasisType hexBasis(order, POINTTYPE_WARPBLEND);
    constexpr ordinal_type dim=3;
    const ordinal_type basisCardinality = hexBasis.getCardinality();
    DynRankViewScalarValueType ConstructWithLabelScalar(lattice_scalar, basisCardinality , dim);
    DynRankViewPointValueType ConstructWithLabelPointView(lattice, basisCardinality , dim);

    hexBasis.getDofCoords(lattice_scalar);
    RealSpaceTools<DeviceSpaceType>::clone(lattice,lattice_scalar);

    auto lattice_host = Kokkos::create_mirror_view(lattice);

    DynRankViewOutValueType ConstructWithLabelOutView(basisAtLattice, basisCardinality, basisCardinality);
    hexBasis.getValues(basisAtLattice, lattice, OPERATOR_VALUE);

    auto h_basisAtLattice = Kokkos::create_mirror_view(basisAtLattice);
    Kokkos::deep_copy(h_basisAtLattice, basisAtLattice);

    for(ordinal_type iface =0; iface<6; iface++) {
      auto numFaceDofs = hexBasis.getDofCount(2,iface);
      for(ordinal_type i=0; i<numFaceDofs; i++) {
        auto idof = hexBasis.getDofOrdinal(2,iface,i);
        for(ordinal_type j=0; j<numFaceDofs; j++) {
          auto jdof = hexBasis.getDofOrdinal(2,iface,j);
          if ( idof==jdof && std::abs( h_basisAtLattice(idof,jdof) - 1.0 ) > tol ) {
            errorFlag++;
            *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
            *outStream << " Basis function " << idof << " does not have unit value at its node (" << h_basisAtLattice(idof,jdof) <<")\n";
          }
          if ( i!=j && std::abs( h_basisAtLattice(idof,jdof) ) > tol ) {
            errorFlag++;
            *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
            *outStream << " Basis function " << idof << " does not vanish at node " << jdof << "\n";
            *outStream << " Basis function value is " << h_basisAtLattice(idof,jdof) << "\n";
          }
        }
      }
    }


    // test for Kronecker property
    for (int i=0;i<basisCardinality;i++) {
      for (int j=0;j<basisCardinality;j++) {
        if ( i==j && std::abs( h_basisAtLattice(i,j) - 1.0 ) > tol ) {
          errorFlag++;
          *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
          *outStream << " Basis function " << i << " does not have unit value at its node (" << h_basisAtLattice(i,j) <<")\n";
        }
        if ( i!=j && std::abs( h_basisAtLattice(i,j) ) > tol ) {
          errorFlag++;
          *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
          *outStream << " Basis function " << i << " does not vanish at node " << j << "\n";
          *outStream << " Basis function value is " << h_basisAtLattice(i,j) << "\n";
        }
      }
    }
  } catch (std::exception err) {
    *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
    *outStream << err.what() << '\n';
    *outStream << "-------------------------------------------------------------------------------" << "\n\n";
    errorFlag = -1000;
  };

  *outStream
  << "\n"
  << "===============================================================================\n"
  << "| TEST 4: 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 scalar_type 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<scalar_type> 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<scalar_type> 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<scalar_type> 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<scalar_type> 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{
    constexpr ordinal_type order = 2;
    if(order < maxOrder) {
      HexBasisType hexBasis(order);

      DynRankViewHostScalarValueType ConstructWithLabelScalar(hexNodesHost, 27, 3);
      DynRankViewPointValueType ConstructWithLabelPointView(hexNodes, 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_scalar = Kokkos::create_mirror_view(typename DeviceSpaceType::memory_space(), hexNodesHost);
      Kokkos::deep_copy(hexNodes_scalar, hexNodesHost);
      
      RealSpaceTools<DeviceSpaceType>::clone(hexNodes, hexNodes_scalar);

      // Dimensions for the output arrays:
      const ordinal_type numFields = hexBasis.getCardinality();
      const ordinal_type numPoints = hexNodes.extent(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:
        DynRankViewOutValueType ConstructWithLabelOutView(vals, numFields, numPoints);
        hexBasis.getValues(vals, hexNodes, OPERATOR_VALUE);
        auto vals_host = Kokkos::create_mirror_view(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
        DynRankViewOutValueType ConstructWithLabelOutView(vals, numFields, numPoints, spaceDim);
        hexBasis.getValues(vals, hexNodes, OPERATOR_GRAD);
        auto vals_host = Kokkos::create_mirror_view(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
        DynRankViewOutValueType ConstructWithLabelOutView(vals, numFields, numPoints, spaceDim);
        hexBasis.getValues(vals, hexNodes, OPERATOR_D1);
        auto vals_host = Kokkos::create_mirror_view(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
        DynRankViewOutValueType ConstructWithLabelOutView(vals, numFields, numPoints, D2Cardin);
        hexBasis.getValues(vals, hexNodes, OPERATOR_D2);
        auto vals_host = Kokkos::create_mirror_view(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
        DynRankViewOutValueType ConstructWithLabelOutView(vals, numFields, numPoints, D3Cardin);
        hexBasis.getValues(vals, hexNodes, OPERATOR_D3);
        auto vals_host = Kokkos::create_mirror_view(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
        DynRankViewOutValueType ConstructWithLabelOutView(vals, numFields, numPoints, D4Cardin);
        hexBasis.getValues(vals, hexNodes, OPERATOR_D4);
        auto vals_host = Kokkos::create_mirror_view(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);

        DynRankViewOutValueType ConstructWithLabelOutView(vals, numFields, numPoints, DkCardin);
        hexBasis.getValues(vals, hexNodes, op);
        auto vals_host = Kokkos::create_mirror_view(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;
}
Exemplo n.º 7
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;
    }
Exemplo n.º 8
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;
    }
Exemplo n.º 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;
    }
Exemplo n.º 10
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;
    }
Exemplo n.º 11
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;
    }