void OrientationTools<SpT>:: modifyBasisByOrientation(/**/ Kokkos::DynRankView<outputValueType,outputProperties...> output, const Kokkos::DynRankView<inputValueType, inputProperties...> input, const Kokkos::DynRankView<ortValueType, ortProperties...> orts, const BasisPtrType basis ) { #ifdef HAVE_INTREPID2_DEBUG { INTREPID2_TEST_FOR_EXCEPTION( input.rank() != output.rank(), std::invalid_argument, ">>> ERROR (OrientationTools::modifyBasisByOrientation): Input and output rank are not 3."); for (ordinal_type i=0;i<input.rank();++i) INTREPID2_TEST_FOR_EXCEPTION( input.dimension(i) != output.dimension(i), std::invalid_argument, ">>> ERROR (OrientationTools::modifyBasisByOrientation): Input and output dimension does not match."); INTREPID2_TEST_FOR_EXCEPTION( input.dimension(1) != basis->getCardinality(), std::invalid_argument, ">>> ERROR (OrientationTools::modifyBasisByOrientation): Field dimension of input/output does not match to basis cardinality."); INTREPID2_TEST_FOR_EXCEPTION( input.dimension(3) != basis->getBaseCellTopology().getDimension(), std::invalid_argument, ">>> ERROR (OrientationTools::modifyBasisByOrientation): Space dimension of input/output does not match to topology dimension."); } #endif if (basis->requireOrientation()) { auto ordinalToTag = Kokkos::create_mirror_view(typename SpT::memory_space(), basis->getAllDofTags()); auto tagToOrdinal = Kokkos::create_mirror_view(typename SpT::memory_space(), basis->getAllDofOrdinal()); Kokkos::deep_copy(ordinalToTag, basis->getAllDofTags()); Kokkos::deep_copy(tagToOrdinal, basis->getAllDofOrdinal()); const ordinal_type numCells = output.dimension(0), //numBasis = output.dimension(1), numPoints = output.dimension(2), dimBasis = output.dimension(3); const CoeffMatrixDataViewType matData = createCoeffMatrix(basis); const shards::CellTopology cellTopo = basis->getBaseCellTopology(); const ordinal_type numVerts = cellTopo.getVertexCount(), numEdges = cellTopo.getEdgeCount(), numFaces = cellTopo.getFaceCount(); const ordinal_type intrDim = ( numEdges == 0 ? 1 : numFaces == 0 ? 2 : /**/ 3 ); for (auto cell=0;cell<numCells;++cell) { auto out = Kokkos::subview(output, cell, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL()); auto in = Kokkos::subview(input, cell, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL()); // vertex copy (no orientation) for (auto vertId=0;vertId<numVerts;++vertId) { const auto i = tagToOrdinal(0, vertId, 0); if (i != -1) // if dof does not exist i returns with -1 for (auto j=0;j<numPoints;++j) for (auto k=0;k<dimBasis;++k) out(i, j, k) = in(i, j, k); } // interior copy { const auto ordIntr = tagToOrdinal(intrDim, 0, 0); if (ordIntr != -1) { const auto ndofIntr = ordinalToTag(ordIntr, 3); for (auto i=0;i<ndofIntr;++i) { const auto ii = tagToOrdinal(intrDim, 0, i); for (auto j=0;j<numPoints;++j) for (auto k=0;k<dimBasis;++k) out(ii, j, k) = in(ii, j, k); } } } // edge transformation if (numEdges > 0) { ordinal_type ortEdges[12]; orts(cell).getEdgeOrientation(ortEdges, numEdges); // apply coeff matrix for (auto edgeId=0;edgeId<numEdges;++edgeId) { const auto ordEdge = tagToOrdinal(1, edgeId, 0); if (ordEdge != -1) { const auto ndofEdge = ordinalToTag(ordEdge, 3); const auto mat = Kokkos::subview(matData, edgeId, ortEdges[edgeId], Kokkos::ALL(), Kokkos::ALL()); for (auto j=0;j<numPoints;++j) for (auto i=0;i<ndofEdge;++i) { const auto ii = tagToOrdinal(1, edgeId, i); for (auto k=0;k<dimBasis;++k) { double temp = 0.0; for (auto l=0;l<ndofEdge;++l) { const auto ll = tagToOrdinal(1, edgeId, l); temp += mat(i,l)*in(ll, j, k); } out(ii, j, k) = temp; } } } } } // face transformation if (numFaces > 0) { ordinal_type ortFaces[12]; orts(cell).getFaceOrientation(ortFaces, numFaces); // apply coeff matrix for (auto faceId=0;faceId<numFaces;++faceId) { const auto ordFace = tagToOrdinal(2, faceId, 0); if (ordFace != -1) { const auto ndofFace = ordinalToTag(ordFace, 3); const auto mat = Kokkos::subview(matData, numEdges+faceId, ortFaces[faceId], Kokkos::ALL(), Kokkos::ALL()); for (auto j=0;j<numPoints;++j) for (auto i=0;i<ndofFace;++i) { const auto ii = tagToOrdinal(2, faceId, i); for (auto k=0;k<dimBasis;++k) { double temp = 0.0; for (auto l=0;l<ndofFace;++l) { const auto ll = tagToOrdinal(2, faceId, l); temp += mat(i,l)*in(ll, j, k); } out(ii, j, k) = temp; } } } } } } } else { Kokkos::deep_copy(output, input); } }
// ---------------------------------------------------------------------- // Main // // int main(int argc, char *argv[]) { Teuchos::GlobalMPISession mpiSession(&argc, &argv); Kokkos::initialize(); // This little trick lets us print to std::cout only if a (dummy) command-line argument is provided. int iprint = argc - 1; for (int i=0;i<argc;++i) { if ((strcmp(argv[i],"--nelement") == 0)) { nelement = atoi(argv[++i]); continue;} if ((strcmp(argv[i],"--apply-orientation") == 0)) { apply_orientation = atoi(argv[++i]); continue;} if ((strcmp(argv[i],"--verbose") == 0)) { verbose = atoi(argv[++i]); continue;} if ((strcmp(argv[i],"--maxp") == 0)) { maxp = atoi(argv[++i]); continue;} } 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 << std::scientific; *outStream \ << "===============================================================================\n" \ << "| |\n" \ << "| Unit Test (Basis_HGRAD_TRI_Cn_FEM) |\n" \ << "| |\n" \ << "| 1) Patch test involving mass and stiffness matrices, |\n" \ << "| for the Neumann problem on a triangular patch |\n" \ << "| Omega with boundary Gamma. |\n" \ << "| |\n" \ << "| - div (grad u) + u = f in Omega, (grad u) . n = g on Gamma |\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" \ << "| TEST 4: Patch test for high order assembly |\n" \ << "===============================================================================\n"; int r_val = 0; // precision control outStream->precision(3); #if defined( INTREPID_USING_EXPERIMENTAL_HIGH_ORDER ) try { // test setup const int ndim = 2; FieldContainer<value_type> base_nodes(1, 4, ndim); base_nodes(0, 0, 0) = 0.0; base_nodes(0, 0, 1) = 0.0; base_nodes(0, 1, 0) = 1.0; base_nodes(0, 1, 1) = 0.0; base_nodes(0, 2, 0) = 0.0; base_nodes(0, 2, 1) = 1.0; base_nodes(0, 3, 0) = 1.0; base_nodes(0, 3, 1) = 1.0; // element 0 has globally permuted edge node const int elt_0[2][3] = { { 0, 1, 2 }, { 0, 2, 1 } }; // element 1 is locally permuted int elt_1[3] = { 1, 2, 3 }; DefaultCubatureFactory<value_type> cubature_factory; // for all test orders for (int nx=0;nx<=maxp;++nx) { for (int ny=0;ny<=maxp-nx;++ny) { // polynomial order of approximation const int minp = std::max(nx+ny, 1); // test for all basis above order p const EPointType pointtype[] = { POINTTYPE_EQUISPACED, POINTTYPE_WARPBLEND }; for (int ptype=0;ptype<2;++ptype) { for (int p=minp;p<=maxp;++p) { *outStream << "\n" \ << "===============================================================================\n" \ << " Order (nx,ny,p) = " << nx << ", " << ny << ", " << p << " , PointType = " << EPointTypeToString(pointtype[ptype]) << "\n" \ << "===============================================================================\n"; BasisSet_HGRAD_TRI_Cn_FEM<value_type,FieldContainer<value_type> > basis_set(p, pointtype[ptype]); const auto& basis = basis_set.getCellBasis(); const shards::CellTopology cell = basis.getBaseCellTopology(); const int nbf = basis.getCardinality(); const int nvert = cell.getVertexCount(); const int nedge = cell.getEdgeCount(); FieldContainer<value_type> nodes(1, 4, ndim); FieldContainer<value_type> cell_nodes(1, nvert, ndim); // ignore the subdimension; the matrix is always considered as 1D array FieldContainer<value_type> A(1, nbf, nbf), b(1, nbf); // ***** Test for different orientations ***** for (int conf0=0;conf0<2;++conf0) { for (int ino=0;ino<3;++ino) { nodes(0, elt_0[conf0][ino], 0) = base_nodes(0, ino, 0); nodes(0, elt_0[conf0][ino], 1) = base_nodes(0, ino, 1); } nodes(0, 3, 0) = base_nodes(0, 3, 0); nodes(0, 3, 1) = base_nodes(0, 3, 1); // reset element connectivity elt_1[0] = 1; elt_1[1] = 2; elt_1[2] = 3; // for all permuations of element 1 for (int conf1=0;conf1<6;++conf1) { // filter out left handed element fill_cell_nodes(cell_nodes, nodes, elt_1, nvert, ndim); if (OrientationTools<value_type>::isLeftHandedCell(cell_nodes)) { // skip left handed } else { const int *element[2] = { elt_0[conf0], elt_1 }; *outStream << "\n" \ << " Element 0 is configured " << conf0 << " " << "(" << element[0][0] << ","<< element[0][1] << "," << element[0][2] << ")" << " Element 1 is configured " << conf1 << " " << "(" << element[1][0] << ","<< element[1][1] << "," << element[1][2] << ")" << "\n"; if (verbose) { *outStream << " - Element nodal connectivity - \n"; for (int iel=0;iel<nelement;++iel) *outStream << " iel = " << std::setw(4) << iel << ", nodes = " << std::setw(4) << element[iel][0] << std::setw(4) << element[iel][1] << std::setw(4) << element[iel][2] << "\n"; } // Step 0: count one-to-one mapping between high order nodes and dofs Example::ToyMesh mesh; int local2global[2][8][2], boundary[2][3], off_global = 0; const int nnodes_per_element = cell.getVertexCount() + cell.getEdgeCount() + 1; for (int iel=0;iel<nelement;++iel) mesh.getLocalToGlobalMap(local2global[iel], off_global, basis, element[iel]); for (int iel=0;iel<nelement;++iel) mesh.getBoundaryFlags(boundary[iel], cell, element[iel]); if (verbose) { *outStream << " - Element one-to-one local2global map -\n"; for (int iel=0;iel<nelement;++iel) { *outStream << " iel = " << std::setw(4) << iel << "\n"; for (int i=0;i<(nnodes_per_element+1);++i) { *outStream << " local = " << std::setw(4) << local2global[iel][i][0] << " global = " << std::setw(4) << local2global[iel][i][1] << "\n"; } } *outStream << " - Element boundary flags -\n"; const int nside = cell.getSideCount(); for (int iel=0;iel<nelement;++iel) { *outStream << " iel = " << std::setw(4) << iel << "\n"; for (int i=0;i<nside;++i) { *outStream << " side = " << std::setw(4) << i << " boundary = " << std::setw(4) << boundary[iel][i] << "\n"; } } } // Step 1: assembly const int ndofs = off_global; FieldContainer<value_type> A_asm(1, ndofs, ndofs), b_asm(1, ndofs); for (int iel=0;iel<nelement;++iel) { // Step 1.1: create element matrices Orientation ort = Orientation::getOrientation(cell, element[iel]); // set element nodal coordinates fill_cell_nodes(cell_nodes, nodes, element[iel], nvert, ndim); build_element_matrix_and_rhs(A, b, cubature_factory, basis_set, element[iel], boundary[iel], cell_nodes, ort, nx, ny); // if p is bigger than 4, not worth to look at the matrix if (verbose && p < 5) { *outStream << " - Element matrix and rhs, iel = " << iel << "\n"; *outStream << std::showpos; for (int i=0;i<nbf;++i) { for (int j=0;j<nbf;++j) *outStream << MatVal(A, i, j) << " "; *outStream << ":: " << MatVal(b, i, 0) << "\n"; } *outStream << std::noshowpos; } // Step 1.2: assemble high order elements assemble_element_matrix_and_rhs(A_asm, b_asm, A, b, local2global[iel], nnodes_per_element); } if (verbose && p < 5) { *outStream << " - Assembled element matrix and rhs -\n"; *outStream << std::showpos; for (int i=0;i<ndofs;++i) { for (int j=0;j<ndofs;++j) *outStream << MatVal(A_asm, i, j) << " "; *outStream << ":: " << MatVal(b_asm, i, 0) << "\n"; } *outStream << std::noshowpos; } // Step 2: solve the system of equations int info = 0; Teuchos::LAPACK<int,value_type> lapack; FieldContainer<int> ipiv(ndofs); lapack.GESV(ndofs, 1, &A_asm(0,0,0), ndofs, &ipiv(0,0), &b_asm(0,0), ndofs, &info); TEUCHOS_TEST_FOR_EXCEPTION( info != 0, std::runtime_error, ">>> ERROR (Intrepid::HGRAD_TRI_Cn::Test 04): " \ "LAPACK solve fails"); // Step 3: construct interpolant and check solutions magnitude_type interpolation_error = 0, solution_norm =0; for (int iel=0;iel<nelement;++iel) { retrieve_element_solution(b, b_asm, local2global[iel], nnodes_per_element); if (verbose && p < 5) { *outStream << " - Element solution, iel = " << iel << "\n"; *outStream << std::showpos; for (int i=0;i<nbf;++i) { *outStream << MatVal(b, i, 0) << "\n"; } *outStream << std::noshowpos; } magnitude_type element_interpolation_error = 0, element_solution_norm = 0; Orientation ort = Orientation::getOrientation(cell, element[iel]); // set element nodal coordinates fill_cell_nodes(cell_nodes, nodes, element[iel], nvert, ndim); compute_element_error(element_interpolation_error, element_solution_norm, element[iel], cell_nodes, basis_set, b, ort, nx, ny); interpolation_error += element_interpolation_error; solution_norm += element_solution_norm; { int edge_orts[3]; ort.getEdgeOrientation(edge_orts, nedge); *outStream << " iel = " << std::setw(4) << iel << ", orientation = " << edge_orts[0] << edge_orts[1] << edge_orts[2] << " , error = " << element_interpolation_error << " , solution norm = " << element_solution_norm << " , relative error = " << (element_interpolation_error/element_solution_norm) << "\n"; } const magnitude_type relative_error = interpolation_error/solution_norm; const magnitude_type tol = p*p*100*INTREPID_TOL; if (relative_error > tol) { ++r_val; *outStream << "\n\nPatch test failed: \n" << " exact polynomial (nx, ny) = " << std::setw(4) << nx << ", " << std::setw(4) << ny << "\n" << " basis order = " << std::setw(4) << p << "\n" << " orientation configuration = " << std::setw(4) << conf0 << std::setw(4) << conf1 << "\n" << " relative error = " << std::setw(4) << relative_error << "\n" << " tolerance = " << std::setw(4) << tol << "\n"; } } } // for next iteration std::next_permutation(elt_1, elt_1+3); } // end of conf1 } // end of conf0 } // end of p } // end of point type } // end of ny } // end of nx } catch (std::logic_error err) { *outStream << err.what() << "\n\n"; r_val = -1000; }; #else *outStream << "\t This test is for high order element assembly. \n" << "\t Use -D INTREPID_USING_EXPERIMENTAL_HIGH_ORDER in CMAKE_CXX_FLAGS \n"; #endif if (r_val != 0) std::cout << "End Result: TEST FAILED :: r_val = " << r_val << "\n"; else std::cout << "End Result: TEST PASSED\n"; // reset format state of std::cout std::cout.copyfmt(oldFormatState); Kokkos::finalize(); return r_val; }
void getLocalToGlobalMap(int (*local2global)[2], int &off_global, const Basis<Scalar,ArrayType> &basis, const int *element) { const int local = 0, global = 1; const int nbf = basis.getCardinality(); const shards::CellTopology cell = basis.getBaseCellTopology(); const int dim = cell.getDimension(); int cnt = 0, off_element = 0; int subcell_verts[4], nids; const int nvert = cell.getVertexCount(); for (int i=0;i<nvert;++i) { const int ord_vert = (off_element < nbf ? basis.getDofOrdinal(0, i, 0) : 0); const int dof_vert = (off_element < nbf ? basis.getDofTag(ord_vert)[3] : 0); local2global[cnt][local] = off_element; off_element += dof_vert; Orientation::getElementNodeMap(subcell_verts, nids, cell, element, 0, i); if (!findNode(local2global[cnt][global], subcell_verts, nids, true)) { addNode(subcell_verts, nids, off_global); local2global[cnt][global] = off_global; off_global += dof_vert; } ++cnt; } const int nedge = cell.getEdgeCount(); for (int i=0;i<nedge;++i) { const int ord_edge = (off_element < nbf ? basis.getDofOrdinal(1, i, 0) : 0); const int dof_edge = (off_element < nbf ? basis.getDofTag(ord_edge)[3] : 0); local2global[cnt][local] = off_element; off_element += dof_edge; Orientation::getElementNodeMap(subcell_verts, nids, cell, element, 1, i); if (!findNode(local2global[cnt][global], subcell_verts, nids, true)) { addNode(subcell_verts, nids, off_global); local2global[cnt][global] = off_global; off_global += dof_edge; } ++cnt; } const int nface = cell.getFaceCount(); for (int i=0;i<nface;++i) { const int ord_face = (off_element < nbf ? basis.getDofOrdinal(2, i, 0) : 0); const int dof_face = (off_element < nbf ? basis.getDofTag(ord_face)[3] : 0); local2global[cnt][local] = off_element; off_element += dof_face; Orientation::getElementNodeMap(subcell_verts, nids, cell, element, 2, i); if (!findNode(local2global[cnt][global], subcell_verts, nids, true)) { addNode(subcell_verts, nids, off_global); local2global[cnt][global] = off_global; off_global += dof_face; } ++cnt; } { const int i = 0; const int ord_intr = (off_element < nbf ? basis.getDofOrdinal(dim, i, 0) : 0); const int dof_intr = (off_element < nbf ? basis.getDofTag(ord_intr)[3] : 0); local2global[cnt][local] = off_element; off_element += dof_intr; Orientation::getElementNodeMap(subcell_verts, nids, cell, element, dim, i); if (!findNode(local2global[cnt][global], subcell_verts, nids, true)) { addNode(subcell_verts, nids, off_global); local2global[cnt][global] = off_global; off_global += dof_intr; } ++cnt; } // add the last offset local2global[cnt][local] = off_element; local2global[cnt][global] = -1; // invalid values }
/** \brief Tests for experimental assembly procedure matching basis values. \param argc [in] - number of command-line arguments \param argv [in] - command-line arguments */ int main(int argc, char *argv[]) { Teuchos::GlobalMPISession mpiSession(&argc, &argv); Kokkos::initialize(); // This little trick lets us print to std::cout only if a (dummy) command-line argument is provided. int iprint = argc - 1; bool verbose = false; int maxp = INTREPID2_MAX_ORDER; for (int i=0;i<argc;++i) { if ((strcmp(argv[i],"--verbose") == 0)) { verbose = atoi(argv[++i]); continue;} if ((strcmp(argv[i],"--maxp") == 0)) { maxp = atoi(argv[++i]); continue;} } 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 HGRAD_TET_Cn_FEM |\n" \ << "| |\n" \ << "| 1) High order assembly |\n" \ << "| |\n" \ << "| Questions? Contact Pavel Bochev ([email protected]) or |\n" \ << "| Denis Ridzal ([email protected]) or |\n" \ << "| Robert Kirby ([email protected]) or |\n" \ << "| Kyungjoo Kim ([email protected]) |\n" \ << "| |\n" \ << "| Intrepid's website: http://trilinos.sandia.gov/packages/intrepid |\n" \ << "| Trilinos website: http://trilinos.sandia.gov |\n" \ << "| |\n" \ << "===============================================================================\n"; int r_val = 0; #if defined( INTREPID_USING_EXPERIMENTAL_HIGH_ORDER ) typedef double value_type; // Let's instantiate a basis try { OrientationTools<value_type>::verboseStreamPtr = outStream.get(); //for (int test_order=1;test_order<=10;++test_order) { for (int test_order=1;test_order<=maxp;++test_order) { // Step 0 : construct basis function set const int order = test_order; BasisSet_HGRAD_TET_Cn_FEM<double,FieldContainer<double> > basis_set(order , POINTTYPE_EQUISPACED); const auto& cell_basis = basis_set.getCellBasis(); const auto& face_basis = basis_set.getTriangleBasis(); const shards::CellTopology cell_topo = cell_basis.getBaseCellTopology(); const shards::CellTopology face_topo = face_basis.getBaseCellTopology(); const int nbf_cell = cell_basis.getCardinality(); const int nbf_face = face_basis.getCardinality(); const int ndim_cell = cell_topo.getDimension(); const int ndim_face = face_topo.getDimension(); const int npts = PointTools::getLatticeSize(face_topo, order, 1); for (int test_face=0;test_face<4;++test_face) { // tricky part const bool left_handed = cell_topo.getNodeMap(2, test_face, 1) > cell_topo.getNodeMap(2, test_face, 2); for (int test_ort=0;test_ort<6;++test_ort) { *outStream << "\n" \ << "===============================================================================\n" \ << " Order = " << test_order << " , Face = " << test_face << " , Orientation = " << test_ort << "\n" \ << "===============================================================================\n"; // Step 1 : create reference and modified triangle points // reference triangle points FieldContainer<value_type> ref_face_pts(npts, ndim_face); PointTools::getLattice<value_type>(ref_face_pts, face_topo, order, 1); // modified triangle points const int left_ort[] = { 0, 2, 1, 3, 5, 4 }; FieldContainer<value_type> ort_face_pts(npts, ndim_face); OrientationTools<value_type>::mapToModifiedReference(ort_face_pts, ref_face_pts, face_topo, (left_handed ? left_ort[test_ort] : test_ort)); // Step 2 : map face points to cell points appropriately const int nface = cell_topo.getFaceCount(); // create orientation object int orts[4] = {}; orts[test_face] = test_ort; Orientation ort; ort.setFaceOrientation(nface, orts); // map triangle points and modified points to reference coordinates FieldContainer<value_type> ref_cell_pts(npts, ndim_cell); CellTools<value_type>::mapToReferenceSubcell(ref_cell_pts, ref_face_pts, ndim_face, test_face, cell_topo); // Step 3 : evaluate modified basis functions with orientation for reference cell points FieldContainer<double> ort_cell_vals(nbf_cell, npts); { // temporary cell workspace FieldContainer<double> tmp_cell_vals(nbf_cell, npts); cell_basis.getValues(tmp_cell_vals, ref_cell_pts, OPERATOR_VALUE); OrientationTools<value_type>::getBasisFunctionsByTopology(ort_cell_vals, tmp_cell_vals, cell_basis); for (int i=0;i<nbf_cell;++i) for (int j=0;j<npts;++j) tmp_cell_vals(i, j) = ort_cell_vals(i, j); OrientationTools<value_type>::verbose = verbose; OrientationTools<value_type>::reverse = true; // for point matching only OrientationTools<value_type>::getModifiedBasisFunctions(ort_cell_vals, tmp_cell_vals, basis_set, ort); OrientationTools<value_type>::verbose = false; } // Step 4 : evaluate reference face basis functions for modified face points FieldContainer<double> ref_face_vals(nbf_face, npts); { // temporary face workspace FieldContainer<double> tmp_face_vals(nbf_face, npts); face_basis.getValues(tmp_face_vals, ort_face_pts, OPERATOR_VALUE); OrientationTools<value_type>::getBasisFunctionsByTopology(ref_face_vals, tmp_face_vals, face_basis); } // Step 5 : compare the basis functions to face functions { // strip the range of cell DOFs int off_cell = 0; { const int nvert = cell_topo.getVertexCount(); for (int i=0;i<nvert;++i) { const int ord_vert = cell_basis.getDofOrdinal(0, i, 0); off_cell += cell_basis.getDofTag(ord_vert)[3]; } if (off_cell < nbf_cell) { const int nedge = cell_topo.getEdgeCount(); for (int i=0;i<nedge;++i) { const int ord_edge = cell_basis.getDofOrdinal(1, i, 0); off_cell += cell_basis.getDofTag(ord_edge)[3]; } } if (off_cell < nbf_cell) { for (int i=0;i<test_face;++i) { const int ord_face = cell_basis.getDofOrdinal(2, i, 0); off_cell += cell_basis.getDofTag(ord_face)[3]; } } } // strip the range of face DOFs int off_face = 0; { const int nvert = face_topo.getVertexCount(); for (int i=0;i<nvert;++i) { const int ord_vert = face_basis.getDofOrdinal(0, i, 0); off_face += face_basis.getDofTag(ord_vert)[3]; } if (off_face < nbf_face) { const int nedge = face_topo.getEdgeCount(); for (int i=0;i<nedge;++i) { const int ord_edge = face_basis.getDofOrdinal(1, i, 0); off_face += face_basis.getDofTag(ord_edge)[3]; } } } const int ndof = nbf_face - off_face; for (int i=0;i<ndof;++i) { for (int j=0;j<npts;++j) { const value_type diff = std::abs(ort_cell_vals(i+off_cell,j) - ref_face_vals(i+off_face,j)); if (diff > INTREPID_TOL) { ++r_val; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; *outStream << " Basis function " << i << " at point " << j << " does not match each other\n"; } } } } } // test ort } // test face } // test order } catch (std::exception err) { std::cout << " Exeption\n"; *outStream << err.what() << "\n\n"; r_val = -1000; } #else *outStream << "\t This test is for high order element assembly. \n" << "\t Use -D INTREPID_USING_EXPERIMENTAL_HIGH_ORDER in CMAKE_CXX_FLAGS \n"; #endif if (r_val != 0) std::cout << "End Result: TEST FAILED, r_val = " << r_val << "\n"; else std::cout << "End Result: TEST PASSED\n"; // reset format state of std::cout std::cout.copyfmt(oldFormatState); Kokkos::finalize(); return r_val; }