int main(int argc, char *argv[]) { Teuchos::GlobalMPISession mpiSession(&argc, &argv); // This little trick lets us print to std::cout only if // a (dummy) command-line argument is provided. int iprint = argc - 1; Teuchos::RCP<std::ostream> outStream; Teuchos::oblackholestream bhs; // outputs nothing if (iprint > 0) outStream = Teuchos::rcp(&std::cout, false); else outStream = Teuchos::rcp(&bhs, false); // Save the format state of the original std::cout. Teuchos::oblackholestream oldFormatState; oldFormatState.copyfmt(std::cout); *outStream \ << "===============================================================================\n" \ << "| |\n" \ << "| Unit Test (Basis_HDIV_QUAD_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"\ << "| TEST 1: Basis creation, exception testing |\n"\ << "===============================================================================\n"; // Define basis and error flag Basis_HDIV_QUAD_I1_FEM<double, FieldContainer<double> > quadBasis; int errorFlag = 0; // Initialize throw counter for exception testing int nException = 0; int throwCounter = 0; // Array with the 4 vertices of the reference Quadrilateral, its center and 4 more points FieldContainer<double> quadNodes(9, 2); quadNodes(0,0) = -1.0; quadNodes(0,1) = -1.0; quadNodes(1,0) = 1.0; quadNodes(1,1) = -1.0; quadNodes(2,0) = 1.0; quadNodes(2,1) = 1.0; quadNodes(3,0) = -1.0; quadNodes(3,1) = 1.0; quadNodes(4,0) = 0.0; quadNodes(4,1) = 0.0; quadNodes(5,0) = 0.0; quadNodes(5,1) = -0.5; quadNodes(6,0) = 0.0; quadNodes(6,1) = 0.5; quadNodes(7,0) = -0.5; quadNodes(7,1) = 0.0; quadNodes(8,0) = 0.5; quadNodes(8,1) = 0.0; // Generic array for the output values; needs to be properly resized depending on the operator type FieldContainer<double> vals; try { int spaceDim = quadBasis.getBaseCellTopology().getDimension(); // exception #1: GRAD cannot be applied to HDIV functions // resize vals to rank-3 container with dimensions (num. basis functions, num. points, arbitrary) vals.resize(quadBasis.getCardinality(), quadNodes.dimension(0), spaceDim ); INTREPID_TEST_COMMAND( quadBasis.getValues(vals, quadNodes, OPERATOR_GRAD), throwCounter, nException ); // exception #2: CURL cannot be applied to HDIV functions INTREPID_TEST_COMMAND( quadBasis.getValues(vals, quadNodes, OPERATOR_CURL), throwCounter, nException ); // 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 INTREPID_TEST_COMMAND( quadBasis.getDofOrdinal(3,0,0), throwCounter, nException ); // exception #4 INTREPID_TEST_COMMAND( quadBasis.getDofOrdinal(1,1,1), throwCounter, nException ); // exception #5 INTREPID_TEST_COMMAND( quadBasis.getDofOrdinal(0,4,1), throwCounter, nException ); // exception #6 INTREPID_TEST_COMMAND( quadBasis.getDofTag(12), throwCounter, nException ); // exception #7 INTREPID_TEST_COMMAND( quadBasis.getDofTag(-1), throwCounter, nException ); #ifdef HAVE_INTREPID_DEBUG // Exceptions 8- test exception handling with incorrectly dimensioned input/output arrays // exception #8: input points array must be of rank-2 FieldContainer<double> badPoints1(4, 5, 3); INTREPID_TEST_COMMAND( quadBasis.getValues(vals, badPoints1, OPERATOR_VALUE), throwCounter, nException ); // exception #9 dimension 1 in the input point array must equal space dimension of the cell FieldContainer<double> badPoints2(4, spaceDim + 1); INTREPID_TEST_COMMAND( quadBasis.getValues(vals, badPoints2, OPERATOR_VALUE), throwCounter, nException ); // exception #10 output values must be of rank-3 for OPERATOR_VALUE FieldContainer<double> badVals1(4, 5); INTREPID_TEST_COMMAND( quadBasis.getValues(badVals1, quadNodes, OPERATOR_VALUE), throwCounter, nException ); // exception #11 output values must be of rank-2 for OPERATOR_DIV FieldContainer<double> badVals2(4, 5, spaceDim); INTREPID_TEST_COMMAND( quadBasis.getValues(badVals2, quadNodes, OPERATOR_DIV), throwCounter, nException ); // exception #12 incorrect 0th dimension of output array (must equal number of basis functions) FieldContainer<double> badVals3(quadBasis.getCardinality() + 1, quadNodes.dimension(0), spaceDim); INTREPID_TEST_COMMAND( quadBasis.getValues(badVals3, quadNodes, OPERATOR_VALUE), throwCounter, nException ); // exception #13 incorrect 0th dimension of output array (must equal number of basis functions) FieldContainer<double> badVals4(quadBasis.getCardinality() + 1, quadNodes.dimension(0)); INTREPID_TEST_COMMAND( quadBasis.getValues(badVals4, quadNodes, OPERATOR_DIV), throwCounter, nException ); // exception #14 incorrect 1st dimension of output array (must equal number of points) FieldContainer<double> badVals5(quadBasis.getCardinality(), quadNodes.dimension(0) + 1, spaceDim); INTREPID_TEST_COMMAND( quadBasis.getValues(badVals5, quadNodes, OPERATOR_VALUE), throwCounter, nException ); // exception #15 incorrect 1st dimension of output array (must equal number of points) FieldContainer<double> badVals6(quadBasis.getCardinality(), quadNodes.dimension(0) + 1); INTREPID_TEST_COMMAND( quadBasis.getValues(badVals6, quadNodes, OPERATOR_DIV), throwCounter, nException ); // exception #16: incorrect 2nd dimension of output array (must equal the space dimension) FieldContainer<double> badVals7(quadBasis.getCardinality(), quadNodes.dimension(0), spaceDim + 1); INTREPID_TEST_COMMAND( quadBasis.getValues(badVals7, quadNodes, OPERATOR_VALUE), throwCounter, nException ); #endif } catch (std::logic_error err) { *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n"; *outStream << err.what() << '\n'; *outStream << "-------------------------------------------------------------------------------" << "\n\n"; errorFlag = -1000; }; // Check if number of thrown exceptions matches the one we expect if (throwCounter != nException) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; } *outStream \ << "\n" << "===============================================================================\n"\ << "| TEST 2: correctness of tag to enum and enum to tag lookups |\n"\ << "===============================================================================\n"; try { std::vector<std::vector<int> > allTags = quadBasis.getAllDofTags(); // Loop over all tags, lookup the associated dof enumeration and then lookup the tag again for (unsigned i = 0; i < allTags.size(); i++) { int bfOrd = quadBasis.getDofOrdinal(allTags[i][0], allTags[i][1], allTags[i][2]); std::vector<int> myTag = quadBasis.getDofTag(bfOrd); if( !( (myTag[0] == allTags[i][0]) && (myTag[1] == allTags[i][1]) && (myTag[2] == allTags[i][2]) && (myTag[3] == allTags[i][3]) ) ) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; *outStream << " getDofOrdinal( {" << allTags[i][0] << ", " << allTags[i][1] << ", " << allTags[i][2] << ", " << allTags[i][3] << "}) = " << bfOrd <<" but \n"; *outStream << " getDofTag(" << bfOrd << ") = { " << myTag[0] << ", " << myTag[1] << ", " << myTag[2] << ", " << myTag[3] << "}\n"; } } // Now do the same but loop over basis functions for( int bfOrd = 0; bfOrd < quadBasis.getCardinality(); bfOrd++) { std::vector<int> myTag = quadBasis.getDofTag(bfOrd); int myBfOrd = quadBasis.getDofOrdinal(myTag[0], myTag[1], myTag[2]); if( bfOrd != myBfOrd) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; *outStream << " getDofTag(" << bfOrd << ") = { " << myTag[0] << ", " << myTag[1] << ", " << myTag[2] << ", " << myTag[3] << "} but getDofOrdinal({" << myTag[0] << ", " << myTag[1] << ", " << myTag[2] << ", " << myTag[3] << "} ) = " << myBfOrd << "\n"; } } } catch (std::logic_error err) { *outStream << err.what() << "\n\n"; errorFlag = -1000; }; *outStream \ << "\n" << "===============================================================================\n"\ << "| TEST 3: correctness of basis function values |\n"\ << "===============================================================================\n"; outStream -> precision(20); // VALUE: Each row pair gives the 6x3 correct basis set values at an evaluation point: (P,F,D) layout double basisValues[] = { 0, -0.500000, 0, 0, 0, 0, -0.500000, 0, 0, -0.500000, 0.500000, 0, 0, \ 0, 0, 0, 0, 0, 0.500000, 0, 0, 0.500000, 0, 0, 0, 0, 0, 0, 0, \ 0.500000, -0.500000, 0, 0, -0.250000, 0.250000, 0, 0, 0.250000, \ -0.250000, 0, 0, -0.375000, 0.250000, 0, 0, 0.125000, -0.250000, 0, \ 0, -0.125000, 0.250000, 0, 0, 0.375000, -0.250000, 0, 0, -0.250000, \ 0.125000, 0, 0, 0.250000, -0.375000, 0, 0, -0.250000, 0.375000, 0, 0, \ 0.250000, -0.125000, 0 }; // DIV: each row gives the 6 correct values of the divergence of the 6 basis functions: (P,F) layout double basisDivs[] = { 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.25, 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.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, }; try { // Dimensions for the output arrays: int numPoints = quadNodes.dimension(0); int numFields = quadBasis.getCardinality(); int spaceDim = quadBasis.getBaseCellTopology().getDimension(); // Generic array for values and curls that will be properly sized before each call FieldContainer<double> vals; // Check VALUE of basis functions: resize vals to rank-3 container: vals.resize(numFields, numPoints, spaceDim); quadBasis.getValues(vals, quadNodes, OPERATOR_VALUE); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { for (int k = 0; k < spaceDim; k++) { // compute offset for (P,F,D) data layout: indices are P->j, F->i, D->k int l = k + i * spaceDim + j * spaceDim * numFields; if (std::abs(vals(i,j,k) - basisValues[l]) > INTREPID_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(i,j,k) << " but reference value: " << basisValues[l] << "\n"; } } } } // Check DIV of basis function: resize vals to rank-2 container vals.resize(numFields, numPoints); quadBasis.getValues(vals, quadNodes, OPERATOR_DIV); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { int l = i + j * numFields; if (std::abs(vals(i,j) - basisDivs[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " "; *outStream << j << " "; *outStream << "} computed divergence component: " << vals(i,j) << " but reference divergence component: " << basisDivs[l] << "\n"; } } } } // Catch unexpected errors catch (std::logic_error err) { *outStream << err.what() << "\n\n"; errorFlag = -1000; }; if (errorFlag != 0) std::cout << "End Result: TEST FAILED\n"; else std::cout << "End Result: TEST PASSED\n"; // reset format state of std::cout std::cout.copyfmt(oldFormatState); return errorFlag; }
int HDIV_QUAD_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_QUAD_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" << "| 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<ValueType>(); int errorFlag = 0; typedef ValueType outputValueType; typedef ValueType pointValueType; Basis_HDIV_QUAD_I1_FEM<DeviceSpaceType,outputValueType,pointValueType> quadBasis; *outStream << "\n" << "===============================================================================\n" << "| TEST 1: Basis creation, exceptions tests |\n" << "===============================================================================\n"; try{ ordinal_type nthrow = 0, ncatch = 0; #ifdef HAVE_INTREPID2_DEBUG // Array with the 4 vertices of the reference Quadrilateral, its center and 4 more points DynRankView ConstructWithLabel(quadNodes, 9, 2); const auto numFields = quadBasis.getCardinality(); const auto numPoints = quadNodes.dimension(0); const auto spaceDim = quadBasis.getBaseCellTopology().getDimension(); DynRankView ConstructWithLabel(vals, numFields, numPoints, spaceDim ); { // exception #1: GRAD cannot be applied to HDIV functions INTREPID2_TEST_ERROR_EXPECTED( quadBasis.getValues(vals, quadNodes, OPERATOR_GRAD) ); // exception #2: CURL cannot be applied to HDIV functions INTREPID2_TEST_ERROR_EXPECTED( quadBasis.getValues(vals, quadNodes, 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( quadBasis.getDofOrdinal(3,0,0) ); // exception #4 INTREPID2_TEST_ERROR_EXPECTED( quadBasis.getDofOrdinal(1,1,1) ); // exception #5 INTREPID2_TEST_ERROR_EXPECTED( quadBasis.getDofOrdinal(0,4,1) ); // exception #6 INTREPID2_TEST_ERROR_EXPECTED( quadBasis.getDofTag(12) ); // exception #7 INTREPID2_TEST_ERROR_EXPECTED( quadBasis.getDofTag(-1) ); } // Exceptions 8- test exception handling with incorrectly dimensioned input/output arrays { // exception #8: input points array must be of rank-2 DynRankView ConstructWithLabel(badPoints1, 4, 5, 3); INTREPID2_TEST_ERROR_EXPECTED( quadBasis.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( quadBasis.getValues(vals, badPoints2, OPERATOR_VALUE) ); } { // exception #10 output values must be of rank-3 for OPERATOR_VALUE DynRankView ConstructWithLabel(badVals1, 4, 5); INTREPID2_TEST_ERROR_EXPECTED( quadBasis.getValues(badVals1, quadNodes, OPERATOR_VALUE) ); } { // exception #11 output values must be of rank-2 for OPERATOR_DIV DynRankView ConstructWithLabel(badVals2, 4, 5, spaceDim); INTREPID2_TEST_ERROR_EXPECTED( quadBasis.getValues(badVals2, quadNodes, OPERATOR_DIV) ); } { // exception #12 incorrect 0th dimension of output array (must equal number of basis functions) DynRankView ConstructWithLabel(badVals3, quadBasis.getCardinality() + 1, quadNodes.dimension(0), spaceDim); INTREPID2_TEST_ERROR_EXPECTED( quadBasis.getValues(badVals3, quadNodes, OPERATOR_VALUE) ); } { // exception #13 incorrect 0th dimension of output array (must equal number of basis functions) DynRankView ConstructWithLabel(badVals4, quadBasis.getCardinality() + 1, quadNodes.dimension(0)); INTREPID2_TEST_ERROR_EXPECTED( quadBasis.getValues(badVals4, quadNodes, OPERATOR_DIV) ); } { // exception #14 incorrect 1st dimension of output array (must equal number of points) DynRankView ConstructWithLabel(badVals5, quadBasis.getCardinality(), quadNodes.dimension(0) + 1, spaceDim); INTREPID2_TEST_ERROR_EXPECTED( quadBasis.getValues(badVals5, quadNodes, OPERATOR_VALUE) ); } { // exception #15 incorrect 1st dimension of output array (must equal number of points) DynRankView ConstructWithLabel(badVals6, quadBasis.getCardinality(), quadNodes.dimension(0) + 1); INTREPID2_TEST_ERROR_EXPECTED( quadBasis.getValues(badVals6, quadNodes, OPERATOR_DIV) ); } { // exception #16: incorrect 2nd dimension of output array (must equal the space dimension) DynRankView ConstructWithLabel(badVals7, quadBasis.getCardinality(), quadNodes.dimension(0), spaceDim + 1); INTREPID2_TEST_ERROR_EXPECTED( quadBasis.getValues(badVals7, quadNodes, OPERATOR_VALUE) ); } #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 = quadBasis.getCardinality(); const auto allTags = quadBasis.getAllDofTags(); // Loop over all tags, lookup the associated dof enumeration and then lookup the tag again const auto dofTagSize = allTags.dimension(0); for (size_type i=0;i<dofTagSize;++i) { const auto bfOrd = quadBasis.getDofOrdinal(allTags(i,0), allTags(i,1), allTags(i,2)); const auto myTag = quadBasis.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 = quadBasis.getDofTag(bfOrd); const auto myBfOrd = quadBasis.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 pair gives the 6x3 correct basis set values at an evaluation point: (P,F,D) layout double basisValues[] = { 0, -0.500000, 0, 0, 0, 0, -0.500000, 0, 0, -0.500000, 0.500000, 0, 0, \ 0, 0, 0, 0, 0, 0.500000, 0, 0, 0.500000, 0, 0, 0, 0, 0, 0, 0, \ 0.500000, -0.500000, 0, 0, -0.250000, 0.250000, 0, 0, 0.250000, \ -0.250000, 0, 0, -0.375000, 0.250000, 0, 0, 0.125000, -0.250000, 0, \ 0, -0.125000, 0.250000, 0, 0, 0.375000, -0.250000, 0, 0, -0.250000, \ 0.125000, 0, 0, 0.250000, -0.375000, 0, 0, -0.250000, 0.375000, 0, 0, \ 0.250000, -0.125000, 0 }; // DIV: each row gives the 6 correct values of the divergence of the 6 basis functions: (P,F) layout double basisDivs[] = { 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.25, 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.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, }; DynRankViewHost ConstructWithLabel(quadNodesHost, 9, 2); quadNodesHost(0,0) = -1.0; quadNodesHost(0,1) = -1.0; quadNodesHost(1,0) = 1.0; quadNodesHost(1,1) = -1.0; quadNodesHost(2,0) = 1.0; quadNodesHost(2,1) = 1.0; quadNodesHost(3,0) = -1.0; quadNodesHost(3,1) = 1.0; quadNodesHost(4,0) = 0.0; quadNodesHost(4,1) = 0.0; quadNodesHost(5,0) = 0.0; quadNodesHost(5,1) = -0.5; quadNodesHost(6,0) = 0.0; quadNodesHost(6,1) = 0.5; quadNodesHost(7,0) = -0.5; quadNodesHost(7,1) = 0.0; quadNodesHost(8,0) = 0.5; quadNodesHost(8,1) = 0.0; const auto quadNodes = Kokkos::create_mirror_view(typename DeviceSpaceType::memory_space(), quadNodesHost); Kokkos::deep_copy(quadNodes, quadNodesHost); // Dimensions for the output arrays: const auto numPoints = quadNodes.dimension(0); const auto numFields = quadBasis.getCardinality(); const auto spaceDim = quadBasis.getBaseCellTopology().getDimension(); { DynRankView ConstructWithLabel(vals, numFields, numPoints, spaceDim); quadBasis.getValues(vals, quadNodes, OPERATOR_VALUE); const 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) { // compute offset for (P,F,D) data layout: indices are P->j, F->i, D->k int l = k + i * spaceDim + j * spaceDim * numFields; if (std::abs(vals_host(i,j,k) - basisValues[l]) > tol) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " ";*outStream << k << " "; *outStream << "} computed value: " << vals_host(i,j,k) << " but reference value: " << basisValues[l] << "\n"; } } } { // Check DIV of basis function: resize vals to rank-2 container DynRankView ConstructWithLabel(vals, numFields, numPoints); quadBasis.getValues(vals, quadNodes, OPERATOR_DIV); const auto vals_host = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), vals); Kokkos::deep_copy(vals_host, vals); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { int l = i + j * numFields; if (std::abs(vals_host(i,j) - basisDivs[l]) > tol) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " "; *outStream << "} computed divergence component: " << vals_host(i,j) << " but reference divergence component: " << basisDivs[l] << "\n"; } } } } // Catch 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 auto numFields = quadBasis.getCardinality(); const auto spaceDim = quadBasis.getBaseCellTopology().getDimension(); // Check exceptions. ordinal_type nthrow = 0, ncatch = 0; #ifdef HAVE_INTREPID2_DEBUG { DynRankView ConstructWithLabel(badVals,1,2,3); INTREPID2_TEST_ERROR_EXPECTED( quadBasis.getDofCoords(badVals) ); } { DynRankView ConstructWithLabel(badVals, 3,2); INTREPID2_TEST_ERROR_EXPECTED( quadBasis.getDofCoords(badVals) ); } { DynRankView ConstructWithLabel(badVals, 4,3); INTREPID2_TEST_ERROR_EXPECTED( quadBasis.getDofCoords(badVals) ); } #endif // Check if number of thrown exceptions matches the one we expect if (nthrow != ncatch) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; } // Check mathematical correctness DynRankViewHost ConstructWithLabel(normals, numFields,spaceDim); // normals at each point basis point normals(0,0) = 0.0; normals(0,1) = -2.0; normals(1,0) = 2.0; normals(1,1) = 0.0; normals(2,0) = 0.0; normals(2,1) = 2.0; normals(3,0) = -2.0; normals(3,1) = 0.0; DynRankView ConstructWithLabel(cvals_dev, numFields,spaceDim); DynRankView ConstructWithLabel(bvals_dev, numFields, numFields, spaceDim); // last dimension is spatial dim quadBasis.getDofCoords(cvals_dev); quadBasis.getValues(bvals_dev, cvals_dev, OPERATOR_VALUE); const auto bvals = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), bvals_dev); Kokkos::deep_copy(bvals, bvals_dev); const auto cvals = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), cvals_dev); Kokkos::deep_copy(cvals, cvals_dev); ValueType expected_normal; for (size_type i=0;i<numFields;++i) { for (size_type j=0;j<numFields;++j) { ValueType normal = 0.0; for (size_type d=0;d<spaceDim;++d) normal += bvals(i,j,d)*normals(j,d); expected_normal = (i == j); if (std::abs(normal - expected_normal) > tol) { errorFlag++; std::stringstream ss; ss << "\nNormal component of basis function " << i << " at (" << cvals(j,0) << ", " << cvals(j,1)<< ") is " << normal << " but should be " << expected_normal << "\n"; *outStream << ss.str(); } } } } catch (std::logic_error err) { *outStream << err.what() << "\n\n"; errorFlag = -1000; }; if (errorFlag != 0) std::cout << "End Result: TEST FAILED\n"; else std::cout << "End Result: TEST PASSED\n"; // reset format state of std::cout std::cout.copyfmt(oldFormatState); return errorFlag; }