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; }
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; }
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; } } }
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"); } } }
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"); } } }
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 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::getDimension() const { const shards::CellTopology ct = getCellTopology(); return ct.getDimension(); }
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 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 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 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."); } } }
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 }
int Intrepid2FieldPattern::getDimension() const { const shards::CellTopology ct = intrepidBasis_->getBaseCellTopology(); return ct.getDimension(); }
/** \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; }