int DofOrdering::maxBasisDegree() { map< pair<int,int>, BasisPtr >::iterator basisIterator; int maxBasisDegree = 0; for (basisIterator = bases.begin(); basisIterator != bases.end(); basisIterator++) { //pair< const pair<int,int>, BasisPtr > basisPair = *basisIterator; BasisPtr basis = (*basisIterator).second; if (maxBasisDegree < basis->getDegree() ) { maxBasisDegree = basis->getDegree(); } } return maxBasisDegree; }
bool basisSumEqualsFunction(FieldContainer<double> &basisCoefficients, BasisPtr basis, FunctionPtr f) { // tests on [0,1] FunctionPtr sumFunction = Teuchos::rcp( new BasisSumFunction(basis, basisCoefficients) ); int cubatureDegree = basis->getDegree() * 2; BasisCachePtr basisCache = BasisCache::basisCache1D(0, 1, cubatureDegree); double tol = 1e-13; return sumFunction->equals(f, basisCache, tol); }
bool basisSumInterpolatesCurveEndPoints(FieldContainer<double> &basisCoefficients_x, FieldContainer<double> &basisCoefficients_y, BasisPtr basis, ParametricCurvePtr curve) { double curve_x0, curve_y0, curve_x1, curve_y1; curve->value(0, curve_x0, curve_y0); curve->value(1, curve_x1, curve_y1); BasisCachePtr basisCache = BasisCache::basisCache1D(0, 1, basis->getDegree()*2); double sum_x0 = basisSumAtParametricPoint(basisCoefficients_x, basis, 0, basisCache); double sum_x1 = basisSumAtParametricPoint(basisCoefficients_x, basis, 1, basisCache); double sum_y0 = basisSumAtParametricPoint(basisCoefficients_y, basis, 0, basisCache); double sum_y1 = basisSumAtParametricPoint(basisCoefficients_y, basis, 1, basisCache); double tol = 1e-13; double x0_err = abs(sum_x0-curve_x0); double y0_err = abs(sum_y0-curve_y0); double x1_err = abs(sum_x1-curve_x1); double y1_err = abs(sum_y1-curve_y1); double sum_err = x0_err + y0_err + x1_err + y1_err; return sum_err < tol; }
bool ParametricCurveTests::testProjectionBasedInterpolation() { bool success = true; // to start with, project a line onto a linear basis shards::CellTopology line_2(shards::getCellTopologyData<shards::Line<2> >() ); /////////////////// TEST LINEAR CURVES RECOVERED ////////////////////// BasisPtr linearBasis = BasisFactory::basisFactory()->getBasis(1, line_2.getKey(), Camellia::FUNCTION_SPACE_HGRAD); double x0=3, y0=-3, x1=5, y1=4; // double dist = sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0)); double dist = 1; // the length of the parametric space BasisCachePtr basisCache = BasisCache::basisCache1D(0, dist, linearBasis->getDegree()*2); ParametricCurvePtr myLine = ParametricCurve::line(x0, y0, x1, y1); bool useH1 = true; double lengthScale = 1.0; FieldContainer<double> basisCoefficients_x, basisCoefficients_y; myLine->projectionBasedInterpolant(basisCoefficients_x, linearBasis, 0, lengthScale, useH1); myLine->projectionBasedInterpolant(basisCoefficients_y, linearBasis, 1, lengthScale, useH1); if ( ! basisSumInterpolatesCurveEndPoints(basisCoefficients_x,basisCoefficients_y, linearBasis, myLine)) { cout << "testProjectionBasedInterpolation() failed: projection-based interpolant doesn't interpolate line endpoints.\n"; cout << "basisCoefficients_x:\n" << basisCoefficients_x; cout << "basisCoefficients_y:\n" << basisCoefficients_y; success = false; } // in fact, we should recover the line in x and y: if ( !basisSumEqualsFunction(basisCoefficients_x, linearBasis, myLine->x()) ) { cout << "testProjectionBasedInterpolation() failed: projection-based interpolant doesn't recover the line in the x component.\n"; success = false; } if ( !basisSumEqualsFunction(basisCoefficients_y, linearBasis, myLine->y()) ) { cout << "testProjectionBasedInterpolation() failed: projection-based interpolant doesn't recover the line in the y component.\n"; success = false; } /////////////////// TEST CUBIC CURVES RECOVERED ////////////////////// FunctionPtr t = Function::xn(1); // define x and y as functions of t: FunctionPtr x_t = t*t*t-2*t; FunctionPtr y_t = t*t*t+8*t*t; ParametricCurvePtr myCurve = ParametricCurve::curve(x_t,y_t); BasisPtr cubicBasis = BasisFactory::basisFactory()->getBasis(3, line_2.getKey(), Camellia::FUNCTION_SPACE_HGRAD); myCurve->projectionBasedInterpolant(basisCoefficients_x, cubicBasis, 0, lengthScale, useH1); myCurve->projectionBasedInterpolant(basisCoefficients_y, cubicBasis, 1, lengthScale, useH1); // we should again recover the curve exactly: if ( !basisSumEqualsFunction(basisCoefficients_x, cubicBasis, myCurve->x()) ) { cout << "testProjectionBasedInterpolation() failed: projection-based interpolant doesn't recover the cubic curve in the x component.\n"; success = false; } if ( !basisSumEqualsFunction(basisCoefficients_y, cubicBasis, myCurve->y()) ) { cout << "testProjectionBasedInterpolation() failed: projection-based interpolant doesn't recover the cubic curve in the y component.\n"; success = false; } /////////////////// TEST UNRECOVERABLE CURVE INTERPOLATED ////////////////////// // finally, project the cubic curve onto a quadratic basis, and check that it interpolates the endpoints BasisPtr quadraticBasis = BasisFactory::basisFactory()->getBasis(2, line_2.getKey(), Camellia::FUNCTION_SPACE_HGRAD); myCurve->projectionBasedInterpolant(basisCoefficients_x, quadraticBasis, 0, lengthScale, useH1); myCurve->projectionBasedInterpolant(basisCoefficients_y, quadraticBasis, 1, lengthScale, useH1); if ( ! basisSumInterpolatesCurveEndPoints(basisCoefficients_x,basisCoefficients_y, quadraticBasis, myCurve)) { cout << "testProjectionBasedInterpolation() failed: quadratic projection-based interpolant doesn't interpolate cubic curve endpoints.\n"; cout << "basisCoefficients_x:\n" << basisCoefficients_x; cout << "basisCoefficients_y:\n" << basisCoefficients_y; success = false; } return success; }
bool testBasisClassifications(BasisPtr basis) { bool success = true; CellTopoPtr cellTopo = basis->domainTopology(); int numVertices = cellTopo->getVertexCount(); int numEdges = cellTopo->getEdgeCount(); int degree = basis->getDegree(); // TODO: finish this vector<int> vertexOrdinals; for (int vertexIndex=0; vertexIndex < numVertices; vertexIndex++) { set<int> dofOrdinals = basis->dofOrdinalsForVertex(vertexIndex); if (dofOrdinals.size() == 0) TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "No dofOrdinal for vertex..."); if (dofOrdinals.size() > 1) TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "More than one dofOrdinal per vertex..."); vertexOrdinals.push_back(*(dofOrdinals.begin())); } // // if (! checkVertexOrdinalsQuad(basis, vertexOrdinals) ) { // success = false; // cout << "vertex dof ordinals don't match expected\n"; // cout << "ordinals: "; // for (int vertexIndex=0; vertexIndex < numVertices; vertexIndex++) { // cout << vertexOrdinals[vertexIndex] << " "; // } // cout << endl; // } // get the points in reference space for each vertex FieldContainer<double> points; if (numVertices == 2) { // line points.resize(2,1); points(0,0) = -1; points(1,0) = 1; } else if (numVertices == 3) { // triangle TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "triangles not yet supported"); } else if (numVertices == 4) { // quad points.resize(4,2); points(0,0) = -1; points(0,1) = -1; points(1,0) = 1; points(1,1) = -1; points(2,0) = 1; points(2,1) = 1; points(3,0) = -1; points(3,1) = 1; } else { TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "unsupported topology"); } FieldContainer<double> vertexValues; if (basis->rangeRank() > 0) { TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "rank > 0 bases not yet supported"); } else { vertexValues.resize(basis->getCardinality(),numVertices); } basis->getValues(vertexValues, points, Intrepid::OPERATOR_VALUE); // test that the points are correctly classified for (int fieldIndex=0; fieldIndex<basis->getCardinality(); fieldIndex++) { for (int ptIndex=0; ptIndex<numVertices; ptIndex++) { int dofOrdinalForPoint = vertexOrdinals[ptIndex]; bool expectZero = (dofOrdinalForPoint != fieldIndex); if (expectZero) { if (vertexValues(fieldIndex,ptIndex) != 0) { success = false; cout << "Expected 0 for fieldIndex " << fieldIndex << " and ptIndex " << ptIndex; cout << ", but got " << vertexValues(fieldIndex,ptIndex) << endl; } } else { if (vertexValues(fieldIndex,ptIndex) == 0) { cout << "Expected nonzero for fieldIndex " << fieldIndex << " and ptIndex " << ptIndex << endl; success = false; } } } } if (!success) { cout << "Failed testBasisClassifications; vertexValues:\n" << vertexValues; } return success; }
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"; } }*/ }