void EricksonManufacturedSolution::rhs(int testVarID, const FieldContainer<double> &physicalPoints, FieldContainer<double> &values) { int numCells = physicalPoints.dimension(0); int numPoints = physicalPoints.dimension(1); int spaceDim = physicalPoints.dimension(2); if (testVarID == ConfusionBilinearForm::V) { // f = - eps * (d^2/dx^2 + d^2/dy^2) ( u ) + beta_x du/dx + beta_y du/dy values.resize(numCells,numPoints); for (int cellIndex=0; cellIndex<numCells; cellIndex++) { for (int ptIndex=0; ptIndex<numPoints; ptIndex++) { double x = physicalPoints(cellIndex,ptIndex,0); double y = physicalPoints(cellIndex,ptIndex,1); F2_2 sx(2,0,x), sy(2,1,y), su; // s for Sacado sx.val() = F2(2,0,x); sy.val() = F2(2,1,y); su = u(sx,sy); /* these are values of convection-diffusion values(cellIndex,ptIndex) = - _epsilon * ( su.dx(0).dx(0) + su.dx(1).dx(1) ) + _beta_x * su.dx(0).val() + _beta_y * su.dx(1).val(); */ // this RHS corresponds to only convection //values(cellIndex,ptIndex) = _beta_x * su.dx(0).val() + _beta_y * su.dx(1).val(); // exact RHS double pi = acos(0.0)*2.0; double epsSquared = _epsilon*_epsilon; // values(cellIndex,ptIndex) = exp((1.0-x)/_epsilon)*(pi*pi - 2*epsSquared)*sin(pi*y/epsSquared)/(epsSquared*_epsilon); values(cellIndex,ptIndex) = 0.0; } } } }
void PreviousSolutionFunction::values(FieldContainer<double> &values, BasisCachePtr basisCache) { int rank = Teuchos::GlobalMPISession::getRank(); if (_overrideMeshCheck) { _solnExpression->evaluate(values, _soln, basisCache); return; } if (!basisCache.get()) cout << "basisCache is nil!\n"; if (!_soln.get()) cout << "_soln is nil!\n"; // values are stored in (C,P,D) order if (basisCache->mesh().get() == _soln->mesh().get()) { _solnExpression->evaluate(values, _soln, basisCache); } else { static bool warningIssued = false; if (!warningIssued) { if (rank==0) cout << "NOTE: In PreviousSolutionFunction, basisCache's mesh doesn't match solution's. If this is not what you intended, it would be a good idea to make sure that the mesh is passed in on BasisCache construction; the evaluation will be a lot slower without it...\n"; warningIssued = true; } // get the physicalPoints, and make a basisCache for each... FieldContainer<double> physicalPoints = basisCache->getPhysicalCubaturePoints(); FieldContainer<double> value(1,1); // assumes scalar-valued solution function. int numCells = physicalPoints.dimension(0); int numPoints = physicalPoints.dimension(1); int spaceDim = physicalPoints.dimension(2); physicalPoints.resize(numCells*numPoints,spaceDim); vector< ElementPtr > elements = _soln->mesh()->elementsForPoints(physicalPoints, false); // false: don't make elements null just because they're off-rank. FieldContainer<double> point(1,spaceDim); FieldContainer<double> refPoint(1,spaceDim); int combinedIndex = 0; vector<GlobalIndexType> cellID; cellID.push_back(-1); BasisCachePtr basisCacheOnePoint; for (int cellIndex=0; cellIndex<numCells; cellIndex++) { for (int ptIndex=0; ptIndex<numPoints; ptIndex++, combinedIndex++) { if (elements[combinedIndex].get()==NULL) continue; // no element found for point; skip it… ElementTypePtr elemType = elements[combinedIndex]->elementType(); for (int d=0; d<spaceDim; d++) { point(0,d) = physicalPoints(combinedIndex,d); } if (elements[combinedIndex]->cellID() != cellID[0]) { cellID[0] = elements[combinedIndex]->cellID(); basisCacheOnePoint = Teuchos::rcp( new BasisCache(elemType, _soln->mesh()) ); basisCacheOnePoint->setPhysicalCellNodes(_soln->mesh()->physicalCellNodesForCell(cellID[0]),cellID,false); // false: don't createSideCacheToo } // compute the refPoint: typedef CellTools<double> CellTools; int whichCell = 0; CellTools::mapToReferenceFrame(refPoint,point,_soln->mesh()->physicalCellNodesForCell(cellID[0]), *(elemType->cellTopoPtr),whichCell); basisCacheOnePoint->setRefCellPoints(refPoint); // cout << "refCellPoints:\n " << refPoint; // cout << "physicalCubaturePoints:\n " << basisCacheOnePoint->getPhysicalCubaturePoints(); _solnExpression->evaluate(value, _soln, basisCacheOnePoint); // cout << "value at point (" << point(0,0) << ", " << point(0,1) << ") = " << value(0,0) << endl; values(cellIndex,ptIndex) = value(0,0); } } } }
/** This example whows how to get vertex IDs for all the elements */ int main( int argc, char **argv ) { using Teuchos::RCP; Teuchos::oblackholestream blackhole; Teuchos::GlobalMPISession mpiSession(&argc,&argv,&blackhole); RCP<const Teuchos::Comm<int> > comm = Teuchos::DefaultComm<int>::getComm(); RCP<Teuchos::ParameterList> pl = rcp(new Teuchos::ParameterList); pl->set("X Blocks",2); pl->set("Y Blocks",1); pl->set("X Elements",6); pl->set("Y Elements",4); panzer_stk_classic::SquareQuadMeshFactory factory; factory.setParameterList(pl); RCP<panzer_stk_classic::STK_Interface> mesh = factory.buildMesh(MPI_COMM_WORLD); if(mesh->isWritable()) mesh->writeToExodus("blocked_mesh.exo"); unsigned dim = mesh->getDimension(); std::vector<std::string> eBlocks; mesh->getElementBlockNames(eBlocks); // loop over all blocks for(std::size_t blk=0;blk<eBlocks.size();++blk) { std::string blockName = eBlocks[blk]; std::vector<stk_classic::mesh::Entity*> elements; std::vector<std::size_t> localIds; mesh->getMyElements(blockName,elements); FieldContainer vertices; vertices.resize(elements.size(),4,dim); // loop over elements of this block for(std::size_t elm=0;elm<elements.size();++elm) { std::vector<stk_classic::mesh::EntityId> nodes; stk_classic::mesh::Entity * element = elements[elm]; localIds.push_back(mesh->elementLocalId(element)); getNodeIds(element,mesh->getNodeRank(),nodes); TEUCHOS_ASSERT(nodes.size()==4); for(std::size_t v=0;v<nodes.size();++v) { const double * coord = mesh->getNodeCoordinates(nodes[v]); for(unsigned d=0;d<dim;++d) vertices(elm,v,d) = coord[d]; } } } return 0; }
void BilinearFormUtility::computeStiffnessMatrixForCell(FieldContainer<double> &stiffness, Teuchos::RCP<Mesh> mesh, int cellID) { Teuchos::RCP<DofOrdering> trialOrder = mesh->getElement(cellID)->elementType()->trialOrderPtr; Teuchos::RCP<DofOrdering> testOrder = mesh->getElement(cellID)->elementType()->testOrderPtr; shards::CellTopology cellTopo = *(mesh->getElement(cellID)->elementType()->cellTopoPtr); FieldContainer<double> physicalCellNodes = mesh->physicalCellNodesForCell(cellID); FieldContainer<double> cellSideParities = mesh->cellSideParitiesForCell(cellID); int numCells = 1; stiffness.resize(numCells,testOrder->totalDofs(),trialOrder->totalDofs()); computeStiffnessMatrix(stiffness,mesh->bilinearForm(),trialOrder,testOrder,cellTopo,physicalCellNodes,cellSideParities); }
void MPIWrapper::allGatherCompact(const Epetra_Comm &Comm, FieldContainer<Scalar> &gatheredValues, FieldContainer<Scalar> &myValues, FieldContainer<int> &offsets) { int mySize = myValues.size(); int totalSize; Comm.SumAll(&mySize, &totalSize, 1); int myOffset = 0; Comm.ScanSum(&mySize,&myOffset,1); myOffset -= mySize; gatheredValues.resize(totalSize); for (int i=0; i<mySize; i++) { gatheredValues[myOffset+i] = myValues[i]; } MPIWrapper::entryWiseSum(Comm, gatheredValues); offsets.resize(Comm.NumProc()); offsets[Comm.MyPID()] = myOffset; MPIWrapper::entryWiseSum(Comm, offsets); }
void LinearTermTests::transposeFieldContainer(FieldContainer<double> &fc) { // this is NOT meant for production code. Could do the transpose in place if we were concerned with efficiency. FieldContainer<double> fcCopy = fc; int numCells = fc.dimension(0); int dim1 = fc.dimension(1); int dim2 = fc.dimension(2); fc.resize(numCells,dim2,dim1); for (int i=0; i<numCells; i++) { for (int j=0; j<dim1; j++) { for (int k=0; k<dim2; k++) { fc(i,k,j) = fcCopy(i,j,k); } } } }
void EricksonManufacturedSolution::getValues(FieldContainer<double> &functionValues, const FieldContainer<double> &physicalPoints){ int numCells = physicalPoints.dimension(0); int numPoints = physicalPoints.dimension(1); int spaceDim = physicalPoints.dimension(2); functionValues.resize(numCells,numPoints); Teuchos::Array<int> pointDimensions; pointDimensions.push_back(spaceDim); for (int i=0;i<numCells;i++){ for (int j=0;j<numPoints;j++){ double x = physicalPoints(i,j,0); double y = physicalPoints(i,j,1); FieldContainer<double> physicalPoint(pointDimensions); physicalPoint(0) = x; physicalPoint(1) = y; functionValues(i,j) = solutionValue(ConfusionBilinearForm::U,physicalPoint); } } }
int main(int argc, char *argv[]) { Teuchos::GlobalMPISession mpiSession(&argc, &argv); // This little trick lets us print to std::cout only if // a (dummy) command-line argument is provided. int iprint = argc - 1; Teuchos::RCP<std::ostream> outStream; Teuchos::oblackholestream bhs; // outputs nothing if (iprint > 0) outStream = Teuchos::rcp(&std::cout, false); else outStream = Teuchos::rcp(&bhs, false); // Save the format state of the original std::cout. Teuchos::oblackholestream oldFormatState; oldFormatState.copyfmt(std::cout); *outStream \ << "===============================================================================\n" \ << "| |\n" \ << "| Unit Test (Basis_HGRAD_TET_COMP12_FEM) |\n" \ << "| |\n" \ << "| 1) Evaluation of Basis Function Values |\n" \ << "| |\n" \ << "| Questions? Contact Pavel Bochev ([email protected]), |\n" \ << "| Denis Ridzal ([email protected]), |\n" \ << "| Kara Peterson ([email protected]), |\n" \ << "| Jake Ostien ([email protected]). |\n" \ << "| |\n" \ << "| Intrepid's website: http://trilinos.sandia.gov/packages/intrepid |\n" \ << "| Trilinos website: http://trilinos.sandia.gov |\n" \ << "| |\n" \ << "===============================================================================\n"\ << "| TEST 1: Basis creation, values |\n"\ << "===============================================================================\n"; // Define basis and error flag Basis_HGRAD_TET_COMP12_FEM<double, FieldContainer<double> > tetBasis; int errorFlag = 0; // Initialize throw counter for exception testing //int nException = 0; //int throwCounter = 0; // Define array containing the 10 vertices of the reference TET FieldContainer<double> tetNodes(10, 3); tetNodes(0,0) = 0.0; tetNodes(0,1) = 0.0; tetNodes(0,2) = 0.0; tetNodes(1,0) = 1.0; tetNodes(1,1) = 0.0; tetNodes(1,2) = 0.0; tetNodes(2,0) = 0.0; tetNodes(2,1) = 1.0; tetNodes(2,2) = 0.0; tetNodes(3,0) = 0.0; tetNodes(3,1) = 0.0; tetNodes(3,2) = 1.0; tetNodes(4,0) = 0.5; tetNodes(4,1) = 0.0; tetNodes(4,2) = 0.0; tetNodes(5,0) = 0.5; tetNodes(5,1) = 0.5; tetNodes(5,2) = 0.0; tetNodes(6,0) = 0.0; tetNodes(6,1) = 0.5; tetNodes(6,2) = 0.0; tetNodes(7,0) = 0.0; tetNodes(7,1) = 0.0; tetNodes(7,2) = 0.5; tetNodes(8,0) = 0.5; tetNodes(8,1) = 0.0; tetNodes(8,2) = 0.5; tetNodes(9,0) = 0.0; tetNodes(9,1) = 0.5; tetNodes(9,2) = 0.5; // Define array containing 5 integration points FieldContainer<double> tetPoints(9, 3); // from the 5 point integration tetPoints(0,0) = 0.25; tetPoints(0,1) = 0.25; tetPoints(0,2) = 0.25; tetPoints(1,0) = 0.5; tetPoints(1,1) = (1./6.); tetPoints(1,2) = (1./6.); tetPoints(2,0) = (1./6.); tetPoints(2,1) = 0.5; tetPoints(2,2) = (1./6.); tetPoints(3,0) = (1./6.); tetPoints(3,1) = (1./6.); tetPoints(3,2) = 0.5; tetPoints(4,0) = (1./6.); tetPoints(4,1) = (1./6.); tetPoints(4,2) = (1./6.); // from the 4 point integration tetPoints(5,0) = 0.1381966011250105151795413165634361882280; tetPoints(5,1) = 0.1381966011250105151795413165634361882280; tetPoints(5,2) = 0.1381966011250105151795413165634361882280; tetPoints(6,0) = 0.5854101966249684544613760503096914353161; tetPoints(6,1) = 0.1381966011250105151795413165634361882280; tetPoints(6,2) = 0.1381966011250105151795413165634361882280; tetPoints(7,0) = 0.1381966011250105151795413165634361882280; tetPoints(7,1) = 0.5854101966249684544613760503096914353161; tetPoints(7,2) = 0.1381966011250105151795413165634361882280; tetPoints(8,0) = 0.1381966011250105151795413165634361882280; tetPoints(8,1) = 0.1381966011250105151795413165634361882280; tetPoints(8,2) = 0.5854101966249684544613760503096914353161; // output precision outStream -> precision(20); // VALUE: Each row gives the 10 correct basis set values at an evaluation point double nodalBasisValues[] = { // first 4 vertices 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, // second 6 vertices 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0 }; double pointBasisValues[] = { // pt 0 {0.25, 0.25, 0.25} 0.0, 0.0, 0.0, 0.0, 1./6., 1./6., 1./6., 1./6., 1./6., 1./6., // pt 1 {0.5, 1/6, 1/6} 0.0, 0.0, 0.0, 0.0, 1./3., 1./3., 0.0, 0.0, 1./3., 0.0, // pt 2 {1/6, 0.5, 0.1/6} 0.0, 0.0, 0.0, 0.0, 0.0, 1./3., 1./3., 0.0, 0.0, 1./3., // pt 3 {1/6, 1/6, 0.5} 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1./3., 1./3., 1./3., // pt 4 {1/6, 1/6, 1/6} 0.0, 0.0, 0.0, 0.0, 1./3., 0.0, 1./3., 1./3., 0.0, 0.0, // pt 5 0.170820393249936908922752100619382870632, 0.0, 0.0, 0.0, 0.276393202250021030359082633126872376456, 0.0, 0.276393202250021030359082633126872376456, 0.276393202250021030359082633126872376456, 0.0, 0.0, // pt 6 0.0, 0.170820393249936908922752100619382870632, 0.0, 0.0, 0.276393202250021030359082633126872376456, 0.276393202250021030359082633126872376456, 0.0, 0.0, 0.276393202250021030359082633126872376456, 0.0, // pt 7 0.0, 0.0, 0.170820393249936908922752100619382870632, 0.0, 0.0, 0.276393202250021030359082633126872376456, 0.276393202250021030359082633126872376456, 0.0, 0.0, 0.276393202250021030359082633126872376456, // pt 8 0.0, 0.0, 0.0, 0.170820393249936908922752100619382870632, 0.0, 0.0, 0.0, 0.276393202250021030359082633126872376456, 0.276393202250021030359082633126872376456, 0.276393202250021030359082633126872376456, }; // GRAD and D1: each row gives the 3x10 correct values of the gradients of the 10 basis functions double pointBasisGrads[] = { // point 0 -1./4., -1./4., -1./4., \ 1./4., 0.0, 0.0, \ 0.0, 1./4., 0.0, \ 0.0, 0.0, 1./4., \ 0.0, -3./4., -3./4., \ 3./4., 3./4., 0.0, \ -3./4., 0.0, -3./4., \ -3./4., -3./4., 0.0, \ 3./4., 0.0, 3./4., \ 0.0, 3./4., 3./4., \ // point 1 -1./24., -1./24., -1./24., \ 7./8., 0.0, 0.0, \ 0.0, 1./24., 0.0, \ 0.0, 0.0, 1./24., \ -35./36., -19./12., -19./12., \ 11./18., 19./12., 0.0, \ -17./36., 0.0, -1./3., \ -17./36., -1./3., 0.0, \ 11./18., 0.0, 19./12., \ -5./36., 1./3., 1./3., \ // point 2 -1./24., -1./24., -1./24., \ 1./24., 0.0, 0.0, \ 0.0, 7./8., 0.0, \ 0.0, 0.0, 1./24., \ 0.0, -17./36., -1./3., \ 19./12., 11./18., 0.0, \ -19./12., -35./36., -19./12., \ -1./3., -17./36., 0.0, \ 1./3., -5./36., 1./3., \ 0.0, 11./18., 19./12., \ // point 3 -1./24., -1./24., -1./24., \ 1./24., 0.0, 0.0, \ 0.0, 1./24., 0.0, \ 0.0, 0.0, 7./8., \ 0.0, -1./3., -17./36., \ 1./3., 1./3., -5./36., \ -1./3., 0.0, -17./36., \ -19./12., -19./12., -35./36., \ 19./12., 0.0, 11./18., \ 0.0, 19./12., 11./18., \ // point 4 -7./8., -7./8., -7./8., \ 1./24., 0.0, 0.0, \ 0.0, 1./24., 0.0, \ 0.0, 0.0, 1./24., \ 35./36., -11./18., -11./18., \ 17./36., 17./36., 5./36., \ -11./18., 35./36., -11./18., \ -11./18., -11./18., 35./36., \ 17./36., 5./36., 17./36., \ 5./36., 17./36., 17./36., \ // point 5 -1.088525491562421136153440125774228588290, -1.088525491562421136153440125774228588290, -1.088525491562421136153440125774228588290, \ -0.029508497187473712051146708591409529430, 0.0, 0.0, \ 0.0, -0.029508497187473712051146708591409529430, 0.0, \ 0.0, 0.0, -0.029508497187473712051146708591409529430, \ 1.30437298687487732290535130675991113734, -0.563661001875017525299235527605726980380, -0.563661001875017525299235527605726980380, \ 0.377322003750035050598471055211453960760, 0.377322003750035050598471055211453960760, 0.186338998124982474700764472394273019620, \ -0.563661001875017525299235527605726980380, 1.30437298687487732290535130675991113734, -0.563661001875017525299235527605726980380, \ -0.563661001875017525299235527605726980380, -0.563661001875017525299235527605726980380, 1.30437298687487732290535130675991113734, \ 0.377322003750035050598471055211453960760, 0.186338998124982474700764472394273019620, 0.377322003750035050598471055211453960760, \ 0.186338998124982474700764472394273019620, 0.377322003750035050598471055211453960760, 0.377322003750035050598471055211453960760, \ // point 6 0.029508497187473712051146708591409529430, 0.029508497187473712051146708591409529430, 0.029508497187473712051146708591409529430, \ 1.088525491562421136153440125774228588290, 0.0, 0.0, \ 0.0, -0.029508497187473712051146708591409529430, 0.0, \ 0.0, 0.0, -0.029508497187473712051146708591409529430, \ -1.30437298687487732290535130675991113734, -1.868033988749894848204586834365638117720, -1.868033988749894848204586834365638117720, \ 0.563661001875017525299235527605726980380, 1.868033988749894848204586834365638117720, 0.0, \ -0.377322003750035050598471055211453960760, 0.0, -0.190983005625052575897706582817180941140, \ -0.377322003750035050598471055211453960760, -0.190983005625052575897706582817180941140, 0.0, \ 0.563661001875017525299235527605726980380, 0.0, 1.868033988749894848204586834365638117720, \ -0.186338998124982474700764472394273019620, 0.190983005625052575897706582817180941140, 0.19098300562505257589770658281718094114, \ // point 7 0.029508497187473712051146708591409529430, 0.029508497187473712051146708591409529430, 0.029508497187473712051146708591409529430, \ -0.029508497187473712051146708591409529430, 0.0, 0.0, \ 0.0, 1.088525491562421136153440125774228588290, 0.0, \ 0.0, 0.0, -0.029508497187473712051146708591409529430, \ 0.0, -0.377322003750035050598471055211453960760, -0.190983005625052575897706582817180941140, \ 1.868033988749894848204586834365638117720, 0.563661001875017525299235527605726980380, 0.0, \ -1.868033988749894848204586834365638117720, -1.30437298687487732290535130675991113734, -1.868033988749894848204586834365638117720, \ -0.190983005625052575897706582817180941140, -0.377322003750035050598471055211453960760, 0.0, \ 0.190983005625052575897706582817180941140, -0.186338998124982474700764472394273019620, 0.190983005625052575897706582817180941140, \ 0.0, 0.563661001875017525299235527605726980380, 1.868033988749894848204586834365638117720, \ // point 8 0.029508497187473712051146708591409529430, 0.029508497187473712051146708591409529430, 0.029508497187473712051146708591409529430, \ -0.029508497187473712051146708591409529430, 0.0, 0.0, \ 0.0, -0.029508497187473712051146708591409529430, 0.0, \ 0.0, 0.0, 1.088525491562421136153440125774228588290, \ 0.0, -0.190983005625052575897706582817180941140, -0.377322003750035050598471055211453960760, \ 0.190983005625052575897706582817180941140, 0.190983005625052575897706582817180941140, -0.186338998124982474700764472394273019620, \ -0.190983005625052575897706582817180941140, 0.0, -0.377322003750035050598471055211453960760, \ -1.868033988749894848204586834365638117720, -1.868033988749894848204586834365638117720, -1.30437298687487732290535130675991113734, 1.868033988749894848204586834365638117720, 0.0, 0.563661001875017525299235527605726980380, \ 0.0, 1.868033988749894848204586834365638117720, 0.563661001875017525299235527605726980380, \ }; try{ // Dimensions for the output arrays: int numFields = tetBasis.getCardinality(); int numNodes = tetNodes.dimension(0); int spaceDim = tetBasis.getBaseCellTopology().getDimension(); // Generic array for values, grads, curls, etc. that will be properly sized before each call FieldContainer<double> vals; // Check VALUE of basis functions at nodes: resize vals to rank-2 container:\n"; *outStream << " check VALUE of basis functions at nodes\n"; vals.resize(numFields, numNodes); tetBasis.getValues(vals, tetNodes, OPERATOR_VALUE); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numNodes; j++) { int l = i + j * numFields; if (std::abs(vals(i,j) - nodalBasisValues[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " "; *outStream << "} computed value: " << vals(i,j) << " but reference value: " << nodalBasisValues[l] << "\n"; } } } // Check VALUE of basis functions at points: resize vals to rank-2 container:\n"; *outStream << " check VALUE of basis functions at points\n"; int numPoints = tetPoints.dimension(0); vals.resize(numFields, numPoints); vals.initialize(0.0); tetBasis.getValues(vals, tetPoints, OPERATOR_VALUE); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { int l = i + j * numFields; if (std::abs(vals(i,j) - pointBasisValues[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " "; *outStream << "} computed value: " << vals(i,j) << " but reference value: " << pointBasisValues[l] << "\n"; } } } // Check VALUE of basis functions at random points: resize vals to rank-2 container:\n"; *outStream << " check VALUE of basis functions at random points\n"; int numRandomPoints = 16384; FieldContainer<double> tetRandomPoints(numRandomPoints, 3); vals.resize(numFields, numRandomPoints); vals.initialize(0.0); int point = 0; int count = 0; std::random_device rd; std::mt19937 gen(rd()); std::uniform_real_distribution<> dis(0, 1); while (point < numRandomPoints) { count++; double r = dis(gen); double s = dis(gen); double t = dis(gen); if (r + s + t > 1.0) continue; tetRandomPoints(point, 0) = r; tetRandomPoints(point, 1) = s; tetRandomPoints(point, 2) = t; point++; } tetBasis.getValues(vals, tetRandomPoints, OPERATOR_VALUE); for (int j = 0; j < numRandomPoints; j++) { double sum = 0.0; for (int i = 0; i < numFields; i++) { sum += vals(i,j); } if (std::abs(sum - 1.0) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Just indicate something bad happened *outStream << " Composite tet basis functions"; *outStream << " are not summing to 1.0\n"; *outStream << " sum : " << sum << "\n"; } } // Check GRAD of basis functions at points: resize vals to rank-3 container:\n"; numPoints = tetPoints.dimension(0); vals.resize(numFields, numPoints, spaceDim); vals.initialize(0.0); tetBasis.getValues(vals, tetPoints, OPERATOR_GRAD); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { for (int k = 0; k < spaceDim; k++) { int l = k + i * spaceDim + j * spaceDim * numFields; if (std::abs(vals(i,j,k) - pointBasisGrads[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " ";*outStream << k << " "; *outStream << "} computed grad component: " << vals(i,j,k) << " but reference grad component: " << pointBasisGrads[l] << "\n"; } } } } } // Catch unexpected errors catch (std::logic_error err) { *outStream << err.what() << "\n\n"; errorFlag = -1000; }; if (errorFlag != 0) std::cout << "End Result: TEST FAILED\n"; else std::cout << "End Result: TEST PASSED\n"; // reset format state of std::cout std::cout.copyfmt(oldFormatState); return errorFlag; }
int 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; Teuchos::RCP<std::ostream> outStream; Teuchos::oblackholestream bhs; // outputs nothing if (iprint > 0) outStream = Teuchos::rcp(&std::cout, false); else outStream = Teuchos::rcp(&bhs, false); // Save the format state of the original std::cout. Teuchos::oblackholestream oldFormatState; oldFormatState.copyfmt(std::cout); *outStream \ << "===============================================================================\n" \ << "| |\n" \ << "| Unit Test (Basis_HCURL_TET_I1_FEM) |\n" \ << "| |\n" \ << "| 1) Conversion of Dof tags into Dof ordinals and back |\n" \ << "| 2) Basis values for VALUE and CURL operators |\n" \ << "| |\n" \ << "| Questions? Contact Pavel Bochev ([email protected]) or |\n" \ << "| Denis Ridzal ([email protected]). |\n" \ << "| |\n" \ << "| Intrepid's website: http://trilinos.sandia.gov/packages/intrepid |\n" \ << "| Trilinos website: http://trilinos.sandia.gov |\n" \ << "| |\n" \ << "===============================================================================\n"\ << "| TEST 1: Basis creation, exception testing |\n"\ << "===============================================================================\n"; // Define basis and error flag Basis_HCURL_TET_I1_FEM<double, FieldContainer<double> > tetBasis; int errorFlag = 0; // Define throw number for exception testing int nException = 0; int throwCounter = 0; // Define array containing the 4 vertices of the reference TET and its 6 edge centers. FieldContainer<double> tetNodes(10, 3); tetNodes(0,0) = 0.0; tetNodes(0,1) = 0.0; tetNodes(0,2) = 0.0; tetNodes(1,0) = 1.0; tetNodes(1,1) = 0.0; tetNodes(1,2) = 0.0; tetNodes(2,0) = 0.0; tetNodes(2,1) = 1.0; tetNodes(2,2) = 0.0; tetNodes(3,0) = 0.0; tetNodes(3,1) = 0.0; tetNodes(3,2) = 1.0; tetNodes(4,0) = 0.5; tetNodes(4,1) = 0.0; tetNodes(4,2) = 0.0; tetNodes(5,0) = 0.5; tetNodes(5,1) = 0.5; tetNodes(5,2) = 0.0; tetNodes(6,0) = 0.0; tetNodes(6,1) = 0.5; tetNodes(6,2) = 0.0; tetNodes(7,0) = 0.0; tetNodes(7,1) = 0.0; tetNodes(7,2) = 0.5; tetNodes(8,0) = 0.5; tetNodes(8,1) = 0.0; tetNodes(8,2) = 0.5; tetNodes(9,0) = 0.0; tetNodes(9,1) = 0.5; tetNodes(9,2) = 0.5; // Generic array for the output values; needs to be properly resized depending on the operator type FieldContainer<double> vals; try{ // exception #1: GRAD cannot be applied to HCURL functions // resize vals to rank-3 container with dimensions (num. basis functions, num. points, arbitrary) vals.resize(tetBasis.getCardinality(), tetNodes.dimension(0), 3 ); INTREPID_TEST_COMMAND( tetBasis.getValues(vals, tetNodes, OPERATOR_GRAD), throwCounter, nException ); // exception #2: DIV cannot be applied to HCURL functions // resize vals to rank-2 container with dimensions (num. basis functions, num. points) vals.resize(tetBasis.getCardinality(), tetNodes.dimension(0) ); INTREPID_TEST_COMMAND( tetBasis.getValues(vals, tetNodes, OPERATOR_DIV), throwCounter, nException ); // Exceptions 3-7: all bf tags/bf Ids below are wrong and should cause getDofOrdinal() and // getDofTag() to access invalid array elements thereby causing bounds check exception // exception #3 INTREPID_TEST_COMMAND( tetBasis.getDofOrdinal(3,0,0), throwCounter, nException ); // exception #4 INTREPID_TEST_COMMAND( tetBasis.getDofOrdinal(1,1,1), throwCounter, nException ); // exception #5 INTREPID_TEST_COMMAND( tetBasis.getDofOrdinal(0,4,1), throwCounter, nException ); // exception #6 INTREPID_TEST_COMMAND( tetBasis.getDofTag(7), throwCounter, nException ); // exception #7 INTREPID_TEST_COMMAND( tetBasis.getDofTag(-1), throwCounter, nException ); #ifdef HAVE_INTREPID2_DEBUG // Exceptions 8-15 test exception handling with incorrectly dimensioned input/output arrays // exception #8: input points array must be of rank-2 FieldContainer<double> badPoints1(4, 5, 3); INTREPID_TEST_COMMAND( tetBasis.getValues(vals,badPoints1,OPERATOR_VALUE), throwCounter, nException ); // exception #9 dimension 1 in the input point array must equal space dimension of the cell FieldContainer<double> badPoints2(4, 2); INTREPID_TEST_COMMAND( tetBasis.getValues(vals,badPoints2,OPERATOR_VALUE), throwCounter, nException ); // exception #10 output values must be of rank-3 for OPERATOR_VALUE FieldContainer<double> badVals1(4, 3); INTREPID_TEST_COMMAND( tetBasis.getValues(badVals1,tetNodes,OPERATOR_VALUE), throwCounter, nException ); // exception #11 output values must be of rank-3 for OPERATOR_CURL INTREPID_TEST_COMMAND( tetBasis.getValues(badVals1,tetNodes,OPERATOR_CURL), throwCounter, nException ); // exception #12 incorrect 0th dimension of output array (must equal number of basis functions) FieldContainer<double> badVals2(tetBasis.getCardinality() + 1, tetNodes.dimension(0), 3); INTREPID_TEST_COMMAND( tetBasis.getValues(badVals2,tetNodes,OPERATOR_VALUE), throwCounter, nException ); // exception #13 incorrect 1st dimension of output array (must equal number of points) FieldContainer<double> badVals3(tetBasis.getCardinality(), tetNodes.dimension(0) + 1, 3); INTREPID_TEST_COMMAND( tetBasis.getValues(badVals3,tetNodes,OPERATOR_VALUE), throwCounter, nException ); // exception #14: incorrect 2nd dimension of output array (must equal the space dimension) FieldContainer<double> badVals4(tetBasis.getCardinality(), tetNodes.dimension(0), 4); INTREPID_TEST_COMMAND( tetBasis.getValues(badVals4,tetNodes,OPERATOR_VALUE), throwCounter, nException ); // exception #15: incorrect 2nd dimension of output array (must equal the space dimension) INTREPID_TEST_COMMAND( tetBasis.getValues(badVals4,tetNodes,OPERATOR_CURL), throwCounter, nException ); #endif } catch (std::logic_error err) { *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n"; *outStream << err.what() << '\n'; *outStream << "-------------------------------------------------------------------------------" << "\n\n"; errorFlag = -1000; }; // Check if number of thrown exceptions matches the one we expect // Note Teuchos throw number will not pick up exceptions 3-7 and therefore will not match. if (throwCounter != nException) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; } *outStream \ << "\n" << "===============================================================================\n"\ << "| TEST 2: correctness of tag to enum and enum to tag lookups |\n"\ << "===============================================================================\n"; try{ std::vector<std::vector<int> > allTags = tetBasis.getAllDofTags(); // Loop over all tags, lookup the associated dof enumeration and then lookup the tag again for (unsigned i = 0; i < allTags.size(); i++) { int bfOrd = tetBasis.getDofOrdinal(allTags[i][0], allTags[i][1], allTags[i][2]); std::vector<int> myTag = tetBasis.getDofTag(bfOrd); if( !( (myTag[0] == allTags[i][0]) && (myTag[1] == allTags[i][1]) && (myTag[2] == allTags[i][2]) && (myTag[3] == allTags[i][3]) ) ) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; *outStream << " getDofOrdinal( {" << allTags[i][0] << ", " << allTags[i][1] << ", " << allTags[i][2] << ", " << allTags[i][3] << "}) = " << bfOrd <<" but \n"; *outStream << " getDofTag(" << bfOrd << ") = { " << myTag[0] << ", " << myTag[1] << ", " << myTag[2] << ", " << myTag[3] << "}\n"; } } // Now do the same but loop over basis functions for( int bfOrd = 0; bfOrd < tetBasis.getCardinality(); bfOrd++) { std::vector<int> myTag = tetBasis.getDofTag(bfOrd); int myBfOrd = tetBasis.getDofOrdinal(myTag[0], myTag[1], myTag[2]); if( bfOrd != myBfOrd) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; *outStream << " getDofTag(" << bfOrd << ") = { " << myTag[0] << ", " << myTag[1] << ", " << myTag[2] << ", " << myTag[3] << "} but getDofOrdinal({" << myTag[0] << ", " << myTag[1] << ", " << myTag[2] << ", " << myTag[3] << "} ) = " << myBfOrd << "\n"; } } } catch (std::logic_error err){ *outStream << err.what() << "\n\n"; errorFlag = -1000; }; *outStream \ << "\n" << "===============================================================================\n"\ << "| TEST 3: correctness of basis function values |\n"\ << "===============================================================================\n"; outStream -> precision(20); // VALUE: Each row pair gives the 6x3 correct basis set values at an evaluation point: (P,F,D) layout double basisValues[] = { // 4 vertices 1.0,0.,0., 0.,0.,0., 0.,-1.0,0., 0.,0.,1.0, 0.,0.,0., 0.,0.,0., 1.0,1.0,1.0, 0.,1.,0., 0.,0.,0., 0.,0.,0., 0.,0.,1., 0.,0.,0., 0.,0.,0., -1.,0.,0., -1.0,-1.0,-1.0, 0.,0.,0., 0.,0.,0., 0.,0.,1., 0.,0.,0., 0.,0.,0., 0.,0.,0., 1.0,1.0,1.0, -1.,0.,0., 0.,-1.,0., // 6 edge centers 1.0,0.5,0.5, 0.,0.5,0., 0.,-0.5,0., 0.,0.,0.5, 0.,0.,0.5, 0.,0.,0., 0.5,0.5,0.5, -0.5,0.5,0., -0.5,-0.5,-0.5, 0.,0.,0., 0.,0.,0.5, 0.,0.,0.5, 0.5,0.,0., -0.5,0.,0., -0.5,-1.0,-0.5, 0.,0.,0.5, 0.,0.,0., 0.,0.,0.5, 0.5,0.,0., 0.,0.,0., 0.,-0.5,0., 0.5,0.5,1.0, -0.5,0.,0., 0.,-0.5,0., 0.5,0.5,0.5, 0.,0.5,0., 0.,0.,0., 0.5,0.5,0.5, -0.5,0.,0.5, 0.,-0.5,0., 0.,0.,0., -0.5,0.,0., -0.5,-0.5,-0.5, 0.5,0.5,0.5, -0.5,0.,0., 0.,-0.5,0.5 }; // CURL: each row pair gives the 3x12 correct values of the curls of the 12 basis functions: (P,F,D) layout double basisCurls[] = { // 4 vertices 0.,-2.0,2.0, 0.,0.,2.0, -2.0,0.,2.0, -2.0,2.0,0., 0.,-2.0,0., 2.0,0.,0., 0.,-2.0,2.0, 0.,0.,2.0, -2.0,0.,2.0, -2.0,2.0,0., 0.,-2.0,0., 2.0,0.,0., 0.,-2.0,2.0, 0.,0.,2.0, -2.0,0.,2.0, -2.0,2.0,0., 0.,-2.0,0., 2.0,0.,0., 0.,-2.0,2.0, 0.,0.,2.0, -2.0,0.,2.0, -2.0,2.0,0., 0.,-2.0,0., 2.0,0.,0., // 6 edge centers 0.,-2.0,2.0, 0.,0.,2.0, -2.0,0.,2.0, -2.0,2.0,0., 0.,-2.0,0., 2.0,0.,0., 0.,-2.0,2.0, 0.,0.,2.0, -2.0,0.,2.0, -2.0,2.0,0., 0.,-2.0,0., 2.0,0.,0., 0.,-2.0,2.0, 0.,0.,2.0, -2.0,0.,2.0, -2.0,2.0,0., 0.,-2.0,0., 2.0,0.,0., 0.,-2.0,2.0, 0.,0.,2.0, -2.0,0.,2.0, -2.0,2.0,0., 0.,-2.0,0., 2.0,0.,0., 0.,-2.0,2.0, 0.,0.,2.0, -2.0,0.,2.0, -2.0,2.0,0., 0.,-2.0,0., 2.0,0.,0., 0.,-2.0,2.0, 0.,0.,2.0, -2.0,0.,2.0, -2.0,2.0,0., 0.,-2.0,0., 2.0,0.,0., }; try{ // Dimensions for the output arrays: int numFields = tetBasis.getCardinality(); int numPoints = tetNodes.dimension(0); int spaceDim = tetBasis.getBaseCellTopology().getDimension(); // Generic array for values and curls that will be properly sized before each call FieldContainer<double> vals; // Check VALUE of basis functions: resize vals to rank-3 container: vals.resize(numFields, numPoints, spaceDim); tetBasis.getValues(vals, tetNodes, OPERATOR_VALUE); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { for (int k = 0; k < spaceDim; k++) { // compute offset for (P,F,D) data layout: indices are P->j, F->i, D->k int l = k + i * spaceDim + j * spaceDim * numFields; if (std::abs(vals(i,j,k) - basisValues[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " ";*outStream << k << " "; *outStream << "} computed value: " << vals(i,j,k) << " but reference value: " << basisValues[l] << "\n"; } } } } // Check CURL of basis function: resize vals to rank-3 container vals.resize(numFields, numPoints, spaceDim); tetBasis.getValues(vals, tetNodes, OPERATOR_CURL); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { for (int k = 0; k < spaceDim; k++) { // compute offset for (P,F,D) data layout: indices are P->j, F->i, D->k int l = k + i * spaceDim + j * spaceDim * numFields; if (std::abs(vals(i,j,k) - basisCurls[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " ";*outStream << k << " "; *outStream << "} computed curl component: " << vals(i,j,k) << " but reference curl component: " << basisCurls[l] << "\n"; } } } } } // Catch unexpected errors catch (std::logic_error err) { *outStream << err.what() << "\n\n"; errorFlag = -1000; }; *outStream \ << "\n" << "===============================================================================\n"\ << "| TEST 4: correctness of DoF locations |\n"\ << "===============================================================================\n"; try{ Teuchos::RCP<Basis<double, FieldContainer<double> > > basis = Teuchos::rcp(new Basis_HCURL_TET_I1_FEM<double, FieldContainer<double> >); Teuchos::RCP<DofCoordsInterface<FieldContainer<double> > > coord_iface = Teuchos::rcp_dynamic_cast<DofCoordsInterface<FieldContainer<double> > >(basis); int spaceDim = 3; FieldContainer<double> cvals; FieldContainer<double> bvals(basis->getCardinality(), basis->getCardinality(),spaceDim); // last dimension is spatial dim // Check exceptions. #ifdef HAVE_INTREPID2_DEBUG cvals.resize(1,2,3); INTREPID_TEST_COMMAND( coord_iface->getDofCoords(cvals), throwCounter, nException ); cvals.resize(3,2); INTREPID_TEST_COMMAND( coord_iface->getDofCoords(cvals), throwCounter, nException ); cvals.resize(4,2); INTREPID_TEST_COMMAND( coord_iface->getDofCoords(cvals), throwCounter, nException ); #endif cvals.resize(6,spaceDim); INTREPID_TEST_COMMAND( coord_iface->getDofCoords(cvals), throwCounter, nException ); nException--; // Check if number of thrown exceptions matches the one we expect if (throwCounter != nException) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; } // Check mathematical correctness FieldContainer<double> tangents(basis->getCardinality(),spaceDim); // tangents at each point basis point tangents(0,0) = 1.0; tangents(0,1) = 0.0; tangents(0,2) = 0.0; tangents(1,0) = -1.0; tangents(1,1) = 1.0; tangents(1,2) = 0.0; tangents(2,0) = 0.0; tangents(2,1) = -1.0; tangents(2,2) = 0.0; tangents(3,0) = 0.0; tangents(3,1) = 0.0; tangents(3,2) = 1.0; tangents(4,0) = -1.0; tangents(4,1) = 0.0; tangents(4,2) = 1.0; tangents(5,0) = 0.0; tangents(5,1) = -1.0; tangents(5,2) = 1.0; basis->getValues(bvals, cvals, OPERATOR_VALUE); char buffer[120]; for (int i=0; i<bvals.dimension(0); i++) { for (int j=0; j<bvals.dimension(1); j++) { double tangent = 0.0; for(int d=0;d<spaceDim;d++) tangent += bvals(i,j,d)*tangents(j,d); if ((i != j) && (std::abs(tangent - 0.0) > INTREPID_TOL)) { errorFlag++; sprintf(buffer, "\nValue of basis function %d at (%6.4e, %6.4e, %6.4e) is %6.4e but should be %6.4e!\n", i, cvals(i,0), cvals(i,1), cvals(i,2), tangent, 0.0); *outStream << buffer; } else if ((i == j) && (std::abs(tangent - 1.0) > INTREPID_TOL)) { errorFlag++; sprintf(buffer, "\nValue of basis function %d at (%6.4e, %6.4e, %6.4e) is %6.4e but should be %6.4e!\n", i, cvals(i,0), cvals(i,1), cvals(i,2), tangent, 1.0); *outStream << buffer; } } } } catch (std::logic_error err){ *outStream << err.what() << "\n\n"; errorFlag = -1000; }; if (errorFlag != 0) std::cout << "End Result: TEST FAILED\n"; else std::cout << "End Result: TEST PASSED\n"; // reset format state of std::cout std::cout.copyfmt(oldFormatState); Kokkos::finalize(); return errorFlag; }
void Projector::projectFunctionOntoBasisInterpolating(FieldContainer<double> &basisCoefficients, FunctionPtr fxn, BasisPtr basis, BasisCachePtr domainBasisCache) { basisCoefficients.initialize(0); CellTopoPtr domainTopo = basis->domainTopology(); unsigned domainDim = domainTopo->getDimension(); IPPtr ip; bool traceVar = domainBasisCache->isSideCache(); pair<IPPtr, VarPtr> ipVarPair = IP::standardInnerProductForFunctionSpace(basis->functionSpace(), traceVar, domainDim); ip = ipVarPair.first; VarPtr v = ipVarPair.second; IPPtr ip_l2 = Teuchos::rcp( new IP ); ip_l2->addTerm(v); // for now, make all projections use L^2... (having some issues with gradients and cell Jacobians--I think we need the restriction of the cell Jacobian to the subcell, e.g., and it's not clear how to do that...) ip = ip_l2; FieldContainer<double> referenceDomainNodes(domainTopo->getVertexCount(),domainDim); CamelliaCellTools::refCellNodesForTopology(referenceDomainNodes, domainTopo); int basisCardinality = basis->getCardinality(); set<int> allDofs; for (int i=0; i<basisCardinality; i++) { allDofs.insert(i); } for (int d=0; d<=domainDim; d++) { FunctionPtr projectionThusFar = NewBasisSumFunction::basisSumFunction(basis, basisCoefficients); FunctionPtr fxnToApproximate = fxn - projectionThusFar; int subcellCount = domainTopo->getSubcellCount(d); for (int subcord=0; subcord<subcellCount; subcord++) { set<int> subcellDofOrdinals = basis->dofOrdinalsForSubcell(d, subcord); if (subcellDofOrdinals.size() > 0) { FieldContainer<double> refCellPoints; FieldContainer<double> cubatureWeightsSubcell; // allows us to integrate over the fine subcell even when domain is higher-dimensioned if (d == 0) { refCellPoints.resize(1,domainDim); for (int d1=0; d1<domainDim; d1++) { refCellPoints(0,d1) = referenceDomainNodes(subcord,d1); } cubatureWeightsSubcell.resize(1); cubatureWeightsSubcell(0) = 1.0; } else { CellTopoPtr subcellTopo = domainTopo->getSubcell(d, subcord); // Teuchos::RCP<Cubature<double> > subcellCubature = cubFactory.create(subcellTopo, domainBasisCache->cubatureDegree()); BasisCachePtr subcellCache = Teuchos::rcp( new BasisCache(subcellTopo, domainBasisCache->cubatureDegree(), false) ); int numPoints = subcellCache->getRefCellPoints().dimension(0); refCellPoints.resize(numPoints,domainDim); cubatureWeightsSubcell = subcellCache->getCubatureWeights(); if (d == domainDim) { refCellPoints = subcellCache->getRefCellPoints(); } else { CamelliaCellTools::mapToReferenceSubcell(refCellPoints, subcellCache->getRefCellPoints(), d, subcord, domainTopo); } } domainBasisCache->setRefCellPoints(refCellPoints, cubatureWeightsSubcell); IPPtr ipForProjection = (d==0) ? ip_l2 : ip; // just use values at vertices (ignore derivatives) set<int> dofsToSkip = allDofs; for (set<int>::iterator dofOrdinalIt=subcellDofOrdinals.begin(); dofOrdinalIt != subcellDofOrdinals.end(); dofOrdinalIt++) { dofsToSkip.erase(*dofOrdinalIt); } FieldContainer<double> newBasisCoefficients; projectFunctionOntoBasis(newBasisCoefficients, fxnToApproximate, basis, domainBasisCache, ipForProjection, v, dofsToSkip); for (int cellOrdinal=0; cellOrdinal<newBasisCoefficients.dimension(0); cellOrdinal++) { for (set<int>::iterator dofOrdinalIt=subcellDofOrdinals.begin(); dofOrdinalIt != subcellDofOrdinals.end(); dofOrdinalIt++) { basisCoefficients(cellOrdinal,*dofOrdinalIt) = newBasisCoefficients(cellOrdinal,*dofOrdinalIt); } } } } } }
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; Teuchos::RCP<std::ostream> outStream; Teuchos::oblackholestream bhs; // outputs nothing if (iprint > 0) outStream = Teuchos::rcp(&std::cout, false); else outStream = Teuchos::rcp(&bhs, false); // Save the format state of the original std::cout. Teuchos::oblackholestream oldFormatState; oldFormatState.copyfmt(std::cout); *outStream \ << "===============================================================================\n" \ << "| |\n" \ << "| Unit Test (Basis_HGRAD_QUAD_Cn_FEM) |\n" \ << "| |\n" \ << "| 1) Conversion of Dof tags into Dof ordinals and back |\n" \ << "| 2) Basis values for VALUE, GRAD, CURL, and Dk operators |\n" \ << "| |\n" \ << "| Questions? Contact Pavel Bochev ([email protected]), |\n" \ << "| Robert Kirby ([email protected]), |\n" \ << "| Denis Ridzal ([email protected]), |\n" \ << "| Kara Peterson ([email protected]). |\n" \ << "| |\n" \ << "| Intrepid's website: http://trilinos.sandia.gov/packages/intrepid |\n" \ << "| Trilinos website: http://trilinos.sandia.gov |\n" \ << "| |\n" \ << "===============================================================================\n"\ << "| TEST 1: Basis creation, exception testing |\n"\ << "===============================================================================\n"; // Define basis and error flag // get points for basis const int deg=2; shards::CellTopology line(shards::getCellTopologyData< shards::Line<> >()); FieldContainer<double> pts(PointTools::getLatticeSize(line,deg),1); PointTools::getLattice<double,FieldContainer<double> >(pts,line,deg); Basis_HGRAD_QUAD_Cn_FEM<double, FieldContainer<double> > quadBasis(deg,deg,pts,pts); int errorFlag = 0; // Initialize throw counter for exception testing int nException = 0; int throwCounter = 0; // Array with the 4 vertices, 4 edge midpoints, center of the reference QUAD and a random point. FieldContainer<double> quadNodes(10, 2); quadNodes(0,0) = -1.0; quadNodes(0,1) = -1.0; quadNodes(1,0) = 1.0; quadNodes(1,1) = -1.0; quadNodes(2,0) = 1.0; quadNodes(2,1) = 1.0; quadNodes(3,0) = -1.0; quadNodes(3,1) = 1.0; // edge midpoints quadNodes(4,0) = 0.0; quadNodes(4,1) = -1.0; quadNodes(5,0) = 1.0; quadNodes(5,1) = 0.0; quadNodes(6,0) = 0.0; quadNodes(6,1) = 1.0; quadNodes(7,0) = -1.0; quadNodes(7,1) = 0.0; // center & random point quadNodes(8,0) = 0.0; quadNodes(8,1) = 0.0; quadNodes(9,0) =1./3.; quadNodes(9,1) =-3./5.; // Generic array for the output values; needs to be properly resized depending on the operator type FieldContainer<double> vals; try{ // exception #1: DIV cannot be applied to scalar functions // resize vals to rank-2 container with dimensions (num. points, num. basis functions) vals.resize(quadBasis.getCardinality(), quadNodes.dimension(0)); INTREPID_TEST_COMMAND( quadBasis.getValues(vals, quadNodes, OPERATOR_DIV), throwCounter, nException ); // Exceptions 2-6: all bf tags/bf Ids below are wrong and should cause getDofOrdinal() and // getDofTag() to access invalid array elements thereby causing bounds check exception // exception #2 INTREPID_TEST_COMMAND( quadBasis.getDofOrdinal(3,0,0), throwCounter, nException ); // exception #3 INTREPID_TEST_COMMAND( quadBasis.getDofOrdinal(1,1,1), throwCounter, nException ); // exception #4 INTREPID_TEST_COMMAND( quadBasis.getDofOrdinal(0,4,0), throwCounter, nException ); // exception #5 INTREPID_TEST_COMMAND( quadBasis.getDofTag(10), throwCounter, nException ); // exception #6 INTREPID_TEST_COMMAND( quadBasis.getDofTag(-1), throwCounter, nException ); #ifdef HAVE_INTREPID_DEBUG // Exceptions 7- test exception handling with incorrectly dimensioned input/output arrays // exception #7: input points array must be of rank-2 FieldContainer<double> badPoints1(4, 5, 3); INTREPID_TEST_COMMAND( quadBasis.getValues(vals, badPoints1, OPERATOR_VALUE), throwCounter, nException ); // exception #8 dimension 1 in the input point array must equal space dimension of the cell FieldContainer<double> badPoints2(4, quadBasis.getBaseCellTopology().getDimension() + 1); INTREPID_TEST_COMMAND( quadBasis.getValues(vals, badPoints2, OPERATOR_VALUE), throwCounter, nException ); // exception #9 output values must be of rank-2 for OPERATOR_VALUE FieldContainer<double> badVals1(4, 3, 1); INTREPID_TEST_COMMAND( quadBasis.getValues(badVals1, quadNodes, OPERATOR_VALUE), throwCounter, nException ); // exception #10 output values must be of rank-3 for OPERATOR_GRAD FieldContainer<double> badVals2(4, 3); INTREPID_TEST_COMMAND( quadBasis.getValues(badVals2, quadNodes, OPERATOR_GRAD), throwCounter, nException ); // exception #11 output values must be of rank-3 for OPERATOR_CURL INTREPID_TEST_COMMAND( quadBasis.getValues(badVals2, quadNodes, OPERATOR_CURL), throwCounter, nException ); // exception #12 output values must be of rank-3 for OPERATOR_D2 INTREPID_TEST_COMMAND( quadBasis.getValues(badVals2, quadNodes, OPERATOR_D2), throwCounter, nException ); // exception #13 incorrect 0th dimension of output array (must equal number of basis functions) FieldContainer<double> badVals3(quadBasis.getCardinality() + 1, quadNodes.dimension(0)); INTREPID_TEST_COMMAND( quadBasis.getValues(badVals3, quadNodes, OPERATOR_VALUE), throwCounter, nException ); // exception #14 incorrect 1st dimension of output array (must equal number of points in quadNodes) FieldContainer<double> badVals4(quadBasis.getCardinality(), quadNodes.dimension(0) + 1); INTREPID_TEST_COMMAND( quadBasis.getValues(badVals4, quadNodes, OPERATOR_VALUE), throwCounter, nException ); // exception #15: incorrect 2nd dimension of output array (must equal the space dimension) FieldContainer<double> badVals5(quadBasis.getCardinality(), quadNodes.dimension(0), quadBasis.getBaseCellTopology().getDimension() + 1); INTREPID_TEST_COMMAND( quadBasis.getValues(badVals5, quadNodes, OPERATOR_GRAD), throwCounter, nException ); // exception #16: incorrect 2nd dimension of output array (must equal D2 cardinality in 2D) FieldContainer<double> badVals6(quadBasis.getCardinality(), quadNodes.dimension(0), 40); INTREPID_TEST_COMMAND( quadBasis.getValues(badVals6, quadNodes, OPERATOR_D2), throwCounter, nException ); // exception #17: incorrect 2nd dimension of output array (must equal D3 cardinality in 2D) INTREPID_TEST_COMMAND( quadBasis.getValues(badVals6, quadNodes, OPERATOR_D3), throwCounter, nException ); #endif } catch (std::logic_error err) { *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n"; *outStream << err.what() << '\n'; *outStream << "-------------------------------------------------------------------------------" << "\n\n"; errorFlag = -1000; }; // Check if number of thrown exceptions matches the one we expect if (throwCounter != nException) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; } *outStream \ << "\n" << "===============================================================================\n"\ << "| TEST 2: correctness of tag to enum and enum to tag lookups |\n"\ << "===============================================================================\n"; try{ std::vector<std::vector<int> > allTags = quadBasis.getAllDofTags(); // Loop over all tags, lookup the associated dof enumeration and then lookup the tag again for (unsigned i = 0; i < allTags.size(); i++) { int bfOrd = quadBasis.getDofOrdinal(allTags[i][0], allTags[i][1], allTags[i][2]); std::vector<int> myTag = quadBasis.getDofTag(bfOrd); if( !( (myTag[0] == allTags[i][0]) && (myTag[1] == allTags[i][1]) && (myTag[2] == allTags[i][2]) && (myTag[3] == allTags[i][3]) ) ) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; *outStream << " getDofOrdinal( {" << allTags[i][0] << ", " << allTags[i][1] << ", " << allTags[i][2] << ", " << allTags[i][3] << "}) = " << bfOrd <<" but \n"; *outStream << " getDofTag(" << bfOrd << ") = { " << myTag[0] << ", " << myTag[1] << ", " << myTag[2] << ", " << myTag[3] << "}\n"; } } // Now do the same but loop over basis functions for( int bfOrd = 0; bfOrd < quadBasis.getCardinality(); bfOrd++) { std::vector<int> myTag = quadBasis.getDofTag(bfOrd); int myBfOrd = quadBasis.getDofOrdinal(myTag[0], myTag[1], myTag[2]); if( bfOrd != myBfOrd) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; *outStream << " getDofTag(" << bfOrd << ") = { " << myTag[0] << ", " << myTag[1] << ", " << myTag[2] << ", " << myTag[3] << "} but getDofOrdinal({" << myTag[0] << ", " << myTag[1] << ", " << myTag[2] << ", " << myTag[3] << "} ) = " << myBfOrd << "\n"; } } } catch (std::logic_error err){ *outStream << err.what() << "\n\n"; errorFlag = -1000; }; *outStream \ << "\n" << "===============================================================================\n"\ << "| TEST 3: correctness of basis function values |\n"\ << "===============================================================================\n"; outStream -> precision(20); // VALUE: Correct basis values in (F,P) format: double basisValues[] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, -0.05333333333333334, \ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0.4266666666666667, \ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0.1066666666666667, \ 0, 0, 0, 0, 0, 0, 0, 1, 0, -0.07111111111111112 , \ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.5688888888888890, \ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0.1422222222222222 ,\ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0.01333333333333333, \ 0, 0, 0, 0, 0, 0, 1, 0, 0, -0.1066666666666667, \ 0, 0, 1, 0, 0, 0, 0, 0, 0, -0.02666666666666666 }; // FIXME HERE: needs to be reordered. // GRAD and D1: Correct gradients and D1 in (F,P,D) format // 9 basis functions, each evaluated at 10 points, with two // components at each point. // that looks like 10 per to me. double basisGrads[] = { // -1.500000000000000, -1.500000000000000, 0.5000000000000000, 0, 0, 0, 0, 0.5000000000000000, -0.5000000000000000, 0, \ 0, 0, 0, 0, 0, -0.5000000000000000, 0, 0, -0.08000000000000002, 0.1222222222222222, \ // 2.000000000000000, 0, -2.000000000000000, 0, 0, 0, 0, 0, 0, -1.500000000000000, \ 0, 0, 0, 0.5000000000000000, 0, 0, 0, -0.5000000000000000, -0.3199999999999999, -0.9777777777777779, \ // -0.5000000000000000, 0, 1.500000000000000, -1.500000000000000, 0, 0.5000000000000000, 0, 0, 0.5000000000000000, 0, \ 0, -0.5000000000000000, 0, 0, 0, 0, 0, 0, 0.3999999999999999, -0.2444444444444444, \ // 0, 2.0, 0, 0, 0, 0, 0, -2.000000000000000, 0, 0, \ 0.5000000000000000, 0, 0, 0, -1.50, 0, -0.50, 0, -0.1066666666666667, -0.1333333333333333, \ // 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.0,\ -2.00, 0, 0, -2.0, 2.0, 0, 0, 0, -0.4266666666666667, 1.066666666666667 , \ // 0, 0, 0, 2.000000000000000, 0, -2.000000000000000, 0, 0, 0, 0, \ 1.5, 0, 0, 0, -0.5, 0, 0.5000000000000000, 0, 0.5333333333333334, 0.2666666666666666 , \ // 0, -0.5000000000000000, 0, 0, 0.5000000000000000, 0, -1.500000000000000, 1.500000000000000, 0, 0, \ 0, 0, -0.5000000000000000, 0, 0, 0.5000000000000000, 0, 0, 0.02000000000000000, 0.01111111111111112 , \ // 0, 0, 0, 0, -2.0, 0, 2.0, 0, 0, -0.50, \ 0, 0, 0, 1.5, 0, 0, 0, 0.5000000000000000, 0.07999999999999997, -0.08888888888888888, \ // 0, 0, 0, -0.5000000000000000, 1.500000000000000, 1.500000000000000, -0.5000000000000000, 0, 0, 0, \ 0, 0.5000000000000000, 0.5000000000000000, 0, 0, 0, 0, 0, -0.09999999999999998, -0.02222222222222221 \ // }; // D2: Correct multiset of second order partials in (F,P,Dk) format. D2 cardinality = 3 for 2D // 10 quad points and 3 values per point, so // each bf consists of 30 values. double basisD2[] = { 1.0, 2.25, 1.0, 1.0, -0.75, 0, 0, 0.25, 0, 0, -0.75, 1.0, 1.0, 0.75, 0, 0, -0.25, 0, 0, -0.25, 0, 0, 0.75, 1.0, 0, 0.25, 0, 0.48, 0.1833333333333334, -0.1111111111111111, // -2.0, -3.0, 0, -2.0, 3.0, 0, 0, -1.0, 0, \ 0, 1.0, 0, -2.0, 0, 1.0, 0, \ 1.0, 0, 0, 0, 1.0, 0, -1.0, \ 0, 0, 0, 1.0, -0.96, 0.7333333333333332, \ 0.8888888888888890, \ // 1.0, 0.75, 0, 1.0, -2.25, 1.0, 0, 0.75, 1.0, 0, -0.25, 0, \ 1.0, -0.75, 0, 0, -0.75, 1.0, 0, 0.25, 0, 0, 0.25, \ 0, 0, -0.25, 0, 0.48, -0.9166666666666666, 0.2222222222222222, // 0, -3.0, -2.0, 0, 1.0, 0, 0, -1.0, 0, 0, 3.0, \ -2.0, 0, -1.0, 0, 1.0, 0, 0, 0, 1.0, 0, 1.0, 0, -2.0, \ 1.0, 0, 0, 0.6400000000000001, -0.2000000000000001, 0.2222222222222222, \ // 0, 4.0, 0, 0, -4.0, 0, 0, 4.0, 0, 0, -4.0, 0, 0, 0, \ -2.0, -2.0, 0, 0, 0, 0, -2.0, -2.0, 0, 0, -2.0, 0, \ -2.0, -1.280000000000000, -0.7999999999999998, -1.777777777777778 , // 0, -1.0, 0, 0, 3.0, -2.0, 0, -3.0, -2.0, 0, \ 1.0, 0, 0, 1.0, 0, 1.0, 0, -2.0, 0, -1.0, 0, 1.0, 0, \ 0, 1.0, 0, 0, 0.6400000000000001, 1.0, -0.4444444444444444, \ // 0, 0.75, 1.0, 0, -0.25, 0, 1.0, 0.75, 0, 1.0, -2.25, 1.0, 0, \ 0.25, 0, 0, 0.25, 0, 1.0, -0.75, 0, 0, -0.75, 1.0, 0, \ -0.25, 0, -0.12, 0.01666666666666666, -0.1111111111111111, \ // 0, -1.0, 0, 0, 1.0, 0, -2.0, -3.0, 0, -2.0, 3.0, 0, 0, 0, 1.0, 0, -1.0, \ 0, -2.0, 0, 1.0, 0, 1.0, 0, \ 0, 0, 1.0, 0.24, 0.06666666666666665, 0.8888888888888890, \ // 0, 0.25, 0, 0, -0.75, 1.0, 1.0, 2.25, 1.0, 1.0, \ -0.75, 0, 0, -0.25, 0, 0, 0.75, 1.0, 1.0, \ 0.75, 0, 0, -0.25, 0, 0, 0.25, 0, -0.12, -0.08333333333333331, 0.2222222222222222 \ }; //D3: Correct multiset of second order partials in (F,P,Dk) format. D3 cardinality = 4 for 2D double basisD3[] = { 0, -1.5, -1.5, 0, 0, -1.5, 0.5, 0, 0, 0.5, 0.5, 0, 0, 0.5, -1.5, 0, 0, -1.5, -0.5, 0, 0, -0.5, 0.5, 0, 0, 0.5, -0.5, 0, 0, -0.5, -1.5, 0, 0, -0.5, -0.5, 0, 0, -1.1, -0.1666666666666667, 0, // 0, 3.0, 2.0, 0, 0, 3.0, -2.0, 0, 0, -1.0, -2.0, 0, 0, -1.0, 2.0, 0, 0, 3.0, 0, 0, 0, 1.0, -2.0, 0, 0, -1.0, 0, 0, 0, 1.0, 2.0, 0, 0, 1.0, 0, 0, 0, 2.2, -0.6666666666666665, 0, // 0, -1.5, -0.5, 0, 0, -1.5, 1.5, 0, 0, 0.5, 1.5, 0, 0, 0.5, -0.5, 0, 0, -1.5, 0.5, 0, 0, -0.5, 1.5, 0, 0, 0.5, 0.5, 0, 0, -0.5, -0.5, 0, 0, -0.5, 0.5, 0, 0, -1.1, 0.8333333333333333, 0, // 0, 2.0, 3.0, 0, 0, 2.0, -1.0, 0, 0, -2.0, -1.0, 0, 0, -2.0, 3.0, 0, 0, 2.0, 1.0, 0, 0, 0, -1.0, 0, 0, -2.0, 1.0, 0, 0, 0, 3.0, 0, 0, 0, 1.0, 0, 0, 1.2, 0.3333333333333334, 0, // 0, -4.0, -4.0, 0, 0, -4.0, 4.0, 0, 0, 4.0, 4.0, 0, 0, 4.0, -4.0, 0, 0, -4.0, 0, 0, 0, 0, 4.0, 0, 0, 4.0, 0, 0, 0, 0, -4.0, 0, 0, 0, 0, 0, 0, -2.40, 1.333333333333333, 0, // 0, 2.0, 1.0, 0, 0, 2.0, -3.0, 0, 0, -2.0, -3.0, 0, 0, -2.0, 1.0, 0, 0, 2.0, -1.0, 0, 0, 0, -3.0, 0, 0, -2.0, -1.0, 0, 0, 0, 1.0, 0, 0, 0, -1.0, 0, 0, 1.2, -1.666666666666667, 0 , // 0, -0.5, -1.5, 0, 0, -0.5, 0.5, 0, 0, 1.5, 0.5, 0, 0, 1.5, -1.5, 0, 0, -0.5, -0.5, 0, 0, 0.5, 0.5, 0, 0, 1.5, -0.5, 0, 0, 0.5, -1.5, 0, 0, 0.5, -0.5, 0, 0, -0.09999999999999998, -0.1666666666666667, 0, // 0, 1.0, 2.0, 0, 0, 1.0, -2.0, 0, 0, -3.0, -2.0, 0, 0, -3.0, 2.0, 0, 0, 1.0, 0, 0, 0, -1.0, -2.0, 0, 0, -3.0, 0, 0, 0, -1.0, 2.0, 0, 0, -1.0, 0, 0, 0, 0.2, -0.6666666666666665, 0, // 0, -0.5, -0.5, 0, 0, -0.5, 1.5, 0, 0, 1.5, 1.5, 0, 0, 1.5, -0.5, 0, 0, -0.5, 0.5, 0, 0, 0.5, 1.5, 0, 0, 1.5, 0.5, 0, 0, 0.5, -0.5, 0, 0, 0.5, 0.5, 0, 0, -0.09999999999999998, 0.8333333333333333, 0 }; //D4: Correct multiset of second order partials in (F,P,Dk) format. D4 cardinality = 5 for 2D double basisD4[] = { 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, // 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, // 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, // 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, // 0, 0, 4.0, 0, 0, 0, 0, 4.0, 0, 0, 0, 0, 4.0, 0, 0, 0, 0, 4.0, 0, 0, 0, 0, 4.0, 0, 0, 0, 0, 4.0, 0, 0, 0, 0, 4.0, 0, 0, 0, 0, 4.0, 0, 0, 0, 0, 4.0, 0, 0, 0, 0, 4.0, 0, 0, // 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, // 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, // 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, 0, 0, -2.0, 0, 0, // 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0 }; try{ // Dimensions for the output arrays: int numFields = quadBasis.getCardinality(); int numPoints = quadNodes.dimension(0); int spaceDim = quadBasis.getBaseCellTopology().getDimension(); // Generic array for values, grads, curls, etc. that will be properly sized before each call FieldContainer<double> vals; // Check VALUE of basis functions: resize vals to rank-2 container: vals.resize(numFields, numPoints); quadBasis.getValues(vals, quadNodes, OPERATOR_VALUE); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { // Compute offset for (F,P) container int l = j + i * numPoints; if (std::abs(vals(i,j) - basisValues[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " "; *outStream << "} computed value: " << vals(i,j) << " but reference value: " << basisValues[l] << "\n"; } } } // Check GRAD of basis function: resize vals to rank-3 container vals.resize(numFields, numPoints, spaceDim); quadBasis.getValues(vals, quadNodes, OPERATOR_GRAD); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { for (int k = 0; k < spaceDim; k++) { // basisGrads is (F,P,D), compute offset: int l = k + j * spaceDim + i * spaceDim * numPoints; if (std::abs(vals(i,j,k) - basisGrads[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " ";*outStream << k << " "; *outStream << "} computed grad component: " << vals(i,j,k) << " but reference grad component: " << basisGrads[l] << "\n"; } } } } // Check D1 of basis function (do not resize vals because it has the correct size: D1 = GRAD) quadBasis.getValues(vals, quadNodes, OPERATOR_D1); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { for (int k = 0; k < spaceDim; k++) { // basisGrads is (F,P,D), compute offset: int l = k + j * spaceDim + i * spaceDim * numPoints; if (std::abs(vals(i,j,k) - basisGrads[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " ";*outStream << k << " "; *outStream << "} computed D1 component: " << vals(i,j,k) << " but reference D1 component: " << basisGrads[l] << "\n"; } } } } // Check CURL of basis function: resize vals just for illustration! vals.resize(numFields, numPoints, spaceDim); quadBasis.getValues(vals, quadNodes, OPERATOR_CURL); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { // We will use "rotated" basisGrads to check CURL: get offsets to extract (u_y, -u_x) int curl_0 = 1 + j * spaceDim + i * spaceDim * numPoints; // position of y-derivative int curl_1 = 0 + j * spaceDim + i * spaceDim * numPoints; // position of x-derivative double curl_value_0 = basisGrads[curl_0]; double curl_value_1 =-basisGrads[curl_1]; if (std::abs(vals(i,j,0) - curl_value_0) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " ";*outStream << 0 << " "; *outStream << "} computed curl component: " << vals(i,j,0) << " but reference curl component: " << curl_value_0 << "\n"; } if (std::abs(vals(i,j,1) - curl_value_1) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " ";*outStream << 1 << " "; *outStream << "} computed curl component: " << vals(i,j,1) << " but reference curl component: " << curl_value_1 << "\n"; } } } // Check D2 of basis function int D2cardinality = Intrepid2::getDkCardinality(OPERATOR_D2, spaceDim); vals.resize(numFields, numPoints, D2cardinality); quadBasis.getValues(vals, quadNodes, OPERATOR_D2); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { for (int k = 0; k < D2cardinality; k++) { // basisD2 is (F,P,Dk), compute offset: int l = k + j * D2cardinality + i * D2cardinality * numPoints; if (std::abs(vals(i,j,k) - basisD2[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " ";*outStream << k << " "; *outStream << "} computed D2 component: " << vals(i,j,k) << " but reference D2 component: " << basisD2[l] << "\n"; } } } } // Check D3 of basis function int D3cardinality = Intrepid2::getDkCardinality(OPERATOR_D3, spaceDim); vals.resize(numFields, numPoints, D3cardinality); quadBasis.getValues(vals, quadNodes, OPERATOR_D3); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { for (int k = 0; k < D3cardinality; k++) { // basisD3 is (F,P,Dk), compute offset: int l = k + j * D3cardinality + i * D3cardinality * numPoints; if (std::abs(vals(i,j,k) - basisD3[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " ";*outStream << k << " "; *outStream << "} computed D3 component: " << vals(i,j,k) << " but reference D3 component: " << basisD2[l] << "\n"; } } } } // Check D4 of basis function int D4cardinality = Intrepid2::getDkCardinality(OPERATOR_D4, spaceDim); vals.resize(numFields, numPoints, D4cardinality); quadBasis.getValues(vals, quadNodes, OPERATOR_D4); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { for (int k = 0; k < D4cardinality; k++) { // basisD4 is (F,P,Dk), compute offset: int l = k + j * D4cardinality + i * D4cardinality * numPoints; if (std::abs(vals(i,j,k) - basisD4[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " ";*outStream << k << " "; *outStream << "} computed D4 component: " << vals(i,j,k) << " but reference D4 component: " << basisD4[l] << "\n"; } } } } // Check all higher derivatives - must be zero. for(EOperator op = OPERATOR_D5; op <= OPERATOR_D6; op++) { // The last dimension is the number of kth derivatives and needs to be resized for every Dk int DkCardin = Intrepid2::getDkCardinality(op, spaceDim); vals.resize(numFields, numPoints, DkCardin); quadBasis.getValues(vals, quadNodes, op); for (int i = 0; i < vals.size(); i++) { if (std::abs(vals[i]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Get the multi-index of the value where the error is and the operator order std::vector<int> myIndex; vals.getMultiIndex(myIndex,i); int ord = Intrepid2::getOperatorOrder(op); *outStream << " At multi-index { "; for(int j = 0; j < vals.rank(); j++) { *outStream << myIndex[j] << " "; } *outStream << "} computed D"<< ord <<" component: " << vals[i] << " but reference D" << ord << " component: 0 \n"; } } } } // Catch unexpected errors catch (std::logic_error err) { *outStream << err.what() << "\n\n"; errorFlag = -1000; }; if (errorFlag != 0) std::cout << "End Result: TEST FAILED\n"; else std::cout << "End Result: TEST PASSED\n"; // reset format state of std::cout std::cout.copyfmt(oldFormatState); Kokkos::finalize(); return errorFlag; }
void Projector::projectFunctionOntoBasis(FieldContainer<double> &basisCoefficients, Teuchos::RCP<AbstractFunction> fxn, BasisPtr basis, const FieldContainer<double> &physicalCellNodes) { CellTopoPtr cellTopo = basis->domainTopology(); DofOrderingPtr dofOrderPtr = Teuchos::rcp(new DofOrdering()); int basisRank = BasisFactory::basisFactory()->getBasisRank(basis); int ID = 0; // only one entry for this fake dofOrderPtr dofOrderPtr->addEntry(ID,basis,basisRank); int maxTrialDegree = dofOrderPtr->maxBasisDegree(); // do not build side caches - no projections for sides supported at the moment if (cellTopo->getTensorialDegree() != 0) { cout << "Projector::projectFunctionOntoBasis() does not yet support tensorial degree > 0.\n"; TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Projector::projectFunctionOntoBasis() does not yet support tensorial degree > 0."); } shards::CellTopology shardsTopo = cellTopo->getShardsTopology(); BasisCache basisCache(physicalCellNodes, shardsTopo, *(dofOrderPtr), maxTrialDegree, false); // assume only L2 projections IntrepidExtendedTypes::EOperatorExtended op = IntrepidExtendedTypes::OP_VALUE; // have information, build inner product matrix int numDofs = basis->getCardinality(); FieldContainer<double> cubPoints = basisCache.getPhysicalCubaturePoints(); FieldContainer<double> basisValues = *(basisCache.getTransformedValues(basis, op)); FieldContainer<double> testBasisValues = *(basisCache.getTransformedWeightedValues(basis, op)); int numCells = physicalCellNodes.dimension(0); int numPts = cubPoints.dimension(1); FieldContainer<double> functionValues; fxn->getValues(functionValues, cubPoints); FieldContainer<double> gramMatrix(numCells,numDofs,numDofs); FieldContainer<double> ipVector(numCells,numDofs); FunctionSpaceTools::integrate<double>(gramMatrix,basisValues,testBasisValues,COMP_BLAS); FunctionSpaceTools::integrate<double>(ipVector,functionValues,testBasisValues,COMP_BLAS); basisCoefficients.resize(numCells,numDofs); for (int cellIndex=0; cellIndex<numCells; cellIndex++){ Epetra_SerialDenseSolver solver; Epetra_SerialDenseMatrix A(Copy, &gramMatrix(cellIndex,0,0), gramMatrix.dimension(2), gramMatrix.dimension(2), gramMatrix.dimension(1)); // stride -- fc stores in row-major order (a.o.t. SDM) Epetra_SerialDenseVector b(Copy, &ipVector(cellIndex,0), ipVector.dimension(1)); Epetra_SerialDenseVector x(gramMatrix.dimension(1)); /* cout << "matrix A = " << endl; for (int i=0;i<gramMatrix.dimension(2);i++){ for (int j=0;j<gramMatrix.dimension(1);j++){ cout << A(i,j) << " "; } cout << endl; } cout << endl; cout << "vector B = " << endl; for (int i=0;i<functionValues.dimension(1);i++){ cout << b(i) << endl; } */ solver.SetMatrix(A); int info = solver.SetVectors(x,b); if (info!=0){ cout << "projectFunctionOntoBasis: failed to SetVectors with error " << info << endl; } bool equilibrated = false; if (solver.ShouldEquilibrate()){ solver.EquilibrateMatrix(); solver.EquilibrateRHS(); equilibrated = true; } info = solver.Solve(); if (info!=0){ cout << "projectFunctionOntoBasis: failed to solve with error " << info << endl; } if (equilibrated) { int successLocal = solver.UnequilibrateLHS(); if (successLocal != 0) { cout << "projection: unequilibration FAILED with error: " << successLocal << endl; } } for (int i=0;i<numDofs;i++){ basisCoefficients(cellIndex,i) = x(i); } } }
void Projector::projectFunctionOntoBasis(FieldContainer<double> &basisCoefficients, FunctionPtr fxn, BasisPtr basis, BasisCachePtr basisCache, IPPtr ip, VarPtr v, set<int> fieldIndicesToSkip) { CellTopoPtr cellTopo = basis->domainTopology(); DofOrderingPtr dofOrderPtr = Teuchos::rcp(new DofOrdering()); if (! fxn.get()) { TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "fxn cannot be null!"); } int cardinality = basis->getCardinality(); int numCells = basisCache->getPhysicalCubaturePoints().dimension(0); int numDofs = cardinality - fieldIndicesToSkip.size(); if (numDofs==0) { // we're skipping all the fields, so just initialize basisCoefficients to 0 and return basisCoefficients.resize(numCells,cardinality); basisCoefficients.initialize(0); return; } FieldContainer<double> gramMatrix(numCells,cardinality,cardinality); FieldContainer<double> ipVector(numCells,cardinality); // fake a DofOrdering DofOrderingPtr dofOrdering = Teuchos::rcp( new DofOrdering ); if (! basisCache->isSideCache()) { dofOrdering->addEntry(v->ID(), basis, v->rank()); } else { dofOrdering->addEntry(v->ID(), basis, v->rank(), basisCache->getSideIndex()); } ip->computeInnerProductMatrix(gramMatrix, dofOrdering, basisCache); ip->computeInnerProductVector(ipVector, v, fxn, dofOrdering, basisCache); // cout << "physical points for projection:\n" << basisCache->getPhysicalCubaturePoints(); // cout << "gramMatrix:\n" << gramMatrix; // cout << "ipVector:\n" << ipVector; map<int,int> oldToNewIndices; if (fieldIndicesToSkip.size() > 0) { // the code to do with fieldIndicesToSkip might not be terribly efficient... // (but it's not likely to be called too frequently) int i_indices_skipped = 0; for (int i=0; i<cardinality; i++) { int new_index; if (fieldIndicesToSkip.find(i) != fieldIndicesToSkip.end()) { i_indices_skipped++; new_index = -1; } else { new_index = i - i_indices_skipped; } oldToNewIndices[i] = new_index; } FieldContainer<double> gramMatrixFiltered(numCells,numDofs,numDofs); FieldContainer<double> ipVectorFiltered(numCells,numDofs); // now filter out the values that we're to skip for (int cellIndex=0; cellIndex<numCells; cellIndex++) { for (int i=0; i<cardinality; i++) { int i_filtered = oldToNewIndices[i]; if (i_filtered == -1) { continue; } ipVectorFiltered(cellIndex,i_filtered) = ipVector(cellIndex,i); for (int j=0; j<cardinality; j++) { int j_filtered = oldToNewIndices[j]; if (j_filtered == -1) { continue; } gramMatrixFiltered(cellIndex,i_filtered,j_filtered) = gramMatrix(cellIndex,i,j); } } } // cout << "gramMatrixFiltered:\n" << gramMatrixFiltered; // cout << "ipVectorFiltered:\n" << ipVectorFiltered; gramMatrix = gramMatrixFiltered; ipVector = ipVectorFiltered; } for (int cellIndex=0; cellIndex<numCells; cellIndex++){ // TODO: rewrite to take advantage of SerialDenseWrapper... Epetra_SerialDenseSolver solver; Epetra_SerialDenseMatrix A(Copy, &gramMatrix(cellIndex,0,0), gramMatrix.dimension(2), gramMatrix.dimension(2), gramMatrix.dimension(1)); // stride -- fc stores in row-major order (a.o.t. SDM) Epetra_SerialDenseVector b(Copy, &ipVector(cellIndex,0), ipVector.dimension(1)); Epetra_SerialDenseVector x(gramMatrix.dimension(1)); solver.SetMatrix(A); int info = solver.SetVectors(x,b); if (info!=0){ cout << "projectFunctionOntoBasis: failed to SetVectors with error " << info << endl; } bool equilibrated = false; if (solver.ShouldEquilibrate()){ solver.EquilibrateMatrix(); solver.EquilibrateRHS(); equilibrated = true; } info = solver.Solve(); if (info!=0){ cout << "projectFunctionOntoBasis: failed to solve with error " << info << endl; } if (equilibrated) { int successLocal = solver.UnequilibrateLHS(); if (successLocal != 0) { cout << "projection: unequilibration FAILED with error: " << successLocal << endl; } } basisCoefficients.resize(numCells,cardinality); for (int i=0;i<cardinality;i++) { if (fieldIndicesToSkip.size()==0) { basisCoefficients(cellIndex,i) = x(i); } else { int i_filtered = oldToNewIndices[i]; if (i_filtered==-1) { basisCoefficients(cellIndex,i) = 0.0; } else { basisCoefficients(cellIndex,i) = x(i_filtered); } } } } }
void ParametricSurface::basisWeightsForProjectedInterpolant(FieldContainer<double> &basisCoefficients, VectorBasisPtr basis, MeshPtr mesh, int cellID) { vector< ParametricCurvePtr > curves = mesh->parametricEdgesForCell(cellID); Teuchos::RCP<TransfiniteInterpolatingSurface> exactSurface = Teuchos::rcp( new TransfiniteInterpolatingSurface(curves) ); exactSurface->setNeglectVertices(false); FieldContainer<double> edgeInterpolationCoefficients(basis->getCardinality()); basisWeightsForEdgeInterpolant(edgeInterpolationCoefficients, basis, mesh, cellID); set<int> edgeFieldIndices = BasisFactory::basisFactory()->sideFieldIndices(basis,true); // true: include vertex dofs TFunctionPtr<double> edgeInterpolant = Teuchos::rcp( new BasisSumFunction(basis, edgeInterpolationCoefficients) ); IPPtr L2 = Teuchos::rcp( new IP ); // we assume that basis is a vector HGRAD basis VarFactoryPtr vf = VarFactory::varFactory(); VarPtr v = vf->testVar("v", VECTOR_HGRAD); L2->addTerm(v); IPPtr H1 = Teuchos::rcp( new IP ); // H1->addTerm(v); // experiment: seminorm is a norm when the edge dofs are excluded--and this is what LD does H1->addTerm(v->grad()); int maxTestDegree = mesh->getElementType(cellID)->testOrderPtr->maxBasisDegree(); TEUCHOS_TEST_FOR_EXCEPTION(maxTestDegree < 1, std::invalid_argument, "Constant test spaces unsupported."); int cubatureDegree = std::max(maxTestDegree*2,15); // chosen to match that used in edge projection. FieldContainer<double> physicalCellNodes; CellTopoPtr cellTopo = mesh->getElementType(cellID)->cellTopoPtr; if (cellTopo->getDimension() == 2) { physicalCellNodes = mesh->physicalCellNodesForCell(cellID); } if ((cellTopo->getDimension() == 3) && (cellTopo->getTensorialDegree() > 0)) { // then we interpret this as space-time, and we just treat the first temporal side: unsigned temporalSideOrdinal = cellTopo->getTemporalSideOrdinal(0); FieldContainer<double> spaceTimePhysicalNodes = mesh->physicalCellNodesForCell(cellID); int sideDim = cellTopo->getDimension() - 1; int nodeCount = cellTopo->getNodeCount(sideDim, temporalSideOrdinal); physicalCellNodes.resize(1,nodeCount,sideDim); for (int node=0; node<nodeCount; node++) { int spaceTimeNode = cellTopo->getNodeMap(sideDim, temporalSideOrdinal, node); for (int d=0; d<sideDim; d++) { physicalCellNodes(0,node,d) = spaceTimePhysicalNodes(0,spaceTimeNode,d); } } // replace space-time cell topology with the purely spatial one: cellTopo = cellTopo->getSide(temporalSideOrdinal); } BasisCachePtr basisCache = BasisCache::basisCacheForCellTopology(cellTopo, cubatureDegree, physicalCellNodes); // project, skipping edgeNodeFieldIndices: Projector<double>::projectFunctionOntoBasis(basisCoefficients, TFunctionPtr<double>(exactSurface)-edgeInterpolant, basis, basisCache, H1, v, edgeFieldIndices); basisCoefficients.resize(basis->getCardinality()); // get rid of dummy numCells dimension // add the two sets of basis coefficients together for (int i=0; i<edgeInterpolationCoefficients.size(); i++) { basisCoefficients[i] += edgeInterpolationCoefficients[i]; } }
void ParametricSurface::basisWeightsForEdgeInterpolant(FieldContainer<double> &edgeInterpolationCoefficients, VectorBasisPtr basis, MeshPtr mesh, int cellID) { vector< ParametricCurvePtr > curves = mesh->parametricEdgesForCell(cellID); Teuchos::RCP<TransfiniteInterpolatingSurface> exactSurface = Teuchos::rcp( new TransfiniteInterpolatingSurface(curves) ); exactSurface->setNeglectVertices(false); int basisDegree = basis->getDegree(); shards::CellTopology line_2(shards::getCellTopologyData<shards::Line<2> >() ); BasisPtr basis1D = BasisFactory::basisFactory()->getBasis(basisDegree, line_2.getKey(), Camellia::FUNCTION_SPACE_HGRAD); BasisPtr compBasis = basis->getComponentBasis(); int numComponents = basis->getNumComponents(); if (numComponents != 2) { TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Only 2D surfaces supported right now"); } edgeInterpolationCoefficients.resize(basis->getCardinality()); set<int> edgeNodeFieldIndices = BasisFactory::basisFactory()->sideFieldIndices(basis,true); // true: include vertex dofs FieldContainer<double> dofCoords(compBasis->getCardinality(),2); IntrepidBasisWrapper< double, Intrepid::FieldContainer<double> >* intrepidBasisWrapper = dynamic_cast< IntrepidBasisWrapper< double, Intrepid::FieldContainer<double> >* >(compBasis.get()); if (!intrepidBasisWrapper) { TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "compBasis does not appear to be an instance of IntrepidBasisWrapper"); } Basis_HGRAD_QUAD_Cn_FEM<double, Intrepid::FieldContainer<double> >* intrepidBasis = dynamic_cast< Basis_HGRAD_QUAD_Cn_FEM<double, Intrepid::FieldContainer<double> >* >(intrepidBasisWrapper->intrepidBasis().get()); if (!intrepidBasis) { TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "IntrepidBasisWrapper does not appear to wrap Basis_HGRAD_QUAD_Cn_FEM."); } intrepidBasis->getDofCoords(dofCoords); int edgeDim = 1; int vertexDim = 0; // set vertex dofs: for (int vertexIndex=0; vertexIndex<curves.size(); vertexIndex++) { double x = exactSurface->vertices()[vertexIndex].first; double y = exactSurface->vertices()[vertexIndex].second; int compDofOrdinal = compBasis->getDofOrdinal(vertexDim, vertexIndex, 0); int basisDofOrdinal_x = basis->getDofOrdinalFromComponentDofOrdinal(compDofOrdinal, 0); int basisDofOrdinal_y = basis->getDofOrdinalFromComponentDofOrdinal(compDofOrdinal, 1); edgeInterpolationCoefficients[basisDofOrdinal_x] = x; edgeInterpolationCoefficients[basisDofOrdinal_y] = y; } for (int edgeIndex=0; edgeIndex<curves.size(); edgeIndex++) { bool edgeDofsFlipped = edgeIndex >= 2; // because Intrepid's ordering of dofs on the quad is not CCW but tensor-product, we need to flip for the opposite edges // (what makes things worse is that the vertex/edge numbering *is* CCW) if (curves.size() != 4) { cout << "WARNING: have not worked out the rule for flipping or not flipping edge dofs for anything but quads.\n"; } double edgeLength = curves[edgeIndex]->linearLength(); // cout << "edgeIndex " << edgeIndex << endl; for (int comp=0; comp<numComponents; comp++) { FieldContainer<double> basisCoefficients_comp; bool useH1ForEdgeInterpolant = true; // an experiment curves[edgeIndex]->projectionBasedInterpolant(basisCoefficients_comp, basis1D, comp, edgeLength, useH1ForEdgeInterpolant); // cout << "for edge " << edgeIndex << " and comp " << comp << ", projection-based interpolant dofs:\n"; // cout << basisCoefficients_comp; //// cout << "basis dof coords:\n" << dofCoords; // int basisDofOrdinal = basis->getDofOrdinalFromComponentDofOrdinal(v0_dofOrdinal_comp, comp); // edgeInterpolationCoefficients[basisDofOrdinal] = basisCoefficients_comp[v0_dofOrdinal_1D]; if (compBasis->getDegree() >= 2) // then there are some "middle" nodes on the edge { // get the first dofOrdinal for the edge, so we can check the number of edge basis functions int firstEdgeDofOrdinal = compBasis->getDofOrdinal(edgeDim, edgeIndex, 0); // cout << "first edge dofOrdinal: " << firstEdgeDofOrdinal << endl; int numEdgeDofs = compBasis->getDofTag(firstEdgeDofOrdinal)[3]; if (numEdgeDofs != basis1D->getCardinality() - 2) { TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "numEdgeDofs does not match 1D basis cardinality"); } for (int edgeDofOrdinal=0; edgeDofOrdinal<numEdgeDofs; edgeDofOrdinal++) { // determine the index into basisCoefficients_comp: int edgeDofOrdinalIn1DBasis = edgeDofsFlipped ? numEdgeDofs - 1 - edgeDofOrdinal : edgeDofOrdinal; int dofOrdinal1D = basis1D->getDofOrdinal(edgeDim, 0, edgeDofOrdinalIn1DBasis); // determine the ordinal of the edge dof in the component basis: int compDofOrdinal = compBasis->getDofOrdinal(edgeDim, edgeIndex, edgeDofOrdinal); // now, determine its ordinal in the vector basis int basisDofOrdinal = basis->getDofOrdinalFromComponentDofOrdinal(compDofOrdinal, comp); // cout << "edge dof ordinal " << edgeDofOrdinal << " has basis weight " << basisCoefficients_comp[dofOrdinal1D] << " for component " << comp << endl; // cout << "node on cell is at (" << dofCoords(compDofOrdinal,0) << ", " << dofCoords(compDofOrdinal,1) << ")\n"; // cout << "mapping to basisDofOrdinal " << basisDofOrdinal << endl; edgeInterpolationCoefficients[basisDofOrdinal] = basisCoefficients_comp[dofOrdinal1D]; } } } } edgeInterpolationCoefficients.resize(edgeInterpolationCoefficients.size()); // print out a report of what the edge interpolation is doing: /*cout << "projection-based interpolation of edges maps the following points:\n"; for (int compDofOrdinal=0; compDofOrdinal<compBasis->getCardinality(); compDofOrdinal++) { double x_ref = dofCoords(compDofOrdinal,0); double y_ref = dofCoords(compDofOrdinal,1); int basisDofOrdinal_x = basis->getDofOrdinalFromComponentDofOrdinal(compDofOrdinal, 0); int basisDofOrdinal_y = basis->getDofOrdinalFromComponentDofOrdinal(compDofOrdinal, 1); if (edgeNodeFieldIndices.find(basisDofOrdinal_x) != edgeNodeFieldIndices.end()) { double x_phys = edgeInterpolationCoefficients[basisDofOrdinal_x]; double y_phys = edgeInterpolationCoefficients[basisDofOrdinal_y]; cout << "(" << x_ref << ", " << y_ref << ") --> (" << x_phys << ", " << y_phys << ")\n"; } }*/ }
int main(int argc, char *argv[]) { Teuchos::GlobalMPISession mpiSession(&argc, &argv); // This little trick lets us print to std::cout only if // a (dummy) command-line argument is provided. int iprint = argc - 1; Teuchos::RCP<std::ostream> outStream; Teuchos::oblackholestream bhs; // outputs nothing if (iprint > 0) outStream = Teuchos::rcp(&std::cout, false); else outStream = Teuchos::rcp(&bhs, false); // Save the format state of the original std::cout. Teuchos::oblackholestream oldFormatState; oldFormatState.copyfmt(std::cout); *outStream \ << "===============================================================================\n" \ << "| |\n" \ << "| Unit Test (Basis_HGRAD_LINE_Cn_FEM_JACOBI) |\n" \ << "| |\n" \ << "| 1) Conversion of Dof tags into Dof ordinals and back |\n" \ << "| 2) Basis values for VALUE, GRAD, CURL, and Dk operators |\n" \ << "| |\n" \ << "| Questions? Contact Pavel Bochev ([email protected]), |\n" \ << "| Denis Ridzal ([email protected]), |\n" \ << "| Kara Peterson ([email protected]). |\n" \ << "| |\n" \ << "| Intrepid's website: http://trilinos.sandia.gov/packages/intrepid |\n" \ << "| Trilinos website: http://trilinos.sandia.gov |\n" \ << "| |\n" \ << "===============================================================================\n"\ << "| TEST 1: Basis creation, exception testing |\n"\ << "===============================================================================\n"; // Define basis and error flag double alpha = 0.0, beta = 0.0; Basis_HGRAD_LINE_Cn_FEM_JACOBI<double, FieldContainer<double> > lineBasis(5, alpha, beta); int errorFlag = 0; // Initialize throw counter for exception testing int nException = 0; int throwCounter = 0; // Define array containing vertices of the reference Line and a few other points int numIntervals = 100; FieldContainer<double> lineNodes(numIntervals+1, 1); for (int i=0; i<numIntervals+1; i++) { lineNodes(i,0) = -1.0+(2.0*(double)i)/(double)numIntervals; } // Generic array for the output values; needs to be properly resized depending on the operator type FieldContainer<double> vals; try{ // Exceptions 1-5: all bf tags/bf Ids below are wrong and should cause getDofOrdinal() and // getDofTag() to access invalid array elements thereby causing bounds check exception // exception #1 INTREPID_TEST_COMMAND( lineBasis.getDofOrdinal(2,0,0), throwCounter, nException ); // exception #2 INTREPID_TEST_COMMAND( lineBasis.getDofOrdinal(1,1,1), throwCounter, nException ); // exception #3 INTREPID_TEST_COMMAND( lineBasis.getDofOrdinal(1,0,7), throwCounter, nException ); // not an exception INTREPID_TEST_COMMAND( lineBasis.getDofOrdinal(1,0,5), throwCounter, nException ); --nException; // exception #4 INTREPID_TEST_COMMAND( lineBasis.getDofTag(6), throwCounter, nException ); // exception #5 INTREPID_TEST_COMMAND( lineBasis.getDofTag(-1), throwCounter, nException ); // not an exception INTREPID_TEST_COMMAND( lineBasis.getDofTag(5), throwCounter, nException ); --nException; #ifdef HAVE_INTREPID_DEBUG // Exceptions 6-16 test exception handling with incorrectly dimensioned input/output arrays // exception #6: input points array must be of rank-2 FieldContainer<double> badPoints1(4, 5, 3); INTREPID_TEST_COMMAND( lineBasis.getValues(vals, badPoints1, OPERATOR_VALUE), throwCounter, nException ); // exception #7: dimension 1 in the input point array must equal space dimension of the cell FieldContainer<double> badPoints2(4, 3); INTREPID_TEST_COMMAND( lineBasis.getValues(vals, badPoints2, OPERATOR_VALUE), throwCounter, nException ); // exception #8: output values must be of rank-2 for OPERATOR_VALUE FieldContainer<double> badVals1(4, 3, 1); INTREPID_TEST_COMMAND( lineBasis.getValues(badVals1, lineNodes, OPERATOR_VALUE), throwCounter, nException ); // exception #9: output values must be of rank-3 for OPERATOR_GRAD FieldContainer<double> badVals2(4, 3); INTREPID_TEST_COMMAND( lineBasis.getValues(badVals2, lineNodes, OPERATOR_GRAD), throwCounter, nException ); // exception #10: output values must be of rank-3 for OPERATOR_CURL INTREPID_TEST_COMMAND( lineBasis.getValues(badVals2, lineNodes, OPERATOR_CURL), throwCounter, nException ); // exception #11: output values must be of rank-2 for OPERATOR_DIV INTREPID_TEST_COMMAND( lineBasis.getValues(badVals2, lineNodes, OPERATOR_DIV), throwCounter, nException ); // exception #12: output values must be of rank-2 for OPERATOR_D1 INTREPID_TEST_COMMAND( lineBasis.getValues(badVals2, lineNodes, OPERATOR_D1), throwCounter, nException ); // exception #13: incorrect 0th dimension of output array (must equal number of basis functions) FieldContainer<double> badVals3(lineBasis.getCardinality() + 1, lineNodes.dimension(0)); INTREPID_TEST_COMMAND( lineBasis.getValues(badVals3, lineNodes, OPERATOR_VALUE), throwCounter, nException ); // exception #14: incorrect 1st dimension of output array (must equal number of points) FieldContainer<double> badVals4(lineBasis.getCardinality(), lineNodes.dimension(0) + 1); INTREPID_TEST_COMMAND( lineBasis.getValues(badVals4, lineNodes, OPERATOR_VALUE), throwCounter, nException ); // exception #15: incorrect 2nd dimension of output array (must equal spatial dimension) FieldContainer<double> badVals5(lineBasis.getCardinality(), lineNodes.dimension(0), 2); INTREPID_TEST_COMMAND( lineBasis.getValues(badVals5, lineNodes, OPERATOR_GRAD), throwCounter, nException ); // not an exception FieldContainer<double> goodVals2(lineBasis.getCardinality(), lineNodes.dimension(0)); INTREPID_TEST_COMMAND( lineBasis.getValues(goodVals2, lineNodes, OPERATOR_VALUE), throwCounter, nException ); --nException; #endif } catch (std::logic_error err) { *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n"; *outStream << err.what() << '\n'; *outStream << "-------------------------------------------------------------------------------" << "\n\n"; errorFlag = -1000; }; // Check if number of thrown exceptions matches the one we expect if (throwCounter != nException) { errorFlag++; *outStream << std::setw(70) << "FAILURE! Incorrect number of exceptions." << "\n"; } *outStream \ << "\n" << "===============================================================================\n"\ << "| TEST 3: orthogonality of basis functions |\n"\ << "===============================================================================\n"; outStream -> precision(20); try { // Check orthogonality property for Legendre polynomials. int maxorder = 10; DefaultCubatureFactory<double> cubFactory; // create factory shards::CellTopology line(shards::getCellTopologyData< shards::Line<> >()); // create cell topology for (int ordi=0; ordi < maxorder; ordi++) { //create left basis Teuchos::RCP<Basis<double,FieldContainer<double> > > lineBasisLeft = Teuchos::rcp(new Basis_HGRAD_LINE_Cn_FEM_JACOBI<double,FieldContainer<double> >(ordi) ); for (int ordj=0; ordj < maxorder; ordj++) { //create right basis Teuchos::RCP<Basis<double,FieldContainer<double> > > lineBasisRight = Teuchos::rcp(new Basis_HGRAD_LINE_Cn_FEM_JACOBI<double,FieldContainer<double> >(ordj) ); // get cubature points and weights Teuchos::RCP<Cubature<double> > lineCub = cubFactory.create(line, ordi+ordj); int numPoints = lineCub->getNumPoints(); FieldContainer<double> cubPoints (numPoints, lineCub->getDimension()); FieldContainer<double> cubWeights(numPoints); FieldContainer<double> cubWeightsC(1, numPoints); lineCub->getCubature(cubPoints, cubWeights); // "reshape" weights for (int i=0; i<numPoints; i++) { cubWeightsC(0,i) = cubWeights(i); } // get basis values int numFieldsLeft = lineBasisLeft ->getCardinality(); int numFieldsRight = lineBasisRight->getCardinality(); FieldContainer<double> valsLeft(numFieldsLeft,numPoints), valsRight(numFieldsRight,numPoints); lineBasisLeft ->getValues(valsLeft, cubPoints, OPERATOR_VALUE); lineBasisRight->getValues(valsRight, cubPoints, OPERATOR_VALUE); // reshape by cloning and integrate FieldContainer<double> valsLeftC(1, numFieldsLeft,numPoints), valsRightC(1, numFieldsRight,numPoints), massMatrix(1, numFieldsLeft, numFieldsRight); ArrayTools::cloneFields<double>(valsLeftC, valsLeft); ArrayTools::cloneFields<double>(valsRightC, valsRight); ArrayTools::scalarMultiplyDataField<double>(valsRightC, cubWeightsC, valsRightC); FunctionSpaceTools::integrate<double>(massMatrix, valsLeftC, valsRightC, COMP_CPP); // check orthogonality property for (int i=0; i<numFieldsLeft; i++) { for (int j=0; j<numFieldsRight; j++) { if (i==j) { if ( std::abs(massMatrix(0,i,j)-(double)(2.0/(2.0*j+1.0))) > INTREPID_TOL ) { *outStream << "Incorrect ii (\"diagonal\") value for i=" << i << ", j=" << j << ": " << massMatrix(0,i,j) << " != " << "2/(2*" << j << "+1)\n\n"; errorFlag++; } } else { if ( std::abs(massMatrix(0,i,j)) > INTREPID_TOL ) { *outStream << "Incorrect ij (\"off-diagonal\") value for i=" << i << ", j=" << j << ": " << massMatrix(0,i,j) << " != " << "0\n\n"; errorFlag++; } } } } } } } // Catch unexpected errors catch (std::logic_error err) { *outStream << err.what() << "\n\n"; errorFlag = -1000; }; *outStream \ << "\n" << "===============================================================================\n"\ << "| TEST 4: correctness of basis function derivatives |\n"\ << "===============================================================================\n"; outStream -> precision(20); // function values stored by bf, then pt double basisValues[] = { 1.000000000000000, 1.000000000000000, 1.000000000000000, \ 1.000000000000000, -1.000000000000000, -0.3333333333333333, \ 0.3333333333333333, 1.000000000000000, 1.000000000000000, \ -0.3333333333333333, -0.3333333333333333, 1.000000000000000, \ -1.000000000000000, 0.4074074074074074, -0.4074074074074074, \ 1.000000000000000}; double basisD1Values[] = {0, 0, 0, 0, 1.000000000000000, 1.000000000000000, 1.000000000000000, \ 1.000000000000000, -3.000000000000000, -1.000000000000000, \ 1.000000000000000, 3.000000000000000, 6.000000000000000, \ -0.6666666666666667, -0.6666666666666667, 6.000000000000000}; double basisD2Values[] = {0, 0, 0, 0, 0, 0, 0, 0, 3.000000000000000, 3.000000000000000, \ 3.000000000000000, 3.000000000000000, -15.00000000000000, \ -5.000000000000000, 5.000000000000000, 15.00000000000000}; double basisD3Values[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15.00000000000000, \ 15.00000000000000, 15.00000000000000, 15.00000000000000}; try { Basis_HGRAD_LINE_Cn_FEM_JACOBI<double, FieldContainer<double> > lineBasis3(3, alpha, beta); int numIntervals = 3; FieldContainer<double> lineNodes3(numIntervals+1, 1); FieldContainer<double> vals; for (int i=0; i<numIntervals+1; i++) { lineNodes3(i,0) = -1.0+(2.0*(double)i)/(double)numIntervals; } int numFields = lineBasis3.getCardinality(); int numPoints = lineNodes3.dimension(0); // test basis values vals.resize(numFields, numPoints); lineBasis3.getValues(vals,lineNodes3,OPERATOR_VALUE); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { // Compute offset for (F,P) container int l = j + i * numPoints; if (std::abs(vals(i,j) - basisValues[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " "; *outStream << "} computed value: " << vals(i,j) << " but reference value: " << basisValues[l] << "\n"; } } } // test basis derivatives vals.resize(numFields, numPoints,1); lineBasis3.getValues(vals,lineNodes3,OPERATOR_D1); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { // Compute offset for (F,P) container int l = j + i * numPoints; if (std::abs(vals(i,j,0) - basisD1Values[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " "; *outStream << "} computed value: " << vals(i,j,0) << " but reference value: " << basisD1Values[l] << "\n"; } } } vals.resize(numFields, numPoints,1); lineBasis3.getValues(vals,lineNodes3,OPERATOR_D2); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { // Compute offset for (F,P) container int l = j + i * numPoints; if (std::abs(vals(i,j,0) - basisD2Values[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " "; *outStream << "} computed value: " << vals(i,j,0) << " but reference value: " << basisD2Values[l] << "\n"; } } } vals.resize(numFields, numPoints,1); lineBasis3.getValues(vals,lineNodes3,OPERATOR_D3); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { // Compute offset for (F,P) container int l = j + i * numPoints; if (std::abs(vals(i,j,0) - basisD3Values[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " "; *outStream << "} computed value: " << vals(i,j,0) << " but reference value: " << basisD3Values[l] << "\n"; } } } } // Catch unexpected errors catch (std::logic_error err) { *outStream << err.what() << "\n\n"; errorFlag = -1000; }; if (errorFlag != 0) std::cout << "End Result: TEST FAILED\n"; else std::cout << "End Result: TEST PASSED\n"; // reset format state of std::cout std::cout.copyfmt(oldFormatState); return errorFlag; }
int main(int argc, char *argv[]) { Teuchos::GlobalMPISession mpiSession(&argc, &argv); // This little trick lets us print to std::cout only if // a (dummy) command-line argument is provided. int iprint = argc - 1; Teuchos::RCP<std::ostream> outStream; Teuchos::oblackholestream bhs; // outputs nothing if (iprint > 0) outStream = Teuchos::rcp(&std::cout, false); else outStream = Teuchos::rcp(&bhs, false); // Save the format state of the original std::cout. Teuchos::oblackholestream oldFormatState; oldFormatState.copyfmt(std::cout); *outStream \ << "===============================================================================\n" \ << "| |\n" \ << "| Unit Test (Basis_HCURL_HEX_In_FEM) |\n" \ << "| |\n" \ << "| 1) Conversion of Dof tags into Dof ordinals and back |\n" \ << "| 2) Basis values for VALUE and CURL operators |\n" \ << "| |\n" \ << "| Questions? Contact Pavel Bochev ([email protected]), |\n" \ << "| Denis Ridzal ([email protected]), |\n" \ << "| Kara Peterson ([email protected]). |\n" \ << "| |\n" \ << "| Intrepid's website: http://trilinos.sandia.gov/packages/intrepid |\n" \ << "| Trilinos website: http://trilinos.sandia.gov |\n" \ << "| |\n" \ << "===============================================================================\n"\ << "| TEST 1: Basis creation, exception testing |\n"\ << "===============================================================================\n"; // Define basis and error flag const int deg = 1; shards::CellTopology line(shards::getCellTopologyData< shards::Line<> >()); FieldContainer<double> closedPts(PointTools::getLatticeSize(line,deg),1); FieldContainer<double> openPts(PointTools::getLatticeSize(line,deg+1,1),1); PointTools::getLattice<double,FieldContainer<double> >(closedPts,line,deg); PointTools::getLattice<double,FieldContainer<double> >(openPts,line,deg+1,1); Basis_HCURL_HEX_In_FEM<double, FieldContainer<double> > hexBasis(deg,closedPts,openPts); int errorFlag = 0; // Initialize throw counter for exception testing int nException = 0; int throwCounter = 0; // Define array containing the 8 vertices of the reference HEX, its center and 6 face centers FieldContainer<double> hexNodes(8, 3); hexNodes(0,0) = -1.0; hexNodes(0,1) = -1.0; hexNodes(0,2) = -1.0; hexNodes(1,0) = 1.0; hexNodes(1,1) = -1.0; hexNodes(1,2) = -1.0; hexNodes(2,0) = -1.0; hexNodes(2,1) = 1.0; hexNodes(2,2) = -1.0; hexNodes(3,0) = 1.0; hexNodes(3,1) = 1.0; hexNodes(3,2) = -1.0; hexNodes(4,0) = -1.0; hexNodes(4,1) = -1.0; hexNodes(4,2) = 1.0; hexNodes(5,0) = 1.0; hexNodes(5,1) = -1.0; hexNodes(5,2) = 1.0; hexNodes(6,0) = -1.0; hexNodes(6,1) = 1.0; hexNodes(6,2) = 1.0; hexNodes(7,0) = 1.0; hexNodes(7,1) = 1.0; hexNodes(7,2) = 1.0; // Generic array for the output values; needs to be properly resized depending on the operator type FieldContainer<double> vals; try{ // exception #1: GRAD cannot be applied to HCURL functions // resize vals to rank-3 container with dimensions (num. basis functions, num. points, arbitrary) vals.resize(hexBasis.getCardinality(), hexNodes.dimension(0), 4 ); INTREPID_TEST_COMMAND( hexBasis.getValues(vals, hexNodes, OPERATOR_GRAD), throwCounter, nException ); // exception #2: DIV cannot be applied to HCURL functions // resize vals to rank-2 container with dimensions (num. points, num. basis functions) vals.resize(hexBasis.getCardinality(), hexNodes.dimension(0) ); INTREPID_TEST_COMMAND( hexBasis.getValues(vals, hexNodes, OPERATOR_DIV), throwCounter, nException ); // Exceptions 3-7: all bf tags/bf Ids below are wrong and should cause getDofOrdinal() and // getDofTag() to access invalid array elements thereby causing bounds check exception // exception #3 INTREPID_TEST_COMMAND( hexBasis.getDofOrdinal(3,0,0), throwCounter, nException ); // exception #4 INTREPID_TEST_COMMAND( hexBasis.getDofOrdinal(1,1,1), throwCounter, nException ); // exception #5 INTREPID_TEST_COMMAND( hexBasis.getDofOrdinal(0,4,1), throwCounter, nException ); // exception #6 INTREPID_TEST_COMMAND( hexBasis.getDofTag(12), throwCounter, nException ); // exception #7 INTREPID_TEST_COMMAND( hexBasis.getDofTag(-1), throwCounter, nException ); #ifdef HAVE_INTREPID_DEBUG // Exceptions 8-15 test exception handling with incorrectly dimensioned input/output arrays // exception #8: input points array must be of rank-2 FieldContainer<double> badPoints1(4, 5, 3); INTREPID_TEST_COMMAND( hexBasis.getValues(vals, badPoints1, OPERATOR_VALUE), throwCounter, nException ); // exception #9 dimension 1 in the input point array must equal space dimension of the cell FieldContainer<double> badPoints2(4, 2); INTREPID_TEST_COMMAND( hexBasis.getValues(vals, badPoints2, OPERATOR_VALUE), throwCounter, nException ); // exception #10 output values must be of rank-3 for OPERATOR_VALUE FieldContainer<double> badVals1(4, 3); INTREPID_TEST_COMMAND( hexBasis.getValues(badVals1, hexNodes, OPERATOR_VALUE), throwCounter, nException ); // exception #11 output values must be of rank-3 for OPERATOR_CURL INTREPID_TEST_COMMAND( hexBasis.getValues(badVals1, hexNodes, OPERATOR_CURL), throwCounter, nException ); // exception #12 incorrect 0th dimension of output array (must equal number of basis functions) FieldContainer<double> badVals2(hexBasis.getCardinality() + 1, hexNodes.dimension(0), 3); INTREPID_TEST_COMMAND( hexBasis.getValues(badVals2, hexNodes, OPERATOR_VALUE), throwCounter, nException ) ; // exception #13 incorrect 1st dimension of output array (must equal number of points) FieldContainer<double> badVals3(hexBasis.getCardinality(), hexNodes.dimension(0) + 1, 3); INTREPID_TEST_COMMAND( hexBasis.getValues(badVals3, hexNodes, OPERATOR_VALUE), throwCounter, nException ) ; // exception #14: incorrect 2nd dimension of output array (must equal the space dimension) FieldContainer<double> badVals4(hexBasis.getCardinality(), hexNodes.dimension(0), 4); INTREPID_TEST_COMMAND( hexBasis.getValues(badVals4, hexNodes, OPERATOR_VALUE), throwCounter, nException ) ; // exception #15: incorrect 2nd dimension of output array (must equal the space dimension) INTREPID_TEST_COMMAND( hexBasis.getValues(badVals4, hexNodes, OPERATOR_CURL), throwCounter, nException ) ; // exception #16: D2 cannot be applied to HCURL functions // resize vals to rank-3 container with dimensions (num. basis functions, num. points, arbitrary) vals.resize(hexBasis.getCardinality(), hexNodes.dimension(0), Intrepid2::getDkCardinality(OPERATOR_D2, hexBasis.getBaseCellTopology().getDimension())); INTREPID_TEST_COMMAND( hexBasis.getValues(vals, hexNodes, OPERATOR_D2), throwCounter, nException ); #endif } catch (std::logic_error err) { *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n"; *outStream << err.what() << '\n'; *outStream << "-------------------------------------------------------------------------------" << "\n\n"; errorFlag = -1000; }; // Check if number of thrown exceptions matches the one we expect // Note Teuchos throw number will not pick up exceptions 3-7 and therefore will not match. if (throwCounter != nException) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; } //#endif *outStream \ << "\n" << "===============================================================================\n"\ << "| TEST 2: correctness of tag to enum and enum to tag lookups |\n"\ << "===============================================================================\n"; try{ std::vector<std::vector<int> > allTags = hexBasis.getAllDofTags(); // Loop over all tags, lookup the associated dof enumeration and then lookup the tag again for (unsigned i = 0; i < allTags.size(); i++) { int bfOrd = hexBasis.getDofOrdinal(allTags[i][0], allTags[i][1], allTags[i][2]); // for (unsigned j=0;j<4;j++) std::cout << allTags[i][j] << " "; std::cout << std::endl; std::vector<int> myTag = hexBasis.getDofTag(bfOrd); if( !( (myTag[0] == allTags[i][0]) && (myTag[1] == allTags[i][1]) && (myTag[2] == allTags[i][2]) && (myTag[3] == allTags[i][3]) ) ) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; *outStream << " getDofOrdinal( {" << allTags[i][0] << ", " << allTags[i][1] << ", " << allTags[i][2] << ", " << allTags[i][3] << "}) = " << bfOrd <<" but \n"; *outStream << " getDofTag(" << bfOrd << ") = { " << myTag[0] << ", " << myTag[1] << ", " << myTag[2] << ", " << myTag[3] << "}\n"; } } // Now do the same but loop over basis functions for( int bfOrd = 0; bfOrd < hexBasis.getCardinality(); bfOrd++) { std::vector<int> myTag = hexBasis.getDofTag(bfOrd); int myBfOrd = hexBasis.getDofOrdinal(myTag[0], myTag[1], myTag[2]); if( bfOrd != myBfOrd) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; *outStream << " getDofTag(" << bfOrd << ") = { " << myTag[0] << ", " << myTag[1] << ", " << myTag[2] << ", " << myTag[3] << "} but getDofOrdinal({" << myTag[0] << ", " << myTag[1] << ", " << myTag[2] << ", " << myTag[3] << "} ) = " << myBfOrd << "\n"; } } } catch (std::logic_error err){ *outStream << err.what() << "\n\n"; errorFlag = -1000; }; *outStream \ << "\n" << "===============================================================================\n"\ << "| TEST 3: correctness of basis function values |\n"\ << "===============================================================================\n"; outStream -> precision(20); // VALUE: Each row pair gives the 12x3 correct basis set values at an evaluation point: (P,F,D) layout double basisValues[] = { 1,0,0, 1,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 1,0,0, 1,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 1,0,0, 1,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 1,0,0, 1,0,0, 0,1,0, 0,0,0, 0,1,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,1,0, 0,0,0, 0,1,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,1,0, 0,0,0, 0,1,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,1,0, 0,0,0, 0,1,0, 0,0,1, 0,0,0, 0,0,0, 0,0,0, 0,0,1, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,1, 0,0,0, 0,0,0, 0,0,0, 0,0,1, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,1, 0,0,0, 0,0,0, 0,0,0, 0,0,1, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,1, 0,0,0, 0,0,0, 0,0,0, 0,0,1 }; // CURL double basisCurls[] = { 0,-0.5,0.5, 0,-0.5,0.5, 0,0,0.5, 0,0,0.5, 0,-0.5,0, 0,-0.5,0, 0,0,0, 0,0,0, 0,0,-0.5, 0,0,-0.5, 0,-0.5,-0.5, 0,-0.5,-0.5, 0,0,0, 0,0,0, 0,-0.5,0, 0,-0.5,0, 0,0.5,0, 0,0.5,0, 0,0,0, 0,0,0, 0,0.5,0.5, 0,0.5,0.5, 0,0,0.5, 0,0,0.5, 0,0,0, 0,0,0, 0,0.5,0, 0,0.5,0, 0,0,-0.5, 0,0,-0.5, 0,0.5,-0.5, 0,0.5,-0.5, // y-component basis functions // first y-component bf is (0,1/4(1-x)(1-z),0) // curl is (1/4(1-x),0,-1/4(1-z)) 0.5,0,-0.5, 0,0,-0.5, 0.5,0,-0.5, 0,0,-0.5, 0.5,0,0, 0,0,0, 0.5,0,0, 0,0,0, // second y-component bf is (0,1/4(1+x)(1-z),0) // curl is (1/4(1+x),0,1/4(1-z)) 0,0,0.5, 0.5,0,0.5, 0,0,0.5, 0.5,0,0.5, 0,0,0, 0.5,0,0, 0,0,0, 0.5,0,0, // third y-component bf is (0,1/4(1-x)(1+z),0) // curl is (-1/4(1-x),0,-1/4(1+z)) -0.5,0,0, 0,0,0, -0.5,0,0, 0,0,0, -0.5,0,-0.5, 0,0,-0.5, -0.5,0,-0.5, 0,0,-0.5, // fourth y-component bf is (0,1/4(1+x)(1+z),0) // curl is (-1/4(1+x),0,1/4(1+z)) 0.0,0,0, -0.5,0,0, 0.0,0,0, -0.5,0,0, 0.0,0,0.5, -0.5,0,0.5, 0.0,0,0.5, -0.5,0,0.5, // first z-component bf is (0,0,1/4(1-x)(1-y)) // curl is (-1/4(1-x),1/4(1-y),0) -0.5,0.5,0, 0,0.5,0, -0.5,0,0, 0,0,0, -0.5,0.5,0, 0,0.5,0, -0.5,0,0, 0,0,0, // second z-component bf is (0,0,1/4(1+x)(1-y)) // curl is (-1/4(1+x),1/4(1-y),0) 0.0,-0.5,0, -0.5,-0.5,0, 0,0,0, -0.5,0,0, 0,-0.5,0, -0.5,-0.5,0, 0,0,0, -0.5,0,0, // third z-component bf is (0,0,1/4(1-x)(1+y)) // curl is (1/4(1-x),1/4(1+y),0) 0.5,0,0, 0,0,0, 0.5,0.5,0, 0,0.5,0, 0.5,0,0, 0,0,0, 0.5,0.5,0, 0,0.5,0, // fourth z-component bf is (0,0,1/4(1+x)(1+y)) // curl is (1/4(1+x),-1/4(1+y),0) 0,0,0, 0.5,0,0, 0,-0.5,0, 0.5,-0.5,0, 0,0,0, 0.5,0,0, 0,-0.5,0, 0.5,-0.5,0 }; try{ // Dimensions for the output arrays: int numFields = hexBasis.getCardinality(); int numPoints = hexNodes.dimension(0); int spaceDim = hexBasis.getBaseCellTopology().getDimension(); // Generic array for values and curls that will be properly sized before each call FieldContainer<double> vals; // Check VALUE of basis functions: resize vals to rank-3 container: vals.resize(numFields, numPoints, spaceDim); hexBasis.getValues(vals, hexNodes, OPERATOR_VALUE); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { for (int k = 0; k < spaceDim; k++) { // compute offset for (P,F,D) data layout: indices are P->j, F->i, D->k int l = k + i * spaceDim * numPoints + j * spaceDim; if (std::abs(vals(i,j,k) - basisValues[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " ";*outStream << k << " "; *outStream << "} computed value: " << vals(i,j,k) << " but reference value: " << basisValues[l] << "\n"; } } } } // Check CURL of basis function: resize vals to rank-3 container vals.resize(numFields, numPoints, spaceDim); hexBasis.getValues(vals, hexNodes, OPERATOR_CURL); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { for (int k = 0; k < spaceDim; k++) { // compute offset for (P,F,D) data layout: indices are P->j, F->i, D->k int l = k + i * spaceDim * numPoints + j * spaceDim; if (std::abs(vals(i,j,k) - basisCurls[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " ";*outStream << k << " "; *outStream << "} computed curl component: " << vals(i,j,k) << " but reference curl component: " << basisCurls[l] << "\n"; } } } } } // Catch unexpected errors catch (std::logic_error err) { *outStream << err.what() << "\n\n"; errorFlag = -1000; }; if (errorFlag != 0) std::cout << "End Result: TEST FAILED\n"; else std::cout << "End Result: TEST PASSED\n"; // reset format state of std::cout std::cout.copyfmt(oldFormatState); return errorFlag; }
int main(int argc, char *argv[]) { Teuchos::GlobalMPISession mpiSession(&argc, &argv); // This little trick lets us print to std::cout only if // a (dummy) command-line argument is provided. int iprint = argc - 1; Teuchos::RCP<std::ostream> outStream; Teuchos::oblackholestream bhs; // outputs nothing if (iprint > 0) outStream = Teuchos::rcp(&std::cout, false); else outStream = Teuchos::rcp(&bhs, false); // Save the format state of the original std::cout. Teuchos::oblackholestream oldFormatState; oldFormatState.copyfmt(std::cout); *outStream \ << "===============================================================================\n" \ << "| |\n" \ << "| Unit Test (Basis_HGRAD_WEDGE_C2_FEM) |\n" \ << "| |\n" \ << "| 1) Conversion of Dof tags into Dof ordinals and back |\n" \ << "| 2) Basis values for VALUE, GRAD, and Dk operators |\n" \ << "| |\n" \ << "| Questions? Contact Pavel Bochev ([email protected]), |\n" \ << "| Denis Ridzal ([email protected]), |\n" \ << "| Kara Peterson ([email protected]). |\n" \ << "| |\n" \ << "| Intrepid's website: http://trilinos.sandia.gov/packages/intrepid |\n" \ << "| Trilinos website: http://trilinos.sandia.gov |\n" \ << "| |\n" \ << "===============================================================================\n"\ << "| TEST 1: Basis creation, exception testing |\n"\ << "===============================================================================\n"; // Define basis and error flag Basis_HGRAD_WEDGE_C2_FEM<double, FieldContainer<double> > wedgeBasis; int errorFlag = 0; // Initialize throw counter for exception testing int nException = 0; int throwCounter = 0; // Nodes of Wedde<18>: vertices, edge midpoints, Quadrilateral face centers FieldContainer<double> wedgeNodes(18, 3); wedgeNodes(0,0) = 0.0; wedgeNodes(0,1) = 0.0; wedgeNodes(0,2) = -1.0; wedgeNodes(1,0) = 1.0; wedgeNodes(1,1) = 0.0; wedgeNodes(1,2) = -1.0; wedgeNodes(2,0) = 0.0; wedgeNodes(2,1) = 1.0; wedgeNodes(2,2) = -1.0; wedgeNodes(3,0) = 0.0; wedgeNodes(3,1) = 0.0; wedgeNodes(3,2) = 1.0; wedgeNodes(4,0) = 1.0; wedgeNodes(4,1) = 0.0; wedgeNodes(4,2) = 1.0; wedgeNodes(5,0) = 0.0; wedgeNodes(5,1) = 1.0; wedgeNodes(5,2) = 1.0; wedgeNodes(6,0) = 0.5; wedgeNodes(6,1) = 0.0; wedgeNodes(6,2) = -1.0; wedgeNodes(7,0) = 0.5; wedgeNodes(7,1) = 0.5; wedgeNodes(7,2) = -1.0; wedgeNodes(8,0) = 0.0; wedgeNodes(8,1) = 0.5; wedgeNodes(8,2) = -1.0; wedgeNodes(9,0) = 0.0; wedgeNodes(9,1) = 0.0; wedgeNodes(9,2) = 0.0; wedgeNodes(10,0)= 1.0; wedgeNodes(10,1)= 0.0; wedgeNodes(10,2)= 0.0; wedgeNodes(11,0)= 0.0; wedgeNodes(11,1)= 1.0; wedgeNodes(11,2)= 0.0; wedgeNodes(12,0)= 0.5; wedgeNodes(12,1)= 0.0; wedgeNodes(12,2)= 1.0; wedgeNodes(13,0)= 0.5; wedgeNodes(13,1)= 0.5; wedgeNodes(13,2)= 1.0; wedgeNodes(14,0)= 0.0; wedgeNodes(14,1)= 0.5; wedgeNodes(14,2)= 1.0; wedgeNodes(15,0)= 0.5; wedgeNodes(15,1)= 0.0; wedgeNodes(15,2)= 0.0; wedgeNodes(16,0)= 0.5; wedgeNodes(16,1)= 0.5; wedgeNodes(16,2)= 0.0; wedgeNodes(17,0)= 0.0; wedgeNodes(17,1)= 0.5; wedgeNodes(17,2)= 0.0; // Generic array for the output values; needs to be properly resized depending on the operator type FieldContainer<double> vals; try{ // exception #1: CURL cannot be applied to scalar functions // resize vals to rank-3 container with dimensions (num. points, num. basis functions) vals.resize(wedgeBasis.getCardinality(), wedgeNodes.dimension(0), 3 ); INTREPID_TEST_COMMAND( wedgeBasis.getValues(vals, wedgeNodes, OPERATOR_DIV), throwCounter, nException ); // exception #2: DIV cannot be applied to scalar functions // resize vals to rank-2 container with dimensions (num. points, num. basis functions) vals.resize(wedgeBasis.getCardinality(), wedgeNodes.dimension(0) ); INTREPID_TEST_COMMAND( wedgeBasis.getValues(vals, wedgeNodes, OPERATOR_DIV), throwCounter, nException ); // Exceptions 3-7: all bf tags/bf Ids below are wrong and should cause getDofOrdinal() and // getDofTag() to access invalid array elements thereby causing bounds check exception // exception #3 INTREPID_TEST_COMMAND( wedgeBasis.getDofOrdinal(3,0,0), throwCounter, nException ); // exception #4 INTREPID_TEST_COMMAND( wedgeBasis.getDofOrdinal(1,1,1), throwCounter, nException ); // exception #5 INTREPID_TEST_COMMAND( wedgeBasis.getDofOrdinal(0,9,0), throwCounter, nException ); // exception #6 INTREPID_TEST_COMMAND( wedgeBasis.getDofTag(18), throwCounter, nException ); // exception #7 INTREPID_TEST_COMMAND( wedgeBasis.getDofTag(-1), throwCounter, nException ); #ifdef HAVE_INTREPID_DEBUG // Exceptions 8-18 test exception handling with incorrectly dimensioned input/output arrays // exception #8: input points array must be of rank-2 FieldContainer<double> badPoints1(4, 5, 3); INTREPID_TEST_COMMAND( wedgeBasis.getValues(vals, badPoints1, OPERATOR_VALUE), throwCounter, nException ); // exception #9 dimension 1 in the input point array must equal space dimension of the cell FieldContainer<double> badPoints2(4, wedgeBasis.getBaseCellTopology().getDimension() + 1); INTREPID_TEST_COMMAND( wedgeBasis.getValues(vals, badPoints2, OPERATOR_VALUE), throwCounter, nException ); // exception #10 output values must be of rank-2 for OPERATOR_VALUE FieldContainer<double> badVals1(4, 3, 1); INTREPID_TEST_COMMAND( wedgeBasis.getValues(badVals1, wedgeNodes, OPERATOR_VALUE), throwCounter, nException ); // exception #11 output values must be of rank-3 for OPERATOR_GRAD FieldContainer<double> badVals2(4, 3); INTREPID_TEST_COMMAND( wedgeBasis.getValues(badVals2, wedgeNodes, OPERATOR_GRAD), throwCounter, nException ); // exception #12 output values must be of rank-3 for OPERATOR_D1 INTREPID_TEST_COMMAND( wedgeBasis.getValues(badVals2, wedgeNodes, OPERATOR_D1), throwCounter, nException ); // exception #13 output values must be of rank-3 for OPERATOR_D2 INTREPID_TEST_COMMAND( wedgeBasis.getValues(badVals2, wedgeNodes, OPERATOR_D2), throwCounter, nException ); // exception #14 incorrect 0th dimension of output array (must equal number of basis functions) FieldContainer<double> badVals3(wedgeBasis.getCardinality() + 1, wedgeNodes.dimension(0)); INTREPID_TEST_COMMAND( wedgeBasis.getValues(badVals3, wedgeNodes, OPERATOR_VALUE), throwCounter, nException ); // exception #15 incorrect 1st dimension of output array (must equal number of points) FieldContainer<double> badVals4(wedgeBasis.getCardinality(), wedgeNodes.dimension(0) + 1); INTREPID_TEST_COMMAND( wedgeBasis.getValues(badVals4, wedgeNodes, OPERATOR_VALUE), throwCounter, nException ); // exception #16: incorrect 2nd dimension of output array (must equal the space dimension) FieldContainer<double> badVals5(wedgeBasis.getCardinality(), wedgeNodes.dimension(0), wedgeBasis.getBaseCellTopology().getDimension() - 1); INTREPID_TEST_COMMAND( wedgeBasis.getValues(badVals5, wedgeNodes, OPERATOR_GRAD), throwCounter, nException ); // exception #17: incorrect 2nd dimension of output array (must equal D2 cardinality in 3D) FieldContainer<double> badVals6(wedgeBasis.getCardinality(), wedgeNodes.dimension(0), 40); INTREPID_TEST_COMMAND( wedgeBasis.getValues(badVals6, wedgeNodes, OPERATOR_D2), throwCounter, nException ); // exception #18: incorrect 2nd dimension of output array (must equal D3 cardinality in 3D) INTREPID_TEST_COMMAND( wedgeBasis.getValues(badVals6, wedgeNodes, OPERATOR_D3), throwCounter, nException ); #endif } catch (std::logic_error err) { *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n"; *outStream << err.what() << '\n'; *outStream << "-------------------------------------------------------------------------------" << "\n\n"; errorFlag = -1000; }; // Check if number of thrown exceptions matches the one we expect - 18 if (throwCounter != nException) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; } *outStream \ << "\n" << "===============================================================================\n"\ << "| TEST 2: correctness of tag to enum and enum to tag lookups |\n"\ << "===============================================================================\n"; try{ std::vector<std::vector<int> > allTags = wedgeBasis.getAllDofTags(); // Loop over all tags, lookup the associated dof enumeration and then lookup the tag again for (unsigned i = 0; i < allTags.size(); i++) { int bfOrd = wedgeBasis.getDofOrdinal(allTags[i][0], allTags[i][1], allTags[i][2]); std::vector<int> myTag = wedgeBasis.getDofTag(bfOrd); if( !( (myTag[0] == allTags[i][0]) && (myTag[1] == allTags[i][1]) && (myTag[2] == allTags[i][2]) && (myTag[3] == allTags[i][3]) ) ) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; *outStream << " getDofOrdinal( {" << allTags[i][0] << ", " << allTags[i][1] << ", " << allTags[i][2] << ", " << allTags[i][3] << "}) = " << bfOrd <<" but \n"; *outStream << " getDofTag(" << bfOrd << ") = { " << myTag[0] << ", " << myTag[1] << ", " << myTag[2] << ", " << myTag[3] << "}\n"; } } // Now do the same but loop over basis functions for( int bfOrd = 0; bfOrd < wedgeBasis.getCardinality(); bfOrd++) { std::vector<int> myTag = wedgeBasis.getDofTag(bfOrd); int myBfOrd = wedgeBasis.getDofOrdinal(myTag[0], myTag[1], myTag[2]); if( bfOrd != myBfOrd) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; *outStream << " getDofTag(" << bfOrd << ") = { " << myTag[0] << ", " << myTag[1] << ", " << myTag[2] << ", " << myTag[3] << "} but getDofOrdinal({" << myTag[0] << ", " << myTag[1] << ", " << myTag[2] << ", " << myTag[3] << "} ) = " << myBfOrd << "\n"; } } } catch (std::logic_error err){ *outStream << err.what() << "\n\n"; errorFlag = -1000; }; *outStream \ << "\n" << "===============================================================================\n"\ << "| TEST 3: correctness of basis function values |\n"\ << "===============================================================================\n"; outStream -> precision(20); // VALUE: correct basis function values in (F,P) format double basisValues[] = { 1.00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, 1.00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 1.00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 1.00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 1.00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, 1.00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 1.00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 1.00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 1.00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00 }; // GRAD, D1, D2, D3 and D4 test values are stored in files due to their large size std::string fileName; std::ifstream dataFile; // GRAD and D1 values are stored in (F,P,D) format in a data file. Read file and do the test std::vector<double> basisGrads; // Flat array for the gradient values. fileName = "./testdata/WEDGE_C2_GradVals.dat"; dataFile.open(fileName.c_str()); TEST_FOR_EXCEPTION( !dataFile.good(), std::logic_error, ">>> ERROR (HGRAD_WEDGE_C2/test01): could not open GRAD values data file, test aborted."); while (!dataFile.eof() ){ double temp; string line; // string for one line of input file std::getline(dataFile, line); // get next line from file stringstream data_line(line); // convert to stringstream while(data_line >> temp){ // extract value from line basisGrads.push_back(temp); // push into vector } } // It turns out that just closing and then opening the ifstream variable does not reset it // and subsequent open() command fails. One fix is to explicitely clear the ifstream, or // scope the variables. dataFile.close(); dataFile.clear(); //D2: flat array with the values of D2 applied to basis functions. Multi-index is (F,P,D2cardinality) std::vector<double> basisD2; fileName = "./testdata/WEDGE_C2_D2Vals.dat"; dataFile.open(fileName.c_str()); TEST_FOR_EXCEPTION( !dataFile.good(), std::logic_error, ">>> ERROR (HGRAD_WEDGE_C2/test01): could not open D2 values data file, test aborted."); while (!dataFile.eof() ){ double temp; string line; // string for one line of input file std::getline(dataFile, line); // get next line from file stringstream data_line(line); // convert to stringstream while(data_line >> temp){ // extract value from line basisD2.push_back(temp); // push into vector } } dataFile.close(); dataFile.clear(); //D3: flat array with the values of D3 applied to basis functions. Multi-index is (F,P,D3cardinality) std::vector<double> basisD3; fileName = "./testdata/WEDGE_C2_D3Vals.dat"; dataFile.open(fileName.c_str()); TEST_FOR_EXCEPTION( !dataFile.good(), std::logic_error, ">>> ERROR (HGRAD_WEDGE_C2/test01): could not open D3 values data file, test aborted."); while (!dataFile.eof() ){ double temp; string line; // string for one line of input file std::getline(dataFile, line); // get next line from file stringstream data_line(line); // convert to stringstream while(data_line >> temp){ // extract value from line basisD3.push_back(temp); // push into vector } } dataFile.close(); dataFile.clear(); //D4: flat array with the values of D3 applied to basis functions. Multi-index is (F,P,D4cardinality) std::vector<double> basisD4; fileName = "./testdata/WEDGE_C2_D4Vals.dat"; dataFile.open(fileName.c_str()); TEST_FOR_EXCEPTION( !dataFile.good(), std::logic_error, ">>> ERROR (HGRAD_WEDGE_C2/test01): could not open D4 values data file, test aborted."); while (!dataFile.eof() ){ double temp; string line; // string for one line of input file std::getline(dataFile, line); // get next line from file stringstream data_line(line); // convert to stringstream while(data_line >> temp){ // extract value from line basisD4.push_back(temp); // push into vector } } dataFile.close(); dataFile.clear(); try{ // Dimensions for the output arrays: int numFields = wedgeBasis.getCardinality(); int numPoints = wedgeNodes.dimension(0); int spaceDim = wedgeBasis.getBaseCellTopology().getDimension(); // Generic array for values, grads, curls, etc. that will be properly sized before each call FieldContainer<double> vals; // Check VALUE of basis functions: resize vals to rank-2 container: vals.resize(numFields, numPoints); wedgeBasis.getValues(vals, wedgeNodes, OPERATOR_VALUE); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { int l = i + j * numFields; if (std::abs(vals(i,j) - basisValues[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " "; *outStream << "} computed value: " << vals(i,j) << " but reference value: " << basisValues[l] << "\n"; } } } // Check GRAD of basis function: resize vals to rank-3 container vals.resize(numFields, numPoints, spaceDim); wedgeBasis.getValues(vals, wedgeNodes, OPERATOR_GRAD); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { for (int k = 0; k < spaceDim; k++) { // basisGrads is (F,P,D), compute offset: int l = k + j * spaceDim + i * spaceDim * numPoints; if (std::abs(vals(i,j,k) - basisGrads[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " ";*outStream << k << " "; *outStream << "} computed grad component: " << vals(i,j,k) << " but reference grad component: " << basisGrads[l] << "\n"; } } } } // Check D1 of basis function (do not resize vals because it has the correct size: D1 = GRAD) wedgeBasis.getValues(vals, wedgeNodes, OPERATOR_D1); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { for (int k = 0; k < spaceDim; k++) { // basisGrads is (F,P,D), compute offset: int l = k + j * spaceDim + i * spaceDim * numPoints; if (std::abs(vals(i,j,k) - basisGrads[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " ";*outStream << k << " "; *outStream << "} computed D1 component: " << vals(i,j,k) << " but reference D1 component: " << basisGrads[l] << "\n"; } } } } // Check D2 of basis function int D2cardinality = Intrepid::getDkCardinality(OPERATOR_D2, spaceDim); vals.resize(numFields, numPoints, D2cardinality); wedgeBasis.getValues(vals, wedgeNodes, OPERATOR_D2); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { for (int k = 0; k < D2cardinality; k++) { // basisD2 is (F,P,Dk), compute offset: int l = k + j * D2cardinality + i * D2cardinality * numPoints; if (std::abs(vals(i,j,k) - basisD2[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " ";*outStream << k << " "; *outStream << "} computed D2 component: " << vals(i,j,k) << " but reference D2 component: " << basisD2[l] << "\n"; } } } } // Check D3 of basis function int D3cardinality = Intrepid::getDkCardinality(OPERATOR_D3, spaceDim); vals.resize(numFields, numPoints, D3cardinality); wedgeBasis.getValues(vals, wedgeNodes, OPERATOR_D3); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { for (int k = 0; k < D3cardinality; k++) { // basisD3 is (F,P,Dk), compute offset: int l = k + j * D3cardinality + i * D3cardinality * numPoints; if (std::abs(vals(i,j,k) - basisD3[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " ";*outStream << k << " "; *outStream << "} computed D3 component: " << vals(i,j,k) << " but reference D3 component: " << basisD3[l] << "\n"; } } } } // Check D4 of basis function int D4cardinality = Intrepid::getDkCardinality(OPERATOR_D4, spaceDim); vals.resize(numFields, numPoints, D4cardinality); wedgeBasis.getValues(vals, wedgeNodes, OPERATOR_D4); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { for (int k = 0; k < D4cardinality; k++) { // basisD4 is (F,P,Dk), compute offset: int l = k + j * D4cardinality + i * D4cardinality * numPoints; if (std::abs(vals(i,j,k) - basisD4[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " ";*outStream << k << " "; *outStream << "} computed D4 component: " << vals(i,j,k) << " but reference D4 component: " << basisD2[l] << "\n"; } } } } // Check all higher derivatives - must be zero. for(EOperator op = OPERATOR_D5; op < OPERATOR_MAX; op++) { // The last dimension is the number of kth derivatives and needs to be resized for every Dk int DkCardin = Intrepid::getDkCardinality(op, spaceDim); vals.resize(numFields, numPoints, DkCardin); wedgeBasis.getValues(vals, wedgeNodes, op); for (int i = 0; i < vals.size(); i++) { if (std::abs(vals[i]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Get the multi-index of the value where the error is and the operator order std::vector<int> myIndex; vals.getMultiIndex(myIndex,i); int ord = Intrepid::getOperatorOrder(op); *outStream << " At multi-index { "; for(int j = 0; j < vals.rank(); j++) { *outStream << myIndex[j] << " "; } *outStream << "} computed D"<< ord <<" component: " << vals[i] << " but reference D" << ord << " component: 0 \n"; } } } } // Catch unexpected errors catch (std::logic_error err) { *outStream << err.what() << "\n\n"; errorFlag = -1000; }; if (errorFlag != 0) std::cout << "End Result: TEST FAILED\n"; else std::cout << "End Result: TEST PASSED\n"; // reset format state of std::cout std::cout.copyfmt(oldFormatState); return errorFlag; }
int main(int argc, char *argv[]) { Teuchos::GlobalMPISession mpiSession(&argc, &argv); typedef CellTools<double> CellTools; typedef RealSpaceTools<double> RealSpaceTools; typedef shards::CellTopology CellTopology; std::cout \ << "===============================================================================\n" \ << "| |\n" \ << "| Example use of the CellTools class |\n" \ << "| |\n" \ << "| 1) Computation of face flux, for a given vector field, on a face workset |\n" \ << "| 2) Computation of edge circulation, for a given vector field, on a face |\n" \ << "| workset. |\n" \ << "| |\n" \ << "| Questions? Contact Pavel Bochev ([email protected]) |\n" \ << "| Denis Ridzal ([email protected]), or |\n" \ << "| Kara Peterson ([email protected]) |\n" \ << "| |\n" \ << "| Intrepid's website: http://trilinos.sandia.gov/packages/intrepid |\n" \ << "| Trilinos website: http://trilinos.sandia.gov |\n" \ << "| |\n" \ << "===============================================================================\n"\ << "| EXAMPLE 1: Computation of face flux on a face workset |\n"\ << "===============================================================================\n"; /** Given a vector field u(x,y,z) and a face workset we want to compute the flux of u on every * face in this workset. A face workset is a set of faces that are images of the same reference * face. It is defined by the following items: * 1. cell topology of a parent cell * 2. a set of nodes in physical frame defining the parenct cells in the workset * 3. subcell dimension and ordinal, relative to the reference cell in 1) * * Given a face workset, the key steps to accomplish the task, , are as follows: * 1. Obtain cubature points on workset faces, i.e., in physical frame; * 2. Obtain (non-normalized) face normals at cubature points on workset faces * 3. Evaluate the vector field u(x,y,z) at cubature points on workset faces * 4. Compute dot product of u(x,y,z) and the face normals, times the cubature weights */ /************************************************************************************************* * * Step 0. Face workset comprising of 1 face of a Hexahedron<8> cell * ************************************************************************************************/ // Step 0.a: Specify cell topology of the parent cell CellTopology hexahedron_8( shards::getCellTopologyData<shards::Hexahedron<8> >() ); // Step 0.b: Specify the vertices of the parent Hexahedron<8> cell int worksetSize = 2; int pCellNodeCount = hexahedron_8.getVertexCount(); int pCellDim = hexahedron_8.getDimension(); FieldContainer<double> hexNodes(worksetSize, pCellNodeCount, pCellDim); // cell 0 bottom face vertices: hexNodes(0, 0, 0) = 0.00; hexNodes(0, 0, 1) = 0.00, hexNodes(0, 0, 2) = 0.00; hexNodes(0, 1, 0) = 1.00; hexNodes(0, 1, 1) = 0.00, hexNodes(0, 1, 2) = 0.00; hexNodes(0, 2, 0) = 1.00; hexNodes(0, 2, 1) = 1.00, hexNodes(0, 2, 2) = 0.00; hexNodes(0, 3, 0) = 0.00; hexNodes(0, 3, 1) = 1.00, hexNodes(0, 3, 2) = 0.00; // cell 0 top face vertices hexNodes(0, 4, 0) = 0.00; hexNodes(0, 4, 1) = 0.00, hexNodes(0, 4, 2) = 1.00; hexNodes(0, 5, 0) = 1.00; hexNodes(0, 5, 1) = 0.00, hexNodes(0, 5, 2) = 1.00; hexNodes(0, 6, 0) = 1.00; hexNodes(0, 6, 1) = 1.00, hexNodes(0, 6, 2) = 1.00; hexNodes(0, 7, 0) = 0.00; hexNodes(0, 7, 1) = 1.00, hexNodes(0, 7, 2) = 1.00; // cell 1 bottom face vertices: hexNodes(1, 0, 0) = 0.00; hexNodes(1, 0, 1) = 0.00, hexNodes(1, 0, 2) = 0.00; hexNodes(1, 1, 0) = 1.00; hexNodes(1, 1, 1) = 0.00, hexNodes(1, 1, 2) = 0.00; hexNodes(1, 2, 0) = 1.00; hexNodes(1, 2, 1) = 1.00, hexNodes(1, 2, 2) = 0.00; hexNodes(1, 3, 0) = 0.00; hexNodes(1, 3, 1) = 1.00, hexNodes(1, 3, 2) = 0.00; // cell 1 top face vertices hexNodes(1, 4, 0) = 0.00; hexNodes(1, 4, 1) = 0.00, hexNodes(1, 4, 2) = 1.00; hexNodes(1, 5, 0) = 1.00; hexNodes(1, 5, 1) = 0.00, hexNodes(1, 5, 2) = 1.00; hexNodes(1, 6, 0) = 1.00; hexNodes(1, 6, 1) = 1.00, hexNodes(1, 6, 2) = 0.75; hexNodes(1, 7, 0) = 0.00; hexNodes(1, 7, 1) = 1.00, hexNodes(1, 7, 2) = 1.00; // Step 0.c: Specify the face ordinal, relative to the reference cell, of the face workset int subcellDim = 2; int subcellOrd = 1; /************************************************************************************************* * * Step 1: Obtain Gauss points on workset faces for Hexahedron<8> topology * 1.1 Define cubature factory, face parametrization domain and arrays for cubature points * 1.2 Select Gauss rule on D = [-1,1]x[-1,1] * 1.3 Map Gauss points from D to reference face and workset faces * ************************************************************************************************/ // Step 1.1.a: Define CubatureFactory DefaultCubatureFactory<double> cubFactory; // Step 1.1.b: Define topology of the face parametrization domain as [-1,1]x[-1,1] CellTopology paramQuadFace(shards::getCellTopologyData<shards::Quadrilateral<4> >() ); // Step 1.1.c: Define storage for cubature points and weights on [-1,1]x[-1,1] FieldContainer<double> paramGaussWeights; FieldContainer<double> paramGaussPoints; // Step 1.1.d: Define storage for cubature points on a reference face FieldContainer<double> refGaussPoints; // Step 1.1.f: Define storage for cubature points on workset faces FieldContainer<double> worksetGaussPoints; //---------------- // Step 1.2.a: selects Gauss rule of order 3 on [-1,1]x[-1,1] Teuchos::RCP<Cubature<double> > hexFaceCubature = cubFactory.create(paramQuadFace, 3); // Step 1.2.b allocate storage for cubature points on [-1,1]x[-1,1] int cubDim = hexFaceCubature -> getDimension(); int numCubPoints = hexFaceCubature -> getNumPoints(); // Arrays must be properly sized for the specified set of Gauss points paramGaussPoints.resize(numCubPoints, cubDim); paramGaussWeights.resize(numCubPoints); hexFaceCubature -> getCubature(paramGaussPoints, paramGaussWeights); //---------------- // Step 1.3.a: Allocate storage for Gauss points on the reference face refGaussPoints.resize(numCubPoints, pCellDim); // Step 1.3.b: Allocate storage for Gauss points on the face in the workset worksetGaussPoints.resize(worksetSize, numCubPoints, pCellDim); // Step 1.3.c: Map Gauss points to reference face: paramGaussPoints -> refGaussPoints CellTools::mapToReferenceSubcell(refGaussPoints, paramGaussPoints, subcellDim, subcellOrd, hexahedron_8); // Step 1.3.d: Map Gauss points from ref. face to face workset: refGaussPoints -> worksetGaussPoints CellTools::mapToPhysicalFrame(worksetGaussPoints, refGaussPoints, hexNodes, hexahedron_8); /************************************************************************************************* * * Step 2. Obtain (non-normalized) face normals at cubature points on workset faces * 2.1 Compute parent cell Jacobians at Gauss points on workset faces * 2.2 Compute face tangents on workset faces and their vector product * ************************************************************************************************/ // Step 2.1.a: Define and allocate storage for workset Jacobians FieldContainer<double> worksetJacobians(worksetSize, numCubPoints, pCellDim, pCellDim); // Step 2.1.b: Compute Jacobians at Gauss pts. on reference face for all parent cells: CellTools::setJacobian(worksetJacobians, refGaussPoints, hexNodes, hexahedron_8); //---------------- // Step 2.2.a: Allocate storage for face tangents and face normals FieldContainer<double> worksetFaceTu(worksetSize, numCubPoints, pCellDim); FieldContainer<double> worksetFaceTv(worksetSize, numCubPoints, pCellDim); FieldContainer<double> worksetFaceN(worksetSize, numCubPoints, pCellDim); // Step 2.2.b: Compute face tangents CellTools::getPhysicalFaceTangents(worksetFaceTu, worksetFaceTv, worksetJacobians, subcellOrd, hexahedron_8); // Step 2.2.c: Face outer normals (relative to parent cell) are uTan x vTan: RealSpaceTools::vecprod(worksetFaceN, worksetFaceTu, worksetFaceTv); /************************************************************************************************* * * Step 3. Evaluate the vector field u(x,y,z) at cubature points on workset faces * ************************************************************************************************/ // Step 3.a: Allocate storage for vector field values at Gauss points on workset faces FieldContainer<double> worksetVFieldVals(worksetSize, numCubPoints, pCellDim); // Step 3.b: Compute vector field at Gauss points: here we take u(x,y,z) = (x,y,z) for(int pCellOrd = 0; pCellOrd < worksetSize; pCellOrd++){ for(int ptOrd = 0; ptOrd < numCubPoints; ptOrd++){ double x = worksetGaussPoints(pCellOrd, ptOrd, 0); double y = worksetGaussPoints(pCellOrd, ptOrd, 1); double z = worksetGaussPoints(pCellOrd, ptOrd, 2); vField(worksetVFieldVals(pCellOrd, ptOrd, 0), worksetVFieldVals(pCellOrd, ptOrd, 1), worksetVFieldVals(pCellOrd, ptOrd, 2), x, y, z); }// pt }//cell /************************************************************************************************* * * Step 4. Compute dot product of u(x,y,z) and the face normals, times the cubature weights * ************************************************************************************************/ // Allocate storage for dot product of vector field and face normals at Gauss points FieldContainer<double> worksetFieldDotNormal(worksetSize, numCubPoints); // Compute the dot product RealSpaceTools::dot(worksetFieldDotNormal, worksetVFieldVals, worksetFaceN); // Allocate storage for face fluxes on the workset FieldContainer<double> worksetFluxes(worksetSize); //---------------- // Integration loop (temporary) for(int pCellOrd = 0; pCellOrd < worksetSize; pCellOrd++){ worksetFluxes(pCellOrd) = 0.0; for(int pt = 0; pt < numCubPoints; pt++ ){ worksetFluxes(pCellOrd) += worksetFieldDotNormal(pCellOrd, pt)*paramGaussWeights(pt); }// pt }//cell std::cout << "Face fluxes on workset faces : \n\n"; for(int pCellOrd = 0; pCellOrd < worksetSize; pCellOrd++){ CellTools::printWorksetSubcell(hexNodes, hexahedron_8, pCellOrd, subcellDim, subcellOrd); std::cout << " Flux = " << worksetFluxes(pCellOrd) << "\n\n"; } /************************************************************************************************* * * Optional: print Gauss points and face normals at Gauss points * ************************************************************************************************/ // Print Gauss points on [-1,1]x[-1,1] and their images on workset faces std::cout \ << "===============================================================================\n" \ << "| Gauss points on workset faces: |\n" \ << "===============================================================================\n"; for(int pCell = 0; pCell < worksetSize; pCell++){ CellTools::printWorksetSubcell(hexNodes, hexahedron_8, pCell, subcellDim, subcellOrd); for(int pt = 0; pt < numCubPoints; pt++){ std::cout << "\t 2D Gauss point (" << std::setw(8) << std::right << paramGaussPoints(pt, 0) << ", " << std::setw(8) << std::right << paramGaussPoints(pt, 1) << ") " << std::setw(8) << " --> " << "(" << std::setw(8) << std::right << worksetGaussPoints(pCell, pt, 0) << ", " << std::setw(8) << std::right << worksetGaussPoints(pCell, pt, 1) << ", " << std::setw(8) << std::right << worksetGaussPoints(pCell, pt, 2) << ")\n"; } std::cout << "\n\n"; }//pCell // Print face normals at Gauss points on workset faces std::cout \ << "===============================================================================\n" \ << "| Face normals (non-unit) at Gauss points on workset faces: |\n" \ << "===============================================================================\n"; for(int pCell = 0; pCell < worksetSize; pCell++){ CellTools::printWorksetSubcell(hexNodes, hexahedron_8, pCell, subcellDim, subcellOrd); for(int pt = 0; pt < numCubPoints; pt++){ std::cout << "\t 3D Gauss point: (" << std::setw(8) << std::right << worksetGaussPoints(pCell, pt, 0) << ", " << std::setw(8) << std::right << worksetGaussPoints(pCell, pt, 1) << ", " << std::setw(8) << std::right << worksetGaussPoints(pCell, pt, 2) << ")" << std::setw(8) << " out. normal: " << "(" << std::setw(8) << std::right << worksetFaceN(pCell, pt, 0) << ", " << std::setw(8) << std::right << worksetFaceN(pCell, pt, 1) << ", " << std::setw(8) << std::right << worksetFaceN(pCell, pt, 2) << ")\n"; } std::cout << "\n"; }//pCell return 0; }
bool MeshTestUtility::determineRefTestPointsForNeighbors(MeshTopologyViewPtr meshTopo, CellPtr fineCell, unsigned int sideOrdinal, FieldContainer<double> &fineSideRefPoints, FieldContainer<double> &fineCellRefPoints, FieldContainer<double> &coarseSideRefPoints, FieldContainer<double> &coarseCellRefPoints) { unsigned spaceDim = meshTopo->getDimension(); unsigned sideDim = spaceDim - 1; if (spaceDim == 1) { fineSideRefPoints.resize(0,0); coarseSideRefPoints.resize(0,0); fineCellRefPoints.resize(1,1); coarseCellRefPoints.resize(1,1); FieldContainer<double> lineRefNodes(2,1); CellTopoPtr line = CellTopology::line(); CamelliaCellTools::refCellNodesForTopology(lineRefNodes, line); fineCellRefPoints[0] = lineRefNodes[sideOrdinal]; unsigned neighborSideOrdinal = fineCell->getNeighborInfo(sideOrdinal, meshTopo).second; if (neighborSideOrdinal != -1) { coarseCellRefPoints[0] = lineRefNodes[neighborSideOrdinal]; return true; } else { return false; } } pair<GlobalIndexType, unsigned> neighborInfo = fineCell->getNeighborInfo(sideOrdinal, meshTopo); if (neighborInfo.first == -1) { // boundary return false; } CellPtr neighborCell = meshTopo->getCell(neighborInfo.first); if (neighborCell->isParent(meshTopo)) { return false; // fineCell isn't the finer of the two... } CellTopoPtr fineSideTopo = fineCell->topology()->getSubcell(sideDim, sideOrdinal); CubatureFactory cubFactory; int cubDegree = 4; // fairly arbitrary choice: enough to get a decent number of test points... Teuchos::RCP<Cubature<double> > fineSideTopoCub = cubFactory.create(fineSideTopo, cubDegree); int numCubPoints = fineSideTopoCub->getNumPoints(); FieldContainer<double> cubPoints(numCubPoints, sideDim); FieldContainer<double> cubWeights(numCubPoints); // we neglect these... fineSideTopoCub->getCubature(cubPoints, cubWeights); FieldContainer<double> sideRefCellNodes(fineSideTopo->getNodeCount(),sideDim); CamelliaCellTools::refCellNodesForTopology(sideRefCellNodes, fineSideTopo); int numTestPoints = numCubPoints + fineSideTopo->getNodeCount(); FieldContainer<double> testPoints(numTestPoints, sideDim); for (int ptOrdinal=0; ptOrdinal<testPoints.dimension(0); ptOrdinal++) { if (ptOrdinal<fineSideTopo->getNodeCount()) { for (int d=0; d<sideDim; d++) { testPoints(ptOrdinal,d) = sideRefCellNodes(ptOrdinal,d); } } else { for (int d=0; d<sideDim; d++) { testPoints(ptOrdinal,d) = cubPoints(ptOrdinal-fineSideTopo->getNodeCount(),d); } } } fineSideRefPoints = testPoints; fineCellRefPoints.resize(numTestPoints, spaceDim); CamelliaCellTools::mapToReferenceSubcell(fineCellRefPoints, testPoints, sideDim, sideOrdinal, fineCell->topology()); CellTopoPtr coarseSideTopo = neighborCell->topology()->getSubcell(sideDim, neighborInfo.second); unsigned fineSideAncestorPermutation = fineCell->ancestralPermutationForSubcell(sideDim, sideOrdinal, meshTopo); unsigned coarseSidePermutation = neighborCell->subcellPermutation(sideDim, neighborInfo.second); unsigned coarseSideAncestorPermutationInverse = CamelliaCellTools::permutationInverse(coarseSideTopo, coarseSidePermutation); unsigned composedPermutation = CamelliaCellTools::permutationComposition(coarseSideTopo, coarseSideAncestorPermutationInverse, fineSideAncestorPermutation); // goes from coarse ordering to fine. RefinementBranch fineRefBranch = fineCell->refinementBranchForSide(sideOrdinal, meshTopo); FieldContainer<double> fineSideNodes(fineSideTopo->getNodeCount(), sideDim); // relative to the ancestral cell whose neighbor is compatible if (fineRefBranch.size() == 0) { CamelliaCellTools::refCellNodesForTopology(fineSideNodes, coarseSideTopo, composedPermutation); } else { FieldContainer<double> ancestralSideNodes(coarseSideTopo->getNodeCount(), sideDim); CamelliaCellTools::refCellNodesForTopology(ancestralSideNodes, coarseSideTopo, composedPermutation); RefinementBranch fineSideRefBranch = RefinementPattern::sideRefinementBranch(fineRefBranch, sideOrdinal); fineSideNodes = RefinementPattern::descendantNodes(fineSideRefBranch, ancestralSideNodes); } BasisCachePtr sideTopoCache = Teuchos::rcp( new BasisCache(fineSideTopo, 1, false) ); sideTopoCache->setRefCellPoints(testPoints); // add cell dimension fineSideNodes.resize(1,fineSideNodes.dimension(0), fineSideNodes.dimension(1)); sideTopoCache->setPhysicalCellNodes(fineSideNodes, vector<GlobalIndexType>(), false); coarseSideRefPoints = sideTopoCache->getPhysicalCubaturePoints(); // strip off the cell dimension: coarseSideRefPoints.resize(coarseSideRefPoints.dimension(1),coarseSideRefPoints.dimension(2)); coarseCellRefPoints.resize(numTestPoints,spaceDim); CamelliaCellTools::mapToReferenceSubcell(coarseCellRefPoints, coarseSideRefPoints, sideDim, neighborInfo.second, neighborCell->topology()); return true; // containers filled.... }
void Boundary::bcsToImpose(FieldContainer<GlobalIndexType> &globalIndices, FieldContainer<Scalar> &globalValues, TBC<Scalar> &bc, DofInterpreter* dofInterpreter) { set< GlobalIndexType > rankLocalCells = _mesh->cellIDsInPartition(); map< GlobalIndexType, double> bcGlobalIndicesAndValues; for (GlobalIndexType cellID : rankLocalCells) { bcsToImpose(bcGlobalIndicesAndValues, bc, cellID, dofInterpreter); } singletonBCsToImpose(bcGlobalIndicesAndValues, bc, dofInterpreter); // ****** New, tag-based BC imposition follows ****** map< GlobalIndexType, double> bcTagGlobalIndicesAndValues; map< int, vector<pair<VarPtr, TFunctionPtr<Scalar>>>> tagBCs = bc.getDirichletTagBCs(); // keys are tags MeshTopology* meshTopo = dynamic_cast<MeshTopology*>(_mesh->getTopology().get()); TEUCHOS_TEST_FOR_EXCEPTION(!meshTopo, std::invalid_argument, "pure MeshTopologyViews are not yet supported by new tag-based BC imposition"); for (auto tagBC : tagBCs) { int tagID = tagBC.first; vector<EntitySetPtr> entitySets = meshTopo->getEntitySetsForTagID(DIRICHLET_SET_TAG_NAME, tagID); for (EntitySetPtr entitySet : entitySets) { // get rank-local cells that match the entity set: set<IndexType> matchingCellIDs = entitySet->cellIDsThatMatch(_mesh->getTopology(), rankLocalCells); for (IndexType cellID : matchingCellIDs) { ElementTypePtr elemType = _mesh->getElementType(cellID); BasisCachePtr basisCache = BasisCache::basisCacheForCell(_mesh, cellID); for (auto varFunctionPair : tagBC.second) { VarPtr var = varFunctionPair.first; FunctionPtr f = varFunctionPair.second; vector<int> sideOrdinals = elemType->trialOrderPtr->getSidesForVarID(var->ID()); for (int sideOrdinal : sideOrdinals) { BasisPtr basis = elemType->trialOrderPtr->getBasis(var->ID(), sideOrdinal); bool isVolume = basis->domainTopology()->getDimension() == _mesh->getDimension(); for (int d=0; d<_mesh->getDimension(); d++) { vector<unsigned> matchingSubcells; if (isVolume) matchingSubcells = entitySet->subcellOrdinals(_mesh->getTopology(), cellID, d); else { CellTopoPtr cellTopo = elemType->cellTopoPtr; int sideDim = cellTopo->getDimension() - 1; vector<unsigned> matchingSubcellsOnSide = entitySet->subcellOrdinalsOnSide(_mesh->getTopology(), cellID, sideOrdinal, d); for (unsigned sideSubcellOrdinal : matchingSubcellsOnSide) { unsigned cellSubcellOrdinal = CamelliaCellTools::subcellOrdinalMap(cellTopo, sideDim, sideOrdinal, d, sideSubcellOrdinal); matchingSubcells.push_back(cellSubcellOrdinal); } } if (matchingSubcells.size() == 0) continue; // nothing to impose /* What follows - projecting the function onto the basis on the whole domain - is more expensive than necessary, in the general case: we can do the projection on just the matching subcells, and if we had a way of taking the restriction of a basis to a subcell of the domain, then we could avoid computing the whole basis as well. But for now, this should work, and it's simple to implement. */ BasisCachePtr basisCacheForImposition = isVolume ? basisCache : basisCache->getSideBasisCache(sideOrdinal); int numCells = 1; FieldContainer<double> basisCoefficients(numCells,basis->getCardinality()); Projector<double>::projectFunctionOntoBasisInterpolating(basisCoefficients, f, basis, basisCacheForImposition); basisCoefficients.resize(basis->getCardinality()); set<GlobalIndexType> matchingGlobalIndices; for (unsigned matchingSubcell : matchingSubcells) { set<GlobalIndexType> subcellGlobalIndices = dofInterpreter->globalDofIndicesForVarOnSubcell(var->ID(),cellID,d,matchingSubcell); matchingGlobalIndices.insert(subcellGlobalIndices.begin(),subcellGlobalIndices.end()); } FieldContainer<double> globalData; FieldContainer<GlobalIndexType> globalDofIndices; // dofInterpreter->interpretLocalBasisCoefficients(cellID, var->ID(), sideOrdinal, basisCoefficientsToImpose, globalData, globalDofIndices); dofInterpreter->interpretLocalBasisCoefficients(cellID, var->ID(), sideOrdinal, basisCoefficients, globalData, globalDofIndices); for (int globalDofOrdinal=0; globalDofOrdinal<globalDofIndices.size(); globalDofOrdinal++) { GlobalIndexType globalDofIndex = globalDofIndices(globalDofOrdinal); if (matchingGlobalIndices.find(globalDofIndex) != matchingGlobalIndices.end()) bcTagGlobalIndicesAndValues[globalDofIndex] = globalData(globalDofOrdinal); } } } } } } } // merge tag-based and legacy BC maps double tol = 1e-15; for (auto tagEntry : bcTagGlobalIndicesAndValues) { if (bcGlobalIndicesAndValues.find(tagEntry.first) != bcGlobalIndicesAndValues.end()) { // then check that they match, within tolerance double diff = abs(bcGlobalIndicesAndValues[tagEntry.first] - tagEntry.second); TEUCHOS_TEST_FOR_EXCEPTION(diff > tol, std::invalid_argument, "Incompatible BC entries encountered"); } else { bcGlobalIndicesAndValues[tagEntry.first] = tagEntry.second; } } globalIndices.resize(bcGlobalIndicesAndValues.size()); globalValues.resize(bcGlobalIndicesAndValues.size()); globalIndices.initialize(0); globalValues.initialize(0.0); int entryOrdinal = 0; for (auto bcEntry : bcGlobalIndicesAndValues) { globalIndices[entryOrdinal] = bcEntry.first; globalValues[entryOrdinal] = bcEntry.second; entryOrdinal++; } }
bool MeshTestUtility::neighborBasesAgreeOnSides(Teuchos::RCP<Mesh> mesh, Epetra_MultiVector &globalSolutionCoefficients) { bool success = true; MeshTopologyViewPtr meshTopo = mesh->getTopology(); int spaceDim = meshTopo->getDimension(); set<IndexType> activeCellIndices = meshTopo->getActiveCellIndices(); for (set<IndexType>::iterator cellIt=activeCellIndices.begin(); cellIt != activeCellIndices.end(); cellIt++) { IndexType cellIndex = *cellIt; CellPtr cell = meshTopo->getCell(cellIndex); BasisCachePtr fineCellBasisCache = BasisCache::basisCacheForCell(mesh, cellIndex); ElementTypePtr fineElemType = mesh->getElementType(cellIndex); DofOrderingPtr fineElemTrialOrder = fineElemType->trialOrderPtr; FieldContainer<double> fineSolutionCoefficients(fineElemTrialOrder->totalDofs()); mesh->globalDofAssignment()->interpretGlobalCoefficients(cellIndex, fineSolutionCoefficients, globalSolutionCoefficients); // if ((cellIndex==0) || (cellIndex==2)) { // cout << "MeshTestUtility: local coefficients for cell " << cellIndex << ":\n" << fineSolutionCoefficients; // } unsigned sideCount = cell->getSideCount(); for (unsigned sideOrdinal=0; sideOrdinal<sideCount; sideOrdinal++) { FieldContainer<double> fineSideRefPoints, fineCellRefPoints, coarseSideRefPoints, coarseCellRefPoints; bool hasCoarserNeighbor = determineRefTestPointsForNeighbors(meshTopo, cell, sideOrdinal, fineSideRefPoints, fineCellRefPoints, coarseSideRefPoints, coarseCellRefPoints); if (!hasCoarserNeighbor) continue; pair<GlobalIndexType, unsigned> neighborInfo = cell->getNeighborInfo(sideOrdinal, meshTopo); CellPtr neighborCell = meshTopo->getCell(neighborInfo.first); unsigned numTestPoints = coarseCellRefPoints.dimension(0); // cout << "testing neighbor agreement between cell " << cellIndex << " and " << neighborCell->cellIndex() << endl; // if we get here, the cell has a neighbor on this side, and is at least as fine as that neighbor. BasisCachePtr fineSideBasisCache = fineCellBasisCache->getSideBasisCache(sideOrdinal); fineCellBasisCache->setRefCellPoints(fineCellRefPoints); BasisCachePtr coarseCellBasisCache = BasisCache::basisCacheForCell(mesh, neighborInfo.first); BasisCachePtr coarseSideBasisCache = coarseCellBasisCache->getSideBasisCache(neighborInfo.second); coarseCellBasisCache->setRefCellPoints(coarseCellRefPoints); bool hasSidePoints = (fineSideRefPoints.size() > 0); if (hasSidePoints) { fineSideBasisCache->setRefCellPoints(fineSideRefPoints); coarseSideBasisCache->setRefCellPoints(coarseSideRefPoints); } // sanity check: do physical points match? FieldContainer<double> fineCellPhysicalCubaturePoints = fineCellBasisCache->getPhysicalCubaturePoints(); FieldContainer<double> coarseCellPhysicalCubaturePoints = coarseCellBasisCache->getPhysicalCubaturePoints(); double tol = 1e-14; double maxDiff = 0; if (! fcsAgree(coarseCellPhysicalCubaturePoints, fineCellPhysicalCubaturePoints, tol, maxDiff) ) { cout << "ERROR: MeshTestUtility::neighborBasesAgreeOnSides internal error: fine and coarse cell cubature points do not agree.\n"; success = false; continue; } if (hasSidePoints) { FieldContainer<double> fineSidePhysicalCubaturePoints = fineSideBasisCache->getPhysicalCubaturePoints(); FieldContainer<double> coarseSidePhysicalCubaturePoints = coarseSideBasisCache->getPhysicalCubaturePoints(); double tol = 1e-14; double maxDiff = 0; if (! fcsAgree(fineSidePhysicalCubaturePoints, fineCellPhysicalCubaturePoints, tol, maxDiff) ) { cout << "ERROR: MeshTestUtility::neighborBasesAgreeOnSides internal error: fine side and cell cubature points do not agree.\n"; success = false; continue; } if (! fcsAgree(coarseSidePhysicalCubaturePoints, coarseCellPhysicalCubaturePoints, tol, maxDiff) ) { cout << "ERROR: MeshTestUtility::neighborBasesAgreeOnSides internal error: coarse side and cell cubature points do not agree.\n"; success = false; continue; } if (! fcsAgree(coarseSidePhysicalCubaturePoints, fineSidePhysicalCubaturePoints, tol, maxDiff) ) { cout << "ERROR: MeshTestUtility::neighborBasesAgreeOnSides internal error: fine and coarse side cubature points do not agree.\n"; success = false; continue; } } ElementTypePtr coarseElementType = mesh->getElementType(neighborInfo.first); DofOrderingPtr coarseElemTrialOrder = coarseElementType->trialOrderPtr; FieldContainer<double> coarseSolutionCoefficients(coarseElemTrialOrder->totalDofs()); mesh->globalDofAssignment()->interpretGlobalCoefficients(neighborInfo.first, coarseSolutionCoefficients, globalSolutionCoefficients); set<int> varIDs = fineElemTrialOrder->getVarIDs(); for (set<int>::iterator varIt = varIDs.begin(); varIt != varIDs.end(); varIt++) { int varID = *varIt; // cout << "MeshTestUtility: varID " << varID << ":\n"; bool isTraceVar = mesh->bilinearForm()->isFluxOrTrace(varID); BasisPtr fineBasis, coarseBasis; BasisCachePtr fineCache, coarseCache; if (isTraceVar) { if (! hasSidePoints) continue; // then nothing to do for traces fineBasis = fineElemTrialOrder->getBasis(varID, sideOrdinal); coarseBasis = coarseElemTrialOrder->getBasis(varID, neighborInfo.second); fineCache = fineSideBasisCache; coarseCache = coarseSideBasisCache; } else { fineBasis = fineElemTrialOrder->getBasis(varID); coarseBasis = coarseElemTrialOrder->getBasis(varID); fineCache = fineCellBasisCache; coarseCache = coarseCellBasisCache; Camellia::EFunctionSpace fs = fineBasis->functionSpace(); if ((fs == Camellia::FUNCTION_SPACE_HVOL) || (fs == Camellia::FUNCTION_SPACE_VECTOR_HVOL) || (fs == Camellia::FUNCTION_SPACE_TENSOR_HVOL)) { // volume L^2 basis: no continuities expected... continue; } } FieldContainer<double> localValuesFine = *fineCache->getTransformedValues(fineBasis, OP_VALUE); FieldContainer<double> localValuesCoarse = *coarseCache->getTransformedValues(coarseBasis, OP_VALUE); bool scalarValued = (localValuesFine.rank() == 3); // the following used if vector or tensor-valued: Teuchos::Array<int> valueDim; unsigned componentsPerValue = 1; FieldContainer<double> valueContainer; // just used for enumeration computation... if (!scalarValued) { localValuesFine.dimensions(valueDim); // clear first three: valueDim.erase(valueDim.begin()); valueDim.erase(valueDim.begin()); valueDim.erase(valueDim.begin()); valueContainer.resize(valueDim); componentsPerValue = valueContainer.size(); } // if (localValuesFine.rank() != 3) { // cout << "WARNING: MeshTestUtility::neighborBasesAgreeOnSides() only supports scalar-valued bases right now. Skipping check for varID " << varID << endl; // continue; // } FieldContainer<double> localPointValuesFine(fineElemTrialOrder->totalDofs()); FieldContainer<double> localPointValuesCoarse(coarseElemTrialOrder->totalDofs()); for (int valueComponentOrdinal=0; valueComponentOrdinal<componentsPerValue; valueComponentOrdinal++) { Teuchos::Array<int> valueMultiIndex(valueContainer.rank()); if (!scalarValued) valueContainer.getMultiIndex(valueMultiIndex, valueComponentOrdinal); Teuchos::Array<int> localValuesMultiIndex(localValuesFine.rank()); for (int r=0; r<valueMultiIndex.size(); r++) { localValuesMultiIndex[r+3] = valueMultiIndex[r]; } for (int ptOrdinal=0; ptOrdinal<numTestPoints; ptOrdinal++) { localPointValuesCoarse.initialize(0); localPointValuesFine.initialize(0); localValuesMultiIndex[2] = ptOrdinal; double fineSolutionValue = 0, coarseSolutionValue = 0; for (int basisOrdinal=0; basisOrdinal < fineBasis->getCardinality(); basisOrdinal++) { int fineDofIndex; if (isTraceVar) fineDofIndex = fineElemTrialOrder->getDofIndex(varID, basisOrdinal, sideOrdinal); else fineDofIndex = fineElemTrialOrder->getDofIndex(varID, basisOrdinal); if (scalarValued) { localPointValuesFine(fineDofIndex) = localValuesFine(0,basisOrdinal,ptOrdinal); } else { localValuesMultiIndex[1] = basisOrdinal; localPointValuesFine(fineDofIndex) = localValuesFine.getValue(localValuesMultiIndex); } fineSolutionValue += fineSolutionCoefficients(fineDofIndex) * localPointValuesFine(fineDofIndex); } for (int basisOrdinal=0; basisOrdinal < coarseBasis->getCardinality(); basisOrdinal++) { int coarseDofIndex; if (isTraceVar) coarseDofIndex = coarseElemTrialOrder->getDofIndex(varID, basisOrdinal, neighborInfo.second); else coarseDofIndex = coarseElemTrialOrder->getDofIndex(varID, basisOrdinal); if (scalarValued) { localPointValuesCoarse(coarseDofIndex) = localValuesCoarse(0,basisOrdinal,ptOrdinal); } else { localValuesMultiIndex[1] = basisOrdinal; localPointValuesCoarse(coarseDofIndex) = localValuesCoarse.getValue(localValuesMultiIndex); } coarseSolutionValue += coarseSolutionCoefficients(coarseDofIndex) * localPointValuesCoarse(coarseDofIndex); } if (abs(coarseSolutionValue - fineSolutionValue) > 1e-13) { success = false; cout << "coarseSolutionValue (" << coarseSolutionValue << ") and fineSolutionValue (" << fineSolutionValue << ") differ by " << abs(coarseSolutionValue - fineSolutionValue); cout << " at point " << ptOrdinal << " for varID " << varID << ". "; cout << "This may be an indication that something is amiss with the global-to-local map.\n"; } else { // // DEBUGGING: // cout << "solution value at point ("; // for (int d=0; d<spaceDim-1; d++) { // cout << fineSidePhysicalCubaturePoints(0,ptOrdinal,d) << ", "; // } // cout << fineSidePhysicalCubaturePoints(0,ptOrdinal,spaceDim-1) << "): "; // cout << coarseSolutionValue << endl; } FieldContainer<double> globalValuesFromFine, globalValuesFromCoarse; FieldContainer<GlobalIndexType> globalDofIndicesFromFine, globalDofIndicesFromCoarse; mesh->globalDofAssignment()->interpretLocalData(cellIndex, localPointValuesFine, globalValuesFromFine, globalDofIndicesFromFine); mesh->globalDofAssignment()->interpretLocalData(neighborInfo.first, localPointValuesCoarse, globalValuesFromCoarse, globalDofIndicesFromCoarse); std::map<GlobalIndexType, double> fineValuesMap; std::map<GlobalIndexType, double> coarseValuesMap; for (int i=0; i<globalDofIndicesFromCoarse.size(); i++) { GlobalIndexType globalDofIndex = globalDofIndicesFromCoarse[i]; coarseValuesMap[globalDofIndex] = globalValuesFromCoarse[i]; } double maxDiff = 0; for (int i=0; i<globalDofIndicesFromFine.size(); i++) { GlobalIndexType globalDofIndex = globalDofIndicesFromFine[i]; fineValuesMap[globalDofIndex] = globalValuesFromFine[i]; double diff = abs( fineValuesMap[globalDofIndex] - coarseValuesMap[globalDofIndex]); maxDiff = std::max(diff, maxDiff); if (diff > tol) { success = false; cout << "interpreted fine and coarse disagree at point ("; for (int d=0; d<spaceDim; d++) { cout << fineCellPhysicalCubaturePoints(0,ptOrdinal,d); if (d==spaceDim-1) cout << ").\n"; else cout << ", "; } } } if (maxDiff > tol) { cout << "maxDiff: " << maxDiff << endl; cout << "globalValuesFromFine:\n" << globalValuesFromFine; cout << "globalValuesFromCoarse:\n" << globalValuesFromCoarse; cout << "globalDofIndicesFromFine:\n" << globalDofIndicesFromFine; cout << "globalDofIndicesFromCoarse:\n" << globalDofIndicesFromCoarse; continue; // only worth testing further if we passed the above } } } } } } // cout << "Completed neighborBasesAgreeOnSides.\n"; return success; }
int main(int argc, char *argv[]) { Teuchos::GlobalMPISession mpiSession(&argc, &argv); // This little trick lets us print to std::cout only if // a (dummy) command-line argument is provided. int iprint = argc - 1; Teuchos::RCP<std::ostream> outStream; Teuchos::oblackholestream bhs; // outputs nothing if (iprint > 0) outStream = Teuchos::rcp(&std::cout, false); else outStream = Teuchos::rcp(&bhs, false); // Save the format state of the original std::cout. Teuchos::oblackholestream oldFormatState; oldFormatState.copyfmt(std::cout); *outStream \ << "===============================================================================\n" \ << "| |\n" \ << "| Unit Test (Basis_HGRAD_TRI_C1_FEM) |\n" \ << "| |\n" \ << "| 1) Conversion of Dof tags into Dof ordinals and back |\n" \ << "| 2) Basis values for VALUE, GRAD, CURL, and Dk operators |\n" \ << "| |\n" \ << "| Questions? Contact Pavel Bochev ([email protected]), |\n" \ << "| Denis Ridzal ([email protected]), |\n" \ << "| Kara Peterson ([email protected]). |\n" \ << "| |\n" \ << "| Intrepid's website: http://trilinos.sandia.gov/packages/intrepid |\n" \ << "| Trilinos website: http://trilinos.sandia.gov |\n" \ << "| |\n" \ << "===============================================================================\n"\ << "| TEST 1: Basis creation, exception testing |\n"\ << "===============================================================================\n"; // Define basis and error flag Basis_HGRAD_TRI_C1_FEM<double, FieldContainer<double> > triBasis; int errorFlag = 0; // Initialize throw counter for exception testing int nException = 0; int throwCounter = 0; // Define array containing the 3 vertices of the reference Triangle, its center and another point FieldContainer<double> triNodes(5, 2); triNodes(0,0) = 0.0; triNodes(0,1) = 0.0; triNodes(1,0) = 1.0; triNodes(1,1) = 0.0; triNodes(2,0) = 0.0; triNodes(2,1) = 1.0; triNodes(3,0) = 0.5; triNodes(3,1) = 0.5; triNodes(4,0) = 0.0; triNodes(4,1) = 0.75; // Generic array for the output values; needs to be properly resized depending on the operator type FieldContainer<double> vals; try{ // exception #1: DIV cannot be applied to scalar functions // resize vals to rank-2 container with dimensions (num. points, num. basis functions) vals.resize(triBasis.getCardinality(), triNodes.dimension(0) ); INTREPID_TEST_COMMAND( triBasis.getValues(vals, triNodes, OPERATOR_DIV), throwCounter, nException ); // Exceptions 2-6: all bf tags/bf Ids below are wrong and should cause getDofOrdinal() and // getDofTag() to access invalid array elements thereby causing bounds check exception // exception #2 INTREPID_TEST_COMMAND( triBasis.getDofOrdinal(2,0,0), throwCounter, nException ); // exception #3 INTREPID_TEST_COMMAND( triBasis.getDofOrdinal(1,1,1), throwCounter, nException ); // exception #4 INTREPID_TEST_COMMAND( triBasis.getDofOrdinal(0,4,0), throwCounter, nException ); // exception #5 INTREPID_TEST_COMMAND( triBasis.getDofTag(5), throwCounter, nException ); // exception #6 INTREPID_TEST_COMMAND( triBasis.getDofTag(-1), throwCounter, nException ); #ifdef HAVE_INTREPID_DEBUG // Exceptions 7-17 test exception handling with incorrectly dimensioned input/output arrays // exception #7: input points array must be of rank-2 FieldContainer<double> badPoints1(4, 5, 3); INTREPID_TEST_COMMAND( triBasis.getValues(vals, badPoints1, OPERATOR_VALUE), throwCounter, nException ); // exception #8 dimension 1 in the input point array must equal space dimension of the cell FieldContainer<double> badPoints2(4, 3); INTREPID_TEST_COMMAND( triBasis.getValues(vals, badPoints2, OPERATOR_VALUE), throwCounter, nException ); // exception #9 output values must be of rank-2 for OPERATOR_VALUE FieldContainer<double> badVals1(4, 3, 1); INTREPID_TEST_COMMAND( triBasis.getValues(badVals1, triNodes, OPERATOR_VALUE), throwCounter, nException ); // exception #10 output values must be of rank-3 for OPERATOR_GRAD FieldContainer<double> badVals2(4, 3); INTREPID_TEST_COMMAND( triBasis.getValues(badVals2, triNodes, OPERATOR_GRAD), throwCounter, nException ); // exception #11 output values must be of rank-3 for OPERATOR_CURL INTREPID_TEST_COMMAND( triBasis.getValues(badVals2, triNodes, OPERATOR_CURL), throwCounter, nException ); // exception #12 output values must be of rank-3 for OPERATOR_D2 INTREPID_TEST_COMMAND( triBasis.getValues(badVals2, triNodes, OPERATOR_D2), throwCounter, nException ); // exception #13 incorrect 1st dimension of output array (must equal number of basis functions) FieldContainer<double> badVals3(triBasis.getCardinality() + 1, triNodes.dimension(0)); INTREPID_TEST_COMMAND( triBasis.getValues(badVals3, triNodes, OPERATOR_VALUE), throwCounter, nException ); // exception #14 incorrect 0th dimension of output array (must equal number of points) FieldContainer<double> badVals4(triBasis.getCardinality(), triNodes.dimension(0) + 1); INTREPID_TEST_COMMAND( triBasis.getValues(badVals4, triNodes, OPERATOR_VALUE), throwCounter, nException ); // exception #15: incorrect 2nd dimension of output array (must equal the space dimension) FieldContainer<double> badVals5(triBasis.getCardinality(), triNodes.dimension(0), 4); INTREPID_TEST_COMMAND( triBasis.getValues(badVals5, triNodes, OPERATOR_GRAD), throwCounter, nException ); // exception #16: incorrect 2nd dimension of output array (must equal D2 cardinality in 2D) FieldContainer<double> badVals6(triBasis.getCardinality(), triNodes.dimension(0), 40); INTREPID_TEST_COMMAND( triBasis.getValues(badVals6, triNodes, OPERATOR_D2), throwCounter, nException ); // exception #17: incorrect 2nd dimension of output array (must equal D3 cardinality in 2D) INTREPID_TEST_COMMAND( triBasis.getValues(badVals6, triNodes, OPERATOR_D3), throwCounter, nException ); #endif } catch (std::logic_error err) { *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n"; *outStream << err.what() << '\n'; *outStream << "-------------------------------------------------------------------------------" << "\n\n"; errorFlag = -1000; }; // Check if number of thrown exceptions matches the one we expect if (throwCounter != nException) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; } *outStream \ << "\n" << "===============================================================================\n"\ << "| TEST 2: correctness of tag to enum and enum to tag lookups |\n"\ << "===============================================================================\n"; try{ std::vector<std::vector<int> > allTags = triBasis.getAllDofTags(); // Loop over all tags, lookup the associated dof enumeration and then lookup the tag again for (unsigned i = 0; i < allTags.size(); i++) { int bfOrd = triBasis.getDofOrdinal(allTags[i][0], allTags[i][1], allTags[i][2]); std::vector<int> myTag = triBasis.getDofTag(bfOrd); if( !( (myTag[0] == allTags[i][0]) && (myTag[1] == allTags[i][1]) && (myTag[2] == allTags[i][2]) && (myTag[3] == allTags[i][3]) ) ) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; *outStream << " getDofOrdinal( {" << allTags[i][0] << ", " << allTags[i][1] << ", " << allTags[i][2] << ", " << allTags[i][3] << "}) = " << bfOrd <<" but \n"; *outStream << " getDofTag(" << bfOrd << ") = { " << myTag[0] << ", " << myTag[1] << ", " << myTag[2] << ", " << myTag[3] << "}\n"; } } // Now do the same but loop over basis functions for( int bfOrd = 0; bfOrd < triBasis.getCardinality(); bfOrd++) { std::vector<int> myTag = triBasis.getDofTag(bfOrd); int myBfOrd = triBasis.getDofOrdinal(myTag[0], myTag[1], myTag[2]); if( bfOrd != myBfOrd) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; *outStream << " getDofTag(" << bfOrd << ") = { " << myTag[0] << ", " << myTag[1] << ", " << myTag[2] << ", " << myTag[3] << "} but getDofOrdinal({" << myTag[0] << ", " << myTag[1] << ", " << myTag[2] << ", " << myTag[3] << "} ) = " << myBfOrd << "\n"; } } } catch (std::logic_error err){ *outStream << err.what() << "\n\n"; errorFlag = -1000; }; *outStream \ << "\n" << "===============================================================================\n"\ << "| TEST 3: correctness of basis function values |\n"\ << "===============================================================================\n"; outStream -> precision(20); // VALUE: Each row gives the 3 correct basis set values at an evaluation point double basisValues[] = { 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.5, 0.5, 0.25,0.0, 0.75 }; // GRAD and D1: each row gives the 6 correct values of the gradients of the 3 basis functions double basisGrads[] = { -1.0, -1.0, 1.0, 0.0, 0.0, 1.0, -1.0, -1.0, 1.0, 0.0, 0.0, 1.0, -1.0, -1.0, 1.0, 0.0, 0.0, 1.0, -1.0, -1.0, 1.0, 0.0, 0.0, 1.0, -1.0, -1.0, 1.0, 0.0, 0.0, 1.0, }; // CURL: each row gives the 6 correct values of the curls of the 3 basis functions double basisCurls[] = { -1.0, 1.0, 0.0, -1.0, 1.0, 0.0, -1.0, 1.0, 0.0, -1.0, 1.0, 0.0, -1.0, 1.0, 0.0, -1.0, 1.0, 0.0, -1.0, 1.0, 0.0, -1.0, 1.0, 0.0, -1.0, 1.0, 0.0, -1.0, 1.0, 0.0 }; try{ // Dimensions for the output arrays: int numFields = triBasis.getCardinality(); int numPoints = triNodes.dimension(0); int spaceDim = triBasis.getBaseCellTopology().getDimension(); // Generic array for values, grads, curls, etc. that will be properly sized before each call FieldContainer<double> vals; // Check VALUE of basis functions: resize vals to rank-2 container: vals.resize(numFields, numPoints); triBasis.getValues(vals, triNodes, OPERATOR_VALUE); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { int l = i + j * numFields; if (std::abs(vals(i,j) - basisValues[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " "; *outStream << "} computed value: " << vals(i,j) << " but reference value: " << basisValues[l] << "\n"; } } } // Check GRAD of basis function: resize vals to rank-3 container vals.resize(numFields, numPoints, spaceDim); triBasis.getValues(vals, triNodes, OPERATOR_GRAD); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { for (int k = 0; k < spaceDim; k++) { int l = k + i * spaceDim + j * spaceDim * numFields; if (std::abs(vals(i,j,k) - basisGrads[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " ";*outStream << k << " "; *outStream << "} computed grad component: " << vals(i,j,k) << " but reference grad component: " << basisGrads[l] << "\n"; } } } } // Check D1 of basis function (do not resize vals because it has the correct size: D1 = GRAD) triBasis.getValues(vals, triNodes, OPERATOR_D1); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { for (int k = 0; k < spaceDim; k++) { int l = k + i * spaceDim + j * spaceDim * numFields; if (std::abs(vals(i,j,k) - basisGrads[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " ";*outStream << k << " "; *outStream << "} computed D1 component: " << vals(i,j,k) << " but reference D1 component: " << basisGrads[l] << "\n"; } } } } // Check CURL of basis function: resize vals just for illustration! vals.resize(numFields, numPoints, spaceDim); triBasis.getValues(vals, triNodes, OPERATOR_CURL); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { for (int k = 0; k < spaceDim; k++) { int l = k + i * spaceDim + j * spaceDim * numFields; if (std::abs(vals(i,j,k) - basisCurls[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " ";*outStream << k << " "; *outStream << "} computed curl component: " << vals(i,j,k) << " but reference curl component: " << basisCurls[l] << "\n"; } } } } // Check all higher derivatives - must be zero. for(EOperator op = OPERATOR_D2; op < OPERATOR_MAX; op++) { // The last dimension is the number of kth derivatives and needs to be resized for every Dk int DkCardin = Intrepid::getDkCardinality(op, spaceDim); vals.resize(numFields, numPoints, DkCardin); triBasis.getValues(vals, triNodes, op); for (int i = 0; i < vals.size(); i++) { if (std::abs(vals[i]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Get the multi-index of the value where the error is and the operator order std::vector<int> myIndex; vals.getMultiIndex(myIndex,i); int ord = Intrepid::getOperatorOrder(op); *outStream << " At multi-index { "; for(int j = 0; j < vals.rank(); j++) { *outStream << myIndex[j] << " "; } *outStream << "} computed D"<< ord <<" component: " << vals[i] << " but reference D" << ord << " component: 0 \n"; } } } } // Catch unexpected errors catch (std::logic_error err) { *outStream << err.what() << "\n\n"; errorFlag = -1000; }; *outStream \ << "\n" << "===============================================================================\n"\ << "| TEST 4: correctness of DoF locations |\n"\ << "===============================================================================\n"; try{ Teuchos::RCP<Basis<double, FieldContainer<double> > > basis = Teuchos::rcp(new Basis_HGRAD_TRI_C1_FEM<double, FieldContainer<double> >); Teuchos::RCP<DofCoordsInterface<FieldContainer<double> > > coord_iface = Teuchos::rcp_dynamic_cast<DofCoordsInterface<FieldContainer<double> > >(basis); FieldContainer<double> cvals; FieldContainer<double> bvals(basis->getCardinality(), basis->getCardinality()); // Check exceptions. #ifdef HAVE_INTREPID_DEBUG cvals.resize(1,2,3); INTREPID_TEST_COMMAND( coord_iface->getDofCoords(cvals), throwCounter, nException ); cvals.resize(4,2); INTREPID_TEST_COMMAND( coord_iface->getDofCoords(cvals), throwCounter, nException ); cvals.resize(4,3); INTREPID_TEST_COMMAND( coord_iface->getDofCoords(cvals), throwCounter, nException ); #endif cvals.resize(3,2); INTREPID_TEST_COMMAND( coord_iface->getDofCoords(cvals), throwCounter, nException ); nException--; // Check if number of thrown exceptions matches the one we expect if (throwCounter != nException) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; } // Check mathematical correctness. basis->getValues(bvals, cvals, OPERATOR_VALUE); char buffer[120]; for (int i=0; i<bvals.dimension(0); i++) { for (int j=0; j<bvals.dimension(1); j++) { if ((i != j) && (std::abs(bvals(i,j) - 0.0) > INTREPID_TOL)) { errorFlag++; sprintf(buffer, "\nValue of basis function %d at (%6.4e, %6.4e) is %6.4e but should be %6.4e!\n", i, cvals(i,0), cvals(i,1), bvals(i,j), 0.0); *outStream << buffer; } else if ((i == j) && (std::abs(bvals(i,j) - 1.0) > INTREPID_TOL)) { errorFlag++; sprintf(buffer, "\nValue of basis function %d at (%6.4e, %6.4e) is %6.4e but should be %6.4e!\n", i, cvals(i,0), cvals(i,1), bvals(i,j), 1.0); *outStream << buffer; } } } } catch (std::logic_error err){ *outStream << err.what() << "\n\n"; errorFlag = -1000; }; if (errorFlag != 0) std::cout << "End Result: TEST FAILED\n"; else std::cout << "End Result: TEST PASSED\n"; // reset format state of std::cout std::cout.copyfmt(oldFormatState); return errorFlag; }
/** This example whows how to get vertex IDs for all the elements */ int main( int argc, char **argv ) { using Teuchos::RCP; Teuchos::oblackholestream blackhole; Teuchos::GlobalMPISession mpiSession(&argc,&argv,&blackhole); RCP<const Teuchos::Comm<int> > comm = Teuchos::DefaultComm<int>::getComm(); RCP<Teuchos::ParameterList> pl = rcp(new Teuchos::ParameterList); pl->set("X Blocks",2); pl->set("Y Blocks",1); pl->set("X Elements",6); pl->set("Y Elements",4); panzer_stk::SquareQuadMeshFactory factory; factory.setParameterList(pl); RCP<panzer_stk::STK_Interface> mesh = factory.buildMesh(MPI_COMM_WORLD); if(mesh->isWritable()) mesh->writeToExodus("blocked_mesh.exo"); unsigned dim = mesh->getDimension(); std::vector<std::string> sideSets; std::vector<std::string> elementBlocks; mesh->getSidesetNames(sideSets); mesh->getElementBlockNames(elementBlocks); // loop over all sidesets for(std::size_t blk=0;blk<elementBlocks.size();++blk) { std::string eBlockId = elementBlocks[blk]; for(std::size_t side=0;side<sideSets.size();++side) { std::string sideName = sideSets[side]; std::vector<stk::mesh::Entity*> sideEntities; mesh->getMySides(sideName,eBlockId,sideEntities); // don't try to build worksets for sides that don't have // any entities if(sideEntities.size()==0) { std::cout << "SIDE = " << sideName << "/" << eBlockId << " <empty>" << std::endl; continue; } std::vector<stk::mesh::Entity*> elements; std::vector<std::size_t> localSideIds; panzer_stk::workset_utils::getSideElements(*mesh,eBlockId,sideEntities,localSideIds,elements); TEUCHOS_ASSERT(localSideIds.size()==elements.size()); FieldContainer vertices; vertices.resize(elements.size(),4,dim); // loop over elements of this block std::vector<std::size_t> localIds; for(std::size_t elm=0;elm<elements.size();++elm) { std::vector<stk::mesh::EntityId> nodes; stk::mesh::Entity * element = elements[elm]; localIds.push_back(mesh->elementLocalId(element)); getNodeIds(mesh->getNodeRank(),element,nodes); TEUCHOS_ASSERT(nodes.size()==4); for(std::size_t v=0;v<nodes.size();++v) { const double * coord = mesh->getNodeCoordinates(nodes[v]); for(unsigned d=0;d<dim;++d) vertices(elm,v,d) = coord[d]; } } // print an excessive amount of information std::cout << "SIDE = " << sideName << "/" << eBlockId << std::endl; for(std::size_t elm=0;elm<elements.size();++elm) { std::cout << " LID = " << localIds[elm]; std::cout << ", Side = " << localSideIds[elm]; std::cout << ", V = "; for(std::size_t v=0;v<4;++v) { std::cout << "[ "; for(unsigned d=0;d<dim;++d) std::cout << vertices(elm,v,d) << " "; std::cout << "], "; } std::cout << std::endl; } } } return 0; }
int main(int argc, char *argv[]) { Teuchos::GlobalMPISession mpiSession(&argc, &argv); // This little trick lets us print to std::cout only if // a (dummy) command-line argument is provided. int iprint = argc - 1; Teuchos::RCP<std::ostream> outStream; Teuchos::oblackholestream bhs; // outputs nothing if (iprint > 0) outStream = Teuchos::rcp(&std::cout, false); else outStream = Teuchos::rcp(&bhs, false); // Save the format state of the original std::cout. Teuchos::oblackholestream oldFormatState; oldFormatState.copyfmt(std::cout); *outStream \ << "===============================================================================\n" \ << "| |\n" \ << "| Unit Test (Basis_HDIV_QUAD_I1_FEM) |\n" \ << "| |\n" \ << "| 1) Conversion of Dof tags into Dof ordinals and back |\n" \ << "| 2) Basis values for VALUE and DIV operators |\n" \ << "| |\n" \ << "| Questions? Contact Pavel Bochev ([email protected]), |\n" \ << "| Denis Ridzal ([email protected]), |\n" \ << "| Kara Peterson ([email protected]). |\n" \ << "| |\n" \ << "| Intrepid's website: http://trilinos.sandia.gov/packages/intrepid |\n" \ << "| Trilinos website: http://trilinos.sandia.gov |\n" \ << "| |\n" \ << "===============================================================================\n"\ << "| TEST 1: Basis creation, exception testing |\n"\ << "===============================================================================\n"; // Define basis and error flag Basis_HDIV_QUAD_I1_FEM<double, FieldContainer<double> > quadBasis; int errorFlag = 0; // Initialize throw counter for exception testing int nException = 0; int throwCounter = 0; // Array with the 4 vertices of the reference Quadrilateral, its center and 4 more points FieldContainer<double> quadNodes(9, 2); quadNodes(0,0) = -1.0; quadNodes(0,1) = -1.0; quadNodes(1,0) = 1.0; quadNodes(1,1) = -1.0; quadNodes(2,0) = 1.0; quadNodes(2,1) = 1.0; quadNodes(3,0) = -1.0; quadNodes(3,1) = 1.0; quadNodes(4,0) = 0.0; quadNodes(4,1) = 0.0; quadNodes(5,0) = 0.0; quadNodes(5,1) = -0.5; quadNodes(6,0) = 0.0; quadNodes(6,1) = 0.5; quadNodes(7,0) = -0.5; quadNodes(7,1) = 0.0; quadNodes(8,0) = 0.5; quadNodes(8,1) = 0.0; // Generic array for the output values; needs to be properly resized depending on the operator type FieldContainer<double> vals; try { int spaceDim = quadBasis.getBaseCellTopology().getDimension(); // exception #1: GRAD cannot be applied to HDIV functions // resize vals to rank-3 container with dimensions (num. basis functions, num. points, arbitrary) vals.resize(quadBasis.getCardinality(), quadNodes.dimension(0), spaceDim ); INTREPID_TEST_COMMAND( quadBasis.getValues(vals, quadNodes, OPERATOR_GRAD), throwCounter, nException ); // exception #2: CURL cannot be applied to HDIV functions INTREPID_TEST_COMMAND( quadBasis.getValues(vals, quadNodes, OPERATOR_CURL), throwCounter, nException ); // Exceptions 3-7: all bf tags/bf Ids below are wrong and should cause getDofOrdinal() and // getDofTag() to access invalid array elements thereby causing bounds check exception // exception #3 INTREPID_TEST_COMMAND( quadBasis.getDofOrdinal(3,0,0), throwCounter, nException ); // exception #4 INTREPID_TEST_COMMAND( quadBasis.getDofOrdinal(1,1,1), throwCounter, nException ); // exception #5 INTREPID_TEST_COMMAND( quadBasis.getDofOrdinal(0,4,1), throwCounter, nException ); // exception #6 INTREPID_TEST_COMMAND( quadBasis.getDofTag(12), throwCounter, nException ); // exception #7 INTREPID_TEST_COMMAND( quadBasis.getDofTag(-1), throwCounter, nException ); #ifdef HAVE_INTREPID_DEBUG // Exceptions 8- test exception handling with incorrectly dimensioned input/output arrays // exception #8: input points array must be of rank-2 FieldContainer<double> badPoints1(4, 5, 3); INTREPID_TEST_COMMAND( quadBasis.getValues(vals, badPoints1, OPERATOR_VALUE), throwCounter, nException ); // exception #9 dimension 1 in the input point array must equal space dimension of the cell FieldContainer<double> badPoints2(4, spaceDim + 1); INTREPID_TEST_COMMAND( quadBasis.getValues(vals, badPoints2, OPERATOR_VALUE), throwCounter, nException ); // exception #10 output values must be of rank-3 for OPERATOR_VALUE FieldContainer<double> badVals1(4, 5); INTREPID_TEST_COMMAND( quadBasis.getValues(badVals1, quadNodes, OPERATOR_VALUE), throwCounter, nException ); // exception #11 output values must be of rank-2 for OPERATOR_DIV FieldContainer<double> badVals2(4, 5, spaceDim); INTREPID_TEST_COMMAND( quadBasis.getValues(badVals2, quadNodes, OPERATOR_DIV), throwCounter, nException ); // exception #12 incorrect 0th dimension of output array (must equal number of basis functions) FieldContainer<double> badVals3(quadBasis.getCardinality() + 1, quadNodes.dimension(0), spaceDim); INTREPID_TEST_COMMAND( quadBasis.getValues(badVals3, quadNodes, OPERATOR_VALUE), throwCounter, nException ); // exception #13 incorrect 0th dimension of output array (must equal number of basis functions) FieldContainer<double> badVals4(quadBasis.getCardinality() + 1, quadNodes.dimension(0)); INTREPID_TEST_COMMAND( quadBasis.getValues(badVals4, quadNodes, OPERATOR_DIV), throwCounter, nException ); // exception #14 incorrect 1st dimension of output array (must equal number of points) FieldContainer<double> badVals5(quadBasis.getCardinality(), quadNodes.dimension(0) + 1, spaceDim); INTREPID_TEST_COMMAND( quadBasis.getValues(badVals5, quadNodes, OPERATOR_VALUE), throwCounter, nException ); // exception #15 incorrect 1st dimension of output array (must equal number of points) FieldContainer<double> badVals6(quadBasis.getCardinality(), quadNodes.dimension(0) + 1); INTREPID_TEST_COMMAND( quadBasis.getValues(badVals6, quadNodes, OPERATOR_DIV), throwCounter, nException ); // exception #16: incorrect 2nd dimension of output array (must equal the space dimension) FieldContainer<double> badVals7(quadBasis.getCardinality(), quadNodes.dimension(0), spaceDim + 1); INTREPID_TEST_COMMAND( quadBasis.getValues(badVals7, quadNodes, OPERATOR_VALUE), throwCounter, nException ); #endif } catch (std::logic_error err) { *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n"; *outStream << err.what() << '\n'; *outStream << "-------------------------------------------------------------------------------" << "\n\n"; errorFlag = -1000; }; // Check if number of thrown exceptions matches the one we expect if (throwCounter != nException) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; } *outStream \ << "\n" << "===============================================================================\n"\ << "| TEST 2: correctness of tag to enum and enum to tag lookups |\n"\ << "===============================================================================\n"; try { std::vector<std::vector<int> > allTags = quadBasis.getAllDofTags(); // Loop over all tags, lookup the associated dof enumeration and then lookup the tag again for (unsigned i = 0; i < allTags.size(); i++) { int bfOrd = quadBasis.getDofOrdinal(allTags[i][0], allTags[i][1], allTags[i][2]); std::vector<int> myTag = quadBasis.getDofTag(bfOrd); if( !( (myTag[0] == allTags[i][0]) && (myTag[1] == allTags[i][1]) && (myTag[2] == allTags[i][2]) && (myTag[3] == allTags[i][3]) ) ) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; *outStream << " getDofOrdinal( {" << allTags[i][0] << ", " << allTags[i][1] << ", " << allTags[i][2] << ", " << allTags[i][3] << "}) = " << bfOrd <<" but \n"; *outStream << " getDofTag(" << bfOrd << ") = { " << myTag[0] << ", " << myTag[1] << ", " << myTag[2] << ", " << myTag[3] << "}\n"; } } // Now do the same but loop over basis functions for( int bfOrd = 0; bfOrd < quadBasis.getCardinality(); bfOrd++) { std::vector<int> myTag = quadBasis.getDofTag(bfOrd); int myBfOrd = quadBasis.getDofOrdinal(myTag[0], myTag[1], myTag[2]); if( bfOrd != myBfOrd) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; *outStream << " getDofTag(" << bfOrd << ") = { " << myTag[0] << ", " << myTag[1] << ", " << myTag[2] << ", " << myTag[3] << "} but getDofOrdinal({" << myTag[0] << ", " << myTag[1] << ", " << myTag[2] << ", " << myTag[3] << "} ) = " << myBfOrd << "\n"; } } } catch (std::logic_error err) { *outStream << err.what() << "\n\n"; errorFlag = -1000; }; *outStream \ << "\n" << "===============================================================================\n"\ << "| TEST 3: correctness of basis function values |\n"\ << "===============================================================================\n"; outStream -> precision(20); // VALUE: Each row pair gives the 6x3 correct basis set values at an evaluation point: (P,F,D) layout double basisValues[] = { 0, -0.500000, 0, 0, 0, 0, -0.500000, 0, 0, -0.500000, 0.500000, 0, 0, \ 0, 0, 0, 0, 0, 0.500000, 0, 0, 0.500000, 0, 0, 0, 0, 0, 0, 0, \ 0.500000, -0.500000, 0, 0, -0.250000, 0.250000, 0, 0, 0.250000, \ -0.250000, 0, 0, -0.375000, 0.250000, 0, 0, 0.125000, -0.250000, 0, \ 0, -0.125000, 0.250000, 0, 0, 0.375000, -0.250000, 0, 0, -0.250000, \ 0.125000, 0, 0, 0.250000, -0.375000, 0, 0, -0.250000, 0.375000, 0, 0, \ 0.250000, -0.125000, 0 }; // DIV: each row gives the 6 correct values of the divergence of the 6 basis functions: (P,F) layout double basisDivs[] = { 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, }; try { // Dimensions for the output arrays: int numPoints = quadNodes.dimension(0); int numFields = quadBasis.getCardinality(); int spaceDim = quadBasis.getBaseCellTopology().getDimension(); // Generic array for values and curls that will be properly sized before each call FieldContainer<double> vals; // Check VALUE of basis functions: resize vals to rank-3 container: vals.resize(numFields, numPoints, spaceDim); quadBasis.getValues(vals, quadNodes, OPERATOR_VALUE); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { for (int k = 0; k < spaceDim; k++) { // compute offset for (P,F,D) data layout: indices are P->j, F->i, D->k int l = k + i * spaceDim + j * spaceDim * numFields; if (std::abs(vals(i,j,k) - basisValues[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " "; *outStream << j << " "; *outStream << k << " "; *outStream << "} computed value: " << vals(i,j,k) << " but reference value: " << basisValues[l] << "\n"; } } } } // Check DIV of basis function: resize vals to rank-2 container vals.resize(numFields, numPoints); quadBasis.getValues(vals, quadNodes, OPERATOR_DIV); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { int l = i + j * numFields; if (std::abs(vals(i,j) - basisDivs[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " "; *outStream << j << " "; *outStream << "} computed divergence component: " << vals(i,j) << " but reference divergence component: " << basisDivs[l] << "\n"; } } } } // Catch unexpected errors catch (std::logic_error err) { *outStream << err.what() << "\n\n"; errorFlag = -1000; }; if (errorFlag != 0) std::cout << "End Result: TEST FAILED\n"; else std::cout << "End Result: TEST PASSED\n"; // reset format state of std::cout std::cout.copyfmt(oldFormatState); return errorFlag; }
int 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; Teuchos::RCP<std::ostream> outStream; Teuchos::oblackholestream bhs; // outputs nothing if (iprint > 0) outStream = Teuchos::rcp(&std::cout, false); else outStream = Teuchos::rcp(&bhs, false); // Save the format state of the original std::cout. Teuchos::oblackholestream oldFormatState; oldFormatState.copyfmt(std::cout); *outStream \ << "===============================================================================\n" \ << "| |\n" \ << "| Unit Test (Basis_HGRAD_LINE_Cn_FEM) |\n" \ << "| |\n" \ << "| 1) Conversion of Dof tags into Dof ordinals and back |\n" \ << "| 2) Basis values for VALUE, GRAD, CURL, and Dk operators |\n" \ << "| |\n" \ << "| Questions? Contact Pavel Bochev ([email protected]), |\n" \ << "| Denis Ridzal ([email protected]), |\n" \ << "| Kara Peterson ([email protected]). |\n" \ << "| |\n" \ << "| Intrepid's website: http://trilinos.sandia.gov/packages/intrepid |\n" \ << "| Trilinos website: http://trilinos.sandia.gov |\n" \ << "| |\n" \ << "===============================================================================\n"\ << "| TEST 1: Basis creation, exception testing |\n"\ << "===============================================================================\n"; // Define basis and error flag shards::CellTopology line(shards::getCellTopologyData< shards::Line<> >()); // create cell topology const int deg = 5; // get the points for the basis FieldContainer<double> pts(PointTools::getLatticeSize(line,deg),1); PointTools::getLattice<double,FieldContainer<double> >(pts,line,deg); Basis_HGRAD_LINE_Cn_FEM<double, FieldContainer<double> > lineBasis(deg, pts); int errorFlag = 0; // Initialize throw counter for exception testing int nException = 0; int throwCounter = 0; // Define array containing vertices of the reference Line and a few other points int numIntervals = 100; FieldContainer<double> lineNodes(numIntervals+1, 1); for (int i=0; i<numIntervals+1; i++) { lineNodes(i,0) = -1.0+(2.0*(double)i)/(double)numIntervals; } // Generic array for the output values; needs to be properly resized depending on the operator type FieldContainer<double> vals; try{ // exception #1: DIV cannot be applied to scalar functions // resize vals to rank-2 container with dimensions (num. points, num. basis functions) vals.resize(lineBasis.getCardinality(), lineNodes.dimension(0) ); //INTREPID_TEST_COMMAND( lineBasis.getValues(vals, lineNodes, OPERATOR_DIV), throwCounter, nException ); // Exceptions 1-5: all bf tags/bf Ids below are wrong and should cause getDofOrdinal() and // getDofTag() to access invalid array elements thereby causing bounds check exception // exception #1 INTREPID_TEST_COMMAND( lineBasis.getDofOrdinal(2,0,0), throwCounter, nException ); // exception #2 INTREPID_TEST_COMMAND( lineBasis.getDofOrdinal(1,1,1), throwCounter, nException ); // exception #3 INTREPID_TEST_COMMAND( lineBasis.getDofOrdinal(1,0,7), throwCounter, nException ); // exception #4 INTREPID_TEST_COMMAND( lineBasis.getDofTag(6), throwCounter, nException ); // exception #5 INTREPID_TEST_COMMAND( lineBasis.getDofTag(-1), throwCounter, nException ); // not an exception INTREPID_TEST_COMMAND( lineBasis.getDofTag(5), throwCounter, nException ); --nException; #ifdef HAVE_INTREPID2_DEBUG // Exceptions 6-14 test exception handling with incorrectly dimensioned input/output arrays // exception #6: input points array must be of rank-2 FieldContainer<double> badPoints1(4, 5, 3); INTREPID_TEST_COMMAND( lineBasis.getValues(vals, badPoints1, OPERATOR_VALUE), throwCounter, nException ); // exception #7: dimension 1 in the input point array must equal space dimension of the cell FieldContainer<double> badPoints2(4, 3); INTREPID_TEST_COMMAND( lineBasis.getValues(vals, badPoints2, OPERATOR_VALUE), throwCounter, nException ); // exception #8: output values must be of rank-2 for OPERATOR_VALUE FieldContainer<double> badVals1(4, 3, 1); INTREPID_TEST_COMMAND( lineBasis.getValues(badVals1, lineNodes, OPERATOR_VALUE), throwCounter, nException ); // exception #9: output values must be of rank-3 for OPERATOR_GRAD FieldContainer<double> badVals2(4, 3); INTREPID_TEST_COMMAND( lineBasis.getValues(badVals2, lineNodes, OPERATOR_GRAD), throwCounter, nException ); // exception #10: output values must be of rank-2 for OPERATOR_D1 INTREPID_TEST_COMMAND( lineBasis.getValues(badVals2, lineNodes, OPERATOR_D1), throwCounter, nException ); // exception #11: incorrect 0th dimension of output array (must equal number of basis functions) FieldContainer<double> badVals3(lineBasis.getCardinality() + 1, lineNodes.dimension(0)); INTREPID_TEST_COMMAND( lineBasis.getValues(badVals3, lineNodes, OPERATOR_VALUE), throwCounter, nException ); // exception #12: incorrect 1st dimension of output array (must equal number of points) FieldContainer<double> badVals4(lineBasis.getCardinality(), lineNodes.dimension(0) + 1); INTREPID_TEST_COMMAND( lineBasis.getValues(badVals4, lineNodes, OPERATOR_VALUE), throwCounter, nException ); // exception #13: incorrect 2nd dimension of output array (must equal spatial dimension) FieldContainer<double> badVals5(lineBasis.getCardinality(), lineNodes.dimension(0), 2); INTREPID_TEST_COMMAND( lineBasis.getValues(badVals5, lineNodes, OPERATOR_GRAD), throwCounter, nException ); // not an exception FieldContainer<double> goodVals2(lineBasis.getCardinality(), lineNodes.dimension(0)); INTREPID_TEST_COMMAND( lineBasis.getValues(goodVals2, lineNodes, OPERATOR_VALUE), throwCounter, nException ); --nException; #endif } catch (std::logic_error err) { *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n"; *outStream << err.what() << '\n'; *outStream << "-------------------------------------------------------------------------------" << "\n\n"; errorFlag = -1000; }; // Check if number of thrown exceptions matches the one we expect if (throwCounter != nException) { errorFlag++; *outStream << std::setw(70) << "FAILURE! Incorrect number of exceptions." << "\n"; } *outStream \ << "\n" << "===============================================================================\n" \ << "| TEST 2: correctness of basis function values |\n" \ << "===============================================================================\n"; outStream -> precision(20); try { // Check Kronecker property for Lagrange polynomials. int maxorder = 4; for (int ordi=1; ordi <= maxorder; ordi++) { FieldContainer<double> pts(PointTools::getLatticeSize(line,ordi),1); PointTools::getLattice<double,FieldContainer<double> >(pts,line,ordi); Basis_HGRAD_LINE_Cn_FEM<double, FieldContainer<double> > lineBasis(ordi, pts); FieldContainer<double> vals(lineBasis.getCardinality(),pts.dimension(0)); lineBasis.getValues(vals,pts,OPERATOR_VALUE); for (int i=0;i<lineBasis.getCardinality();i++) { for (int j=0;j<pts.dimension(0);j++) { if ( i==j && std::abs( vals(i,j) - 1.0 ) > INTREPID_TOL ) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; *outStream << " Basis function " << i << " does not have unit value at its node\n"; } if ( i!=j && std::abs( vals(i,j) ) > INTREPID_TOL ) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; *outStream << " Basis function " << i << " does not vanish at node " << j << "\n"; } } } } } // Catch unexpected errors catch (std::logic_error err) { *outStream << err.what() << "\n\n"; errorFlag = -1000; }; if (errorFlag != 0) std::cout << "End Result: TEST FAILED\n"; else std::cout << "End Result: TEST PASSED\n"; // reset format state of std::cout std::cout.copyfmt(oldFormatState); Kokkos::finalize(); return errorFlag; }
FieldContainer<double> SubBasisDofMatrixMapper::mapData(bool transposeConstraint, FieldContainer<double> &localData, bool applyOnLeftOnly) { // localData must be rank 2, and must have the same size as FilteredLocalDofOrdinals in its first dimension bool didReshape = false; if (localData.rank() == 1) { // reshape as a rank 2 container (column vector as a matrix): localData.resize(localData.dimension(0),1); didReshape = true; } if (localData.rank() != 2) { cout << "localData must have rank 1 or 2.\n"; TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "localData must have rank 1 or 2"); } int constraintRows = transposeConstraint ? _constraintMatrix.dimension(1) : _constraintMatrix.dimension(0); int constraintCols = transposeConstraint ? _constraintMatrix.dimension(0) : _constraintMatrix.dimension(1); int dataCols = localData.dimension(1); int dataRows = localData.dimension(0); if ((dataCols==0) || (dataRows==0) || (constraintRows==0) || (constraintCols==0)) { cout << "degenerate matrix encountered.\n"; } // given the multiplication we'll do, we need constraint columns = data rows if (constraintCols != dataRows) { cout << "Missized container in SubBasisDofMatrixMapper::mapData() for left-multiplication by constraint matrix.\n"; TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Missized container in SubBasisDofMatrixMapper::mapData()."); } // (could also test that the dimensions match what we expect in terms of the size of the mapped global dof ordinals or basisDofOrdinal filter) FieldContainer<double> result1(constraintRows,dataCols); char constraintTransposeFlag = transposeConstraint ? 'T' : 'N'; char dataTransposeFlag = 'N'; SerialDenseWrapper::multiply(result1,_constraintMatrix,localData,constraintTransposeFlag,dataTransposeFlag); if (didReshape) // change the shape of localData back, and return result { localData.resize(localData.dimension(0)); result1.resize(result1.size()); return result1; } if (applyOnLeftOnly) return result1; if (constraintCols != dataCols) { cout << "Missized container in SubBasisDofMatrixMapper::mapData() for right-multiplication by constraint matrix.\n"; TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Missized container in SubBasisDofMatrixMapper::mapData()."); } constraintTransposeFlag = (!transposeConstraint) ? 'T' : 'N'; // opposite of the above choice, since now we multiply on the right char resultTransposeFlag = 'N'; FieldContainer<double> result(constraintRows,constraintRows); SerialDenseWrapper::multiply(result,result1,_constraintMatrix,resultTransposeFlag,constraintTransposeFlag); return result; }
bool testBasisClassifications(BasisPtr basis) { bool success = true; CellTopoPtr cellTopo = basis->domainTopology(); int numVertices = cellTopo->getVertexCount(); int numEdges = cellTopo->getEdgeCount(); int degree = basis->getDegree(); // TODO: finish this vector<int> vertexOrdinals; for (int vertexIndex=0; vertexIndex < numVertices; vertexIndex++) { set<int> dofOrdinals = basis->dofOrdinalsForVertex(vertexIndex); if (dofOrdinals.size() == 0) TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "No dofOrdinal for vertex..."); if (dofOrdinals.size() > 1) TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "More than one dofOrdinal per vertex..."); vertexOrdinals.push_back(*(dofOrdinals.begin())); } // // if (! checkVertexOrdinalsQuad(basis, vertexOrdinals) ) { // success = false; // cout << "vertex dof ordinals don't match expected\n"; // cout << "ordinals: "; // for (int vertexIndex=0; vertexIndex < numVertices; vertexIndex++) { // cout << vertexOrdinals[vertexIndex] << " "; // } // cout << endl; // } // get the points in reference space for each vertex FieldContainer<double> points; if (numVertices == 2) { // line points.resize(2,1); points(0,0) = -1; points(1,0) = 1; } else if (numVertices == 3) { // triangle TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "triangles not yet supported"); } else if (numVertices == 4) { // quad points.resize(4,2); points(0,0) = -1; points(0,1) = -1; points(1,0) = 1; points(1,1) = -1; points(2,0) = 1; points(2,1) = 1; points(3,0) = -1; points(3,1) = 1; } else { TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "unsupported topology"); } FieldContainer<double> vertexValues; if (basis->rangeRank() > 0) { TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "rank > 0 bases not yet supported"); } else { vertexValues.resize(basis->getCardinality(),numVertices); } basis->getValues(vertexValues, points, Intrepid::OPERATOR_VALUE); // test that the points are correctly classified for (int fieldIndex=0; fieldIndex<basis->getCardinality(); fieldIndex++) { for (int ptIndex=0; ptIndex<numVertices; ptIndex++) { int dofOrdinalForPoint = vertexOrdinals[ptIndex]; bool expectZero = (dofOrdinalForPoint != fieldIndex); if (expectZero) { if (vertexValues(fieldIndex,ptIndex) != 0) { success = false; cout << "Expected 0 for fieldIndex " << fieldIndex << " and ptIndex " << ptIndex; cout << ", but got " << vertexValues(fieldIndex,ptIndex) << endl; } } else { if (vertexValues(fieldIndex,ptIndex) == 0) { cout << "Expected nonzero for fieldIndex " << fieldIndex << " and ptIndex " << ptIndex << endl; success = false; } } } } if (!success) { cout << "Failed testBasisClassifications; vertexValues:\n" << vertexValues; } return success; }
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; Teuchos::RCP<std::ostream> outStream; Teuchos::oblackholestream bhs; // outputs nothing if (iprint > 0) outStream = Teuchos::rcp(&std::cout, false); else outStream = Teuchos::rcp(&bhs, false); // Save the format state of the original std::cout. Teuchos::oblackholestream oldFormatState; oldFormatState.copyfmt(std::cout); *outStream \ << "===============================================================================\n" \ << "| |\n" \ << "| Unit Test (Basis_HGRAD_TET_C2_FEM) |\n" \ << "| |\n" \ << "| 1) Conversion of Dof tags into Dof ordinals and back |\n" \ << "| 2) Basis values for VALUE, GRAD, and Dk operators |\n" \ << "| |\n" \ << "| Questions? Contact Pavel Bochev ([email protected]), |\n" \ << "| Denis Ridzal ([email protected]), |\n" \ << "| Kara Peterson ([email protected]). |\n" \ << "| |\n" \ << "| Intrepid's website: http://trilinos.sandia.gov/packages/intrepid |\n" \ << "| Trilinos website: http://trilinos.sandia.gov |\n" \ << "| |\n" \ << "===============================================================================\n"\ << "| TEST 1: Basis creation, exception testing |\n"\ << "===============================================================================\n"; // Define basis and error flag Basis_HGRAD_TET_C2_FEM<double, FieldContainer<double> > tetBasis; int errorFlag = 0; // Initialize throw counter for exception testing int nException = 0; int throwCounter = 0; // Define array containing the 10 nodes of Tetrahedron<10>: 4 vertices + 6 edge midpoints FieldContainer<double> tetNodes(10, 3); tetNodes(0,0) = 0.0; tetNodes(0,1) = 0.0; tetNodes(0,2) = 0.0; tetNodes(1,0) = 1.0; tetNodes(1,1) = 0.0; tetNodes(1,2) = 0.0; tetNodes(2,0) = 0.0; tetNodes(2,1) = 1.0; tetNodes(2,2) = 0.0; tetNodes(3,0) = 0.0; tetNodes(3,1) = 0.0; tetNodes(3,2) = 1.0; tetNodes(4,0) = 0.5; tetNodes(4,1) = 0.0; tetNodes(4,2) = 0.0; tetNodes(5,0) = 0.5; tetNodes(5,1) = 0.5; tetNodes(5,2) = 0.0; tetNodes(6,0) = 0.0; tetNodes(6,1) = 0.5; tetNodes(6,2) = 0.0; tetNodes(7,0) = 0.0; tetNodes(7,1) = 0.0; tetNodes(7,2) = 0.5; tetNodes(8,0) = 0.5; tetNodes(8,1) = 0.0; tetNodes(8,2) = 0.5; tetNodes(9,0) = 0.0; tetNodes(9,1) = 0.5; tetNodes(9,2) = 0.5; // Generic array for the output values; needs to be properly resized depending on the operator type FieldContainer<double> vals; try{ // exception #1: CURL cannot be applied to scalar functions // resize vals to rank-3 container with dimensions (num. points, num. basis functions, arbitrary) vals.resize(tetBasis.getCardinality(), tetNodes.dimension(0), 4 ); INTREPID_TEST_COMMAND( tetBasis.getValues(vals, tetNodes, OPERATOR_CURL), throwCounter, nException ); // exception #2: DIV cannot be applied to scalar functions // resize vals to rank-2 container with dimensions (num. points, num. basis functions) vals.resize(tetBasis.getCardinality(), tetNodes.dimension(0) ); INTREPID_TEST_COMMAND( tetBasis.getValues(vals, tetNodes, OPERATOR_DIV), throwCounter, nException ); // Exceptions 3-7: all bf tags/bf Ids below are wrong and should cause getDofOrdinal() and // getDofTag() to access invalid array elements thereby causing bounds check exception // exception #3 INTREPID_TEST_COMMAND( tetBasis.getDofOrdinal(3,0,0), throwCounter, nException ); // exception #4 INTREPID_TEST_COMMAND( tetBasis.getDofOrdinal(1,1,1), throwCounter, nException ); // exception #5 INTREPID_TEST_COMMAND( tetBasis.getDofOrdinal(0,4,0), throwCounter, nException ); // exception #6 INTREPID_TEST_COMMAND( tetBasis.getDofTag(10), throwCounter, nException ); // exception #7 INTREPID_TEST_COMMAND( tetBasis.getDofTag(-1), throwCounter, nException ); #ifdef HAVE_INTREPID2_DEBUG // Exceptions 8-18 test exception handling with incorrectly dimensioned input/output arrays // exception #8: input points array must be of rank-2 FieldContainer<double> badPoints1(4, 5, 3); INTREPID_TEST_COMMAND( tetBasis.getValues(vals, badPoints1, OPERATOR_VALUE), throwCounter, nException ); // exception #9 dimension 1 in the input point array must equal space dimension of the cell FieldContainer<double> badPoints2(4, tetBasis.getBaseCellTopology().getDimension() - 1); INTREPID_TEST_COMMAND( tetBasis.getValues(vals, badPoints2, OPERATOR_VALUE), throwCounter, nException ); // exception #10 output values must be of rank-2 for OPERATOR_VALUE FieldContainer<double> badVals1(4, 3, 1); INTREPID_TEST_COMMAND( tetBasis.getValues(badVals1, tetNodes, OPERATOR_VALUE), throwCounter, nException ); // exception #11 output values must be of rank-3 for OPERATOR_GRAD FieldContainer<double> badVals2(4, 3); INTREPID_TEST_COMMAND( tetBasis.getValues(badVals2, tetNodes, OPERATOR_GRAD), throwCounter, nException ); // exception #12 output values must be of rank-3 for OPERATOR_D1 INTREPID_TEST_COMMAND( tetBasis.getValues(badVals2, tetNodes, OPERATOR_D1), throwCounter, nException ); // exception #13 output values must be of rank-3 for OPERATOR_D2 INTREPID_TEST_COMMAND( tetBasis.getValues(badVals2, tetNodes, OPERATOR_D2), throwCounter, nException ); // exception #14 incorrect 0th dimension of output array (must equal number of basis functions) FieldContainer<double> badVals3(tetBasis.getCardinality() + 1, tetNodes.dimension(0)); INTREPID_TEST_COMMAND( tetBasis.getValues(badVals3, tetNodes, OPERATOR_VALUE), throwCounter, nException ); // exception #15 incorrect 1st dimension of output array (must equal number of points) FieldContainer<double> badVals4(tetBasis.getCardinality(), tetNodes.dimension(0) + 1); INTREPID_TEST_COMMAND( tetBasis.getValues(badVals4, tetNodes, OPERATOR_VALUE), throwCounter, nException ); // exception #16: incorrect 2nd dimension of output array (must equal the space dimension) FieldContainer<double> badVals5(tetBasis.getCardinality(), tetNodes.dimension(0), tetBasis.getBaseCellTopology().getDimension() + 1); INTREPID_TEST_COMMAND( tetBasis.getValues(badVals5, tetNodes, OPERATOR_GRAD), throwCounter, nException ); // exception #17: incorrect 2nd dimension of output array (must equal D2 cardinality in 2D) FieldContainer<double> badVals6(tetBasis.getCardinality(), tetNodes.dimension(0), 40); INTREPID_TEST_COMMAND( tetBasis.getValues(badVals6, tetNodes, OPERATOR_D1), throwCounter, nException ); // exception #18: incorrect 2nd dimension of output array (must equal D3 cardinality in 2D) INTREPID_TEST_COMMAND( tetBasis.getValues(badVals6, tetNodes, OPERATOR_D2), throwCounter, nException ); #endif } catch (std::logic_error err) { *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n"; *outStream << err.what() << '\n'; *outStream << "-------------------------------------------------------------------------------" << "\n\n"; errorFlag = -1000; }; // Check if number of thrown exceptions matches the one we expect if (throwCounter != nException) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; } *outStream \ << "\n" << "===============================================================================\n"\ << "| TEST 2: correctness of tag to enum and enum to tag lookups |\n"\ << "===============================================================================\n"; try{ std::vector<std::vector<int> > allTags = tetBasis.getAllDofTags(); // Loop over all tags, lookup the associated dof enumeration and then lookup the tag again for (unsigned i = 0; i < allTags.size(); i++) { int bfOrd = tetBasis.getDofOrdinal(allTags[i][0], allTags[i][1], allTags[i][2]); std::vector<int> myTag = tetBasis.getDofTag(bfOrd); if( !( (myTag[0] == allTags[i][0]) && (myTag[1] == allTags[i][1]) && (myTag[2] == allTags[i][2]) && (myTag[3] == allTags[i][3]) ) ) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; *outStream << " getDofOrdinal( {" << allTags[i][0] << ", " << allTags[i][1] << ", " << allTags[i][2] << ", " << allTags[i][3] << "}) = " << bfOrd <<" but \n"; *outStream << " getDofTag(" << bfOrd << ") = { " << myTag[0] << ", " << myTag[1] << ", " << myTag[2] << ", " << myTag[3] << "}\n"; } } // Now do the same but loop over basis functions for( int bfOrd = 0; bfOrd < tetBasis.getCardinality(); bfOrd++) { std::vector<int> myTag = tetBasis.getDofTag(bfOrd); int myBfOrd = tetBasis.getDofOrdinal(myTag[0], myTag[1], myTag[2]); if( bfOrd != myBfOrd) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; *outStream << " getDofTag(" << bfOrd << ") = { " << myTag[0] << ", " << myTag[1] << ", " << myTag[2] << ", " << myTag[3] << "} but getDofOrdinal({" << myTag[0] << ", " << myTag[1] << ", " << myTag[2] << ", " << myTag[3] << "} ) = " << myBfOrd << "\n"; } } } catch (std::logic_error err){ *outStream << err.what() << "\n\n"; errorFlag = -1000; }; *outStream \ << "\n" << "===============================================================================\n"\ << "| TEST 3: correctness of basis function values |\n"\ << "===============================================================================\n"; outStream -> precision(20); // VALUE: in (F,P) format double basisValues[] = { 1.00000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00000, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 1.00000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00000, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 1.00000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00000, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 1.00000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.00000, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 1.00000 }; // GRAD and D1: in (F,P,D) format double basisGrads[] = { -3.00000, -3.00000, -3.00000, 1.00000, 1.00000, 1.00000, 1.00000, \ 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, -1.00000, -1.00000, \ -1.00000, 1.00000, 1.00000, 1.00000, -1.00000, -1.00000, -1.00000, \ -1.00000, -1.00000, -1.00000, 1.00000, 1.00000, 1.00000, 1.00000, \ 1.00000, 1.00000, -1.00000, 0, 0, 3.00000, 0, 0, -1.00000, 0, 0, \ -1.00000, 0, 0, 1.00000, 0, 0, 1.00000, 0, 0, -1.00000, 0, 0, \ -1.00000, 0, 0, 1.00000, 0, 0, -1.00000, 0, 0, 0, -1.00000, 0, 0, \ -1.00000, 0, 0, 3.00000, 0, 0, -1.00000, 0, 0, -1.00000, 0, 0, \ 1.00000, 0, 0, 1.00000, 0, 0, -1.00000, 0, 0, -1.00000, 0, 0, \ 1.00000, 0, 0, 0, -1.00000, 0, 0, -1.00000, 0, 0, -1.00000, 0, 0, \ 3.00000, 0, 0, -1.00000, 0, 0, -1.00000, 0, 0, -1.00000, 0, 0, \ 1.00000, 0, 0, 1.00000, 0, 0, 1.00000, 4.00000, 0, 0, -4.00000, \ -4.00000, -4.00000, 0, 0, 0, 0, 0, 0, 0, -2.00000, -2.00000, \ -2.00000, -2.00000, -2.00000, 2.00000, 0, 0, 2.00000, 0, 0, -2.00000, \ -2.00000, -2.00000, 0, 0, 0, 0, 0, 0, 0, 4.00000, 0, 4.00000, 0, 0, \ 0, 0, 0, 0, 2.00000, 0, 2.00000, 2.00000, 0, 2.00000, 0, 0, 0, 0, 0, \ 0, 2.00000, 0, 2.00000, 0, 0, 0, 4.00000, 0, 0, 0, 0, -4.00000, \ -4.00000, -4.00000, 0, 0, 0, 0, 2.00000, 0, -2.00000, -2.00000, \ -2.00000, -2.00000, 0, -2.00000, 0, 2.00000, 0, 0, 0, 0, -2.00000, \ -2.00000, -2.00000, 0, 0, 4.00000, 0, 0, 0, 0, 0, 0, -4.00000, \ -4.00000, -4.00000, 0, 0, 2.00000, 0, 0, 0, 0, 0, 2.00000, -2.00000, \ -2.00000, 0, -2.00000, -2.00000, -2.00000, -2.00000, -2.00000, \ -2.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 4.00000, 0, 0, 0, 0, \ 2.00000, 0, 0, 2.00000, 0, 0, 0, 2.00000, 0, 0, 2.00000, 0, 2.00000, \ 2.00000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.00000, 0, 4.00000, 0, 0, 0, \ 0, 0, 0, 2.00000, 0, 0, 2.00000, 0, 2.00000, 0, 0, 2.00000, 0, 0, \ 2.00000, 2.00000}; // D2 values in (F,P, Dk) format double basisD2[]={ 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, \ 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, \ 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, \ 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, \ 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, \ 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, \ 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, \ 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, \ 4.00000, 4.00000, 4.00000, 4.00000, 4.00000, 0, 0, 0, 0, 0, 4.00000, \ 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, \ 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, \ 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, \ 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, \ 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, \ 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, \ 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 0, 0, 4.00000, \ 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, \ 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, \ 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, \ 0, 0, 4.00000, -8.00000, -4.00000, -4.00000, 0, 0, 0, -8.00000, \ -4.00000, -4.00000, 0, 0, 0, -8.00000, -4.00000, -4.00000, 0, 0, 0, \ -8.00000, -4.00000, -4.00000, 0, 0, 0, -8.00000, -4.00000, -4.00000, \ 0, 0, 0, -8.00000, -4.00000, -4.00000, 0, 0, 0, -8.00000, -4.00000, \ -4.00000, 0, 0, 0, -8.00000, -4.00000, -4.00000, 0, 0, 0, -8.00000, \ -4.00000, -4.00000, 0, 0, 0, -8.00000, -4.00000, -4.00000, 0, 0, 0, \ 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, \ 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, \ 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, \ 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, -4.00000, 0, -8.00000, -4.00000, \ 0, 0, -4.00000, 0, -8.00000, -4.00000, 0, 0, -4.00000, 0, -8.00000, \ -4.00000, 0, 0, -4.00000, 0, -8.00000, -4.00000, 0, 0, -4.00000, 0, \ -8.00000, -4.00000, 0, 0, -4.00000, 0, -8.00000, -4.00000, 0, 0, \ -4.00000, 0, -8.00000, -4.00000, 0, 0, -4.00000, 0, -8.00000, \ -4.00000, 0, 0, -4.00000, 0, -8.00000, -4.00000, 0, 0, -4.00000, 0, \ -8.00000, -4.00000, 0, 0, 0, -4.00000, 0, -4.00000, -8.00000, 0, 0, \ -4.00000, 0, -4.00000, -8.00000, 0, 0, -4.00000, 0, -4.00000, \ -8.00000, 0, 0, -4.00000, 0, -4.00000, -8.00000, 0, 0, -4.00000, 0, \ -4.00000, -8.00000, 0, 0, -4.00000, 0, -4.00000, -8.00000, 0, 0, \ -4.00000, 0, -4.00000, -8.00000, 0, 0, -4.00000, 0, -4.00000, \ -8.00000, 0, 0, -4.00000, 0, -4.00000, -8.00000, 0, 0, -4.00000, 0, \ -4.00000, -8.00000, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, \ 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, \ 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, \ 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 0, 0, \ 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, \ 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, \ 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, 0, 0, 0, 4.00000, 0, 0, \ 0, 0, 0, 4.00000, 0 }; try{ // Dimensions for the output arrays: int numFields = tetBasis.getCardinality(); int numPoints = tetNodes.dimension(0); int spaceDim = tetBasis.getBaseCellTopology().getDimension(); // Generic array for values, grads, curls, etc. that will be properly sized before each call FieldContainer<double> vals; // Check VALUE of basis functions: resize vals to rank-2 container: vals.resize(numFields, numPoints); tetBasis.getValues(vals, tetNodes, OPERATOR_VALUE); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { int l = i + j * numFields; if (std::abs(vals(i,j) - basisValues[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " "; *outStream << "} computed value: " << vals(i,j) << " but reference value: " << basisValues[l] << "\n"; } } } // Check GRAD of basis function: resize vals to rank-3 container vals.resize(numFields, numPoints, spaceDim); tetBasis.getValues(vals, tetNodes, OPERATOR_GRAD); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { for (int k = 0; k < spaceDim; k++) { // basisGrads is (F,P,D), compute offset: int l = k + j * spaceDim + i * spaceDim * numPoints; if (std::abs(vals(i,j,k) - basisGrads[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " ";*outStream << k << " "; *outStream << "} computed grad component: " << vals(i,j,k) << " but reference grad component: " << basisGrads[l] << "\n"; } } } } // Check D1 of basis function (do not resize vals because it has the correct size: D1 = GRAD) tetBasis.getValues(vals, tetNodes, OPERATOR_D1); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { for (int k = 0; k < spaceDim; k++) { // basisGrads is (F,P,D), compute offset: int l = k + j * spaceDim + i * spaceDim * numPoints; if (std::abs(vals(i,j,k) - basisGrads[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " ";*outStream << k << " "; *outStream << "} computed D1 component: " << vals(i,j,k) << " but reference D1 component: " << basisGrads[l] << "\n"; } } } } // Check D2 of basis function int D2cardinality = Intrepid2::getDkCardinality(OPERATOR_D2, spaceDim); vals.resize(numFields, numPoints, D2cardinality); tetBasis.getValues(vals, tetNodes, OPERATOR_D2); for (int i = 0; i < numFields; i++) { for (int j = 0; j < numPoints; j++) { for (int k = 0; k < D2cardinality; k++) { // basisD2 is (F,P,Dk), compute offset: int l = k + j * D2cardinality + i * D2cardinality * numPoints; if (std::abs(vals(i,j,k) - basisD2[l]) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " ";*outStream << j << " ";*outStream << k << " "; *outStream << "} computed D2 component: " << vals(i,j,k) << " but reference D2 component: " << basisD2[l] << "\n"; } } } } // Check all higher derivatives - must be zero. for(EOperator op = OPERATOR_D3; op < OPERATOR_MAX; op++) { // The last dimension is the number of kth derivatives and needs to be resized for every Dk int DkCardin = Intrepid2::getDkCardinality(op, spaceDim); vals.resize(numFields, numPoints, DkCardin); tetBasis.getValues(vals, tetNodes, op); for (int i1 = 0; i1 < numFields; i1++) for (int i2 = 0; i2 < numPoints; i2++) for (int i3 = 0; i3 < DkCardin; i3++) { if (std::abs(vals(i1,i2,i3)) > INTREPID_TOL) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Get the multi-index of the value where the error is and the operator order int ord = Intrepid2::getOperatorOrder(op); *outStream << " At multi-index { "<<i1<<" "<<i2 <<" "<<i3; *outStream << "} computed D"<< ord <<" component: " << vals(i1,i2,i3) << " but reference D" << ord << " component: 0 \n"; } } } } // Catch unexpected errors catch (std::logic_error err) { *outStream << err.what() << "\n\n"; errorFlag = -1000; }; if (errorFlag != 0) std::cout << "End Result: TEST FAILED\n"; else std::cout << "End Result: TEST PASSED\n"; // reset format state of std::cout std::cout.copyfmt(oldFormatState); Kokkos::finalize(); return errorFlag; }
void ExactSolution::L2NormOfError(FieldContainer<double> &errorSquaredPerCell, Solution &solution, ElementTypePtr elemTypePtr, int trialID, int sideIndex, int cubDegree, double solutionLift) { // BasisCache(ElementTypePtr elemType, Teuchos::RCP<Mesh> mesh = Teuchos::rcp( (Mesh*) NULL ), bool testVsTest=false, int cubatureDegreeEnrichment = 0) DofOrdering dofOrdering = *(elemTypePtr->trialOrderPtr.get()); BasisPtr basis = dofOrdering.getBasis(trialID,sideIndex); bool boundaryIntegral = solution.mesh()->bilinearForm()->isFluxOrTrace(trialID); BasisCachePtr basisCache; if (cubDegree <= 0) { // then take the default cub. degree basisCache = Teuchos::rcp( new BasisCache( elemTypePtr, solution.mesh() ) ); } else { // we could eliminate the logic below if we just added BasisCache::setCubatureDegree()... // (the logic below is just to make the enriched cubature match the requested cubature degree...) int maxTrialDegree; if (!boundaryIntegral) { maxTrialDegree = elemTypePtr->trialOrderPtr->maxBasisDegreeForVolume(); } else { maxTrialDegree = elemTypePtr->trialOrderPtr->maxBasisDegree(); // generally, this will be the trace degree } int maxTestDegree = elemTypePtr->testOrderPtr->maxBasisDegree(); int cubDegreeEnrichment = max(cubDegree - (maxTrialDegree + maxTestDegree), 0); basisCache = Teuchos::rcp( new BasisCache( elemTypePtr, solution.mesh(), false, cubDegreeEnrichment) ); } // much of this code is the same as what's in the volume integration in computeStiffness... FieldContainer<double> physicalCellNodes = solution.mesh()->physicalCellNodes(elemTypePtr); vector<GlobalIndexType> cellIDs = solution.mesh()->cellIDsOfType(elemTypePtr); basisCache->setPhysicalCellNodes(physicalCellNodes, cellIDs, true); if (boundaryIntegral) { basisCache = basisCache->getSideBasisCache(sideIndex); } FieldContainer<double> weightedMeasure = basisCache->getWeightedMeasures(); FieldContainer<double> weightedErrorSquared; int numCells = basisCache->getPhysicalCubaturePoints().dimension(0); int numCubPoints = basisCache->getPhysicalCubaturePoints().dimension(1); int spaceDim = basisCache->getPhysicalCubaturePoints().dimension(2); Teuchos::Array<int> dimensions; dimensions.push_back(numCells); dimensions.push_back(numCubPoints); int basisRank = BasisFactory::basisFactory()->getBasisRank(basis); if (basisRank==1) { dimensions.push_back(spaceDim); } FieldContainer<double> computedValues(dimensions); FieldContainer<double> exactValues(dimensions); if (solutionLift != 0.0) { int size = computedValues.size(); for (int i=0; i<size; i++) { computedValues[i] += solutionLift; } } solution.solutionValues(computedValues, trialID, basisCache); this->solutionValues(exactValues, trialID, basisCache); // cout << "ExactSolution: exact values:\n" << exactValues; // cout << "ExactSolution: computed values:\n" << computedValues; FieldContainer<double> errorSquared(numCells,numCubPoints); squaredDifference(errorSquared,computedValues,exactValues); weightedErrorSquared.resize(numCells,numCubPoints); for (int cellIndex=0; cellIndex<numCells; cellIndex++) { for (int ptIndex=0; ptIndex<numCubPoints; ptIndex++) { // following two lines for viewing in the debugger: double weight = weightedMeasure(cellIndex,ptIndex); double errorSquaredVal = errorSquared(cellIndex,ptIndex); weightedErrorSquared(cellIndex,ptIndex) = errorSquared(cellIndex,ptIndex) * weightedMeasure(cellIndex,ptIndex); } } // compute the integral errorSquaredPerCell.initialize(0.0); int numPoints = weightedErrorSquared.dimension(1); for (int cellIndex=0; cellIndex<numCells; cellIndex++) { for (int ptIndex=0; ptIndex<numPoints; ptIndex++) { errorSquaredPerCell(cellIndex) += weightedErrorSquared(cellIndex,ptIndex); } } }