int Orientation_Test05(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"; *outStream << "===============================================================================\n" << "| |\n" << "| Unit Test (OrientationTools, getModifiedHcurl_I1_Basis) |\n" << "| |\n" << "===============================================================================\n"; int errorFlag = 0; const double tol = tolerence(); typedef OrientationTools<DeviceSpaceType> ots; try { { *outStream << "\n -- Testing Quadrilateral \n\n"; Basis_HCURL_QUAD_I1_FEM<DeviceSpaceType> cellBasis; const auto cellTopo = cellBasis.getBaseCellTopology(); const ordinal_type ndofBasis = cellBasis.getCardinality(); // // 9 12 13 16 // 4 3 11 15 // 5 2 8 14 // 1 6 7 10 ordinal_type refMesh[9][4] = { { 1, 6, 2, 5 }, { 6, 7, 8, 2 }, { 7,10,14, 8 }, { 5, 2, 3, 4 }, { 2, 8,11, 3 }, { 8,14,15,11 }, { 4, 3,12, 9 }, { 3,11,13,12 }, {11,15,16,13 } }; const ordinal_type numCells = 9, numVerts = 4, numEdges = 4; // view to import refMesh from host Kokkos::DynRankView<ordinal_type,Kokkos::LayoutRight,HostSpaceType> elemNodesHost(&refMesh[0][0], numCells, numVerts); auto elemNodes = Kokkos::create_mirror_view(typename DeviceSpaceType::memory_space(), elemNodesHost); Kokkos::deep_copy(elemNodes, elemNodesHost); // compute orientations for cells (one time computation) Kokkos::DynRankView<Orientation,DeviceSpaceType> elemOrts("elemOrts", numCells); ots::getOrientation(elemOrts, elemNodes, cellTopo); auto elemOrtsHost = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), elemOrts); Kokkos::deep_copy(elemOrtsHost, elemOrts); // cell specific modified basis Kokkos::DynRankView<double,DeviceSpaceType> outValues("outValues", numCells, ndofBasis); Kokkos::DynRankView<double,DeviceSpaceType> refValues("refValues", numCells, ndofBasis); auto refValuesHost = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), refValues); for (auto cell=0;cell<numCells;++cell) for (auto bf=0;bf<ndofBasis;++bf) refValuesHost(cell, bf) = bf; Kokkos::deep_copy(refValues, refValuesHost); // modify refValues accounting for orientations ots::modifyBasisByOrientation(outValues, refValues, elemOrts, &cellBasis); auto outValuesHost = Kokkos::create_mirror_view(typename HostSpaceType::memory_space(), outValues); Kokkos::deep_copy(outValuesHost, outValues); for (auto cell=0;cell<numCells;++cell) { int flag = 0 ; std::stringstream s1, s2; ordinal_type orts[numEdges]; elemOrtsHost(cell).getEdgeOrientation(orts, numEdges); const double ortVal[2] = { 1.0 , - 1.0 }; s1 << " :: edge(0000) = " ; s2 << " :: edge(" << orts[0] << orts[1] << orts[2] << orts[3] << ") = "; for (auto edgeId=0;edgeId<numEdges;++edgeId) { const auto ndof = cellBasis.getDofTag(cellBasis.getDofOrdinal(1, edgeId, 0))(3); for (auto i=0;i<ndof;++i) { const auto refOrd = cellBasis.getDofOrdinal(1, edgeId, i); const auto outOrd = cellBasis.getDofOrdinal(1, edgeId, i); s1 << std::setw(4) << refValuesHost(cell, outOrd); s2 << std::setw(4) << outValuesHost(cell, outOrd); flag += (std::abs(ortVal[orts[edgeId]]*outValuesHost(cell, outOrd) - refValuesHost(cell, refOrd)) > tol); } s1 << " // "; s2 << " // "; } *outStream << "\n cell = " << cell << "\n" << " - refValues = " << s1.str() << "\n" << " - outValues = " << s2.str() << "\n"; if (flag) { *outStream << " ^^^^^^^^^^^^ FAILURE\n"; errorFlag += flag; } } ots::clearCoeffMatrix(); } } catch (std::exception err) { std::cout << " Exeption\n"; *outStream << err.what() << "\n\n"; errorFlag = -1000; } if (errorFlag != 0) std::cout << "End Result: TEST FAILED = " << errorFlag << "\n"; else std::cout << "End Result: TEST PASSED\n"; // reset format state of std::cout std::cout.copyfmt(oldFormatState); return errorFlag; }
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_HCURL_QUAD_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" \ << "| |\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_HCURL_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{ // exception #1: GRAD cannot be applied to HCURL functions // resize vals to rank-3 container with dimensions (num. basis functions, num. points, arbitrary) vals.resize(quadBasis.getCardinality(), quadNodes.dimension(0), 4 ); INTREPID_TEST_COMMAND( quadBasis.getValues(vals, quadNodes, OPERATOR_GRAD), throwCounter, nException ); // exception #2: DIV cannot be applied to HCURL functions // resize vals to rank-2 container with dimensions (num. points, num. basis functions) vals.resize(quadBasis.getCardinality(), quadNodes.dimension(0) ); INTREPID_TEST_COMMAND( quadBasis.getValues(vals, quadNodes, OPERATOR_DIV), 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-15 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, quadBasis.getBaseCellTopology().getDimension() + 1); INTREPID_TEST_COMMAND( quadBasis.getValues(vals, badPoints2, OPERATOR_VALUE), throwCounter, nException ); // exception #10 output values must be of rank-3 for OPERATOR_VALUE in 2D FieldContainer<double> badVals1(4, 3); INTREPID_TEST_COMMAND( quadBasis.getValues(badVals1, quadNodes, OPERATOR_VALUE), throwCounter, nException ); FieldContainer<double> badCurls1(4,3,2); // exception #11 output values must be of rank-2 for OPERATOR_CURL INTREPID_TEST_COMMAND( quadBasis.getValues(badCurls1, quadNodes, OPERATOR_CURL), throwCounter, nException ); // exception #12 incorrect 0th dimension of output array (must equal number of basis functions) FieldContainer<double> badVals2(quadBasis.getCardinality() + 1, quadNodes.dimension(0), quadBasis.getBaseCellTopology().getDimension()); INTREPID_TEST_COMMAND( quadBasis.getValues(badVals2, quadNodes, OPERATOR_VALUE), throwCounter, nException ) ; // exception #13 incorrect 1st dimension of output array (must equal number of points) FieldContainer<double> badVals3(quadBasis.getCardinality(), quadNodes.dimension(0) + 1, quadBasis.getBaseCellTopology().getDimension() ); INTREPID_TEST_COMMAND( quadBasis.getValues(badVals3, quadNodes, OPERATOR_VALUE), throwCounter, nException ) ; // exception #14: incorrect 2nd dimension of output array for VALUE (must equal the space dimension) FieldContainer<double> badVals4(quadBasis.getCardinality(), quadNodes.dimension(0), quadBasis.getBaseCellTopology().getDimension() - 1); INTREPID_TEST_COMMAND( quadBasis.getValues(badVals4, quadNodes, OPERATOR_VALUE), throwCounter, nException ) ; // 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(quadBasis.getCardinality(), quadNodes.dimension(0), Intrepid2::getDkCardinality(OPERATOR_D2, quadBasis.getBaseCellTopology().getDimension())); INTREPID_TEST_COMMAND( quadBasis.getValues(vals, quadNodes, OPERATOR_D2), 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 // Note Teuchos throw number will not pick up exceptions 3-7 and therefore will not match. if (throwCounter != nException) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; } //#endif *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 4x2 correct basis set values at an evaluation point: (P,F,D) layout double basisValues[] = { 0.500000, 0, 0, 0, 0, 0, 0, -0.500000, 0.500000, 0, 0, 0.500000, 0, \ 0, 0, 0, 0, 0, 0, 0.500000, -0.500000, 0, 0, 0, 0, 0, 0, 0, \ -0.500000, 0, 0, -0.500000, 0.250000, 0, 0, 0.250000, -0.250000, 0, \ 0, -0.250000, 0.375000, 0, 0, 0.250000, -0.125000, 0, 0, -0.250000, \ 0.125000, 0, 0, 0.250000, -0.375000, 0, 0, -0.250000, 0.250000, 0, 0, \ 0.125000, -0.250000, 0, 0, -0.375000, 0.250000, 0, 0, 0.375000, \ -0.250000, 0, 0, -0.125000 }; // CURL: correct values in (F,P) format double basisCurls[] = { 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 numFields = quadBasis.getCardinality(); int numPoints = quadNodes.dimension(0); 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 CURL of basis function: resize vals to rank-2 container vals.resize(numFields, numPoints); quadBasis.getValues(vals, quadNodes, OPERATOR_CURL); 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) - basisCurls[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 curl component: " << vals(i,j) << " but reference curl component: " << basisCurls[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{ Teuchos::RCP<Basis<double, FieldContainer<double> > > basis = Teuchos::rcp(new Basis_HCURL_QUAD_I1_FEM<double, FieldContainer<double> >); Teuchos::RCP<DofCoordsInterface<FieldContainer<double> > > coord_iface = Teuchos::rcp_dynamic_cast<DofCoordsInterface<FieldContainer<double> > >(basis); int spaceDim = 2; FieldContainer<double> cvals; FieldContainer<double> bvals(basis->getCardinality(), basis->getCardinality(),2); // last dimension is spatial dim // Check exceptions. #ifdef HAVE_INTREPID_DEBUG cvals.resize(1,2,3); INTREPID_TEST_COMMAND( coord_iface->getDofCoords(cvals), throwCounter, nException ); cvals.resize(3,2); INTREPID_TEST_COMMAND( coord_iface->getDofCoords(cvals), throwCounter, nException ); cvals.resize(4,3); INTREPID_TEST_COMMAND( coord_iface->getDofCoords(cvals), throwCounter, nException ); #endif cvals.resize(4,spaceDim); INTREPID_TEST_COMMAND( coord_iface->getDofCoords(cvals), throwCounter, nException ); nException--; // Check if number of thrown exceptions matches the one we expect if (throwCounter != nException) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; } // Check mathematical correctness FieldContainer<double> tangents(basis->getCardinality(),spaceDim); // tangents at each point basis point tangents(0,0) = 2.0; tangents(0,1) = 0.0; tangents(1,0) = 0.0; tangents(1,1) = 2.0; tangents(2,0) = -2.0; tangents(2,1) = 0.0; tangents(3,0) = 0.0; tangents(3,1) = -2.0; basis->getValues(bvals, cvals, OPERATOR_VALUE); char buffer[120]; for (int i=0; i<bvals.dimension(0); i++) { for (int j=0; j<bvals.dimension(1); j++) { double tangent = 0.0; for(int d=0;d<spaceDim;d++) tangent += bvals(i,j,d)*tangents(j,d); if ((i != j) && (std::abs(tangent - 0.0) > INTREPID_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(i,0), cvals(i,1), tangent, 0.0); *outStream << buffer; } else if ((i == j) && (std::abs(tangent - 1.0) > INTREPID_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(i,0), cvals(i,1), tangent, 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; }