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; // } }
void LagrangeConstraints::getCoefficients(FieldContainer<double> &lhs, FieldContainer<double> &rhs, int elemConstraintIndex, DofOrderingPtr trialOrdering, BasisCachePtr basisCache) { LinearTermPtr lt = _constraints[elemConstraintIndex].linearTerm(); TFunctionPtr<double> f = _constraints[elemConstraintIndex].f(); lt->integrate(lhs, trialOrdering, basisCache); bool onBoundary = f->boundaryValueOnly(); if ( !onBoundary ) { f->integrate(rhs, basisCache); } else { int numSides = basisCache->cellTopology()->getSideCount(); rhs.initialize(0); for (int sideIndex=0; sideIndex<numSides; sideIndex++) { f->integrate(rhs, basisCache->getSideBasisCache(sideIndex), true); // true: sumInto } } }
bool FunctionTests::testBasisSumFunction() { bool success = true; // on a single-element mesh, the BasisSumFunction should be identical to // the Solution with those coefficients // define a new mesh: more interesting if we're not on the ref cell int spaceDim = 2; FieldContainer<double> quadPoints(4,2); quadPoints(0,0) = 0.0; // x1 quadPoints(0,1) = 0.0; // y1 quadPoints(1,0) = 2.0; quadPoints(1,1) = 0.0; quadPoints(2,0) = 1.0; quadPoints(2,1) = 1.0; quadPoints(3,0) = 0.0; quadPoints(3,1) = 1.0; int H1Order = 1, pToAdd = 0; int horizontalCells = 1, verticalCells = 1; // create a pointer to a new mesh: MeshPtr spectralConfusionMesh = MeshFactory::buildQuadMesh(quadPoints, horizontalCells, verticalCells, _confusionBF, H1Order, H1Order+pToAdd); BCPtr bc = BC::bc(); SolutionPtr soln = Teuchos::rcp( new Solution(spectralConfusionMesh, bc) ); soln->initializeLHSVector(); int cellID = 0; double tol = 1e-16; // overly restrictive, just for now. DofOrderingPtr trialSpace = spectralConfusionMesh->getElementType(cellID)->trialOrderPtr; set<int> trialIDs = trialSpace->getVarIDs(); BasisCachePtr volumeCache = BasisCache::basisCacheForCell(spectralConfusionMesh, cellID); for (set<int>::iterator trialIt=trialIDs.begin(); trialIt != trialIDs.end(); trialIt++) { int trialID = *trialIt; const vector<int>* sidesForVar = &trialSpace->getSidesForVarID(trialID); bool boundaryValued = sidesForVar->size() != 1; // note that for volume trialIDs, sideIndex = 0, and numSides = 1… for (vector<int>::const_iterator sideIt = sidesForVar->begin(); sideIt != sidesForVar->end(); sideIt++) { int sideIndex = *sideIt; BasisCachePtr sideCache = volumeCache->getSideBasisCache(sideIndex); BasisPtr basis = trialSpace->getBasis(trialID, sideIndex); int basisCardinality = basis->getCardinality(); for (int basisOrdinal = 0; basisOrdinal<basisCardinality; basisOrdinal++) { FieldContainer<double> basisCoefficients(basisCardinality); basisCoefficients(basisOrdinal) = 1.0; soln->setSolnCoeffsForCellID(basisCoefficients, cellID, trialID, sideIndex); VarPtr v = Var::varForTrialID(trialID, spectralConfusionMesh->bilinearForm()); FunctionPtr solnFxn = Function::solution(v, soln, false); FunctionPtr basisSumFxn = Teuchos::rcp( new BasisSumFunction(basis, basisCoefficients, Teuchos::rcp((BasisCache*)NULL), OP_VALUE, boundaryValued) ); if (!boundaryValued) { double l2diff = (solnFxn - basisSumFxn)->l2norm(spectralConfusionMesh); // cout << "l2diff = " << l2diff << endl; if (l2diff > tol) { success = false; cout << "testBasisSumFunction: l2diff of " << l2diff << " exceeds tol of " << tol << endl; cout << "l2norm of basisSumFxn: " << basisSumFxn->l2norm(spectralConfusionMesh) << endl; cout << "l2norm of solnFxn: " << solnFxn->l2norm(spectralConfusionMesh) << endl; } l2diff = (solnFxn->dx() - basisSumFxn->dx())->l2norm(spectralConfusionMesh); // cout << "l2diff = " << l2diff << endl; if (l2diff > tol) { success = false; cout << "testBasisSumFunction: l2diff of dx() " << l2diff << " exceeds tol of " << tol << endl; cout << "l2norm of basisSumFxn->dx(): " << basisSumFxn->dx()->l2norm(spectralConfusionMesh) << endl; cout << "l2norm of solnFxn->dx(): " << solnFxn->dx()->l2norm(spectralConfusionMesh) << endl; } // test that the restriction to a side works int numSides = volumeCache->cellTopology()->getSideCount(); for (int i=0; i<numSides; i++) { BasisCachePtr mySideCache = volumeCache->getSideBasisCache(i); if (! solnFxn->equals(basisSumFxn, mySideCache, tol)) { success = false; cout << "testBasisSumFunction: on side 0, l2diff of " << l2diff << " exceeds tol of " << tol << endl; reportFunctionValueDifferences(solnFxn, basisSumFxn, mySideCache, tol); } if (! solnFxn->grad(spaceDim)->equals(basisSumFxn->grad(spaceDim), mySideCache, tol)) { success = false; cout << "testBasisSumFunction: on side 0, l2diff of dx() " << l2diff << " exceeds tol of " << tol << endl; reportFunctionValueDifferences(solnFxn->grad(spaceDim), basisSumFxn->grad(spaceDim), mySideCache, tol); } } } else { FieldContainer<double> cellIntegral(1); // compute l2 diff of integral along the one side where we can legitimately assert equality: FunctionPtr diffFxn = solnFxn - basisSumFxn; (diffFxn*diffFxn)->integrate(cellIntegral, sideCache); double l2diff = sqrt(cellIntegral(0)); if (l2diff > tol) { success = false; cout << "testBasisSumFunction: on side " << sideIndex << ", l2diff of " << l2diff << " exceeds tol of " << tol << endl; int numCubPoints = sideCache->getPhysicalCubaturePoints().dimension(1); FieldContainer<double> solnFxnValues(1,numCubPoints); FieldContainer<double> basisFxnValues(1,numCubPoints); solnFxn->values(solnFxnValues, sideCache); basisSumFxn->values(basisFxnValues, sideCache); cout << "solnFxnValues:\n" << solnFxnValues; cout << "basisFxnValues:\n" << basisFxnValues; } else { // cout << "testBasisSumFunction: on side " << sideIndex << ", l2diff of " << l2diff << " is within tol of " << tol << endl; } } } } } return success; }
void values(FieldContainer<double> &values, BasisCachePtr basisCache) { // sets values(_cellIndex,P,D) TEUCHOS_TEST_FOR_EXCEPTION(_cellIndex == -1, std::invalid_argument, "must call setCellIndex before calling values!"); // cout << "_basisCoefficients:\n" << _basisCoefficients; BasisCachePtr spaceTimeBasisCache; if (basisCache->cellTopologyIsSpaceTime()) { // then we require that the basisCache provided be a space-time basis cache SpaceTimeBasisCache* spaceTimeCache = dynamic_cast<SpaceTimeBasisCache*>(basisCache.get()); TEUCHOS_TEST_FOR_EXCEPTION(!spaceTimeCache, std::invalid_argument, "space-time requires a SpaceTimeBasisCache"); spaceTimeBasisCache = basisCache; basisCache = spaceTimeCache->getSpatialBasisCache(); } int numDofs = _basis->getCardinality(); int spaceDim = basisCache->getSpaceDim(); bool basisIsVolumeBasis = (spaceDim == _basis->domainTopology()->getDimension()); bool useCubPointsSideRefCell = basisIsVolumeBasis && basisCache->isSideCache(); int numPoints = values.dimension(1); // check if we're taking a temporal derivative int component; Intrepid::EOperator relatedOp = BasisEvaluation::relatedOperator(_op, _basis->functionSpace(), spaceDim, component); if ((relatedOp == Intrepid::OPERATOR_GRAD) && (component==spaceDim)) { // then we are taking the temporal part of the Jacobian of the reference to curvilinear-reference space // based on our assumptions that curvilinearity is just in the spatial direction (and is orthogonally extruded in the // temporal direction), this is always the identity. for (int ptIndex=0; ptIndex<numPoints; ptIndex++) { for (int d=0; d<values.dimension(2); d++) { if (d < spaceDim) values(_cellIndex,ptIndex,d) = 0.0; else values(_cellIndex,ptIndex,d) = 1.0; } } return; } constFCPtr transformedValues = basisCache->getTransformedValues(_basis, _op, useCubPointsSideRefCell); // transformedValues has dimensions (C,F,P,[D,D]) // therefore, the rank of the sum is transformedValues->rank() - 3 int rank = transformedValues->rank() - 3; TEUCHOS_TEST_FOR_EXCEPTION(rank != values.rank()-2, std::invalid_argument, "values rank is incorrect."); int spaceTimeSideOrdinal = (spaceTimeBasisCache != Teuchos::null) ? spaceTimeBasisCache->getSideIndex() : -1; // I'm pretty sure much of this treatment of the time dimension could be simplified by taking advantage of SpaceTimeBasisCache::getTemporalBasisCache()... double t0 = -1, t1 = -1; if ((spaceTimeSideOrdinal != -1) && (!spaceTimeBasisCache->cellTopology()->sideIsSpatial(spaceTimeSideOrdinal))) { unsigned sideTime0 = spaceTimeBasisCache->cellTopology()->getTemporalSideOrdinal(0); unsigned sideTime1 = spaceTimeBasisCache->cellTopology()->getTemporalSideOrdinal(1); // get first node of each of the time-orthogonal sides, and use that to determine t0 and t1: unsigned spaceTimeNodeTime0 = spaceTimeBasisCache->cellTopology()->getNodeMap(spaceDim, sideTime0, 0); unsigned spaceTimeNodeTime1 = spaceTimeBasisCache->cellTopology()->getNodeMap(spaceDim, sideTime1, 0); t0 = spaceTimeBasisCache->getPhysicalCellNodes()(_cellIndex,spaceTimeNodeTime0,spaceDim); t1 = spaceTimeBasisCache->getPhysicalCellNodes()(_cellIndex,spaceTimeNodeTime1,spaceDim); } // initialize the values we're responsible for setting if (_op == OP_VALUE) { for (int ptIndex=0; ptIndex<numPoints; ptIndex++) { for (int d=0; d<values.dimension(2); d++) { if (d < spaceDim) values(_cellIndex,ptIndex,d) = 0.0; else if ((spaceTimeBasisCache != Teuchos::null) && (spaceTimeSideOrdinal == -1)) values(_cellIndex,ptIndex,spaceDim) = spaceTimeBasisCache->getPhysicalCubaturePoints()(_cellIndex,ptIndex,spaceDim); else if ((spaceTimeBasisCache != Teuchos::null) && (spaceTimeSideOrdinal != -1)) { if (spaceTimeBasisCache->cellTopology()->sideIsSpatial(spaceTimeSideOrdinal)) { values(_cellIndex,ptIndex,spaceDim) = spaceTimeBasisCache->getPhysicalCubaturePoints()(_cellIndex,ptIndex,spaceDim-1); } else { double temporalPoint; unsigned temporalNode = spaceTimeBasisCache->cellTopology()->getTemporalComponentSideOrdinal(spaceTimeSideOrdinal); if (temporalNode==0) temporalPoint = t0; else temporalPoint = t1; values(_cellIndex,ptIndex,spaceDim) = temporalPoint; } } } } } else if ((_op == OP_DX) || (_op == OP_DY) || (_op == OP_DZ)) { for (int ptIndex=0; ptIndex<numPoints; ptIndex++) { for (int d=0; d<values.dimension(2); d++) { if (d < spaceDim) values(_cellIndex,ptIndex,d) = 0.0; else if (_op == OP_DZ) values(_cellIndex,ptIndex,d) = 1.0; else values(_cellIndex,ptIndex,d) = 0.0; } } } else { TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Unhandled _op"); } int numSpatialPoints = transformedValues->dimension(2); int numTemporalPoints = numPoints / numSpatialPoints; TEUCHOS_TEST_FOR_EXCEPTION(numTemporalPoints * numSpatialPoints != numPoints, std::invalid_argument, "numPoints is not evenly divisible by numSpatialPoints"); for (int i=0; i<numDofs; i++) { double weight = _basisCoefficients(i); for (int timePointOrdinal=0; timePointOrdinal<numTemporalPoints; timePointOrdinal++) { for (int spacePointOrdinal=0; spacePointOrdinal<numSpatialPoints; spacePointOrdinal++) { int spaceTimePointOrdinal = TENSOR_POINT_ORDINAL(spacePointOrdinal, timePointOrdinal, numSpatialPoints); for (int d=0; d<spaceDim; d++) { values(_cellIndex,spaceTimePointOrdinal,d) += weight * (*transformedValues)(_cellIndex,i,spacePointOrdinal,d); } } } } }