Пример #1
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;
    }
Пример #2
0
    int HDIV_TRI_I1_FEM_Test01(const bool verbose) {

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

      outStream -> precision(20);

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

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



      try{

        DynRankViewHost ConstructWithLabel(triNodesHost, 6, 2);

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

      // reset format state of std::cout
      std::cout.copyfmt(oldFormatState);
      return errorFlag;
     }
Пример #3
0
    int HCURL_TRI_I1_FEM_Test01(const bool verbose) {
      
      Teuchos::RCP<std::ostream> outStream;
      Teuchos::oblackholestream bhs; // outputs nothing

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

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

      int errorFlag = 0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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