void DofOrdering::copyLikeCoefficients( FieldContainer<double> &newValues, Teuchos::RCP<DofOrdering> oldDofOrdering, const FieldContainer<double> &oldValues ) { // copy the coefficients for the bases that agree between the two DofOrderings // requires that "like" bases are actually pointers to the same memory location TEUCHOS_TEST_FOR_EXCEPTION( newValues.rank() != 1, std::invalid_argument, "newValues.rank() != 1"); TEUCHOS_TEST_FOR_EXCEPTION( newValues.size() != totalDofs(), std::invalid_argument, "newValues.size() != totalDofs()"); TEUCHOS_TEST_FOR_EXCEPTION( oldValues.rank() != 1, std::invalid_argument, "oldValues.rank() != 1"); TEUCHOS_TEST_FOR_EXCEPTION( oldValues.size() != oldDofOrdering->totalDofs(), std::invalid_argument, "oldValues.size() != oldDofOrdering->totalDofs()"); newValues.initialize(0.0); for (set<int>::iterator varIDIt = varIDs.begin(); varIDIt != varIDs.end(); varIDIt++) { int varID = *varIDIt; int numSides = getNumSidesForVarID(varID); if ( numSides == oldDofOrdering->getNumSidesForVarID(varID) ) { for (int sideIndex=0; sideIndex < numSides; sideIndex++) { BasisPtr basis = getBasis(varID,sideIndex); if (basis.get() == oldDofOrdering->getBasis(varID,sideIndex).get() ) { // bases alike: copy coefficients int cardinality = basis->getCardinality(); for (int dofOrdinal=0; dofOrdinal < cardinality; dofOrdinal++) { int dofIndex = getDofIndex(varID,dofOrdinal,sideIndex); newValues(dofIndex) = oldValues( oldDofOrdering->getDofIndex(varID,dofOrdinal,sideIndex) ); } } } } } }
double MeshUtilities::computeMaxLocalConditionNumber(Teuchos::RCP< DPGInnerProduct > ip, MeshPtr mesh, bool jacobiScaling, string sparseFileToWriteTo) { int rank = Teuchos::GlobalMPISession::getRank(); int numProcs = Teuchos::GlobalMPISession::getNProc(); vector< ElementPtr > elements = mesh->elementsInPartition(rank); // cout << "Checking condition numbers on rank " << rank << endl; FieldContainer<double> maxConditionNumberIPMatrix; int maxCellID = -1; double myMaxConditionNumber = -1; for (vector< ElementPtr >::iterator elemIt = elements.begin(); elemIt != elements.end(); elemIt++) { int cellID = (*elemIt)->cellID(); bool testVsTest = true; BasisCachePtr cellBasisCache = BasisCache::basisCacheForCell(mesh, cellID, testVsTest); DofOrderingPtr testSpace = (*elemIt)->elementType()->testOrderPtr; int testDofs = testSpace->totalDofs(); int numCells = 1; FieldContainer<double> innerProductMatrix(numCells,testDofs,testDofs); ip->computeInnerProductMatrix(innerProductMatrix, testSpace, cellBasisCache); // reshape: innerProductMatrix.resize(testDofs,testDofs); if (jacobiScaling) SerialDenseMatrixUtility::jacobiScaleMatrix(innerProductMatrix); // double conditionNumber = SerialDenseMatrixUtility::estimate1NormConditionNumber(innerProductMatrix); double conditionNumber = SerialDenseMatrixUtility::estimate2NormConditionNumber(innerProductMatrix); if (conditionNumber > myMaxConditionNumber) { myMaxConditionNumber = conditionNumber; maxConditionNumberIPMatrix = innerProductMatrix; maxCellID = cellID; } else if (maxConditionNumberIPMatrix.size()==0) { // could be that the estimation failed--we still want a copy of the matrix written to file. maxConditionNumberIPMatrix = innerProductMatrix; } } // cout << "Determined condition numbers on rank " << rank << endl; FieldContainer<double> maxConditionNumbers(numProcs); maxConditionNumbers[rank] = myMaxConditionNumber; MPIWrapper::entryWiseSum(maxConditionNumbers); double maxConditionNumber = maxConditionNumbers[0]; int maxConditionNumberOwner = 0; // the MPI node with the max condition number for (int i=1; i<numProcs; i++) { if (maxConditionNumber < maxConditionNumbers[i]) { maxConditionNumber = maxConditionNumbers[i]; maxConditionNumberOwner = i; } } if (rank==maxConditionNumberOwner) { // owner is responsible for writing to file // cout << "max condition number is on rank " << rank << endl; if (sparseFileToWriteTo.length() > 0) { if (maxConditionNumberIPMatrix.size() > 0) { DataIO::writeMatrixToSparseDataFile(maxConditionNumberIPMatrix, sparseFileToWriteTo); } } } // cout << "max condition number occurs in cellID " << maxCellID << endl; return maxConditionNumber; }
void MeshTransformationFunction::values(FieldContainer<double> &values, BasisCachePtr basisCache) { CHECK_VALUES_RANK(values); vector<GlobalIndexType> cellIDs = basisCache->cellIDs(); // identity map is the right thing most of the time // we'll do something different only where necessary int spaceDim = values.dimension(2); TEUCHOS_TEST_FOR_EXCEPTION(basisCache->cellTopology()->getDimension() != spaceDim, std::invalid_argument, "cellTopology dimension does not match the shape of the values container"); if (_op == OP_VALUE) { values = basisCache->getPhysicalCubaturePoints(); // identity } else if (_op == OP_DX) { // identity map is 1 in all the x slots, 0 in all others int mod_value = 0; // the x slots are the mod spaceDim = 0 slots; for (int i=0; i<values.size(); i++) { values[i] = (i%spaceDim == mod_value) ? 1.0 : 0.0; } } else if (_op == OP_DY) { // identity map is 1 in all the y slots, 0 in all others int mod_value = 1; // the y slots are the mod spaceDim = 1 slots; for (int i=0; i<values.size(); i++) { values[i] = (i%spaceDim == mod_value) ? 1.0 : 0.0; } } else if (_op == OP_DZ) { // identity map is 1 in all the z slots, 0 in all others int mod_value = 2; // the z slots are the mod spaceDim = 2 slots; for (int i=0; i<values.size(); i++) { values[i] = (i%spaceDim == mod_value) ? 1.0 : 0.0; } } // if (_op == OP_DX) { // cout << "values before cellTransformation:\n" << values; // } for (int cellIndex=0; cellIndex < cellIDs.size(); cellIndex++) { GlobalIndexType cellID = cellIDs[cellIndex]; if (_cellTransforms.find(cellID) == _cellTransforms.end()) continue; TFunctionPtr<double> cellTransformation = _cellTransforms[cellID]; ((CellTransformationFunction*)cellTransformation.get())->setCellIndex(cellIndex); cellTransformation->values(values, basisCache); } // if (_op == OP_DX) { // cout << "values after cellTransformation:\n" << values; // } }
bool MeshTestUtility::fcsAgree(const FieldContainer<double> &fc1, const FieldContainer<double> &fc2, double tol, double &maxDiff) { if (fc1.size() != fc2.size()) { maxDiff = -1.0; // a signal something's wrong… return false; } maxDiff = 0.0; for (int i=0; i<fc1.size(); i++) { maxDiff = std::max(maxDiff, abs(fc1[i] - fc2[i])); } return (maxDiff <= tol); }
virtual void values(FieldContainer<double> &values, BasisCachePtr basisCache) { // not the most efficient implementation _fxn->values(values,basisCache); vector<GlobalIndexType> contextCellIDs = basisCache->cellIDs(); int cellIndex=0; // keep track of index into values int entryCount = values.size(); int numCells = values.dimension(0); int numEntriesPerCell = entryCount / numCells; for (vector<GlobalIndexType>::iterator cellIt = contextCellIDs.begin(); cellIt != contextCellIDs.end(); cellIt++) { GlobalIndexType cellID = *cellIt; if (_cellIDs.find(cellID) == _cellIDs.end()) { // clear out the associated entries for (int j=0; j<numEntriesPerCell; j++) { values[cellIndex*numEntriesPerCell + j] = 0; } } cellIndex++; } }
void MPIWrapper::allGatherHomogeneous(const Epetra_Comm &Comm, FieldContainer<int> &allValues, FieldContainer<int> &myValues) { int numProcs = Teuchos::GlobalMPISession::getNProc(); if (numProcs != allValues.dimension(0)) { TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "allValues first dimension must be #procs"); } if (allValues.size() / numProcs != myValues.size()) { TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "myValues size invalid"); } #ifdef HAVE_MPI Comm.GatherAll(&myValues[0], &allValues[0], allValues.size()/numProcs); #else #endif }
void MPIWrapper::entryWiseSum(FieldContainer<int> &values) { #ifdef HAVE_MPI Epetra_MpiComm Comm(MPI_COMM_WORLD); FieldContainer<int> valuesCopy = values; // it appears this copy is necessary Comm.SumAll(&valuesCopy[0], &values[0], values.size()); #else #endif }
// sum the contents of valuesToSum across all processors, and returns the result: // (valuesToSum may vary in length across processors) GlobalIndexType MPIWrapper::sum(const FieldContainer<GlobalIndexType> &valuesToSum) { // this is fairly inefficient in the sense that the MPI overhead will dominate the cost here. // insofar as it's possible to group such calls into entryWiseSum() calls, this is preferred. GlobalIndexType mySum = 0; for (int i=0; i<valuesToSum.size(); i++) { mySum += valuesToSum[i]; } return sum(mySum); }
void MPIWrapper::entryWiseSum(FieldContainer<GlobalIndexType> &values) { #ifdef HAVE_MPI // cast to long long: Teuchos::Array<int> dim; values.dimensions(dim); FieldContainer<long long> valuesLongLong(dim); for (int i=0; i<values.size(); i++) { valuesLongLong[i] = (long long) values[i]; } Epetra_MpiComm Comm(MPI_COMM_WORLD); FieldContainer<long long> valuesLongLongCopy = valuesLongLong; // it appears this copy is necessary Comm.SumAll(&valuesLongLongCopy[0], &valuesLongLong[0], valuesLongLong.size()); // copy back to original container: for (int i=0; i<values.size(); i++) { values[i] = (GlobalIndexType) valuesLongLong[i]; } #else #endif }
double basisSumAtParametricPoint(FieldContainer<double> &basisCoefficients, BasisPtr basis, double tValue, BasisCachePtr parametricBasisCache) { int numPoints = 1; int spaceDim = 1; FieldContainer<double> parametricPoints(numPoints,spaceDim); parametricPoints[0] = tValue; FieldContainer<double> refCellPoints = parametricBasisCache->getRefCellPointsForPhysicalPoints(parametricPoints); parametricBasisCache->setRefCellPoints(refCellPoints); Teuchos::RCP< const FieldContainer<double> > basisValues = parametricBasisCache->getValues(basis, OP_VALUE); double sum = 0; int ptIndex = 0; // one point for (int fieldIndex=0; fieldIndex<basisCoefficients.size(); fieldIndex++) { sum += (*basisValues)(fieldIndex,ptIndex) * basisCoefficients(fieldIndex); } return sum; }
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 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_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; }
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); 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; }
bool MeshTestUtility::checkLocalGlobalConsistency(MeshPtr mesh, double tol) { bool success = true; set<GlobalIndexType> cellIDs = mesh->getActiveCellIDs(); GlobalDofAssignmentPtr gda = mesh->globalDofAssignment(); // TODO: make this only check the locally-owned cells (right now does the whole mesh on every rank) int numGlobalDofs = gda->globalDofCount(); FieldContainer<double> globalCoefficients(numGlobalDofs); for (int i=0; i<numGlobalDofs; i++) { globalCoefficients(i) = 2*i + 1; // arbitrary cofficients } FieldContainer<double> globalCoefficientsExpected = globalCoefficients; FieldContainer<double> globalCoefficientsActual(numGlobalDofs); FieldContainer<double> localCoefficients; Epetra_SerialComm Comm; Epetra_BlockMap map(numGlobalDofs, 1, 0, Comm); Epetra_Vector globalCoefficientsVector(map); for (int i=0; i<numGlobalDofs; i++) { globalCoefficientsVector[i] = globalCoefficients(i); } cellIDs = mesh->getActiveCellIDs(); for (set<GlobalIndexType>::iterator cellIDIt = cellIDs.begin(); cellIDIt != cellIDs.end(); cellIDIt++) { GlobalIndexType cellID = *cellIDIt; gda->interpretGlobalCoefficients(cellID, localCoefficients, globalCoefficientsVector); FieldContainer<GlobalIndexType> globalDofIndices; FieldContainer<double> globalCoefficientsForCell; DofOrderingPtr trialOrder = mesh->getElementType(cellID)->trialOrderPtr; set<int> varIDs = trialOrder->getVarIDs(); for (set<int>::iterator varIt=varIDs.begin(); varIt != varIDs.end(); varIt++) { int varID = *varIt; const vector<int>* sidesForVar = &trialOrder->getSidesForVarID(varID); for (vector<int>::const_iterator sideIt = sidesForVar->begin(); sideIt != sidesForVar->end(); sideIt++) { int sideOrdinal = *sideIt; BasisPtr basis; if (sidesForVar->size() == 1) { basis = trialOrder->getBasis(varID); } else { basis = trialOrder->getBasis(varID,sideOrdinal); } FieldContainer<double> basisCoefficients(basis->getCardinality()); for (int dofOrdinal=0; dofOrdinal<basis->getCardinality(); dofOrdinal++) { int localDofIndex; if (sidesForVar->size() == 1) { localDofIndex = trialOrder->getDofIndex(varID, dofOrdinal); } else { localDofIndex = trialOrder->getDofIndex(varID, dofOrdinal, sideOrdinal); } basisCoefficients(dofOrdinal) = localCoefficients(localDofIndex); } gda->interpretLocalBasisCoefficients(cellID, varID, sideOrdinal, basisCoefficients, globalCoefficientsForCell, globalDofIndices); // if ( (cellID==2) && (sideOrdinal==1) && (varID==0) ) { // cout << "DEBUGGING: (cellID==2) && (sideOrdinal==1).\n"; // cout << "globalDofIndices:\n" << globalDofIndices; // cout << "globalCoefficientsForCell:\n" << globalCoefficientsForCell; // cout << "basisCoefficients:\n" << basisCoefficients; // } for (int dofOrdinal=0; dofOrdinal < globalDofIndices.size(); dofOrdinal++) { GlobalIndexType dofIndex = globalDofIndices(dofOrdinal); globalCoefficientsActual(dofIndex) = globalCoefficientsForCell(dofOrdinal); double diff = abs(globalCoefficientsForCell(dofOrdinal) - globalCoefficientsExpected(dofIndex)) / globalCoefficientsExpected(dofIndex); if (diff > tol) { cout << "In mapping for cell " << cellID << " and var " << varID << " on side " << sideOrdinal << ", "; cout << "expected coefficient for global dof index " << dofIndex << " to be " << globalCoefficientsExpected(dofIndex); cout << ", but was " << globalCoefficientsForCell(dofOrdinal); cout << " (relative diff = " << diff << "; tol = " << tol << ")\n"; success = false; } } } } } // double maxDiff; // if (TestSuite::fcsAgree(globalCoefficientsActual, globalCoefficientsExpected, tol, maxDiff)) { // // cout << "global data actual and expected AGREE; max difference is " << maxDiff << endl; // // cout << "globalCoefficientsActual:\n" << globalCoefficientsActual; // } else { // cout << "global data actual and expected DISAGREE; max difference is " << maxDiff << endl; // success = false; // cout << "Expected:\n" << globalCoefficientsExpected; // cout << "Actual:\n" << globalCoefficientsActual; // } return success; }
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; }
void Boundary::bcsToImpose( map< GlobalIndexType, Scalar > &globalDofIndicesAndValues, TBC<Scalar> &bc, GlobalIndexType cellID, DofInterpreter* dofInterpreter) { // this is where we actually compute the BCs; the other bcsToImpose variants call this one. CellPtr cell = _mesh->getTopology()->getCell(cellID); // define a couple of important inner products: TIPPtr<Scalar> ipL2 = Teuchos::rcp( new TIP<Scalar> ); TIPPtr<Scalar> ipH1 = Teuchos::rcp( new TIP<Scalar> ); VarFactoryPtr varFactory = VarFactory::varFactory(); VarPtr trace = varFactory->traceVar("trace"); VarPtr flux = varFactory->traceVar("flux"); ipL2->addTerm(flux); ipH1->addTerm(trace); ipH1->addTerm(trace->grad()); ElementTypePtr elemType = _mesh->getElementType(cellID); DofOrderingPtr trialOrderingPtr = elemType->trialOrderPtr; vector< int > trialIDs = _mesh->bilinearForm()->trialIDs(); vector<unsigned> boundarySides = cell->boundarySides(); if (boundarySides.size() > 0) { BasisCachePtr basisCache = BasisCache::basisCacheForCell(_mesh, cellID); for (vector< int >::iterator trialIt = trialIDs.begin(); trialIt != trialIDs.end(); trialIt++) { int trialID = *(trialIt); if ( bc.bcsImposed(trialID) ) { // // DEBUGGING: keep track of which sides we impose BCs on: // set<unsigned> bcImposedSides; // // Determine global dof indices and values, in one pass per side for (int i=0; i<boundarySides.size(); i++) { unsigned sideOrdinal = boundarySides[i]; // TODO: here, we need to treat the volume basis case. /* To do this: 1. (Determine which dofs in the basis have support on the side.) 2. (Probably should resize dirichletValues to match number of dofs with support on the side.) 3. (Within coefficientsForBC, and the projection method it calls, when it's a side cache, check whether the basis being projected has a higher dimension. If so, do the same determination regarding the support of basis on the side as #1.) 4. DofInterpreter::interpretLocalBasisCoefficients() needs to handle the case that trialID has volume support, and in this case interpret the provided data appropriately. */ BasisPtr basis; int numDofsSide; if (trialOrderingPtr->getSidesForVarID(trialID).size() == 1) { // volume basis basis = trialOrderingPtr->getBasis(trialID); // get the dof ordinals for the side (interpreted as a "continuous" basis) numDofsSide = basis->dofOrdinalsForSide(sideOrdinal).size(); } else if (! trialOrderingPtr->hasBasisEntry(trialID, sideOrdinal)) { continue; } else { basis = trialOrderingPtr->getBasis(trialID,sideOrdinal); numDofsSide = basis->getCardinality(); } GlobalIndexType numCells = 1; if (numCells > 0) { FieldContainer<double> dirichletValues(numCells,numDofsSide); // project bc function onto side basis: BCPtr bcPtr = Teuchos::rcp(&bc, false); Teuchos::RCP<BCFunction<double>> bcFunction = BCFunction<double>::bcFunction(bcPtr, trialID); bcPtr->coefficientsForBC(dirichletValues, bcFunction, basis, basisCache->getSideBasisCache(sideOrdinal)); dirichletValues.resize(numDofsSide); if (bcFunction->imposeOnCell(0)) { FieldContainer<double> globalData; FieldContainer<GlobalIndexType> globalDofIndices; dofInterpreter->interpretLocalBasisCoefficients(cellID, trialID, sideOrdinal, dirichletValues, globalData, globalDofIndices); for (int globalDofOrdinal=0; globalDofOrdinal<globalDofIndices.size(); globalDofOrdinal++) { GlobalIndexType globalDofIndex = globalDofIndices(globalDofOrdinal); Scalar value = globalData(globalDofOrdinal); // sanity check: if this has been previously set, do the two values roughly agree? if (globalDofIndicesAndValues.find(globalDofIndex) != globalDofIndicesAndValues.end()) { double tol = 1e-10; Scalar prevValue = globalDofIndicesAndValues[globalDofIndex]; double absDiff = abs(prevValue - value); if (absDiff > tol) { double relativeDiff = absDiff / max(abs(prevValue),abs(value)); int rank = _mesh->Comm()->MyPID(); if (relativeDiff > tol) { cout << "WARNING: in Boundary::bcsToImpose(), inconsistent values for BC: " << prevValue << " and "; cout << value << " prescribed for global dof index " << globalDofIndex; cout << " on rank " << rank << endl; } } } globalDofIndicesAndValues[globalDofIndex] = value; } } } } } } } }
void Boundary::singletonBCsToImpose(std::map<GlobalIndexType,Scalar> &dofIndexToValue, TBC<Scalar> &bc, DofInterpreter* dofInterpreter) { // first, let's check for any singletons (one-point BCs) map<IndexType, set < pair<int, unsigned> > > singletonsForCell; const set<GlobalIndexType>* rankLocalCells = &_mesh->cellIDsInPartition(); vector< int > trialIDs = _mesh->bilinearForm()->trialIDs(); for (int trialID : trialIDs) { if (bc.singlePointBC(trialID)) { auto knownActiveCells = &_mesh->getTopology()->getLocallyKnownActiveCellIndices(); vector<double> spatialVertex = bc.pointForSpatialPointBC(trialID); vector<IndexType> matchingVertices = _mesh->getTopology()->getVertexIndicesMatching(spatialVertex); unsigned vertexDim = 0; for (IndexType vertexIndex : matchingVertices) { set< pair<IndexType, unsigned> > cellsForVertex = _mesh->getTopology()->getCellsContainingEntity(vertexDim, vertexIndex); for (pair<IndexType, unsigned> cellForVertex : cellsForVertex) { // active cell IndexType matchingCellID = cellForVertex.first; if (rankLocalCells->find(matchingCellID) != rankLocalCells->end()) // we own this cell, so we're responsible for imposing the singleton BC { CellPtr cell = _mesh->getTopology()->getCell(matchingCellID); unsigned vertexOrdinal = cell->findSubcellOrdinal(vertexDim, vertexIndex); TEUCHOS_TEST_FOR_EXCEPTION(vertexOrdinal == -1, std::invalid_argument, "Internal error: vertexOrdinal not found for cell to which it supposedly belongs"); singletonsForCell[matchingCellID].insert(make_pair(trialID, vertexOrdinal)); } } } } } for (auto cellEntry : singletonsForCell) { GlobalIndexType cellID = cellEntry.first; auto singletons = cellEntry.second; ElementTypePtr elemType = _mesh->getElementType(cellID); map<int, vector<unsigned> > vertexOrdinalsForTrialID; for (pair<int, unsigned> trialVertexPair : singletons) { vertexOrdinalsForTrialID[trialVertexPair.first].push_back(trialVertexPair.second); } for (auto trialVertexOrdinals : vertexOrdinalsForTrialID) { int trialID = trialVertexOrdinals.first; vector<unsigned> vertexOrdinalsInCell = trialVertexOrdinals.second; CellTopoPtr cellTopo = elemType->cellTopoPtr; CellTopoPtr spatialCellTopo; bool spaceTime; int vertexOrdinalInSpatialCell; if (vertexOrdinalsInCell.size() == 2) { // we'd better be doing space-time in this case, and the vertices should be the same spatially spaceTime = (cellTopo->getTensorialDegree() > 0); TEUCHOS_TEST_FOR_EXCEPTION(!spaceTime, std::invalid_argument, "multiple vertices for spatial point only supported for space-time"); spatialCellTopo = cellTopo->getTensorialComponent(); vertexOrdinalInSpatialCell = -1; for (unsigned spatialVertexOrdinal = 0; spatialVertexOrdinal < spatialCellTopo->getNodeCount(); spatialVertexOrdinal++) { vector<unsigned> tensorComponentNodes = {spatialVertexOrdinal,0}; unsigned spaceTimeVertexOrdinal_t0 = cellTopo->getNodeFromTensorialComponentNodes(tensorComponentNodes); if ((spaceTimeVertexOrdinal_t0 == vertexOrdinalsInCell[0]) || (spaceTimeVertexOrdinal_t0 == vertexOrdinalsInCell[1])) { // then this should be our match. Confirm this: tensorComponentNodes = {spatialVertexOrdinal,1}; unsigned spaceTimeVertexOrdinal_t1 = cellTopo->getNodeFromTensorialComponentNodes(tensorComponentNodes); bool t1VertexMatches = (spaceTimeVertexOrdinal_t1 == vertexOrdinalsInCell[0]) || (spaceTimeVertexOrdinal_t1 == vertexOrdinalsInCell[1]); TEUCHOS_TEST_FOR_EXCEPTION(!t1VertexMatches, std::invalid_argument, "Internal error: space-time vertices do not belong to the same spatial vertex"); vertexOrdinalInSpatialCell = spatialVertexOrdinal; break; } } TEUCHOS_TEST_FOR_EXCEPTION(vertexOrdinalInSpatialCell == -1, std::invalid_argument, "Internal error: spatial vertex ordinal not found"); } else if (vertexOrdinalsInCell.size() == 1) { spaceTime = false; spatialCellTopo = cellTopo; vertexOrdinalInSpatialCell = vertexOrdinalsInCell[0]; } else { TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "vertexOrdinalsInCell must have 1 or 2 vertices"); } set<GlobalIndexType> globalIndicesForVariable; DofOrderingPtr trialOrderingPtr = elemType->trialOrderPtr; int numSpatialSides = spatialCellTopo->getSideCount(); vector<unsigned> spatialSidesForVertex; vector<unsigned> sideVertexOrdinals; // same index in this container as spatialSidesForVertex: gets the node ordinal of the vertex in that side int sideDim = spatialCellTopo->getDimension() - 1; if (!_mesh->bilinearForm()->isFluxOrTrace(trialID)) { spatialSidesForVertex.push_back(VOLUME_INTERIOR_SIDE_ORDINAL); sideVertexOrdinals.push_back(vertexOrdinalInSpatialCell); } else { for (int spatialSideOrdinal=0; spatialSideOrdinal < numSpatialSides; spatialSideOrdinal++) { CellTopoPtr sideTopo = spatialCellTopo->getSide(spatialSideOrdinal); for (unsigned sideVertexOrdinal = 0; sideVertexOrdinal < sideTopo->getNodeCount(); sideVertexOrdinal++) { unsigned spatialVertexOrdinal = spatialCellTopo->getNodeMap(sideDim, spatialSideOrdinal, sideVertexOrdinal); if (spatialVertexOrdinal == vertexOrdinalInSpatialCell) { spatialSidesForVertex.push_back(spatialSideOrdinal); sideVertexOrdinals.push_back(sideVertexOrdinal); break; // this is the only match we should find on this side } } } if (spatialSidesForVertex.size() == 0) { cout << "ERROR: no spatial side for vertex found during singleton BC imposition.\n"; TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "no spatial side for vertex found during singleton BC imposition"); } } for (int i=0; i<spatialSidesForVertex.size(); i++) { unsigned spatialSideOrdinal = spatialSidesForVertex[i]; unsigned vertexOrdinalInSide = sideVertexOrdinals[i]; unsigned sideForImposition; BasisPtr spatialBasis, temporalBasis, spaceTimeBasis, basisForImposition; if (!spaceTime) { spatialBasis = trialOrderingPtr->getBasis(trialID,spatialSideOrdinal); sideForImposition = spatialSideOrdinal; } else { unsigned spaceTimeSideOrdinal; if (!_mesh->bilinearForm()->isFluxOrTrace(trialID)) { spaceTimeSideOrdinal = VOLUME_INTERIOR_SIDE_ORDINAL; } else { spaceTimeSideOrdinal = cellTopo->getSpatialSideOrdinal(spatialSideOrdinal); } spaceTimeBasis = trialOrderingPtr->getBasis(trialID,spaceTimeSideOrdinal); sideForImposition = spaceTimeSideOrdinal; TensorBasis<>* tensorBasis = dynamic_cast<TensorBasis<>*>(spaceTimeBasis.get()); TEUCHOS_TEST_FOR_EXCEPTION(!tensorBasis, std::invalid_argument, "space-time basis must be a subclass of TensorBasis"); if (tensorBasis) { spatialBasis = tensorBasis->getSpatialBasis(); temporalBasis = tensorBasis->getTemporalBasis(); } } bool constantSpatialBasis = false; // upgrade bases to continuous ones of the same cardinality, if they are discontinuous. if (spatialBasis->getDegree() == 0) { constantSpatialBasis = true; } else if ((spatialBasis->functionSpace() == Camellia::FUNCTION_SPACE_HVOL) || (spatialBasis->functionSpace() == Camellia::FUNCTION_SPACE_HVOL_DISC)) { spatialBasis = BasisFactory::basisFactory()->getBasis(spatialBasis->getDegree(), spatialBasis->domainTopology(), Camellia::FUNCTION_SPACE_HGRAD); } else if (Camellia::functionSpaceIsDiscontinuous(spatialBasis->functionSpace())) { Camellia::EFunctionSpace fsContinuous = Camellia::continuousSpaceForDiscontinuous((spatialBasis->functionSpace())); spatialBasis = BasisFactory::basisFactory()->getBasis(spatialBasis->getDegree(), spatialBasis->domainTopology(), fsContinuous, Camellia::FUNCTION_SPACE_HGRAD); } if (temporalBasis.get()) { if ((temporalBasis->functionSpace() == Camellia::FUNCTION_SPACE_HVOL) || (temporalBasis->functionSpace() == Camellia::FUNCTION_SPACE_HVOL_DISC)) { temporalBasis = BasisFactory::basisFactory()->getBasis(temporalBasis->getDegree(), temporalBasis->domainTopology(), Camellia::FUNCTION_SPACE_HGRAD); } else if (Camellia::functionSpaceIsDiscontinuous(temporalBasis->functionSpace())) { Camellia::EFunctionSpace fsContinuous = Camellia::continuousSpaceForDiscontinuous((temporalBasis->functionSpace())); temporalBasis = BasisFactory::basisFactory()->getBasis(temporalBasis->getDegree(), temporalBasis->domainTopology(), fsContinuous, Camellia::FUNCTION_SPACE_HGRAD); } } if (spaceTime) { if (constantSpatialBasis) { // then use the original basis for imposition basisForImposition = spaceTimeBasis; } else { vector<int> H1Orders = {spatialBasis->getDegree(),temporalBasis->getDegree()}; spaceTimeBasis = BasisFactory::basisFactory()->getBasis(H1Orders, spaceTimeBasis->domainTopology(), spatialBasis->functionSpace(), temporalBasis->functionSpace()); basisForImposition = spaceTimeBasis; } } else { basisForImposition = spatialBasis; } vector<int> spatialDofOrdinalsForVertex = constantSpatialBasis ? vector<int>{0} : spatialBasis->dofOrdinalsForVertex(vertexOrdinalInSide); if (spatialDofOrdinalsForVertex.size() != 1) { cout << "ERROR: spatialDofOrdinalsForVertex.size() != 1 during singleton BC imposition.\n"; TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "spatialDofOrdinalsForVertex.size() != 1 during singleton BC imposition"); } int spatialDofOrdinalForVertex = spatialDofOrdinalsForVertex[0]; vector<int> basisDofOrdinals; if (!spaceTime) { basisDofOrdinals.push_back(spatialDofOrdinalForVertex); } else { int temporalBasisCardinality = temporalBasis->getCardinality(); TensorBasis<>* tensorBasis = dynamic_cast<TensorBasis<>*>(spaceTimeBasis.get()); for (int temporalBasisOrdinal=0; temporalBasisOrdinal<temporalBasisCardinality; temporalBasisOrdinal++) { basisDofOrdinals.push_back(tensorBasis->getDofOrdinalFromComponentDofOrdinals({spatialDofOrdinalForVertex, temporalBasisOrdinal})); } } for (int dofOrdinal : basisDofOrdinals) { FieldContainer<double> basisCoefficients(basisForImposition->getCardinality()); basisCoefficients[dofOrdinal] = 1.0; FieldContainer<double> globalCoefficients; FieldContainer<GlobalIndexType> globalDofIndices; dofInterpreter->interpretLocalBasisCoefficients(cellID, trialID, sideForImposition, basisCoefficients, globalCoefficients, globalDofIndices); double tol = 1e-14; int nonzeroEntryOrdinal = -1; for (int fieldOrdinal=0; fieldOrdinal < globalCoefficients.size(); fieldOrdinal++) { if (abs(globalCoefficients[fieldOrdinal]) > tol) { if (nonzeroEntryOrdinal != -1) { // previous nonzero entry found; this is a problem--it means we have multiple global coefficients that depend on this vertex // (could happen if user specified a hanging node) cout << "Error: vertex for single-point imposition has multiple global degrees of freedom.\n"; TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Error: vertex for single-point imposition has multiple global degrees of freedom."); } // nonzero entry: store the fact, and impose the constraint nonzeroEntryOrdinal = fieldOrdinal; bool isRankLocal = dofInterpreter->isLocallyOwnedGlobalDofIndex(globalDofIndices[fieldOrdinal]); if (isRankLocal) { dofIndexToValue[globalDofIndices[fieldOrdinal]] = bc.valueForSinglePointBC(trialID) * globalCoefficients[fieldOrdinal]; } else { cout << "ERROR: global dof index for single-point BC is not locally owned.\n"; TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "ERROR: global dof index for single-point BC is not locally owned"); } } } } } } } }
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_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_WEDGE_C1_FEM<double, FieldContainer<double> > wedgeBasis; int errorFlag = 0; // Initialize throw counter for exception testing int nException = 0; int throwCounter = 0; // Define array containing the 6 vertices of the reference TRIPRISM and some other points. FieldContainer<double> wedgeNodes(12, 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.25; wedgeNodes(6,1) = 0.5; wedgeNodes(6,2) = -1.0; wedgeNodes(7,0) = 0.5; wedgeNodes(7,1) = 0.25; wedgeNodes(7,2) = 0.0; wedgeNodes(8,0) = 0.25; wedgeNodes(8,1) = 0.30; wedgeNodes(8,2) = 1.0; wedgeNodes(9,0) = 0.3; wedgeNodes(9,1) = 0.0; wedgeNodes(9,2) = 0.75; wedgeNodes(10,0)= 0.0; wedgeNodes(10,1)= 0.44; wedgeNodes(10,2)= -0.23; wedgeNodes(11,0)= 0.4; wedgeNodes(11,1)= 0.6; wedgeNodes(11,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,6,0), throwCounter, nException ); // exception #6 INTREPID_TEST_COMMAND( wedgeBasis.getDofTag(7), 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, 2); 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), 4); 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: Each row gives the 4 correct basis set values at an evaluation point double basisValues[] = { 1.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, 1.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, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, // 0.25, 0.25, 0.5, 0., 0., 0., 0.125, 0.25, 0.125, 0.125, 0.25, 0.125, 0., 0., 0., 0.45, 0.25, 0.3, 0.0875, 0.0375, 0, 0.6125, 0.2625, 0, 0.3444, 0, 0.2706, 0.2156, 0, 0.1694, 0., 0.2, 0.3, 0., 0.2, 0.3 }; // GRAD and D1: each row gives the 3 x 4 correct values of the gradients of the 4 basis functions double basisGrads[] = { -1., -1., -0.5, 1., 0, 0, 0, 1., 0, 0., 0., 0.5, 0., 0, 0, 0, 0., 0, \ -1., -1., 0., 1., 0, -0.5, 0, 1., 0, 0., 0., 0., 0., 0, 0.5, 0, 0., \ 0, -1., -1., 0., 1., 0, 0, 0, 1., -0.5, 0., 0., 0., 0., 0, 0, 0, 0., \ 0.5, 0., 0., -0.5, 0., 0, 0, 0, 0., 0, -1., -1., 0.5, 1., 0, 0, 0, \ 1., 0, 0., 0., 0., 0., 0, -0.5, 0, 0., 0, -1., -1., 0., 1., 0, 0.5, \ 0, 1., 0, 0., 0., 0., 0., 0, 0, 0, 0., -0.5, -1., -1., 0., 1., 0, 0, \ 0, 1., 0.5, -1., -1., -0.125, 1., 0, -0.125, 0, 1., -0.25, 0., 0., \ 0.125, 0., 0, 0.125, 0, 0., 0.25, -0.5, -0.5, -0.125, 0.5, 0, -0.25, \ 0, 0.5, -0.125, -0.5, -0.5, 0.125, 0.5, 0, 0.25, 0, 0.5, 0.125, 0., \ 0., -0.225, 0., 0, -0.125, 0, 0., -0.15, -1., -1., 0.225, 1., 0, \ 0.125, 0, 1., 0.15, -0.125, -0.125, -0.35, 0.125, 0, -0.15, 0, 0.125, \ 0, -0.875, -0.875, 0.35, 0.875, 0, 0.15, 0, 0.875, 0, -0.615, -0.615, \ -0.28, 0.615, 0, 0, 0, 0.615, -0.22, -0.385, -0.385, 0.28, 0.385, 0, \ 0, 0, 0.385, 0.22, -0.5, -0.5, 0., 0.5, 0, -0.2, 0, 0.5, -0.3, -0.5, \ -0.5, 0., 0.5, 0, 0.2, 0, 0.5, 0.3 }; //D2: flat array with the values of D2 applied to basis functions. Multi-index is (P,F,K) double basisD2[] = { 0, 0, 0.5, 0, 0.5, 0, 0, 0, -0.5, 0, 0, 0, 0, 0, 0, 0, -0.5, 0, 0, 0, \ -0.5, 0, -0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0.5, 0, 0, 0, 0.5, \ 0, 0.5, 0, 0, 0, -0.5, 0, 0, 0, 0, 0, 0, 0, -0.5, 0, 0, 0, -0.5, 0, \ -0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0.5, \ 0, 0, 0, -0.5, 0, 0, 0, 0, 0, 0, 0, -0.5, 0, 0, 0, -0.5, 0, -0.5, 0, \ 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0.5, 0, 0, 0, \ -0.5, 0, 0, 0, 0, 0, 0, 0, -0.5, 0, 0, 0, -0.5, 0, -0.5, 0, 0, 0, \ 0.5, 0, 0, 0, 0, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0.5, 0, 0, 0, -0.5, \ 0, 0, 0, 0, 0, 0, 0, -0.5, 0, 0, 0, -0.5, 0, -0.5, 0, 0, 0, 0.5, 0, \ 0, 0, 0, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0.5, 0, 0, 0, -0.5, 0, 0, 0, \ 0, 0, 0, 0, -0.5, 0, 0, 0, -0.5, 0, -0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, \ 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0.5, 0, 0, 0, -0.5, 0, 0, 0, 0, 0, 0, \ 0, -0.5, 0, 0, 0, -0.5, 0, -0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, \ 0.5, 0, 0, 0, 0.5, 0, 0.5, 0, 0, 0, -0.5, 0, 0, 0, 0, 0, 0, 0, -0.5, \ 0, 0, 0, -0.5, 0, -0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0.5, 0, 0, \ 0, 0.5, 0, 0.5, 0, 0, 0, -0.5, 0, 0, 0, 0, 0, 0, 0, -0.5, 0, 0, 0, \ -0.5, 0, -0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0.5, 0, 0, 0, 0.5, \ 0, 0.5, 0, 0, 0, -0.5, 0, 0, 0, 0, 0, 0, 0, -0.5, 0, 0, 0, -0.5, 0, \ -0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0.5, \ 0, 0, 0, -0.5, 0, 0, 0, 0, 0, 0, 0, -0.5, 0, 0, 0, -0.5, 0, -0.5, 0, \ 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0.5, 0, 0, 0, \ -0.5, 0, 0, 0, 0, 0, 0, 0, -0.5, 0, 0, 0, -0.5, 0, -0.5, 0, 0, 0, \ 0.5, 0, 0, 0, 0, 0, 0, 0, 0.5, 0 }; try{ // Dimensions for the output arrays: int numFields = wedgeBasis.getCardinality(); int numPoints = wedgeNodes.dimension(0); int spaceDim = wedgeBasis.getBaseCellTopology().getDimension(); int D2Cardin = Intrepid2::getDkCardinality(OPERATOR_D2, spaceDim); // 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++) { 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) 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++) { 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 D2 of basis function vals.resize(numFields, numPoints, D2Cardin); 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 < D2Cardin; k++) { int l = k + i * D2Cardin + j * D2Cardin * numFields; 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); 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 = 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); return errorFlag; }
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++; } }