int Intrepid2FieldPattern:: getSubcellCount(int dim) const { const shards::CellTopology ct = intrepidBasis_->getBaseCellTopology(); return ct.getSubcellCount(dim); }
void Intrepid2FieldPattern::buildSubcellClosure(const shards::CellTopology & cellTopo,unsigned dim,unsigned subCell, std::set<std::pair<unsigned,unsigned> > & closure) { switch(dim) { case 0: closure.insert(std::make_pair(0,subCell)); break; case 1: closure.insert(std::make_pair(0,cellTopo.getNodeMap(dim,subCell,0))); closure.insert(std::make_pair(0,cellTopo.getNodeMap(dim,subCell,1))); closure.insert(std::make_pair(1,subCell)); break; case 2: { unsigned cnt = (shards::CellTopology(cellTopo.getCellTopologyData(dim,subCell))).getSubcellCount(dim-1); for(unsigned i=0;i<cnt;i++) { int edge = mapCellFaceEdge(cellTopo.getCellTopologyData(),subCell,i); buildSubcellClosure(cellTopo,dim-1,edge,closure); } closure.insert(std::make_pair(2,subCell)); } break; default: // beyond a two dimension surface this thing crashes! TEUCHOS_ASSERT(false); }; }
inline void OrientationTools:: mapToModifiedReference(outPointViewType outPoints, const refPointViewType refPoints, const shards::CellTopology cellTopo, const ordinal_type cellOrt) { #ifdef HAVE_INTREPID2_DEBUG { const auto cellDim = cellTopo.getDimension(); INTREPID2_TEST_FOR_EXCEPTION( !( (1 <= cellDim) && (cellDim <= 2 ) ), std::invalid_argument, ">>> ERROR (Intrepid::OrientationTools::mapToModifiedReference): " \ "Method defined only for 1 and 2-dimensional subcells."); INTREPID2_TEST_FOR_EXCEPTION( !( outPoints.dimension(0) == refPoints.dimension(0) ), std::invalid_argument, ">>> ERROR (Intrepid::OrientationTools::mapToModifiedReference): " \ "Size of input and output point arrays does not match each other."); } #endif // Apply the parametrization map to every point in parameter domain const auto numPts = outPoints.dimension(0); const auto key = cellTopo.getBaseCellTopologyData()->key; switch (key) { case shards::Line<>::key : { for (auto pt=0;pt<numPts;++pt) getModifiedLinePoint(outPoints(pt, 0), refPoints(pt, 0), cellOrt); break; } case shards::Triangle<>::key : { for (auto pt=0;pt<numPts;++pt) getModifiedTrianglePoint(outPoints(pt, 0), outPoints(pt, 1), refPoints(pt, 0), refPoints(pt, 1), cellOrt); break; } case shards::Quadrilateral<>::key : { for (auto pt=0;pt<numPts;++pt) getModifiedQuadrilateralPoint(outPoints(pt, 0), outPoints(pt, 1), refPoints(pt, 0), refPoints(pt, 1), cellOrt); break; } default: { INTREPID2_TEST_FOR_EXCEPTION( true, std::invalid_argument, ">>> ERROR (Intrepid2::OrientationTools::mapToModifiedReference): " \ "Invalid cell topology." ); break; } } }
inline ordinal_type PointTools:: getLatticeSize( const shards::CellTopology cellType, const ordinal_type order, const ordinal_type offset ) { #ifdef HAVE_INTREPID2_DEBUG INTREPID2_TEST_FOR_EXCEPTION( order < 0 || offset < 0, std::invalid_argument , ">>> ERROR (PointTools::getLatticeSize): order and offset must be positive values." ); #endif ordinal_type r_val = 0; switch (cellType.getBaseKey()) { case shards::Tetrahedron<>::key: { const auto effectiveOrder = order - 4 * offset; r_val = (effectiveOrder < 0 ? 0 :(effectiveOrder+1)*(effectiveOrder+2)*(effectiveOrder+3)/6); break; } case shards::Triangle<>::key: { const auto effectiveOrder = order - 3 * offset; r_val = (effectiveOrder < 0 ? 0 : (effectiveOrder+1)*(effectiveOrder+2)/2); break; } case shards::Line<>::key: { const auto effectiveOrder = order - 2 * offset; r_val = (effectiveOrder < 0 ? 0 : (effectiveOrder+1)); break; } default: { INTREPID2_TEST_FOR_EXCEPTION( true , std::invalid_argument , ">>> ERROR (Intrepid2::PointTools::getLatticeSize): the specified cell type is not supported." ); } } return r_val; }
void Intrepid2FieldPattern::getSubcellNodes(const shards::CellTopology & cellTopo,unsigned dim,unsigned subCell, std::vector<unsigned> & nodes) { if(dim==0) { nodes.push_back(subCell); return; } // get all nodes on requested sub cell unsigned subCellNodeCount = cellTopo.getNodeCount(dim,subCell); for(unsigned node=0;node<subCellNodeCount;++node) nodes.push_back(cellTopo.getNodeMap(dim,subCell,node)); // sort them so they are ordered correctly for "includes" call std::sort(nodes.begin(),nodes.end()); }
void Intrepid2FieldPattern::findContainedSubcells(const shards::CellTopology & cellTopo,unsigned dim, const std::vector<unsigned> & nodes, std::set<std::pair<unsigned,unsigned> > & subCells) { unsigned subCellCount = cellTopo.getSubcellCount(dim); for(unsigned subCellOrd=0;subCellOrd<subCellCount;++subCellOrd) { // get all nodes in sub cell std::vector<unsigned> subCellNodes; getSubcellNodes(cellTopo,dim,subCellOrd,subCellNodes); // if subCellNodes \subset nodes => add (dim,subCellOrd) to subCells bool isSubset = std::includes( nodes.begin(), nodes.end(), subCellNodes.begin(), subCellNodes.end()); if(isSubset) subCells.insert(std::make_pair(dim,subCellOrd)); } // stop recursion base case if(dim==0) return; // find subcells in next sub dimension findContainedSubcells(cellTopo,dim-1,nodes,subCells); }
IntrepidSideCell<MDArray>::IntrepidSideCell( const shards::CellTopology& side_topology, const unsigned side_id, const shards::CellTopology& parent_topology, const unsigned degree ) : Base( side_topology, degree ) , d_side_id( side_id ) , d_parent_topology( parent_topology ) { // Map the side cubature points to the cell frame. MDArray mapped_cub_points( this->d_cubature->getNumPoints(), parent_topology.getDimension() ); Intrepid::CellTools<Scalar>::mapToReferenceSubcell( mapped_cub_points, this->d_cub_points, side_topology.getDimension(), d_side_id, d_parent_topology ); this->d_cub_points = mapped_cub_points; }
Basis_HGRAD_POLY_C1_FEM<Scalar, ArrayScalar>::Basis_HGRAD_POLY_C1_FEM(const shards::CellTopology& cellTopology){ this -> basisCardinality_ = cellTopology.getNodeCount(); this -> basisDegree_ = 1; this -> basisCellTopology_ = cellTopology; this -> basisType_ = BASIS_FEM_DEFAULT; this -> basisCoordinates_ = COORDINATES_CARTESIAN; this -> basisTagsAreSet_ = false; }
unsigned getLocalSubcellIndexFromGlobalNodeList(const ArrayCellGIDs& cellGIDs, const ArraySideGIDs& subcellGIDs, const shards::CellTopology& cell,unsigned subcell_dim) { unsigned local_subcell; bool found_local_subcell = false; unsigned subcell = 0; while ( (subcell < cell.getSubcellCount(subcell_dim)) && (!found_local_subcell) ) { unsigned num_subcell_nodes = cell.getCellTopologyData()->subcell[subcell_dim][subcell].topology->node_count; std::list<unsigned> tmp_subcell_gid_list; for (unsigned node = 0; node < num_subcell_nodes; ++node) tmp_subcell_gid_list.push_back(cellGIDs[cell.getNodeMap(subcell_dim, subcell, node)]); bool subcell_matches = true; unsigned node = 0; while ( subcell_matches && (node < num_subcell_nodes) ) { std::list<unsigned>::iterator search = std::find(tmp_subcell_gid_list.begin(), tmp_subcell_gid_list.end(), subcellGIDs[node]); if (search == tmp_subcell_gid_list.end()) subcell_matches = false; ++node; } if (subcell_matches) { found_local_subcell = true; local_subcell = subcell; } ++subcell; } TEUCHOS_TEST_FOR_EXCEPTION(!found_local_subcell, std::runtime_error, "Failed to find subcell!"); return local_subcell; }
void getBoundaryFlags(int *boundary, const shards::CellTopology cell, const int *element) { int subcell_verts[4], nids; const int dim = cell.getDimension(); const int nside = cell.getSideCount(); for (int i=0;i<nside;++i) { Orientation::getElementNodeMap(subcell_verts, nids, cell, element, dim-1, i); if (!findBoundary(boundary[i], subcell_verts, nids)) { TEUCHOS_TEST_FOR_EXCEPTION( true, std::runtime_error, ">>> ERROR (Intrepid::HGRAD_TRI_Cn::Test 04): " \ "Side node is not found"); } } }
void PointTools:: getWarpBlendLattice( /**/ Kokkos::DynRankView<pointValueType,pointProperties...> points, const shards::CellTopology cell, const ordinal_type order, const ordinal_type offset ) { switch (cell.getBaseKey()) { // case shards::Tetrahedron<>::key: getWarpBlendLatticeTetrahedron( points, order, offset ); break; // case shards::Triangle<>::key: getWarpBlendLatticeTriangle ( points, order, offset ); break; case shards::Line<>::key: getWarpBlendLatticeLine ( points, order, offset ); break; default: { INTREPID2_TEST_FOR_EXCEPTION( true , std::invalid_argument , ">>> ERROR (Intrepid2::PointTools::getWarpBlendLattice): the specified cell type is not supported." ); } } }
unsigned getLocalSideIndexFromGlobalNodeList(const ArrayCellGIDs& cellGIDs, const ArraySideGIDs& sideGIDs, const shards::CellTopology& cell) { unsigned cell_dim = cell.getDimension(); //TEUCHOS_TEST_FOR_EXCEPTION(!cell.getSubcellHomogeneity(cell_dim - 1), // std::runtime_error, "Sides are not homogeneous!"); unsigned local_side; bool found_local_side = false; unsigned side = 0; while ( (side < cell.getSideCount()) && (!found_local_side) ) { const shards::CellTopology side_topo(cell.getCellTopologyData(cell.getDimension()-1, side)); unsigned num_side_nodes = cell.getCellTopologyData()->side[side].topology->node_count; std::list<unsigned> tmp_side_gid_list; for (unsigned node = 0; node < num_side_nodes; ++node) tmp_side_gid_list.push_back(cellGIDs[cell.getNodeMap(cell_dim - 1, side, node)]); bool side_matches = true; unsigned node = 0; while ( side_matches && (node < num_side_nodes) ) { std::list<unsigned>::iterator search = std::find(tmp_side_gid_list.begin(), tmp_side_gid_list.end(), sideGIDs[node]); if (search == tmp_side_gid_list.end()) side_matches = false; ++node; } if (side_matches) { found_local_side = true; local_side = side; } ++side; } TEUCHOS_TEST_FOR_EXCEPTION(!found_local_side, std::runtime_error, "Failed to find side!"); return local_side; }
Basis_Constant_FEM<SpT,OT,PT>:: Basis_Constant_FEM(const shards::CellTopology cellTopo) { const ordinal_type spaceDim = cellTopo.getDimension(); this->basisCardinality_ = 1; this->basisDegree_ = 0; this->basisCellTopology_ = cellTopo; this->basisType_ = Intrepid2::BASIS_FEM_DEFAULT; this->basisCoordinates_ = Intrepid2::COORDINATES_CARTESIAN; // initialize tags { // Basis-dependent intializations const ordinal_type tagSize = 4; // size of DoF tag, i.e., number of fields in the tag const ordinal_type posScDim = 0; // position in the tag, counting from 0, of the subcell dim const ordinal_type posScOrd = 1; // position in the tag, counting from 0, of the subcell ordinal const ordinal_type posDfOrd = 2; // position in the tag, counting from 0, of DoF ordinal relative to the subcell // An array with local DoF tags assigned to the basis functions, in the order of their local enumeration ordinal_type tags[4] = { spaceDim, 0, 0, 1 }; ordinal_type_array_1d_host tagView(&tags[0], 4); this->setOrdinalTagData(this->tagToOrdinal_, this->ordinalToTag_, tagView, this->basisCardinality_, tagSize, posScDim, posScOrd, posDfOrd); } // dofCoords on host and create its mirror view to device Kokkos::DynRankView<typename scalarViewType::value_type,typename SpT::array_layout,Kokkos::HostSpace> dofCoords("dofCoordsHost", this->basisCardinality_, spaceDim), cellVerts("cellVerts", spaceDim); CellTools<SpT>::getReferenceCellCenter(Kokkos::subview(dofCoords, 0, Kokkos::ALL()), cellVerts, cellTopo); this->dofCoords_ = Kokkos::create_mirror_view(typename SpT::memory_space(), dofCoords); Kokkos::deep_copy(this->dofCoords_, dofCoords); }
void mapToPhysicalFrame(ArrayPhysPoint & physPoints, const ArrayRefPoint & refPoints, const ArrayCell & cellWorkset, const shards::CellTopology & cellTopo, const int & whichCell) { int spaceDim = (int)cellTopo.getDimension(); int numCells = cellWorkset.dimension(0); //points can be rank-2 (P,D), or rank-3 (C,P,D) int numPoints = (refPoints.rank() == 2) ? refPoints.dimension(0) : refPoints.dimension(1); // Initialize physPoints for(int i = 0; i < physPoints.dimentions(0); i++) for(int j = 0; j < physPoints.dimentions(1); j++) for(int k = 0; k < physPoints.dimentions(2); k++) physPoints(i,j,k) = 0.0; }
void PointTools:: getLattice( /**/ Kokkos::DynRankView<pointValueType,pointProperties...> points, const shards::CellTopology cell, const ordinal_type order, const ordinal_type offset, const EPointType pointType ) { #ifdef HAVE_INTREPID2_DEBUG INTREPID2_TEST_FOR_EXCEPTION( points.rank() != 2, std::invalid_argument , ">>> ERROR (PointTools::getLattice): points rank must be 2." ); INTREPID2_TEST_FOR_EXCEPTION( order < 0 || offset < 0, std::invalid_argument , ">>> ERROR (PointTools::getLattice): order and offset must be positive values." ); const size_type latticeSize = getLatticeSize( cell, order, offset ); const size_type spaceDim = cell.getDimension(); INTREPID2_TEST_FOR_EXCEPTION( points.dimension(0) != latticeSize || points.dimension(1) != spaceDim, std::invalid_argument , ">>> ERROR (PointTools::getLattice): dimension does not match to lattice size." ); #endif // const auto latticeSize = getLatticeSize( cell, order, offset ); // const auto spaceDim = cell.getDimension(); // // the interface assumes that the input array follows the cell definition // // so, let's match all dimensions according to the cell specification // typedef Kokkos::pair<ordinal_type,ordinal_type> range_type; // auto pts = Kokkos::subview( points, // range_type(0, latticeSize), // range_type(0, spaceDim) ); switch (pointType) { case POINTTYPE_EQUISPACED: getEquispacedLattice( points, cell, order, offset ); break; case POINTTYPE_WARPBLEND: getWarpBlendLattice ( points, cell, order, offset ); break; default: { INTREPID2_TEST_FOR_EXCEPTION( true , std::invalid_argument , ">>> ERROR (PointTools::getLattice): invalid EPointType." ); } } }
void CellTools<SpT>:: mapToReferenceSubcell( /**/ Kokkos::DynRankView<refSubcellPointValueType,refSubcellPointProperties...> refSubcellPoints, const Kokkos::DynRankView<paramPointValueType,paramPointProperties...> paramPoints, const ordinal_type subcellDim, const ordinal_type subcellOrd, const shards::CellTopology parentCell ) { #ifdef HAVE_INTREPID2_DEBUG INTREPID2_TEST_FOR_EXCEPTION( !hasReferenceCell(parentCell), std::invalid_argument, ">>> ERROR (Intrepid2::CellTools::mapToReferenceSubcell): the specified cell topology does not have a reference cell."); INTREPID2_TEST_FOR_EXCEPTION( subcellDim != 1 && subcellDim != 2, std::invalid_argument, ">>> ERROR (Intrepid2::CellTools::mapToReferenceSubcell): method defined only for 1 and 2-dimensional subcells."); INTREPID2_TEST_FOR_EXCEPTION( subcellOrd < 0 || subcellOrd >= parentCell.getSubcellCount(subcellDim), std::invalid_argument, ">>> ERROR (Intrepid2::CellTools::mapToReferenceSubcell): subcell ordinal out of range."); // refSubcellPoints is rank-2 (P,D1), D1 = cell dimension INTREPID2_TEST_FOR_EXCEPTION( refSubcellPoints.rank() != 2, std::invalid_argument, ">>> ERROR (Intrepid2::CellTools::mapToReferenceSubcell): refSubcellPoints must have rank 2."); INTREPID2_TEST_FOR_EXCEPTION( refSubcellPoints.dimension(1) != parentCell.getDimension(), std::invalid_argument, ">>> ERROR (Intrepid2::CellTools::mapToReferenceSubcell): refSubcellPoints dimension (1) does not match to parent cell dimension."); // paramPoints is rank-2 (P,D2) with D2 = subcell dimension INTREPID2_TEST_FOR_EXCEPTION( paramPoints.rank() != 2, std::invalid_argument, ">>> ERROR (Intrepid2::CellTools::mapToReferenceSubcell): paramPoints must have rank 2."); INTREPID2_TEST_FOR_EXCEPTION( paramPoints.dimension(1) != subcellDim, std::invalid_argument, ">>> ERROR (Intrepid2::CellTools::mapToReferenceSubcell): paramPoints dimension (1) does not match to subcell dimension."); // cross check: refSubcellPoints and paramPoints: dimension 0 must match INTREPID2_TEST_FOR_EXCEPTION( refSubcellPoints.dimension(0) < paramPoints.dimension(0), std::invalid_argument, ">>> ERROR (Intrepid2::CellTools::mapToReferenceSubcell): refSubcellPoints dimension (0) does not match to paramPoints dimension(0)."); #endif const auto cellDim = parentCell.getDimension(); const auto numPts = paramPoints.dimension(0); // Get the subcell map, i.e., the coefficients of the parametrization function for the subcell // can i get this map from devices ? subcellParamViewType subcellMap; getSubcellParametrization( subcellMap, subcellDim, parentCell ); // subcell parameterization should be small computation (numPts is small) and it should be decorated with // kokkos inline... let's not do this yet // Apply the parametrization map to every point in parameter domain switch (subcellDim) { case 2: { for (size_type pt=0;pt<numPts;++pt) { const auto u = paramPoints(pt, 0); const auto v = paramPoints(pt, 1); // map_dim(u,v) = c_0(dim) + c_1(dim)*u + c_2(dim)*v because both Quad and Tri ref faces are affine! for (size_type i=0;i<cellDim;++i) refSubcellPoints(pt, i) = subcellMap(subcellOrd, i, 0) + ( subcellMap(subcellOrd, i, 1)*u + subcellMap(subcellOrd, i, 2)*v ); } break; } case 1: { for (size_type pt=0;pt<numPts;++pt) { const auto u = paramPoints(pt, 0); for (size_type i=0;i<cellDim;++i) refSubcellPoints(pt, i) = subcellMap(subcellOrd, i, 0) + ( subcellMap(subcellOrd, i, 1)*u ); } break; } default: { INTREPID2_TEST_FOR_EXCEPTION( subcellDim != 1 && subcellDim != 2, std::invalid_argument, ">>> ERROR (Intrepid2::CellTools::mapToReferenceSubcell): method defined only for 1 and 2-subcells"); } } }
int Intrepid2FieldPattern::getDimension() const { const shards::CellTopology ct = intrepidBasis_->getBaseCellTopology(); return ct.getDimension(); }
void mapToPhysicalFrame(ArrayPhysPoint & physPoints, const ArrayRefPoint & refPoints, const ArrayCell & cellWorkset, const shards::CellTopology & cellTopo, const int & whichCell) { int spaceDim = (int)cellTopo.getDimension(); int numCells = cellWorkset.dimension(0); //points can be rank-2 (P,D), or rank-3 (C,P,D) int numPoints = (refPoints.rank() == 2) ? refPoints.dimension(0) : refPoints.dimension(1); /* // Mapping is computed using an appropriate H(grad) basis function: define RCP to the base class Teuchos::RCP<Basis<Scalar, FieldContainer<Scalar> > > HGRAD_Basis; // Choose the H(grad) basis depending on the cell topology. \todo define maps for shells and beams switch( cellTopo.getKey() ){ // Standard Base topologies (number of cellWorkset = number of vertices) case shards::Line<2>::key: HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_LINE_C1_FEM<Scalar, FieldContainer<Scalar> >() ); break; case shards::Triangle<3>::key: HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_TRI_C1_FEM<Scalar, FieldContainer<Scalar> >() ); break; case shards::Quadrilateral<4>::key: HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_QUAD_C1_FEM<Scalar, FieldContainer<Scalar> >() ); break; case shards::Tetrahedron<4>::key: HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_TET_C1_FEM<Scalar, FieldContainer<Scalar> >() ); break; case shards::Hexahedron<8>::key: HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_HEX_C1_FEM<Scalar, FieldContainer<Scalar> >() ); break; case shards::Wedge<6>::key: HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_WEDGE_C1_FEM<Scalar, FieldContainer<Scalar> >() ); break; case shards::Pyramid<5>::key: HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_PYR_C1_FEM<Scalar, FieldContainer<Scalar> >() ); break; // Standard Extended topologies case shards::Triangle<6>::key: HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_TRI_C2_FEM<Scalar, FieldContainer<Scalar> >() ); break; case shards::Quadrilateral<9>::key: HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_QUAD_C2_FEM<Scalar, FieldContainer<Scalar> >() ); break; case shards::Tetrahedron<10>::key: HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_TET_C2_FEM<Scalar, FieldContainer<Scalar> >() ); break; case shards::Tetrahedron<11>::key: HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_TET_COMP12_FEM<Scalar, FieldContainer<Scalar> >() ); break; case shards::Hexahedron<27>::key: HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_HEX_C2_FEM<Scalar, FieldContainer<Scalar> >() ); break; case shards::Wedge<18>::key: HGRAD_Basis = Teuchos::rcp( new Basis_HGRAD_WEDGE_C2_FEM<Scalar, FieldContainer<Scalar> >() ); break; // These extended topologies are not used for mapping purposes case shards::Quadrilateral<8>::key: case shards::Hexahedron<20>::key: case shards::Wedge<15>::key: TEUCHOS_TEST_FOR_EXCEPTION( (true), std::invalid_argument, ">>> ERROR (Intrepid::CellTools::mapToPhysicalFrame): Cell topology not supported. "); break; // Base and Extended Line, Beam and Shell topologies case shards::Line<3>::key: case shards::Beam<2>::key: case shards::Beam<3>::key: case shards::ShellLine<2>::key: case shards::ShellLine<3>::key: case shards::ShellTriangle<3>::key: case shards::ShellTriangle<6>::key: case shards::ShellQuadrilateral<4>::key: case shards::ShellQuadrilateral<8>::key: case shards::ShellQuadrilateral<9>::key: TEUCHOS_TEST_FOR_EXCEPTION( (true), std::invalid_argument, ">>> ERROR (Intrepid::CellTools::mapToPhysicalFrame): Cell topology not supported. "); break; default: TEUCHOS_TEST_FOR_EXCEPTION( (true), std::invalid_argument, ">>> ERROR (Intrepid::CellTools::mapToPhysicalFrame): Cell topology not supported."); }// switch // Temp (F,P) array for the values of nodal basis functions at the reference points int basisCardinality = HGRAD_Basis -> getCardinality(); FieldContainer<Scalar> basisVals(basisCardinality, numPoints); */ // Initialize physPoints for(int i = 0; i < physPoints.dimentions(0); i++) for(int j = 0; j < physPoints.dimentions(1); j++) for(int k = 0; k < physPoints.dimentions(2); k++) physPoints(i,j,k) = 0.0; }
void testSubcellParametrizations(int& errorFlag, const shards::CellTopology& parentCell, const FieldContainer<double>& subcParamVert_A, const FieldContainer<double>& subcParamVert_B, const int subcDim, const Teuchos::RCP<std::ostream>& outStream){ // Get cell dimension and subcell count int cellDim = parentCell.getDimension(); int subcCount = parentCell.getSubcellCount(subcDim); // Loop over subcells of the specified dimension for(int subcOrd = 0; subcOrd < subcCount; subcOrd++){ int subcVertexCount = parentCell.getVertexCount(subcDim, subcOrd); // Storage for correct reference subcell vertices and for the images of the parametrization domain points FieldContainer<double> refSubcellVertices(subcVertexCount, cellDim); FieldContainer<double> mappedParamVertices(subcVertexCount, cellDim); // Retrieve correct reference subcell vertices CellTools<double>::getReferenceSubcellVertices(refSubcellVertices, subcDim, subcOrd, parentCell); // Map vertices of the parametrization domain to 1 or 2-subcell with ordinal subcOrd // For edges parametrization domain is always 1-cube passed as "subcParamVert_A" if(subcDim == 1) { CellTools<double>::mapToReferenceSubcell(mappedParamVertices, subcParamVert_A, subcDim, subcOrd, parentCell); } // For faces need to treat Triangle and Quadrilateral faces separately else if(subcDim == 2) { // domain "subcParamVert_A" is the standard 2-simplex if(subcVertexCount == 3){ CellTools<double>::mapToReferenceSubcell(mappedParamVertices, subcParamVert_A, subcDim, subcOrd, parentCell); } // Domain "subcParamVert_B" is the standard 2-cube else if(subcVertexCount == 4){ CellTools<double>::mapToReferenceSubcell(mappedParamVertices, subcParamVert_B, subcDim, subcOrd, parentCell); } } // Compare the images of the parametrization domain vertices with the true vertices. for(int subcVertOrd = 0; subcVertOrd < subcVertexCount; subcVertOrd++){ for(int dim = 0; dim < cellDim; dim++){ if(mappedParamVertices(subcVertOrd, dim) != refSubcellVertices(subcVertOrd, dim) ) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n" << " Cell Topology = " << parentCell.getName() << "\n" << " Parametrization of subcell " << subcOrd << " which is " << parentCell.getName(subcDim,subcOrd) << " failed for vertex " << subcVertOrd << ":\n" << " parametrization map fails to map correctly coordinate " << dim << " of that vertex\n\n"; }//if }// for dim }// for subcVertOrd }// for subcOrd }
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); } }
void build_element_matrix_and_rhs(FieldContainer<value_type> & A, FieldContainer<value_type> & b, DefaultCubatureFactory<value_type> & cubature_factory, const BasisSet_HGRAD_TRI_Cn_FEM<value_type,FieldContainer<value_type> > &basis_set, const int *element, const int *boundary, const FieldContainer<value_type> & cell_nodes, const Orientation ort, const int nx, const int ny) { // Step 0: initilization const auto &cell_basis = basis_set.getCellBasis(); const auto &side_basis = basis_set.getLineBasis(); const shards::CellTopology cell_topo = cell_basis.getBaseCellTopology(); const shards::CellTopology side_topo = side_basis.getBaseCellTopology(); const int nbf_cell = cell_basis.getCardinality(); //const int nbf_side = side_basis.getCardinality(); const int ndim_cell = cell_topo.getDimension(); const int ndim_side = side_topo.getDimension(); //const int nside = cell_topo.getEdgeCount(); const int p = cell_basis.getDegree(); // Step 1: create cubature data for integration Teuchos::RCP<Cubature<value_type> > cell_cub = cubature_factory.create(cell_topo, 2*p); Teuchos::RCP<Cubature<value_type> > side_cub = cubature_factory.create(side_topo, 2*p); const int npts_cell_cub = cell_cub->getNumPoints(); const int npts_side_cub = side_cub->getNumPoints(); // - cell related containers FieldContainer<value_type> cub_points_cell(npts_cell_cub, ndim_cell); FieldContainer<value_type> cub_points_cell_physical(1, npts_cell_cub, ndim_cell); FieldContainer<value_type> cub_weights_cell(npts_cell_cub); FieldContainer<value_type> jacobian_cell(1, npts_cell_cub, ndim_cell, ndim_cell); FieldContainer<value_type> jacobian_inv_cell(1, npts_cell_cub, ndim_cell, ndim_cell); FieldContainer<value_type> jacobian_det_cell(1, npts_cell_cub); FieldContainer<value_type> weighted_measure_cell(1, npts_cell_cub); FieldContainer<value_type> value_of_basis_at_cub_points_cell(nbf_cell, npts_cell_cub); FieldContainer<value_type> value_of_reordered_basis_at_cub_points_cell(nbf_cell, npts_cell_cub); FieldContainer<value_type> transformed_value_of_basis_at_cub_points_cell(1, nbf_cell, npts_cell_cub); FieldContainer<value_type> weighted_transformed_value_of_basis_at_cub_points_cell(1, nbf_cell, npts_cell_cub); FieldContainer<value_type> grad_of_basis_at_cub_points_cell(nbf_cell, npts_cell_cub, ndim_cell); FieldContainer<value_type> grad_of_reordered_basis_at_cub_points_cell(nbf_cell, npts_cell_cub, ndim_cell); FieldContainer<value_type> transformed_grad_of_basis_at_cub_points_cell(1, nbf_cell, npts_cell_cub, ndim_cell); FieldContainer<value_type> weighted_transformed_grad_of_basis_at_cub_points_cell(1, nbf_cell, npts_cell_cub, ndim_cell); FieldContainer<value_type> rhs_at_cub_points_cell_physical(1, npts_cell_cub); FieldContainer<value_type> rhs_and_soln_vector(1, nbf_cell); // - subcell related containders FieldContainer<value_type> cub_points_side(npts_side_cub, ndim_side); FieldContainer<value_type> cub_weights_side(npts_side_cub); FieldContainer<value_type> cub_points_side_refcell(npts_side_cub, ndim_cell); FieldContainer<value_type> cub_points_side_physical(1, npts_side_cub, ndim_cell); FieldContainer<value_type> jacobian_side_refcell(1, npts_side_cub, ndim_cell, ndim_cell); FieldContainer<value_type> jacobian_det_side_refcell(1, npts_side_cub); FieldContainer<value_type> weighted_measure_side_refcell(1, npts_side_cub); FieldContainer<value_type> value_of_basis_at_cub_points_side_refcell(nbf_cell, npts_side_cub); FieldContainer<value_type> value_of_reordered_basis_at_cub_points_side_refcell(nbf_cell, npts_side_cub); FieldContainer<value_type> transformed_value_of_basis_at_cub_points_side_refcell(1, nbf_cell, npts_side_cub); FieldContainer<value_type> weighted_transformed_value_of_basis_at_cub_points_side_refcell(1, nbf_cell, npts_side_cub); FieldContainer<value_type> neumann_data_at_cub_points_side_physical(1, npts_side_cub); FieldContainer<value_type> neumann_fields_per_side(1, nbf_cell); // get cubature points and weights cell_cub->getCubature(cub_points_cell, cub_weights_cell); CellTools<value_type>::setJacobian (jacobian_cell, cub_points_cell, cell_nodes, cell_topo); CellTools<value_type>::setJacobianInv(jacobian_inv_cell, jacobian_cell); CellTools<value_type>::setJacobianDet(jacobian_det_cell, jacobian_cell); // compute weighted measure FunctionSpaceTools::computeCellMeasure<value_type>(weighted_measure_cell, jacobian_det_cell, cub_weights_cell); // Step 1: mass matrix: tabulate values of basis functions at cubature points cell_basis.getValues(value_of_basis_at_cub_points_cell, cub_points_cell, OPERATOR_VALUE); if (apply_orientation) { OrientationTools<value_type>::verbose = false; OrientationTools<value_type>::getBasisFunctionsByTopology(value_of_reordered_basis_at_cub_points_cell, value_of_basis_at_cub_points_cell, cell_basis); OrientationTools<value_type>::getModifiedBasisFunctions(value_of_basis_at_cub_points_cell, value_of_reordered_basis_at_cub_points_cell, basis_set, ort); OrientationTools<value_type>::verbose = false; } // transform values of basis functions FunctionSpaceTools::HGRADtransformVALUE<value_type>(transformed_value_of_basis_at_cub_points_cell, value_of_basis_at_cub_points_cell); // multiply with weighted measure FunctionSpaceTools::multiplyMeasure<value_type>(weighted_transformed_value_of_basis_at_cub_points_cell, weighted_measure_cell, transformed_value_of_basis_at_cub_points_cell); // integrate FunctionSpaceTools::integrate<value_type>(A, transformed_value_of_basis_at_cub_points_cell, weighted_transformed_value_of_basis_at_cub_points_cell, COMP_BLAS); // Step 2: stiffness matrix: tabulate grad values of basis functions at cubature points cell_basis.getValues(grad_of_basis_at_cub_points_cell, cub_points_cell, OPERATOR_GRAD); if (apply_orientation) { OrientationTools<value_type>::getBasisFunctionsByTopology(grad_of_reordered_basis_at_cub_points_cell, grad_of_basis_at_cub_points_cell, cell_basis); OrientationTools<value_type>::getModifiedBasisFunctions(grad_of_basis_at_cub_points_cell, grad_of_reordered_basis_at_cub_points_cell, basis_set, ort); } // transform gradients of basis functions FunctionSpaceTools::HGRADtransformGRAD<value_type>(transformed_grad_of_basis_at_cub_points_cell, jacobian_inv_cell, grad_of_basis_at_cub_points_cell); // multiply with weighted measure FunctionSpaceTools::multiplyMeasure<value_type>(weighted_transformed_grad_of_basis_at_cub_points_cell, weighted_measure_cell, transformed_grad_of_basis_at_cub_points_cell); // compute stiffness matrices and sum into fe_matrix FunctionSpaceTools::integrate<value_type>(A, transformed_grad_of_basis_at_cub_points_cell, weighted_transformed_grad_of_basis_at_cub_points_cell, COMP_BLAS, true); // Step 3: compute rhs function CellTools<value_type>::mapToPhysicalFrame(cub_points_cell_physical, cub_points_cell, cell_nodes, cell_topo); // evaluate rhs function eval_rhs(rhs_at_cub_points_cell_physical, cub_points_cell_physical, nx, ny); // compute rhs FunctionSpaceTools::integrate<value_type>(b, rhs_at_cub_points_cell_physical, weighted_transformed_value_of_basis_at_cub_points_cell, COMP_BLAS); // Step 4: compute boundary condition side_cub->getCubature(cub_points_side, cub_weights_side); const int nside = cell_topo.getSideCount(); for (int i=0;i<nside;++i) { if (boundary[i]) { // compute geometric cell information CellTools<value_type>::mapToReferenceSubcell(cub_points_side_refcell, cub_points_side, ndim_side, i, cell_topo); CellTools<value_type>::setJacobian (jacobian_side_refcell, cub_points_side_refcell, cell_nodes, cell_topo); CellTools<value_type>::setJacobianDet(jacobian_det_side_refcell, jacobian_side_refcell); // compute weighted edge measure FunctionSpaceTools::computeEdgeMeasure<value_type>(weighted_measure_side_refcell, jacobian_side_refcell, cub_weights_side, i, cell_topo); // tabulate values of basis functions at side cubature points, in the reference parent cell domain cell_basis.getValues(value_of_basis_at_cub_points_side_refcell, cub_points_side_refcell, OPERATOR_VALUE); if (apply_orientation) { OrientationTools<value_type>::getBasisFunctionsByTopology(value_of_reordered_basis_at_cub_points_side_refcell, value_of_basis_at_cub_points_side_refcell, cell_basis); OrientationTools<value_type>::getModifiedBasisFunctions(value_of_basis_at_cub_points_side_refcell, value_of_reordered_basis_at_cub_points_side_refcell, basis_set, ort); } // transform FunctionSpaceTools::HGRADtransformVALUE<value_type>(transformed_value_of_basis_at_cub_points_side_refcell, value_of_basis_at_cub_points_side_refcell); // multiply with weighted measure FunctionSpaceTools::multiplyMeasure<value_type>(weighted_transformed_value_of_basis_at_cub_points_side_refcell, weighted_measure_side_refcell, transformed_value_of_basis_at_cub_points_side_refcell); // compute neumann boundary // map side cubature points in reference parent cell domain to physical space CellTools<value_type>::mapToPhysicalFrame(cub_points_side_physical, cub_points_side_refcell, cell_nodes, cell_topo); // now compute data eval_neumann(neumann_data_at_cub_points_side_physical, cub_points_side_physical, jacobian_side_refcell, cell_topo, i, nx, ny); FunctionSpaceTools::integrate<value_type>(neumann_fields_per_side, neumann_data_at_cub_points_side_physical, weighted_transformed_value_of_basis_at_cub_points_side_refcell, COMP_BLAS); // adjust rhs RealSpaceTools<value_type>::add(b, neumann_fields_per_side);; } } }
void compute_element_error(magnitude_type & interpolation_error, magnitude_type & solution_norm, const int *element, const FieldContainer<value_type> & cell_nodes, const BasisSet_HGRAD_TRI_Cn_FEM<value_type,FieldContainer<value_type> > &basis_set, const FieldContainer<value_type> &sol, const Orientation ort, const int nx, const int ny) { // initialize return values interpolation_error = 0.0; solution_norm = 0.0; // general environment const auto &cell_basis = basis_set.getCellBasis(); const shards::CellTopology cell_topo = cell_basis.getBaseCellTopology(); const int nbf_cell = cell_basis.getCardinality(); const int ndim_cell = cell_topo.getDimension(); // create points to evaluate in the reference cell const int order = 10; const int npts = PointTools::getLatticeSize(cell_topo, order, 1); FieldContainer<value_type> ref_cell_pts(npts, ndim_cell); PointTools::getLattice<value_type>(ref_cell_pts, cell_topo, order, 1); // map the points to physical frame FieldContainer<value_type> phy_cell_pts(1, npts, ndim_cell); CellTools<value_type>::mapToPhysicalFrame(phy_cell_pts, ref_cell_pts, cell_nodes, cell_topo); phy_cell_pts.resize(npts, ndim_cell); // Step 1: compute L2 error // evaluate exact solution FieldContainer<double> exact_solution_val(1, npts); eval_exact(exact_solution_val, phy_cell_pts, nx, ny); // evaluate basis at interpolation points FieldContainer<value_type> value_of_basis_at_ref_cell_pts(nbf_cell, npts); FieldContainer<value_type> value_of_reordered_basis_at_ref_cell_pts(nbf_cell, npts); cell_basis.getValues(value_of_basis_at_ref_cell_pts, ref_cell_pts, OPERATOR_VALUE); if (apply_orientation) { OrientationTools<value_type>::getBasisFunctionsByTopology(value_of_reordered_basis_at_ref_cell_pts, value_of_basis_at_ref_cell_pts, cell_basis); OrientationTools<value_type>::getModifiedBasisFunctions(value_of_basis_at_ref_cell_pts, value_of_reordered_basis_at_ref_cell_pts, basis_set, ort); } // transform values of basis functions FieldContainer<double> transformed_value_of_basis_at_ref_cell_pts(1, nbf_cell, npts); FunctionSpaceTools::HGRADtransformVALUE<value_type>(transformed_value_of_basis_at_ref_cell_pts, value_of_basis_at_ref_cell_pts); FieldContainer<double> interpolant(1, npts); FunctionSpaceTools::evaluate<value_type>(interpolant, sol, transformed_value_of_basis_at_ref_cell_pts); // compute error and magnitude of solution RealSpaceTools<value_type>::subtract(interpolant, exact_solution_val); interpolation_error += RealSpaceTools<value_type>::vectorNorm(&interpolant[0], interpolant.dimension(1), NORM_TWO); solution_norm += RealSpaceTools<value_type>::vectorNorm(&exact_solution_val[0], exact_solution_val.dimension(1), NORM_TWO); // Step 2: compute H1 error // skip for now, not meaningful for this unit test }
//---------------------------------------------------------------------------// Teuchos::RCP<Intrepid::Basis<double,Intrepid::FieldContainer<double> > > IntrepidBasisFactory::create( const shards::CellTopology& cell_topo ) { Teuchos::RCP<Intrepid::Basis<double,Intrepid::FieldContainer<double> > > basis; switch( cell_topo.getKey() ){ case shards::Line<2>::key: basis = Teuchos::rcp( new Intrepid::Basis_HGRAD_LINE_C1_FEM< double,Intrepid::FieldContainer<double> >() ); break; case shards::Triangle<3>::key: basis = Teuchos::rcp( new Intrepid::Basis_HGRAD_TRI_C1_FEM< double,Intrepid::FieldContainer<double> >() ); break; case shards::Triangle<6>::key: basis = Teuchos::rcp( new Intrepid::Basis_HGRAD_TRI_C2_FEM< double,Intrepid::FieldContainer<double> >() ); break; case shards::Quadrilateral<4>::key: basis = Teuchos::rcp( new Intrepid::Basis_HGRAD_QUAD_C1_FEM< double,Intrepid::FieldContainer<double> >() ); break; case shards::Quadrilateral<9>::key: basis = Teuchos::rcp( new Intrepid::Basis_HGRAD_QUAD_C2_FEM< double,Intrepid::FieldContainer<double> >() ); break; case shards::Tetrahedron<4>::key: basis = Teuchos::rcp( new Intrepid::Basis_HGRAD_TET_C1_FEM< double,Intrepid::FieldContainer<double> >() ); break; case shards::Tetrahedron<10>::key: basis = Teuchos::rcp( new Intrepid::Basis_HGRAD_TET_C2_FEM< double,Intrepid::FieldContainer<double> >() ); break; case shards::Hexahedron<8>::key: basis = Teuchos::rcp( new Intrepid::Basis_HGRAD_HEX_C1_FEM< double,Intrepid::FieldContainer<double> >() ); break; case shards::Hexahedron<27>::key: basis = Teuchos::rcp( new Intrepid::Basis_HGRAD_HEX_C2_FEM< double,Intrepid::FieldContainer<double> >() ); break; case shards::Wedge<6>::key: basis = Teuchos::rcp( new Intrepid::Basis_HGRAD_WEDGE_C1_FEM< double,Intrepid::FieldContainer<double> >() ); break; case shards::Wedge<18>::key: basis = Teuchos::rcp( new Intrepid::Basis_HGRAD_WEDGE_C2_FEM< double,Intrepid::FieldContainer<double> >() ); break; case shards::Pyramid<5>::key: case shards::Pyramid<13>::key: case shards::Pyramid<14>::key: basis = Teuchos::rcp( new Intrepid::Basis_HGRAD_PYR_C1_FEM< double,Intrepid::FieldContainer<double> >() ); break; default: bool topology_supported = false; DTK_INSIST( topology_supported ); break; } return basis; }
// ---------------------------------------------------------------------- // 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 BilinearFormUtility::computeOptimalStiffnessMatrix(FieldContainer<double> &stiffness, FieldContainer<double> &optimalTestWeights, BilinearFormPtr bilinearForm, Teuchos::RCP<DofOrdering> trialOrdering, Teuchos::RCP<DofOrdering> testOrdering, shards::CellTopology &cellTopo, FieldContainer<double> &physicalCellNodes, FieldContainer<double> &cellSideParities) { // lots of code copied and pasted from the very similar computeStiffnessMatrix. The difference here is that for each optimal test function, // we need to ask the bilinear form about each of its components (it's a vector whereas the other guy had just a single basis function // for each...), and then apply the appropriate weights.... // physicalCellNodes: the nodal points for the element(s) with topology cellTopo // The dimensions are (numCells, numNodesPerElement, spaceDimension) // optimalTestWeights dimensions are: (numCells, numTrial, numTest) -- numTrial is the optTest index // stiffness dimensions are: (numCells, # trialOrdering Dofs, # trialOrdering Dofs) // (while (cell,trial,test) is more natural conceptually, I believe the above ordering makes // more sense given the inversion that we must do to compute the optimal test functions...) // steps: // 0. Set up BasisCache // 3. For each (test, trial) combination: // a. Apply the specified operators to the basis in the DofOrdering, at the cubature points // b. Multiply the two bases together, weighted with Jacobian/Piola transform and cubature weights // c. Pass the result to bilinearForm's applyBilinearFormData method // d. Sum up (integrate) and place in stiffness matrix according to DofOrdering indices // 0. Set up Cubature unsigned numCells = physicalCellNodes.dimension(0); unsigned numNodesPerElem = physicalCellNodes.dimension(1); unsigned spaceDim = physicalCellNodes.dimension(2); // Check that cellTopo and physicalCellNodes agree TEUCHOS_TEST_FOR_EXCEPTION( ( numNodesPerElem != cellTopo.getNodeCount() ), std::invalid_argument, "Second dimension of physicalCellNodes and cellTopo.getNodeCount() do not match."); TEUCHOS_TEST_FOR_EXCEPTION( ( spaceDim != cellTopo.getDimension() ), std::invalid_argument, "Third dimension of physicalCellNodes and cellTopo.getDimension() do not match."); int numOptTestFunctions = optimalTestWeights.dimension(1); // should also == numTrialDofs TEUCHOS_TEST_FOR_EXCEPTION( ( optimalTestWeights.dimension(1) != stiffness.dimension(2) ), std::invalid_argument, "optimalTestWeights.dimension(1) (=" << optimalTestWeights.dimension(1) << ") and stiffness.dimension(2) (=" << stiffness.dimension(2) << ") do not match."); TEUCHOS_TEST_FOR_EXCEPTION( ( stiffness.dimension(1) != stiffness.dimension(2) ), std::invalid_argument, "stiffness.dimension(1) (=" << stiffness.dimension(1) << ") and stiffness.dimension(2) (=" << stiffness.dimension(2) << ") do not match."); // Set up BasisCache int cubDegreeTrial = trialOrdering->maxBasisDegree(); int cubDegreeTest = testOrdering->maxBasisDegree(); int cubDegree = cubDegreeTrial + cubDegreeTest; BasisCache basisCache(physicalCellNodes, cellTopo, *trialOrdering, cubDegreeTest, true); // DO create side caches, too unsigned numSides = CamelliaCellTools::getSideCount(cellTopo); vector<int> testIDs = bilinearForm->testIDs(); vector<int>::iterator testIterator; vector<int> trialIDs = bilinearForm->trialIDs(); vector<int>::iterator trialIterator; BasisPtr trialBasis,testBasis; stiffness.initialize(0.0); for (trialIterator = trialIDs.begin(); trialIterator != trialIDs.end(); trialIterator++) { int trialID = *trialIterator; for (int optTestIndex=0; optTestIndex < numOptTestFunctions; optTestIndex++) { FieldContainer<double> weights(numCells,testOrdering->totalDofs()); for (unsigned i=0; i<numCells; i++) { for (int j=0; j<testOrdering->totalDofs(); j++) { weights(i,j) = optimalTestWeights(i,optTestIndex,j); } } for (testIterator = testIDs.begin(); testIterator != testIDs.end(); testIterator++) { int testID = *testIterator; vector<EOperatorExtended> trialOperators, testOperators; bilinearForm->trialTestOperators(trialID, testID, trialOperators, testOperators); vector<EOperatorExtended>::iterator trialOpIt, testOpIt; testOpIt = testOperators.begin(); int operatorIndex = -1; for (trialOpIt = trialOperators.begin(); trialOpIt != trialOperators.end(); trialOpIt++) { IntrepidExtendedTypes::EOperatorExtended trialOperator = *trialOpIt; IntrepidExtendedTypes::EOperatorExtended testOperator = *testOpIt; operatorIndex++; if (testOperator==OP_TIMES_NORMAL) { TEUCHOS_TEST_FOR_EXCEPTION(true,std::invalid_argument,"OP_TIMES_NORMAL not supported for tests. Use for trial only"); } Teuchos::RCP < const FieldContainer<double> > testValuesTransformed; Teuchos::RCP < const FieldContainer<double> > trialValuesTransformed; Teuchos::RCP < const FieldContainer<double> > testValuesTransformedWeighted; if (! bilinearForm->isFluxOrTrace(trialID)) { trialBasis = trialOrdering->getBasis(trialID); testBasis = testOrdering->getBasis(testID); FieldContainer<double> miniStiffness( numCells, testBasis->getCardinality(), trialBasis->getCardinality() ); trialValuesTransformed = basisCache.getTransformedValues(trialBasis,trialOperator); testValuesTransformedWeighted = basisCache.getTransformedWeightedValues(testBasis,testOperator); FieldContainer<double> physicalCubaturePoints = basisCache.getPhysicalCubaturePoints(); FieldContainer<double> materialDataAppliedToTrialValues = *trialValuesTransformed; // copy first FieldContainer<double> materialDataAppliedToTestValues = *testValuesTransformedWeighted; // copy first bilinearForm->applyBilinearFormData(materialDataAppliedToTrialValues,materialDataAppliedToTestValues, trialID,testID,operatorIndex,physicalCubaturePoints); int testDofOffset = testOrdering->getDofIndex(testID,0); // note that weightCellBasisValues does depend on contiguous test basis dofs... // (this is the plan, since there shouldn't be any kind of identification between different test dofs, // especially since test functions live only inside the cell) weightCellBasisValues(materialDataAppliedToTestValues, weights, testDofOffset); FunctionSpaceTools::integrate<double>(miniStiffness,materialDataAppliedToTestValues,materialDataAppliedToTrialValues,COMP_BLAS); // place in the appropriate spot in the element-stiffness matrix // copy goes from (cell,trial_basis_dof,test_basis_dof) to (cell,element_trial_dof,element_test_dof) // there may be a more efficient way to do this copying: // (one strategy would be to reimplement fst::integrate to support offsets, so that no copying needs to be done...) for (int i=0; i < testBasis->getCardinality(); i++) { for (int j=0; j < trialBasis->getCardinality(); j++) { int trialDofIndex = trialOrdering->getDofIndex(trialID,j); for (unsigned k=0; k < numCells; k++) { stiffness(k,optTestIndex,trialDofIndex) += miniStiffness(k,i,j); } } } } else { // boundary integral int trialBasisRank = trialOrdering->getBasisRank(trialID); int testBasisRank = testOrdering->getBasisRank(testID); TEUCHOS_TEST_FOR_EXCEPTION( ( trialBasisRank != 0 ), std::invalid_argument, "Boundary trial variable (flux or trace) given with non-scalar basis. Unsupported."); bool isFlux = false; // i.e. the normal is "folded into" the variable definition, so that we must take parity into account const set<int> normalOperators = BilinearForm::normalOperators(); if ( (normalOperators.find(testOperator) == normalOperators.end() ) && (normalOperators.find(trialOperator) == normalOperators.end() ) ) { // normal not yet taken into account -- so it must be "hidden" in the trial variable isFlux = true; } for (unsigned sideOrdinal=0; sideOrdinal<numSides; sideOrdinal++) { trialBasis = trialOrdering->getBasis(trialID,sideOrdinal); testBasis = testOrdering->getBasis(testID); FieldContainer<double> miniStiffness( numCells, testBasis->getCardinality(), trialBasis->getCardinality() ); // for trial: we never dot with normal, and the value lives on the side, so we don't use the volume coords either: trialValuesTransformed = basisCache.getTransformedValues(trialBasis,trialOperator,sideOrdinal,false); // for test: first, don't dot with normal, but do use the volume coords: //testValuesTransformed = basisCache.getTransformedValues(testBasis,testOperator,sideOrdinal,true); testValuesTransformedWeighted = basisCache.getTransformedWeightedValues(testBasis,testOperator,sideOrdinal,true); // copy before manipulating trialValues--these are the ones stored in the cache, so we're not allowed to change them!! FieldContainer<double> materialDataAppliedToTrialValues = *trialValuesTransformed; if (isFlux) { // this being a flux ==> take cell parity into account (because then there must be a normal folded into the flux definition) // we need to multiply the trialValues by the parity of the normal, since // the trial implicitly contains an outward normal, and we need to adjust for the fact // that the neighboring cells have opposite normal // trialValues should have dimensions (numCells,numFields,numCubPointsSide) int numFields = trialValuesTransformed->dimension(1); int numPoints = trialValuesTransformed->dimension(2); for (unsigned cellIndex=0; cellIndex<numCells; cellIndex++) { double parity = cellSideParities(cellIndex,sideOrdinal); if (parity != 1.0) { // otherwise, we can just leave things be... for (int fieldIndex=0; fieldIndex<numFields; fieldIndex++) { for (int ptIndex=0; ptIndex<numPoints; ptIndex++) { materialDataAppliedToTrialValues(cellIndex,fieldIndex,ptIndex) *= parity; } } } } } FieldContainer<double> cubPointsSidePhysical = basisCache.getPhysicalCubaturePointsForSide(sideOrdinal); FieldContainer<double> materialDataAppliedToTestValues = *testValuesTransformedWeighted; // copy first bilinearForm->applyBilinearFormData(materialDataAppliedToTrialValues,materialDataAppliedToTestValues, trialID,testID,operatorIndex,cubPointsSidePhysical); int testDofOffset = testOrdering->getDofIndex(testID,0,0); weightCellBasisValues(materialDataAppliedToTestValues, weights, testDofOffset); // d. Sum up (integrate) and place in stiffness matrix according to DofOrdering indices FunctionSpaceTools::integrate<double>(miniStiffness,materialDataAppliedToTestValues,materialDataAppliedToTrialValues,COMP_BLAS); // place in the appropriate spot in the element-stiffness matrix // copy goes from (cell,trial_basis_dof,test_basis_dof) to (cell,element_trial_dof,element_test_dof) for (int i=0; i < testBasis->getCardinality(); i++) { for (int j=0; j < trialBasis->getCardinality(); j++) { int trialDofIndex = trialOrdering->getDofIndex(trialID,j,sideOrdinal); for (unsigned k=0; k < numCells; k++) { stiffness(k,optTestIndex,trialDofIndex) += miniStiffness(k,i,j); } } } } } testOpIt++; } } } } }
void CellTools<SpT>:: getSubcellParametrization( subcellParamViewType &subcellParam, const ordinal_type subcellDim, const shards::CellTopology parentCell ) { #ifdef HAVE_INTREPID2_DEBUG INTREPID2_TEST_FOR_EXCEPTION( !hasReferenceCell(parentCell), std::invalid_argument, ">>> ERROR (Intrepid2::CellTools::getSubcellParametrization): the specified cell topology does not have a reference cell."); #endif if (!isSubcellParametrizationSet_) setSubcellParametrization(); // Select subcell parametrization according to its parent cell type const auto pcd = parentCell.getDimension(); // parent cell dim INTREPID2_TEST_FOR_EXCEPTION( subcellDim < 1 || subcellDim > static_cast<ordinal_type>(pcd-1), std::invalid_argument, ">>> ERROR (Intrepid2::CellTools::getSubcellParametrization): Parametrizations defined in a range between 1 and (dim-1)"); switch (parentCell.getKey() ) { case shards::Tetrahedron<4>::key: case shards::Tetrahedron<8>::key: case shards::Tetrahedron<10>::key: case shards::Tetrahedron<11>::key: subcellParam = ( subcellDim == 2 ? subcellParamData_.tetFaces : subcellParamData_.tetEdges ); break; case shards::Hexahedron<8>::key: case shards::Hexahedron<20>::key: case shards::Hexahedron<27>::key: subcellParam = ( subcellDim == 2 ? subcellParamData_.hexFaces : subcellParamData_.hexEdges ); break; case shards::Pyramid<5>::key: case shards::Pyramid<13>::key: case shards::Pyramid<14>::key: subcellParam = ( subcellDim == 2 ? subcellParamData_.pyrFaces : subcellParamData_.pyrEdges ); break; case shards::Wedge<6>::key: case shards::Wedge<15>::key: case shards::Wedge<18>::key: subcellParam = ( subcellDim == 2 ? subcellParamData_.wedgeFaces : subcellParamData_.wedgeEdges ); break; case shards::Triangle<3>::key: case shards::Triangle<4>::key: case shards::Triangle<6>::key: subcellParam = subcellParamData_.triEdges; break; case shards::Quadrilateral<4>::key: case shards::Quadrilateral<8>::key: case shards::Quadrilateral<9>::key: subcellParam = subcellParamData_.quadEdges; break; // case shards::ShellTriangle<3>::key: // case shards::ShellTriangle<6>::key: subcellParam = ( subcellDim == 2 ? subcellParamData_.shellTriFaces : subcellParamData_.shellTriEdges ); break; // case shards::ShellQuadrilateral<4>::key: // case shards::ShellQuadrilateral<8>::key: // case shards::ShellQuadrilateral<9>::key: subcellParam = ( subcellDim == 2 ? subcellParamData_.shellQuadFaces : subcellParamData_.shellQuadEdges ); break; case shards::ShellLine<2>::key: case shards::ShellLine<3>::key: case shards::Beam<2>::key: case shards::Beam<3>::key: subcellParam = subcellParamData_.lineEdges; break; default: { INTREPID2_TEST_FOR_EXCEPTION( true, std::invalid_argument, ">>> ERROR (Intrepid2::CellTools::getSubcellParametrization): invalid cell topology."); } } }
int NodalFieldPattern::getDimension() const { const shards::CellTopology ct = getCellTopology(); return ct.getDimension(); }
void CellTools<SpT>:: setSubcellParametrization( subcellParamViewType &subcellParam, const ordinal_type subcellDim, const shards::CellTopology parentCell ) { #ifdef HAVE_INTREPID2_DEBUG INTREPID2_TEST_FOR_EXCEPTION( !hasReferenceCell(parentCell), std::invalid_argument, ">>> ERROR (Intrepid2::CellTools::setSubcellParametrization): the specified cell topology does not have a reference cell."); #endif // subcellParametrization is rank-3 FieldContainer with dimensions (SC, PCD, COEF) where: // - SC is the subcell count of subcells with the specified dimension in the parent cell // - PCD is Parent Cell Dimension, which gives the number of coordinate functions in the map // PCD = 2 for standard 2D cells and non-standard 2D cells: shell line and beam // PCD = 3 for standard 3D cells and non-standard 3D cells: shell Tri and Quad // - COEF is number of coefficients needed to specify a coordinate function: // COEFF = 2 for edge parametrizations // COEFF = 3 for both Quad and Tri face parametrizations. Because all Quad reference faces // are affine, the coefficient of the bilinear term u*v is zero and is not stored, i.e., // 3 coefficients are sufficient to store Quad face parameterization maps. // // Edge parametrization maps [-1,1] to edge defined by (v0, v1) // Face parametrization maps [-1,1]^2 to quadrilateral face (v0, v1, v2, v3), or // standard 2-simplex {(0,0),(1,0),(0,1)} to traingle face (v0, v1, v2). // This defines orientation-preserving parametrizations with respect to reference edge and // face orientations induced by their vertex order. // get subcellParametrization dimensions: (sc, pcd, coeff) const auto sc = parentCell.getSubcellCount(subcellDim); const auto pcd = parentCell.getDimension(); const auto coeff = (subcellDim == 1) ? 2 : 3; INTREPID2_TEST_FOR_EXCEPTION( subcellDim < 1 || subcellDim > static_cast<ordinal_type>(pcd-1), std::invalid_argument, ">>> ERROR (Intrepid2::CellTools::setSubcellParametrization): Parametrizations defined in a range between 1 and (dim-1)"); // create a view subcellParam = subcellParamViewType("CellTools::setSubcellParametrization", sc, pcd, coeff); referenceNodeDataViewType v0("CellTools::setSubcellParametrization::v0", Parameters::MaxDimension), v1("CellTools::setSubcellParametrization::v1", Parameters::MaxDimension), v2("CellTools::setSubcellParametrization::v1", Parameters::MaxDimension), v3("CellTools::setSubcellParametrization::v1", Parameters::MaxDimension); if (subcellDim == 1) { // Edge parametrizations of 2D and 3D cells (shell lines and beams are 2D cells with edges) for (size_type subcellOrd=0;subcellOrd<sc;++subcellOrd) { // vertexK[0] = x_k; vertexK[1] = y_k; vertexK[2] = z_k; z_k = 0 for 2D cells // Note that ShellLine and Beam are 2D cells! const auto v0ord = parentCell.getNodeMap(subcellDim, subcellOrd, 0); const auto v1ord = parentCell.getNodeMap(subcellDim, subcellOrd, 1); getReferenceVertex(v0, parentCell, v0ord); getReferenceVertex(v1, parentCell, v1ord); // x(t) = (x0 + x1)/2 + t*(x1 - x0)/2 subcellParam(subcellOrd, 0, 0) = (v0[0] + v1[0])/2.0; subcellParam(subcellOrd, 0, 1) = (v1[0] - v0[0])/2.0; // y(t) = (y0 + y1)/2 + t*(y1 - y0)/2 subcellParam(subcellOrd, 1, 0) = (v0[1] + v1[1])/2.0; subcellParam(subcellOrd, 1, 1) = (v1[1] - v0[1])/2.0; if( pcd == 3 ) { // z(t) = (z0 + z1)/2 + t*(z1 - z0)/2 subcellParam(subcellOrd, 2, 0) = (v0[2] + v1[2])/2.0; subcellParam(subcellOrd, 2, 1) = (v1[2] - v0[2])/2.0; } } } else if (subcellDim == 2) { // Face parametrizations of 3D cells: (shell Tri and Quad are 3D cells with faces) // A 3D cell can have both Tri and Quad faces, but because they are affine images of the // parametrization domain, 3 coefficients are enough to store them in both cases. for (size_type subcellOrd=0;subcellOrd<sc;++subcellOrd) { switch (parentCell.getKey(subcellDim,subcellOrd)) { case shards::Triangle<3>::key: case shards::Triangle<4>::key: case shards::Triangle<6>::key: { const auto v0ord = parentCell.getNodeMap(subcellDim, subcellOrd, 0); const auto v1ord = parentCell.getNodeMap(subcellDim, subcellOrd, 1); const auto v2ord = parentCell.getNodeMap(subcellDim, subcellOrd, 2); getReferenceVertex(v0, parentCell, v0ord); getReferenceVertex(v1, parentCell, v1ord); getReferenceVertex(v2, parentCell, v2ord); // x(u,v) = x0 + (x1 - x0)*u + (x2 - x0)*v subcellParam(subcellOrd, 0, 0) = v0[0]; subcellParam(subcellOrd, 0, 1) = v1[0] - v0[0]; subcellParam(subcellOrd, 0, 2) = v2[0] - v0[0]; // y(u,v) = y0 + (y1 - y0)*u + (y2 - y0)*v subcellParam(subcellOrd, 1, 0) = v0[1]; subcellParam(subcellOrd, 1, 1) = v1[1] - v0[1]; subcellParam(subcellOrd, 1, 2) = v2[1] - v0[1]; // z(u,v) = z0 + (z1 - z0)*u + (z2 - z0)*v subcellParam(subcellOrd, 2, 0) = v0[2]; subcellParam(subcellOrd, 2, 1) = v1[2] - v0[2]; subcellParam(subcellOrd, 2, 2) = v2[2] - v0[2]; break; } case shards::Quadrilateral<4>::key: case shards::Quadrilateral<8>::key: case shards::Quadrilateral<9>::key: { const auto v0ord = parentCell.getNodeMap(subcellDim, subcellOrd, 0); const auto v1ord = parentCell.getNodeMap(subcellDim, subcellOrd, 1); const auto v2ord = parentCell.getNodeMap(subcellDim, subcellOrd, 2); const auto v3ord = parentCell.getNodeMap(subcellDim, subcellOrd, 3); getReferenceVertex(v0, parentCell, v0ord); getReferenceVertex(v1, parentCell, v1ord); getReferenceVertex(v2, parentCell, v2ord); getReferenceVertex(v3, parentCell, v3ord); // x(u,v) = (x0+x1+x2+x3)/4+u*(-x0+x1+x2-x3)/4+v*(-x0-x1+x2+x3)/4+uv*(0=x0-x1+x2-x3)/4 subcellParam(subcellOrd, 0, 0) = ( v0[0] + v1[0] + v2[0] + v3[0])/4.0; subcellParam(subcellOrd, 0, 1) = (-v0[0] + v1[0] + v2[0] - v3[0])/4.0; subcellParam(subcellOrd, 0, 2) = (-v0[0] - v1[0] + v2[0] + v3[0])/4.0; // y(u,v) = (y0+y1+y2+y3)/4+u*(-y0+y1+y2-y3)/4+v*(-y0-y1+y2+y3)/4+uv*(0=y0-y1+y2-y3)/4 subcellParam(subcellOrd, 1, 0) = ( v0[1] + v1[1] + v2[1] + v3[1])/4.0; subcellParam(subcellOrd, 1, 1) = (-v0[1] + v1[1] + v2[1] - v3[1])/4.0; subcellParam(subcellOrd, 1, 2) = (-v0[1] - v1[1] + v2[1] + v3[1])/4.0; // z(u,v) = (z0+z1+z2+z3)/4+u*(-z0+z1+z2-z3)/4+v*(-z0-z1+z2+z3)/4+uv*(0=z0-z1+z2-z3)/4 subcellParam(subcellOrd, 2, 0) = ( v0[2] + v1[2] + v2[2] + v3[2])/4.0; subcellParam(subcellOrd, 2, 1) = (-v0[2] + v1[2] + v2[2] - v3[2])/4.0; subcellParam(subcellOrd, 2, 2) = (-v0[2] - v1[2] + v2[2] + v3[2])/4.0; break; } default: { INTREPID2_TEST_FOR_EXCEPTION( true, std::invalid_argument, ">>> ERROR (Intrepid2::CellTools::setSubcellParametrization): parametrization not defined for the specified face topology."); } } } } }
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 }
int NodalFieldPattern::getSubcellCount(int dim) const { const shards::CellTopology ct = getCellTopology(); return ct.getSubcellCount(dim); }