void FunctionTests::checkFunctionsAgree(FunctionPtr f1, FunctionPtr f2, BasisCachePtr basisCache) { ASSERT_EQ(f1->rank(), f2->rank()) << "f1->rank() " << f1->rank() << " != f2->rank() " << f2->rank() << endl; int rank = f1->rank(); int numCells = basisCache->getPhysicalCubaturePoints().dimension(0); int numPoints = basisCache->getPhysicalCubaturePoints().dimension(1); int spaceDim = basisCache->getPhysicalCubaturePoints().dimension(2); Teuchos::Array<int> dim; dim.append(numCells); dim.append(numPoints); for (int i=0; i<rank; i++) { dim.append(spaceDim); } FieldContainer<double> f1Values(dim); FieldContainer<double> f2Values(dim); f1->values(f1Values,basisCache); f2->values(f2Values,basisCache); double tol = 1e-14; double maxDiff; EXPECT_TRUE(fcsAgree(f1Values,f2Values,tol,maxDiff)) << "Test failed: f1 and f2 disagree; maxDiff " << maxDiff << ".\n" << "f1Values: \n" << f1Values << "f2Values: \n" << f2Values; }
bool ElementTests::testNeighborPointMapping() { bool success = true; double tol = 1e-15; double maxDiff; int SOUTH = 0, EAST = 1, NORTH = 2, WEST = 3; // determine expected values int numPoints = _testPoints1D.dimension(0); FieldContainer<double> neighborPointsForSW_east_side = FieldContainer<double>(numPoints,1); // universal rule is just flip along (-1,1): x --> -x for (int i=0; i<numPoints; i++) { neighborPointsForSW_east_side(i, 0) = - _testPoints1D(i,0); } // determine actual values, and compare FieldContainer<double> neighborRefPoints = FieldContainer<double>(numPoints,1); _sw->getSidePointsInNeighborRefCoords(neighborRefPoints, EAST, _testPoints1D); if ( !fcsAgree(neighborRefPoints,neighborPointsForSW_east_side,tol,maxDiff) ) { cout << "Failure in mapping to neighbor ref coords; maxDiff = " << maxDiff << endl; success = false; } return success; }
bool ScratchPadTests::testConstantFunctionProduct() { bool success = true; // set up basisCache (even though it won't really be used here) BasisCachePtr basisCache = Teuchos::rcp( new BasisCache( _elemType, _spectralConfusionMesh ) ); vector<GlobalIndexType> cellIDs; int cellID = 0; cellIDs.push_back(cellID); basisCache->setPhysicalCellNodes( _spectralConfusionMesh->physicalCellNodesForCell(cellID), cellIDs, true ); int numCells = _basisCache->getPhysicalCubaturePoints().dimension(0); int numPoints = _testPoints.dimension(0); FunctionPtr three = Function::constant(3.0); FunctionPtr two = Function::constant(2.0); FieldContainer<double> values(numCells,numPoints); two->values(values,basisCache); three->scalarMultiplyBasisValues( values, basisCache ); FieldContainer<double> expectedValues(numCells,numPoints); expectedValues.initialize( 3.0 * 2.0 ); double tol = 1e-15; double maxDiff = 0.0; if ( ! fcsAgree(expectedValues, values, tol, maxDiff) ) { success = false; cout << "Expected product differs from actual; maxDiff: " << maxDiff << endl; } return success; }
bool ElementTests::testParentPointMapping() { bool success = true; double tol = 1e-15; double maxDiff; int SOUTH = 0, EAST = 1, NORTH = 2, WEST = 3; // determine expected values int numPoints = _testPoints1D.dimension(0); FieldContainer<double> sw_east_points_for_ne_child = FieldContainer<double>(numPoints,1); // along the east side, ne child is the second: so rule is add 1 and divide by 2 for (int i=0; i<numPoints; i++) { sw_east_points_for_ne_child(i, 0) = (_testPoints1D(i,0)+1.0)/2.0; } FieldContainer<double> sw_east_points_for_se_child = FieldContainer<double>(numPoints,1); // along the east side, se child is the first: so rule is subtract 1 and divide by 2 for (int i=0; i<numPoints; i++) { sw_east_points_for_se_child(i, 0) = (_testPoints1D(i,0)-1.0)/2.0; } // determine actual values, and compare FieldContainer<double> parentRefPoints = FieldContainer<double>(numPoints,1); _sw_ne->getSidePointsInParentRefCoords(parentRefPoints, EAST, _testPoints1D); if ( !fcsAgree(parentRefPoints,sw_east_points_for_ne_child,tol,maxDiff) ) { cout << "Failure in mapping to parent ref coords for NE child; maxDiff = " << maxDiff << endl; success = false; } _sw_se->getSidePointsInParentRefCoords(parentRefPoints, EAST, _testPoints1D); if ( !fcsAgree(parentRefPoints,sw_east_points_for_se_child,tol,maxDiff) ) { cout << "Failure in mapping to parent ref coords for SE child; maxDiff = " << maxDiff << endl; success = false; } return success; }
bool ScratchPadTests::testSpatiallyFilteredFunction() { bool success = true; FunctionPtr one = Function::constant(1.0); SpatialFilterPtr positiveX = Teuchos::rcp( new PositiveX ); FunctionPtr heaviside = Teuchos::rcp( new SpatiallyFilteredFunction<double>(one, positiveX) ); int numCells = _basisCache->getPhysicalCubaturePoints().dimension(0); int numPoints = _testPoints.dimension(0); FieldContainer<double> values(numCells,numPoints); FieldContainer<double> expectedValues(numCells,numPoints); for (int cellIndex=0; cellIndex<numCells; cellIndex++) { for (int ptIndex=0; ptIndex<numPoints; ptIndex++) { double x = _basisCache->getPhysicalCubaturePoints()(cellIndex,ptIndex,0); if (x > 0) { expectedValues(cellIndex,ptIndex) = 1.0; } else { expectedValues(cellIndex,ptIndex) = 0.0; } } } heaviside->values(values,_basisCache); double tol = 1e-15; double maxDiff = 0.0; if ( ! fcsAgree(expectedValues, values, tol, maxDiff) ) { success = false; cout << "testSpatiallyFilteredFunction: Expected values differ from actual; maxDiff: " << maxDiff << endl; } return success; }
TEST_F(MPIWrapperTests, TestEntryWiseSum) { int numProcs = Teuchos::GlobalMPISession::getNProc(); int rank = Teuchos::GlobalMPISession::getRank(); FieldContainer<double> expectedValues(2); for (int i=0; i<numProcs; i++) { expectedValues[0] += i*i; expectedValues[1] += 1; } FieldContainer<double> values(2); values[0] = rank*rank; values[1] = 1; MPIWrapper::entryWiseSum(values); double tol = 1e-16; double maxDiff = 0; EXPECT_TRUE(fcsAgree(values, expectedValues, tol, maxDiff)) << "MPIWrapperTests::testentryWiseSum() failed with maxDiff " << maxDiff << endl; // EXPECT_EQ(rank, 2) << "rank " << rank << endl; }
bool MPIWrapperTests::testentryWiseSum() { bool success = true; int numProcs = Teuchos::GlobalMPISession::getNProc(); int rank = Teuchos::GlobalMPISession::getRank(); FieldContainer<double> expectedValues(2); for (int i=0; i<numProcs; i++) { expectedValues[0] += i*i; expectedValues[1] += 1; } FieldContainer<double> values(2); values[0] = rank*rank; values[1] = 1; MPIWrapper::entryWiseSum(values); double tol = 1e-16; double maxDiff = 0; if (! fcsAgree(values, expectedValues, tol, maxDiff) ) { success = false; cout << "MPIWrapperTests::testentryWiseSum() failed with maxDiff " << maxDiff << endl; } return success; }
bool LinearTermTests::testBoundaryPlusVolumeTerms() { bool success = true; // notion is integration by parts: // (div f, v) = < f * n, v > - (f, grad v) // We perform two subtests for each test: first we try with a particular // function substituted for the variable. Second, we integrate over the // basis for the mesh (i.e. we test a whole bunch of functions, whose // precise definition is a bit complicated). // A third test is against the two-term LinearTerm::integrate() method. // This doesn't do integration by parts, but rather tests that // (u + u->dot_normal(), v) = (u,v) + (u->dot_normal(), v) ///////////// FIRST TEST //////////////// // start simply: define f to be (x, 0) // (div f, v) = (1, v) // < f * n, v > - (f, grad v) = < x n1, v > - ( x, v->dx() ) FunctionPtr x = Function::xn(1); FunctionPtr y = Function::yn(1); FunctionPtr x2 = Function::xn(2); FunctionPtr y2 = Function::yn(2); FunctionPtr x3 = Function::xn(3); FunctionPtr y3 = Function::yn(3); vector< FunctionPtr > f_fxns; f_fxns.push_back( Function::vectorize( x, Function::zero() ) ); // div of this = 1 f_fxns.push_back( Function::vectorize( x2 / 6.0, x2 * y / 2.0 ) ); // div of this = x / 3 + x^2 / 2 for ( vector< FunctionPtr >::iterator fIt = f_fxns.begin(); fIt != f_fxns.end(); fIt++) { FunctionPtr vector_fxn = *fIt; LinearTermPtr lt_v = vector_fxn->div()*v1; // part a: substitute v1 = x*y^2 FunctionPtr v1_value = x*y2; map< int, FunctionPtr > var_values; var_values[v1->ID()] = v1_value; double expectedValue = lt_v->evaluate(var_values, false)->integrate(mesh); FunctionPtr n = Function::normal(); LinearTermPtr ibp = vector_fxn * n * v1 - vector_fxn * v1->grad(); int numCells = basisCache->getPhysicalCubaturePoints().dimension(0); int numPoints = basisCache->getPhysicalCubaturePoints().dimension(1); int spaceDim = basisCache->getSpaceDim(); FieldContainer<double> vector_fxn_values(numCells,numPoints,spaceDim); vector_fxn->values(vector_fxn_values,basisCache); // cout << "vector_fxn values: \n" << vector_fxn_values; double boundaryIntegralSum = ibp->evaluate(var_values,true)->integrate(mesh); double volumeIntegralSum = ibp->evaluate(var_values,false)->integrate(mesh); double actualValue = boundaryIntegralSum + volumeIntegralSum; double tol = 1e-14; if (abs(expectedValue - actualValue)>tol) { success = false; } // part b: integrate the bases over each of the cells: int num_dofs = testOrder->totalDofs(); FieldContainer<double> integrals_expected( mesh->numActiveElements(), num_dofs ); FieldContainer<double> integrals_actual( mesh->numActiveElements(), num_dofs ); lt_v->integrate(integrals_expected,testOrder,basisCache); ibp->integrate(integrals_actual,testOrder,basisCache); double maxDiff = 0; if (! fcsAgree(integrals_actual, integrals_expected, tol, maxDiff) ) { cout << "LT integrated by parts does not agree with the original; maxDiff: " << maxDiff << endl; success = false; } // just on the odd chance that ordering makes a difference, repeat this test with the opposite order in ibp: ibp = - vector_fxn * v1->grad() + vector_fxn * n * v1; ibp->integrate(integrals_actual,testOrder,basisCache, false, false); maxDiff = 0; if (! fcsAgree(integrals_actual, integrals_expected, tol, maxDiff) ) { cout << "LT integrated by parts does not agree with the original; maxDiff: " << maxDiff << endl; success = false; } // part c: two-term integrals FieldContainer<double> integrals_expected_two_term( mesh->numActiveElements(), num_dofs, num_dofs); FieldContainer<double> integrals_actual_two_term( mesh->numActiveElements(), num_dofs, num_dofs ); LinearTermPtr ibp1 = vector_fxn * n * v1; LinearTermPtr ibp2 = - vector_fxn * v1->grad(); lt_v->integrate(integrals_expected_two_term, testOrder, ibp1 + ibp2, testOrder, basisCache, false, false); lt_v->integrate(integrals_actual_two_term, testOrder, ibp1, testOrder, basisCache, false, false); // don't forceBoundary, don't sumInto lt_v->integrate(integrals_actual_two_term, testOrder, ibp2, testOrder, basisCache, false, true); // DO sumInto maxDiff = 0; if (! fcsAgree(integrals_actual_two_term, integrals_expected_two_term, tol, maxDiff) ) { cout << "two-term integration is not bilinear; maxDiff: " << maxDiff << endl; success = false; } // now, same thing but with the roles of ibp{1|2} and lt_v reversed: (ibp1 + ibp2)->integrate(integrals_expected_two_term, testOrder, lt_v, testOrder, basisCache, false, false); ibp1->integrate(integrals_actual_two_term, testOrder, lt_v, testOrder, basisCache, false, false); // don't forceBoundary, don't sumInto ibp2->integrate(integrals_actual_two_term, testOrder, lt_v, testOrder, basisCache, false, true); // DO sumInto maxDiff = 0; if (! fcsAgree(integrals_actual_two_term, integrals_expected_two_term, tol, maxDiff) ) { cout << "two-term integration is not bilinear; maxDiff: " << maxDiff << endl; success = false; } // now, test that two-term integration commutes in the two terms: ibp1->integrate(integrals_expected_two_term, testOrder, lt_v, testOrder, basisCache, false, false); lt_v->integrate(integrals_actual_two_term, testOrder, ibp1, testOrder, basisCache, false, false); // we expect the integrals to commute up to a transpose, so let's transpose one of the containers: transposeFieldContainer(integrals_expected_two_term); maxDiff = 0; if (! fcsAgree(integrals_actual_two_term, integrals_expected_two_term, tol, maxDiff) ) { cout << "two-term integration does not commute for boundary value (ibp1); maxDiff: " << maxDiff << endl; success = false; } ibp2->integrate(integrals_expected_two_term, testOrder, lt_v, testOrder, basisCache, false, false); lt_v->integrate(integrals_actual_two_term, testOrder, ibp2, testOrder, basisCache, false, false); // we expect the integrals to commute up to a transpose, so let's transpose one of the containers: transposeFieldContainer(integrals_expected_two_term); maxDiff = 0; if (! fcsAgree(integrals_actual_two_term, integrals_expected_two_term, tol, maxDiff) ) { cout << "two-term integration does not commute for volume value (ibp2); maxDiff: " << maxDiff << endl; success = false; } // part d: to suss out where the integration failure happens in the non-commuting case: // 1. Substitute v1 = 1 in ibp2; get a function ibp2_at_v1_equals_one back. // 2. Substitute v1 = 1 in lt_v; get a function lt_v_at_v1_equals_one back. // 3. Integrate ibp2_at_v1_equals_one * lt_v_at_v1_equals_one over the mesh. Get a double result. // 4. Because basis is nodal, the representation for v1 = 1 is just all 1s for coefficients. // Therefore, the sum of the entries in the integrals_*_two_term matrices will should match // the function integral. Whichever doesn't match is wrong. // first, let's confirm that the v1 basis *is* nodal: BasisPtr v1Basis = testOrder->getBasis(v1->ID()); if (! v1Basis->isNodal()) { cout << "testBoundaryPlusVolumeTerms: final part of test relies on a nodal basis, but the basis is not nodal."; cout << " Exiting test early (with whatever success value we have thus far).\n"; return success; } map< int, FunctionPtr > v1_equals_one; v1_equals_one[v1->ID()] = Function::constant(1.0); FunctionPtr ibp1_at_v1_equals_one = ibp1->evaluate(v1_equals_one,true); // ibp1 has only a boundary term, so we just ask for this FunctionPtr ibp2_at_v1_equals_one = ibp2->evaluate(v1_equals_one,false); // ibp2 has no boundary terms, so we don't ask for these FunctionPtr lt_v_at_v1_equals_one = lt_v->evaluate(v1_equals_one,false); // lt_v also has no boundary terms if (ibp1_at_v1_equals_one->isZero()) { cout << "ibp1_at_v1_equals_one->isZero() = true.\n"; } if (lt_v_at_v1_equals_one->isZero()) { cout << "lt_v_at_v1_equals_one->isZero() = true.\n"; } FieldContainer<double> integrals_lt_v_first( mesh->numActiveElements(), num_dofs, num_dofs ); FieldContainer<double> integrals_ibp1_first( mesh->numActiveElements(), num_dofs, num_dofs ); FieldContainer<double> integrals_ibp2_first( mesh->numActiveElements(), num_dofs, num_dofs ); double lt_v_first_integral = 0.0, ibp1_first_integral = 0.0, ibp2_first_integral = 0.0; double integral = (ibp1_at_v1_equals_one * lt_v_at_v1_equals_one)->integrate(mesh); ibp1->integrate(integrals_ibp1_first, testOrder, lt_v, testOrder, basisCache, false, false); lt_v->integrate(integrals_lt_v_first, testOrder, ibp1, testOrder, basisCache, false, false); for (int i=0; i<integrals_lt_v_first.size(); i++) { lt_v_first_integral += integrals_lt_v_first[i]; ibp1_first_integral += integrals_ibp1_first[i]; } if (abs(lt_v_first_integral - integral) > tol) { double diff = abs(lt_v_first_integral - integral); success = false; cout << "Integral with v1=1 substituted does not match two-term integration of (lt_v,ibp1) with lt_v as this. diff = " << diff << "\n"; cout << "lt_v_first_integral = " << lt_v_first_integral << endl; cout << " (true) integral = " << integral << endl; } if (abs(ibp1_first_integral - integral) > tol) { double diff = abs(ibp1_first_integral - integral); success = false; cout << "Integral with v1=1 substituted does not match two-term integration of (lt_v,ibp1) with ibp1 as this. diff = " << diff << "\n"; cout << "ibp1_first_integral = " << ibp1_first_integral << endl; cout << " (true) integral = " << integral << endl; } // now, do the same but for ibp2 integral = (ibp2_at_v1_equals_one * lt_v_at_v1_equals_one)->integrate(mesh); ibp2->integrate(integrals_ibp2_first, testOrder, lt_v, testOrder, basisCache, false, false); lt_v->integrate(integrals_lt_v_first, testOrder, ibp2, testOrder, basisCache, false, false); // reset the sums: lt_v_first_integral = 0.0; ibp1_first_integral = 0.0; ibp2_first_integral = 0.0; for (int i=0; i<integrals_lt_v_first.size(); i++) { lt_v_first_integral += integrals_lt_v_first[i]; ibp2_first_integral += integrals_ibp2_first[i]; } if (abs(lt_v_first_integral - integral) > tol) { double diff = abs(lt_v_first_integral - integral); success = false; cout << "Integral with v1=1 substituted does not match two-term integration of (lt_v,ibp2) with lt_v as this. diff = " << diff << "\n"; cout << "lt_v_first_integral = " << lt_v_first_integral << endl; cout << " (true) integral = " << integral << endl; } if (abs(ibp2_first_integral - integral) > tol) { double diff = abs(ibp2_first_integral - integral); success = false; cout << "Integral with v1=1 substituted does not match two-term integration of (lt_v,ibp2) with ibp2 as this. diff = " << diff << "\n"; cout << "ibp1_first_integral = " << ibp1_first_integral << endl; cout << " (true) integral = " << integral << endl; } } return success; }
bool ParametricCurveTests::testGradientWrapper() { bool success = true; // create an artificial function whose gradient is "interesting" and known FunctionPtr t1 = Function::xn(1); FunctionPtr t2 = Function::yn(1); FunctionPtr xt = t1 + t1 * t2; FunctionPtr yt = t2 + 2 * t1 * t2; FunctionPtr xt_dt1 = 1 + t2; FunctionPtr xt_dt2 = t1; FunctionPtr yt_dt1 = 2 * t2; FunctionPtr yt_dt2 = 1 + 2 * t1; FunctionPtr ft = Function::vectorize(xt, yt); FunctionPtr ft_dt1 = Function::vectorize(xt_dt1, yt_dt1); FunctionPtr ft_dt2 = Function::vectorize(xt_dt2, yt_dt2); FunctionPtr ft_gradt = Function::vectorize(ft_dt1, ft_dt2); // first test: confirm that on a parametric quad, the wrapped function agrees with the naked one int cubatureDegree = 5; BasisCachePtr parametricQuadCache = BasisCache::parametricQuadCache(cubatureDegree); FunctionPtr fx_gradx = ParametricCurve::parametricGradientWrapper(ft_gradt, true); double tol = 1e-14; if (! ft_gradt->equals(fx_gradx, parametricQuadCache)) { success = false; cout << "on a parametric quad, the wrapped gradient doesn't agree with the naked one"; reportFunctionValueDifferences(ft_gradt, fx_gradx, parametricQuadCache, tol); } if (! ft_gradt->equals(ft->grad(), parametricQuadCache)) { success = false; cout << "on a parametric quad, manual gradient disagrees with automatic one (error in test construction, likely)."; reportFunctionValueDifferences(ft_gradt, ft->grad(), parametricQuadCache, tol); } // on the quad domain defined by (0,0), (1,0), (2,3), (0,1), // some algebra shows that for x and y as functions of the parametric // coordinates, we have // x = t1 + t1 * t2 // y = t2 + 2 * t1 * t2 // which gives the result that our original function f(t1,t2) = (t1 + t1 * t2, t2 + 2 * t1 * t2) = (x, y) FunctionPtr x = Function::xn(1); // understood in physical space FunctionPtr y = Function::yn(1); FunctionPtr f1_xy = x; FunctionPtr f2_xy = y; FunctionPtr f_xy = Function::vectorize(f1_xy, f2_xy); // set up the quad domain FieldContainer<double> physicalCellNodes(1,4,2); // (C,P,D) physicalCellNodes(0,0,0) = 0; physicalCellNodes(0,0,1) = 0; physicalCellNodes(0,1,0) = 1; physicalCellNodes(0,1,1) = 0; physicalCellNodes(0,2,0) = 2; physicalCellNodes(0,2,1) = 3; physicalCellNodes(0,3,0) = 0; physicalCellNodes(0,3,1) = 1; // physical space BasisCache: shards::CellTopology quad_4(shards::getCellTopologyData<shards::Quadrilateral<4> >() ); BasisCachePtr basisCache = Teuchos::rcp( new BasisCache(physicalCellNodes, quad_4, cubatureDegree)); // as a preliminary test, check that the Jacobian values and inverse values agree with our expectations // we expect the Jacobian to be: // [ 1 + t2 t1 ] // 1/2 * [ ] // [ 2 * t2 1 + t2 ] // where (t1,t2) are parametric coordinates and the 1/2 comes from the transformation from reference // to parametric space int numCells = 1; int numPoints = basisCache->getRefCellPoints().dimension(0); int spaceDim = 2; FieldContainer<double> jacobianExpected(numCells,numPoints,spaceDim,spaceDim); FieldContainer<double> jacobianInvExpected(numCells,numPoints,spaceDim,spaceDim); // also check that the function we've chosen has the expected values // by first computing its gradient in parametric space and then dividing by 2 to account // for the transformation from reference to parametric space FieldContainer<double> fgrad_based_jacobian(numCells,numPoints,spaceDim,spaceDim); ft_gradt->values(fgrad_based_jacobian, parametricQuadCache); FieldContainer<double> parametricPoints = basisCache->computeParametricPoints(); for (int ptIndex=0; ptIndex<numPoints; ptIndex++) { double t1 = parametricPoints(0,ptIndex,0); double t2 = parametricPoints(0,ptIndex,1); jacobianExpected(0,ptIndex,0,0) = 0.5 * (1 + t2); jacobianExpected(0,ptIndex,0,1) = 0.5 * (t1); jacobianExpected(0,ptIndex,1,0) = 0.5 * (2 * t2); jacobianExpected(0,ptIndex,1,1) = 0.5 * (1 + 2 * t1); jacobianInvExpected(0,ptIndex,0,0) = (2.0 / (1 + 2 * t1 + t2) ) * (1 + 2 * t1); jacobianInvExpected(0,ptIndex,0,1) = (2.0 / (1 + 2 * t1 + t2) ) * (- t1); jacobianInvExpected(0,ptIndex,1,0) = (2.0 / (1 + 2 * t1 + t2) ) * (- 2 * t2); jacobianInvExpected(0,ptIndex,1,1) = (2.0 / (1 + 2 * t1 + t2) ) * (1 + t2); fgrad_based_jacobian(0,ptIndex,0,0) /= 2.0; fgrad_based_jacobian(0,ptIndex,0,1) /= 2.0; fgrad_based_jacobian(0,ptIndex,1,0) /= 2.0; fgrad_based_jacobian(0,ptIndex,1,1) /= 2.0; } FieldContainer<double> jacobian = basisCache->getJacobian(); FieldContainer<double> jacobianInv = basisCache->getJacobianInv(); double maxDiff = 0; if (! fcsAgree(jacobianExpected, jacobian, tol, maxDiff)) { success = false; cout << "Jacobian expected does not match actual.\n"; reportFunctionValueDifferences(parametricPoints, jacobian, jacobianExpected, tol); } if (! fcsAgree(jacobianInvExpected, jacobianInv, tol, maxDiff)) { success = false; cout << "Jacobian inverse expected does not match actual.\n"; reportFunctionValueDifferences(parametricPoints, jacobianInv, jacobianInvExpected, tol); } if (! fcsAgree(fgrad_based_jacobian, jacobianExpected, tol, maxDiff)) { success = false; cout << "Jacobian from fgrad does not agree with the transformation jacobian (problem with test?).\n"; reportFunctionValueDifferences(parametricPoints, fgrad_based_jacobian, jacobianExpected, tol); } // test that the gradient values agree if (! fx_gradx->equals(f_xy->grad(), basisCache)) { success = false; cout << "wrapped gradient does not agree with analytically transformed function.\n"; reportFunctionValueDifferences(fx_gradx, f_xy->grad(), basisCache, tol); } // finally, although this isn't really the right place for this, it is convenient here // to test the TFI for the "mesh" we were concerned with above. int H1Order = 5; BFPtr bf = VGPStokesFormulation(1.0).bf(); physicalCellNodes.resize(4,2); int horizontalElements = 1, verticalElements = 1; MeshPtr mesh = MeshFactory::quadMesh(bf, H1Order, physicalCellNodes); int cellID = 0; vector< ParametricCurvePtr > edges = mesh->parametricEdgesForCell(cellID); ParametricSurfacePtr tfi = ParametricSurface::transfiniteInterpolant(edges); double v2[2]; edges[2]->value(0, v2[0], v2[1]); // cout << "v2 = (" << v2[0] << ", " << v2[1] << ")\n"; if ( ! tfi->equals(f_xy, basisCache) ) { success = false; cout << "TFI does not agree with analytically constructed transformation function.\n"; reportFunctionValueDifferences(tfi, f_xy, basisCache, tol); } if ( ! tfi->grad()->equals(f_xy->grad(), basisCache) ) { success = false; cout << "TFI does not agree with analytically constructed transformation function.\n"; reportFunctionValueDifferences(tfi->grad(), f_xy->grad(), basisCache, tol); } return success; }
bool FunctionTests::testValuesDottedWithTensor() { bool success = true; vector< FunctionPtr > vectorFxns; double xValue = 3, yValue = 4; FunctionPtr simpleVector = Function::vectorize(Function::constant(xValue), Function::constant(yValue)); vectorFxns.push_back(simpleVector); FunctionPtr x = Function::xn(1); FunctionPtr y = Function::yn(1); vectorFxns.push_back( Function::vectorize(x*x, x*y) ); VGPStokesFormulation vgpStokes = VGPStokesFormulation(1.0); BFPtr bf = vgpStokes.bf(); int h1Order = 1; MeshPtr mesh = MeshFactory::quadMesh(bf, h1Order); int cellID=0; // the only cell BasisCachePtr basisCache = BasisCache::basisCacheForCell(mesh, cellID); for (int i=0; i<vectorFxns.size(); i++) { FunctionPtr vectorFxn_i = vectorFxns[i]; for (int j=0; j<vectorFxns.size(); j++) { FunctionPtr vectorFxn_j = vectorFxns[j]; FunctionPtr dotProduct = vectorFxn_i * vectorFxn_j; FunctionPtr expectedDotProduct = vectorFxn_i->x() * vectorFxn_j->x() + vectorFxn_i->y() * vectorFxn_j->y(); if (! expectedDotProduct->equals(dotProduct, basisCache)) { cout << "testValuesDottedWithTensor() failed: expected dot product does not match dotProduct.\n"; success = false; double tol = 1e-14; reportFunctionValueDifferences(dotProduct, expectedDotProduct, basisCache, tol); } } } // now, let's try the same thing, but for a LinearTerm dot product VarFactoryPtr vf = VarFactory::varFactory(); VarPtr v = vf->testVar("v", HGRAD); DofOrderingPtr dofOrdering = Teuchos::rcp( new DofOrdering(CellTopology::quad()) ); shards::CellTopology quad_4(shards::getCellTopologyData<shards::Quadrilateral<4> >() ); BasisPtr basis = BasisFactory::basisFactory()->getBasis(h1Order, quad_4.getKey(), Camellia::FUNCTION_SPACE_HGRAD); dofOrdering->addEntry(v->ID(), basis, v->rank()); int numCells = 1; int numFields = basis->getCardinality(); for (int i=0; i<vectorFxns.size(); i++) { FunctionPtr f_i = vectorFxns[i]; LinearTermPtr lt_i = f_i * v; LinearTermPtr lt_i_x = f_i->x() * v; LinearTermPtr lt_i_y = f_i->y() * v; for (int j=0; j<vectorFxns.size(); j++) { FunctionPtr f_j = vectorFxns[j]; LinearTermPtr lt_j = f_j * v; LinearTermPtr lt_j_x = f_j->x() * v; LinearTermPtr lt_j_y = f_j->y() * v; FieldContainer<double> values(numCells,numFields,numFields); lt_i->integrate(values, dofOrdering, lt_j, dofOrdering, basisCache); FieldContainer<double> values_expected(numCells,numFields,numFields); lt_i_x->integrate(values_expected,dofOrdering,lt_j_x,dofOrdering,basisCache); lt_i_y->integrate(values_expected,dofOrdering,lt_j_y,dofOrdering,basisCache); double tol = 1e-14; double maxDiff = 0; if (!fcsAgree(values, values_expected, tol, maxDiff)) { cout << "FunctionTests::testValuesDottedWithTensor: "; cout << "dot product and sum of the products of scalar components differ by maxDiff " << maxDiff; cout << " in LinearTerm::integrate().\n"; success = false; } } } // // finally, let's try the same sort of thing, but now with a vector-valued basis // BasisPtr vectorBasisTemp = BasisFactory::basisFactory()->getBasis(h1Order, quad_4.getKey(), Camellia::FUNCTION_SPACE_VECTOR_HGRAD); // VectorBasisPtr vectorBasis = Teuchos::rcp( (VectorizedBasis<double, FieldContainer<double> > *)vectorBasisTemp.get(),false); // // BasisPtr compBasis = vectorBasis->getComponentBasis(); // // // create a new v, and a new dofOrdering // VarPtr v_vector = vf->testVar("v_vector", VECTOR_HGRAD); // dofOrdering = Teuchos::rcp( new DofOrdering ); // dofOrdering->addEntry(v_vector->ID(), vectorBasis, v_vector->rank()); // // DofOrderingPtr dofOrderingComp = Teuchos::rcp( new DofOrdering ); // dofOrderingComp->addEntry(v->ID(), compBasis, v->rank()); // return success; }
bool FunctionTests::testJacobianOrdering() { bool success = true; FunctionPtr y = Function::yn(1); FunctionPtr f = Function::vectorize(y, Function::zero()); // test 1: Jacobian ordering is f_i,j int spaceDim = 2; int cellID = 0; BasisCachePtr basisCache = BasisCache::basisCacheForCell(_spectralConfusionMesh, cellID); FieldContainer<double> physicalPoints = basisCache->getPhysicalCubaturePoints(); int numCells = physicalPoints.dimension(0); int numPoints = physicalPoints.dimension(1); FieldContainer<double> expectedValues(numCells, numPoints, spaceDim, spaceDim); for (int cellIndex=0; cellIndex<numCells; cellIndex++) { for (int ptIndex=0; ptIndex<numPoints; ptIndex++) { expectedValues(cellIndex,ptIndex,0,0) = 0; expectedValues(cellIndex,ptIndex,0,1) = 1; expectedValues(cellIndex,ptIndex,1,0) = 0; expectedValues(cellIndex,ptIndex,1,1) = 0; } } FieldContainer<double> values(numCells, numPoints, spaceDim, spaceDim); f->grad(spaceDim)->values(values, basisCache); double maxDiff = 0; double tol = 1e-14; if (! fcsAgree(expectedValues, values, tol, maxDiff)) { cout << "expectedValues does not match values in testJacobianOrdering().\n"; reportFunctionValueDifferences(physicalPoints, expectedValues, values, tol); success = false; } // test 2: ordering of VectorizedBasis agrees // (actually implemented where it belongs, in Vectorized_BasisTestSuite) // test 3: ordering of CellTools::getJacobian FieldContainer<double> nodes(1,4,2); nodes(0,0,0) = 1; nodes(0,0,1) = -2; nodes(0,1,0) = 1; nodes(0,1,1) = 2; nodes(0,2,0) = -1; nodes(0,2,1) = 2; nodes(0,3,0) = -1; nodes(0,3,1) = -2; shards::CellTopology quad_4(shards::getCellTopologyData<shards::Quadrilateral<4> >() ); int cubDegree = 4; BasisCachePtr rotatedCache = Teuchos::rcp( new BasisCache(nodes, quad_4, cubDegree) ); physicalPoints = rotatedCache->getPhysicalCubaturePoints(); numCells = physicalPoints.dimension(0); numPoints = physicalPoints.dimension(1); FieldContainer<double> expectedJacobian(numCells,numPoints,spaceDim,spaceDim); for (int cellIndex=0; cellIndex<numCells; cellIndex++) { for (int ptIndex=0; ptIndex<numPoints; ptIndex++) { expectedJacobian(cellIndex,ptIndex,0,0) = 0; expectedJacobian(cellIndex,ptIndex,0,1) = -1; expectedJacobian(cellIndex,ptIndex,1,0) = 2; expectedJacobian(cellIndex,ptIndex,1,1) = 0; } } FieldContainer<double> jacobianValues = rotatedCache->getJacobian(); maxDiff = 0; if (! fcsAgree(expectedJacobian, jacobianValues, tol, maxDiff)) { cout << "expectedJacobian does not match jacobianValues in testJacobianOrdering().\n"; reportFunctionValueDifferences(physicalPoints, expectedJacobian, jacobianValues, tol); success = false; } return success; }