// computes riesz representation over a single element - map is from int (testID) to FieldContainer of values (sized cellIndex, numPoints) void RieszRep::computeRepresentationValues(FieldContainer<double> &values, int testID, IntrepidExtendedTypes::EOperatorExtended op, BasisCachePtr basisCache){ if (_repsNotComputed){ cout << "Computing riesz rep dofs" << endl; computeRieszRep(); } int spaceDim = _mesh->getTopology()->getSpaceDim(); int numCells = values.dimension(0); int numPoints = values.dimension(1); vector<GlobalIndexType> cellIDs = basisCache->cellIDs(); // all elems coming in should be of same type ElementPtr elem = _mesh->getElement(cellIDs[0]); ElementTypePtr elemTypePtr = elem->elementType(); DofOrderingPtr testOrderingPtr = elemTypePtr->testOrderPtr; CellTopoPtrLegacy cellTopoPtr = elemTypePtr->cellTopoPtr; int numTestDofsForVarID = testOrderingPtr->getBasisCardinality(testID, 0); BasisPtr testBasis = testOrderingPtr->getBasis(testID); bool testBasisIsVolumeBasis = (spaceDim == testBasis->domainTopology()->getDimension()); bool useCubPointsSideRefCell = testBasisIsVolumeBasis && basisCache->isSideCache(); Teuchos::RCP< const FieldContainer<double> > transformedBasisValues = basisCache->getTransformedValues(testBasis,op,useCubPointsSideRefCell); int rank = values.rank() - 2; // if values are shaped as (C,P), scalar... if (rank > 1) { cout << "ranks greater than 1 not presently supported...\n"; TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "ranks greater than 1 not presently supported..."); } // Camellia::print("cellIDs",cellIDs); values.initialize(0.0); for (int cellIndex = 0;cellIndex<numCells;cellIndex++){ int cellID = cellIDs[cellIndex]; for (int j = 0;j<numTestDofsForVarID;j++) { int dofIndex = testOrderingPtr->getDofIndex(testID, j); for (int i = 0;i<numPoints;i++) { if (rank==0) { double basisValue = (*transformedBasisValues)(cellIndex,j,i); values(cellIndex,i) += basisValue*_rieszRepDofsGlobal[cellID](dofIndex); } else { for (int d = 0; d<spaceDim; d++) { double basisValue = (*transformedBasisValues)(cellIndex,j,i,d); values(cellIndex,i,d) += basisValue*_rieszRepDofsGlobal[cellID](dofIndex); } } } } } // TestSuite::serializeOutput("rep values", values); }
void Projector::projectFunctionOntoBasisInterpolating(FieldContainer<double> &basisCoefficients, FunctionPtr fxn, BasisPtr basis, BasisCachePtr domainBasisCache) { basisCoefficients.initialize(0); CellTopoPtr domainTopo = basis->domainTopology(); unsigned domainDim = domainTopo->getDimension(); IPPtr ip; bool traceVar = domainBasisCache->isSideCache(); pair<IPPtr, VarPtr> ipVarPair = IP::standardInnerProductForFunctionSpace(basis->functionSpace(), traceVar, domainDim); ip = ipVarPair.first; VarPtr v = ipVarPair.second; IPPtr ip_l2 = Teuchos::rcp( new IP ); ip_l2->addTerm(v); // for now, make all projections use L^2... (having some issues with gradients and cell Jacobians--I think we need the restriction of the cell Jacobian to the subcell, e.g., and it's not clear how to do that...) ip = ip_l2; FieldContainer<double> referenceDomainNodes(domainTopo->getVertexCount(),domainDim); CamelliaCellTools::refCellNodesForTopology(referenceDomainNodes, domainTopo); int basisCardinality = basis->getCardinality(); set<int> allDofs; for (int i=0; i<basisCardinality; i++) { allDofs.insert(i); } for (int d=0; d<=domainDim; d++) { FunctionPtr projectionThusFar = NewBasisSumFunction::basisSumFunction(basis, basisCoefficients); FunctionPtr fxnToApproximate = fxn - projectionThusFar; int subcellCount = domainTopo->getSubcellCount(d); for (int subcord=0; subcord<subcellCount; subcord++) { set<int> subcellDofOrdinals = basis->dofOrdinalsForSubcell(d, subcord); if (subcellDofOrdinals.size() > 0) { FieldContainer<double> refCellPoints; FieldContainer<double> cubatureWeightsSubcell; // allows us to integrate over the fine subcell even when domain is higher-dimensioned if (d == 0) { refCellPoints.resize(1,domainDim); for (int d1=0; d1<domainDim; d1++) { refCellPoints(0,d1) = referenceDomainNodes(subcord,d1); } cubatureWeightsSubcell.resize(1); cubatureWeightsSubcell(0) = 1.0; } else { CellTopoPtr subcellTopo = domainTopo->getSubcell(d, subcord); // Teuchos::RCP<Cubature<double> > subcellCubature = cubFactory.create(subcellTopo, domainBasisCache->cubatureDegree()); BasisCachePtr subcellCache = Teuchos::rcp( new BasisCache(subcellTopo, domainBasisCache->cubatureDegree(), false) ); int numPoints = subcellCache->getRefCellPoints().dimension(0); refCellPoints.resize(numPoints,domainDim); cubatureWeightsSubcell = subcellCache->getCubatureWeights(); if (d == domainDim) { refCellPoints = subcellCache->getRefCellPoints(); } else { CamelliaCellTools::mapToReferenceSubcell(refCellPoints, subcellCache->getRefCellPoints(), d, subcord, domainTopo); } } domainBasisCache->setRefCellPoints(refCellPoints, cubatureWeightsSubcell); IPPtr ipForProjection = (d==0) ? ip_l2 : ip; // just use values at vertices (ignore derivatives) set<int> dofsToSkip = allDofs; for (set<int>::iterator dofOrdinalIt=subcellDofOrdinals.begin(); dofOrdinalIt != subcellDofOrdinals.end(); dofOrdinalIt++) { dofsToSkip.erase(*dofOrdinalIt); } FieldContainer<double> newBasisCoefficients; projectFunctionOntoBasis(newBasisCoefficients, fxnToApproximate, basis, domainBasisCache, ipForProjection, v, dofsToSkip); for (int cellOrdinal=0; cellOrdinal<newBasisCoefficients.dimension(0); cellOrdinal++) { for (set<int>::iterator dofOrdinalIt=subcellDofOrdinals.begin(); dofOrdinalIt != subcellDofOrdinals.end(); dofOrdinalIt++) { basisCoefficients(cellOrdinal,*dofOrdinalIt) = newBasisCoefficients(cellOrdinal,*dofOrdinalIt); } } } } } }
void Projector::projectFunctionOntoBasis(FieldContainer<double> &basisCoefficients, FunctionPtr fxn, BasisPtr basis, BasisCachePtr basisCache, IPPtr ip, VarPtr v, set<int> fieldIndicesToSkip) { CellTopoPtr cellTopo = basis->domainTopology(); DofOrderingPtr dofOrderPtr = Teuchos::rcp(new DofOrdering()); if (! fxn.get()) { TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "fxn cannot be null!"); } int cardinality = basis->getCardinality(); int numCells = basisCache->getPhysicalCubaturePoints().dimension(0); int numDofs = cardinality - fieldIndicesToSkip.size(); if (numDofs==0) { // we're skipping all the fields, so just initialize basisCoefficients to 0 and return basisCoefficients.resize(numCells,cardinality); basisCoefficients.initialize(0); return; } FieldContainer<double> gramMatrix(numCells,cardinality,cardinality); FieldContainer<double> ipVector(numCells,cardinality); // fake a DofOrdering DofOrderingPtr dofOrdering = Teuchos::rcp( new DofOrdering ); if (! basisCache->isSideCache()) { dofOrdering->addEntry(v->ID(), basis, v->rank()); } else { dofOrdering->addEntry(v->ID(), basis, v->rank(), basisCache->getSideIndex()); } ip->computeInnerProductMatrix(gramMatrix, dofOrdering, basisCache); ip->computeInnerProductVector(ipVector, v, fxn, dofOrdering, basisCache); // cout << "physical points for projection:\n" << basisCache->getPhysicalCubaturePoints(); // cout << "gramMatrix:\n" << gramMatrix; // cout << "ipVector:\n" << ipVector; map<int,int> oldToNewIndices; if (fieldIndicesToSkip.size() > 0) { // the code to do with fieldIndicesToSkip might not be terribly efficient... // (but it's not likely to be called too frequently) int i_indices_skipped = 0; for (int i=0; i<cardinality; i++) { int new_index; if (fieldIndicesToSkip.find(i) != fieldIndicesToSkip.end()) { i_indices_skipped++; new_index = -1; } else { new_index = i - i_indices_skipped; } oldToNewIndices[i] = new_index; } FieldContainer<double> gramMatrixFiltered(numCells,numDofs,numDofs); FieldContainer<double> ipVectorFiltered(numCells,numDofs); // now filter out the values that we're to skip for (int cellIndex=0; cellIndex<numCells; cellIndex++) { for (int i=0; i<cardinality; i++) { int i_filtered = oldToNewIndices[i]; if (i_filtered == -1) { continue; } ipVectorFiltered(cellIndex,i_filtered) = ipVector(cellIndex,i); for (int j=0; j<cardinality; j++) { int j_filtered = oldToNewIndices[j]; if (j_filtered == -1) { continue; } gramMatrixFiltered(cellIndex,i_filtered,j_filtered) = gramMatrix(cellIndex,i,j); } } } // cout << "gramMatrixFiltered:\n" << gramMatrixFiltered; // cout << "ipVectorFiltered:\n" << ipVectorFiltered; gramMatrix = gramMatrixFiltered; ipVector = ipVectorFiltered; } for (int cellIndex=0; cellIndex<numCells; cellIndex++){ // TODO: rewrite to take advantage of SerialDenseWrapper... Epetra_SerialDenseSolver solver; Epetra_SerialDenseMatrix A(Copy, &gramMatrix(cellIndex,0,0), gramMatrix.dimension(2), gramMatrix.dimension(2), gramMatrix.dimension(1)); // stride -- fc stores in row-major order (a.o.t. SDM) Epetra_SerialDenseVector b(Copy, &ipVector(cellIndex,0), ipVector.dimension(1)); Epetra_SerialDenseVector x(gramMatrix.dimension(1)); solver.SetMatrix(A); int info = solver.SetVectors(x,b); if (info!=0){ cout << "projectFunctionOntoBasis: failed to SetVectors with error " << info << endl; } bool equilibrated = false; if (solver.ShouldEquilibrate()){ solver.EquilibrateMatrix(); solver.EquilibrateRHS(); equilibrated = true; } info = solver.Solve(); if (info!=0){ cout << "projectFunctionOntoBasis: failed to solve with error " << info << endl; } if (equilibrated) { int successLocal = solver.UnequilibrateLHS(); if (successLocal != 0) { cout << "projection: unequilibration FAILED with error: " << successLocal << endl; } } basisCoefficients.resize(numCells,cardinality); for (int i=0;i<cardinality;i++) { if (fieldIndicesToSkip.size()==0) { basisCoefficients(cellIndex,i) = x(i); } else { int i_filtered = oldToNewIndices[i]; if (i_filtered==-1) { basisCoefficients(cellIndex,i) = 0.0; } else { basisCoefficients(cellIndex,i) = x(i_filtered); } } } } }
void Projector::projectFunctionOntoBasis(FieldContainer<double> &basisCoefficients, FunctionPtr fxn, BasisPtr basis, BasisCachePtr basisCache) { VarFactory varFactory; VarPtr var; if (! basisCache->isSideCache()) { if (fxn->rank()==0) { var = varFactory.fieldVar("dummyField"); } else if (fxn->rank()==1) { var = varFactory.fieldVar("dummyField",VECTOR_L2); } else { TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "projectFunctionOntoBasis does not yet support functions of rank > 1."); } } else { // for present purposes, distinction between trace and flux doesn't really matter, // except that parities come into the IP computation for fluxes (even though they'll cancel), // and since basisCache doesn't necessarily have parities defined (especially in tests), // it's simpler all around to use traces. var = varFactory.traceVar("dummyTrace"); } IPPtr ip = Teuchos::rcp( new IP ); ip->addTerm(var); // simple L^2 IP projectFunctionOntoBasis(basisCoefficients, fxn, basis, basisCache, ip, var); /* // TODO: rewrite this to use the version above (define L2 inner product for a dummy variable, then pass in this ip and varPtr) shards::CellTopology cellTopo = basis->domainTopology(); DofOrderingPtr dofOrderPtr = Teuchos::rcp(new DofOrdering()); // assume only L2 projections IntrepidExtendedTypes::EOperatorExtended op = IntrepidExtendedTypes::OP_VALUE; // have information, build inner product matrix int numDofs = basis->getCardinality(); const FieldContainer<double> *cubPoints = &(basisCache->getPhysicalCubaturePoints()); constFCPtr basisValues = basisCache->getTransformedValues(basis, op); constFCPtr testBasisValues = basisCache->getTransformedWeightedValues(basis, op); int numCells = cubPoints->dimension(0); int numPts = cubPoints->dimension(1); FieldContainer<double> functionValues(numCells,numPts); fxn->values(functionValues, basisCache); FieldContainer<double> gramMatrix(numCells,numDofs,numDofs); FieldContainer<double> ipVector(numCells,numDofs); FunctionSpaceTools::integrate<double>(gramMatrix,*basisValues,*testBasisValues,COMP_BLAS); FunctionSpaceTools::integrate<double>(ipVector,functionValues,*testBasisValues,COMP_BLAS); basisCoefficients.resize(numCells,numDofs); for (int cellIndex=0; cellIndex<numCells; cellIndex++){ Epetra_SerialDenseSolver solver; Epetra_SerialDenseMatrix A(Copy, &gramMatrix(cellIndex,0,0), gramMatrix.dimension(2), gramMatrix.dimension(2), gramMatrix.dimension(1)); // stride -- fc stores in row-major order (a.o.t. SDM) Epetra_SerialDenseVector b(Copy, &ipVector(cellIndex,0), ipVector.dimension(1)); Epetra_SerialDenseVector x(gramMatrix.dimension(1)); if (cellIndex==0) { cout << "legacy projectFunctionOntoBasis: matrix A for cellIndex 0 = " << endl; for (int i=0;i<gramMatrix.dimension(2);i++){ for (int j=0;j<gramMatrix.dimension(1);j++){ cout << A(i,j) << " "; } cout << endl; } cout << endl; cout << "legacy projectFunctionOntoBasis: vector B for cellIndex 0 = " << endl; for (int i=0;i<ipVector.dimension(1);i++){ cout << b(i) << endl; } } solver.SetMatrix(A); int info = solver.SetVectors(x,b); if (info!=0){ cout << "projectFunctionOntoBasis: failed to SetVectors with error " << info << endl; } bool equilibrated = false; if (solver.ShouldEquilibrate()){ solver.EquilibrateMatrix(); solver.EquilibrateRHS(); equilibrated = true; } info = solver.Solve(); if (info!=0){ cout << "projectFunctionOntoBasis: failed to solve with error " << info << endl; } if (equilibrated) { int successLocal = solver.UnequilibrateLHS(); if (successLocal != 0) { cout << "projection: unequilibration FAILED with error: " << successLocal << endl; } } for (int i=0;i<numDofs;i++){ basisCoefficients(cellIndex,i) = x(i); } }*/ }
void 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); } } } } }
virtual void localStiffnessMatrixAndRHS(FieldContainer<double> &localStiffness, FieldContainer<double> &rhsVector, IPPtr ip, BasisCachePtr ipBasisCache, RHSPtr rhs, BasisCachePtr basisCache) { double testMatrixAssemblyTime = 0, testMatrixInversionTime = 0, localStiffnessDeterminationFromTestsTime = 0; #ifdef HAVE_MPI Epetra_MpiComm Comm(MPI_COMM_WORLD); //cout << "rank: " << rank << " of " << numProcs << endl; #else Epetra_SerialComm Comm; #endif Epetra_Time timer(Comm); // localStiffness should have dim. (numCells, numTrialFields, numTrialFields) MeshPtr mesh = basisCache->mesh(); if (mesh.get() == NULL) { cout << "localStiffnessMatrix requires BasisCache to have mesh set.\n"; TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "localStiffnessMatrix requires BasisCache to have mesh set."); } const vector<GlobalIndexType>* cellIDs = &basisCache->cellIDs(); int numCells = cellIDs->size(); if (numCells != localStiffness.dimension(0)) { cout << "localStiffnessMatrix requires basisCache->cellIDs() to have the same # of cells as the first dimension of localStiffness\n"; TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "localStiffnessMatrix requires basisCache->cellIDs() to have the same # of cells as the first dimension of localStiffness"); } ElementTypePtr elemType = mesh->getElementType((*cellIDs)[0]); // we assume all cells provided are of the same type DofOrderingPtr trialOrder = elemType->trialOrderPtr; DofOrderingPtr fieldOrder = mesh->getDofOrderingFactory().getFieldOrdering(trialOrder); DofOrderingPtr traceOrder = mesh->getDofOrderingFactory().getTraceOrdering(trialOrder); map<int, int> stiffnessIndexForTraceIndex; map<int, int> stiffnessIndexForFieldIndex; 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); bool isTrace = (sidesForVar->size() > 1); for (vector<int>::const_iterator sideIt = sidesForVar->begin(); sideIt != sidesForVar->end(); sideIt++) { int sideOrdinal = *sideIt; vector<int> dofIndices = trialOrder->getDofIndices(varID,sideOrdinal); if (isTrace) { vector<int> traceDofIndices = traceOrder->getDofIndices(varID,sideOrdinal); for (int i=0; i<traceDofIndices.size(); i++) { stiffnessIndexForTraceIndex[traceDofIndices[i]] = dofIndices[i]; } } else { vector<int> fieldDofIndices = fieldOrder->getDofIndices(varID); for (int i=0; i<fieldDofIndices.size(); i++) { stiffnessIndexForFieldIndex[fieldDofIndices[i]] = dofIndices[i]; } } } } int numTrialDofs = trialOrder->totalDofs(); if ((numTrialDofs != localStiffness.dimension(1)) || (numTrialDofs != localStiffness.dimension(2))) { cout << "localStiffness should have dimensions (C,numTrialFields,numTrialFields).\n"; TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "localStiffness should have dimensions (C,numTrialFields,numTrialFields)."); } map<int,int> traceTestMap, fieldTestMap; int numEquations = _virtualTerms.getFieldTestVars().size(); for (int eqn=0; eqn<numEquations; eqn++) { VarPtr testVar = _virtualTerms.getFieldTestVars()[eqn]; VarPtr traceVar = _virtualTerms.getAssociatedTrace(testVar); VarPtr fieldVar = _virtualTerms.getAssociatedField(testVar); traceTestMap[traceVar->ID()] = testVar->ID(); fieldTestMap[fieldVar->ID()] = testVar->ID(); } int maxDegreeField = fieldOrder->maxBasisDegree(); int testDegreeInterior = maxDegreeField + _virtualTerms.getTestEnrichment(); int testDegreeTrace = testDegreeInterior + 2; cout << "ERROR in Virtual: getRelabeledDofOrdering() is commented out in DofOrderingFactory. Need to rewrite for the new caching scheme.\n"; DofOrderingPtr testOrderInterior; // = mesh->getDofOrderingFactory().getRelabeledDofOrdering(fieldOrder, fieldTestMap); testOrderInterior = mesh->getDofOrderingFactory().setBasisDegree(testOrderInterior, testDegreeInterior, false); DofOrderingPtr testOrderTrace = mesh->getDofOrderingFactory().setBasisDegree(testOrderInterior, testDegreeTrace, true); // this has a bunch of extra dofs (interior guys) map<int, int> remappedTraceIndices; // go from the index that includes the interior dofs to one that doesn't set<int> testIDs = testOrderTrace->getVarIDs(); int testTraceIndex = 0; for (set<int>::iterator testIDIt = testIDs.begin(); testIDIt != testIDs.end(); testIDIt++) { int testID = *testIDIt; BasisPtr basis = testOrderTrace->getBasis(testID); vector<int> interiorDofs = basis->dofOrdinalsForInterior(); for (int basisOrdinal=0; basisOrdinal<basis->getCardinality(); basisOrdinal++) { if (std::find(interiorDofs.begin(),interiorDofs.end(),basisOrdinal) == interiorDofs.end()) { int dofIndex = testOrderTrace->getDofIndex(testID, basisOrdinal); remappedTraceIndices[dofIndex] = testTraceIndex; testTraceIndex++; } } } // DofOrderingPtr testOrderTrace = mesh->getDofOrderingFactory().getRelabeledDofOrdering(traceOrder, traceTestMap); // testOrderTrace = mesh->getDofOrderingFactory().setBasisDegree(testOrderTrace, testDegreeTrace); int numTestInteriorDofs = testOrderInterior->totalDofs(); int numTestTraceDofsIncludingInterior = testOrderTrace->totalDofs(); int numTestTraceDofs = testTraceIndex; int numTestDofs = numTestTraceDofs + numTestInteriorDofs; timer.ResetStartTime(); bool printTimings = true; if (printTimings) { cout << "numCells: " << numCells << endl; cout << "numTestDofs: " << numTestDofs << endl; } FieldContainer<double> rhsVectorTest(numCells,testOrderInterior->totalDofs()); // rhsVector is zero for the "trace" test dofs { // project the load f onto the space of interior test dofs. LinearTermPtr f = rhs->linearTerm(); set<int> testIDs = f->varIDs(); for (int eqn=0; eqn<numEquations; eqn++) { VarPtr v = _virtualTerms.getFieldTestVars()[eqn]; if (testIDs.find(v->ID()) != testIDs.end()) { BasisPtr testInteriorBasis = testOrderInterior->getBasis(v->ID()); FieldContainer<double> fValues(numCells,testInteriorBasis->getCardinality()); // DofOrderingPtr oneVarOrderingTest = Teuchos::rcp(new DofOrdering(testInteriorBasis->domainTopology())); DofOrderingPtr oneVarOrderingTest = Teuchos::rcp(new DofOrdering); oneVarOrderingTest->addEntry(v->ID(), testInteriorBasis, testInteriorBasis->rangeRank()); LinearTermPtr f_v = Teuchos::rcp( new LinearTerm ); typedef pair< FunctionPtr, VarPtr > LinearSummand; vector<LinearSummand> summands = f->summands(); for (int i=0; i<summands.size(); i++) { FunctionPtr f = summands[i].first; if (v->ID() == summands[i].second->ID()) { f_v->addTerm(f * v); f_v->integrate(fValues, oneVarOrderingTest, basisCache); } } LinearTermPtr v_lt = 1.0 * v; FieldContainer<double> l2(numCells,testInteriorBasis->getCardinality(),testInteriorBasis->getCardinality()); v_lt->integrate(l2,oneVarOrderingTest,v_lt,oneVarOrderingTest,basisCache,basisCache->isSideCache()); Teuchos::Array<int> testTestDim(2), testOneDim(2); testTestDim[0] = testInteriorBasis->getCardinality(); testTestDim[1] = testInteriorBasis->getCardinality(); testOneDim[0] = testInteriorBasis->getCardinality(); testOneDim[1] = 1; FieldContainer<double> projection(testOneDim); for (int cellOrdinal=0; cellOrdinal<numCells; cellOrdinal++) { FieldContainer<double> l2cell(testTestDim,&l2(cellOrdinal,0,0)); FieldContainer<double> f_cell(testOneDim,&fValues(cellOrdinal,0)); SerialDenseWrapper::solveSystemUsingQR(projection, l2cell, f_cell); // rows in projection correspond to Ae_i, columns to the e_j. I.e. projection coefficients for e_i are found in the ith row for (int basisOrdinal_j=0; basisOrdinal_j<projection.dimension(0); basisOrdinal_j++) { int testIndex = testOrderInterior->getDofIndex(v->ID(), basisOrdinal_j); rhsVectorTest(cellOrdinal,testIndex) = projection(basisOrdinal_j,0); } } } } } // project strong operator applied to field terms, and use this to populate the top left portion of stiffness matrix: { FieldContainer<double> trialFieldTestInterior(numCells, fieldOrder->totalDofs(), testOrderInterior->totalDofs()); for (int eqn=0; eqn<numEquations; eqn++) { LinearTermPtr Au = _virtualTerms.getFieldOperators()[eqn]; VarPtr v = _virtualTerms.getFieldTestVars()[eqn]; set<int> fieldIDs = Au->varIDs(); for (set<int>::iterator fieldIt = fieldIDs.begin(); fieldIt != fieldIDs.end(); fieldIt++) { int fieldID = *fieldIt; // int testID = fieldTestMap[fieldID]; // // LinearTermPtr testInteriorVar = 1.0 * this->varFactory().test(testID); BasisPtr vBasis = testOrderInterior->getBasis(v->ID()); BasisPtr fieldTrialBasis = fieldOrder->getBasis(fieldID); // DofOrderingPtr oneVarOrderingTest = Teuchos::rcp(new DofOrdering(vBasis->domainTopology())); DofOrderingPtr oneVarOrderingTest = Teuchos::rcp(new DofOrdering()); oneVarOrderingTest->addEntry(v->ID(), vBasis, vBasis->rangeRank()); FieldContainer<double> Au_values(numCells,vBasis->getCardinality(),fieldTrialBasis->getCardinality()); FieldContainer<double> l2(numCells,vBasis->getCardinality(),vBasis->getCardinality()); DofOrderingPtr oneVarOrderingTrial = Teuchos::rcp(new DofOrdering()); // DofOrderingPtr oneVarOrderingTrial = Teuchos::rcp(new DofOrdering(fieldTrialBasis->domainTopology())); oneVarOrderingTrial->addEntry(fieldID, fieldTrialBasis, fieldTrialBasis->rangeRank()); LinearTermPtr Au_restricted_to_field = Teuchos::rcp( new LinearTerm ); typedef pair< FunctionPtr, VarPtr > LinearSummand; vector<LinearSummand> summands = Au->summands(); for (int i=0; i<summands.size(); i++) { FunctionPtr f = summands[i].first; VarPtr v = summands[i].second; if (v->ID() == fieldID) { Au_restricted_to_field->addTerm(f * v); } } LinearTermPtr v_lt = 1.0 * v; Au_restricted_to_field->integrate(Au_values,oneVarOrderingTrial,v_lt,oneVarOrderingTest,basisCache,basisCache->isSideCache()); v_lt->integrate(l2,oneVarOrderingTest,v_lt,oneVarOrderingTest,basisCache,basisCache->isSideCache()); double maxValue = 0; for (int i=0; i<l2.size(); i++) { maxValue = max(abs(l2[i]),maxValue); } cout << "maxValue in l2 is " << maxValue << endl; Teuchos::Array<int> testTestDim(2), trialTestDim(2); testTestDim[0] = vBasis->getCardinality(); testTestDim[1] = vBasis->getCardinality(); trialTestDim[0] = vBasis->getCardinality(); trialTestDim[1] = fieldTrialBasis->getCardinality(); FieldContainer<double> projection(trialTestDim); for (int cellOrdinal=0; cellOrdinal<numCells; cellOrdinal++) { FieldContainer<double> l2cell(testTestDim,&l2(cellOrdinal,0,0)); FieldContainer<double> AuCell(trialTestDim,&Au_values(cellOrdinal,0,0)); // TODO: confirm that I'm doing the right projection here. I could be missing a key point, but it seems to me that we must // project onto an *orthonormal* basis here, to achieve the required identity structure of the (field,field) part of the // Gram matrix. OTOH, it looks to me like the computation here achieves exactly that, even though I didn't initially // have that in mind... // SerialDenseWrapper::solveSystemUsingQR(projection, l2cell, AuCell); SerialDenseWrapper::solveSystemMultipleRHS(projection, l2cell, AuCell); // rows in projection correspond to Ae_i, columns to the e_j. I.e. projection coefficients for e_i are found in the ith row for (int basisOrdinal_i=0; basisOrdinal_i<projection.dimension(0); basisOrdinal_i++) { int testIndex = testOrderInterior->getDofIndex(v->ID(), basisOrdinal_i); for (int basisOrdinal_j=0; basisOrdinal_j<projection.dimension(1); basisOrdinal_j++) { int trialIndex = fieldOrder->getDofIndex(fieldID, basisOrdinal_j); // in the *trial* space trialFieldTestInterior(cellOrdinal,trialIndex,testIndex) = projection(basisOrdinal_i,basisOrdinal_j); } } } } } Teuchos::Array<int> trialTestDim(2); trialTestDim[0] = fieldOrder->totalDofs(); trialTestDim[1] = testOrderInterior->totalDofs(); for (int cellOrdinal=0; cellOrdinal<numCells; cellOrdinal++) { FieldContainer<double> trialFieldTrialField(fieldOrder->totalDofs(), fieldOrder->totalDofs()); FieldContainer<double> trialTestCell(trialTestDim, &trialFieldTestInterior(cellOrdinal,0,0)); SerialDenseWrapper::multiply(trialFieldTrialField, trialTestCell, trialTestCell, 'N', 'T'); // transpose the second one // now, accumulate into localStiffness for (int i=0; i<trialFieldTrialField.dimension(0); i++) { int stiff_i = stiffnessIndexForFieldIndex[i]; for (int j=0; j<trialFieldTrialField.dimension(1); j++) { int stiff_j = stiffnessIndexForFieldIndex[j]; localStiffness(cellOrdinal,stiff_i,stiff_j) = trialFieldTrialField(i,j); } } } // multiply RHS integrated against the interior test space by the trialFieldTestInterior for (int cellOrdinal=0; cellOrdinal<numCells; cellOrdinal++) { Teuchos::Array<int> trialTestDim(2), oneTestDim(2); trialTestDim[0] = fieldOrder->totalDofs(); trialTestDim[1] = testOrderInterior->totalDofs(); oneTestDim[0] = 1; oneTestDim[1] = testOrderInterior->totalDofs(); FieldContainer<double> trialTestCell(trialTestDim, &trialFieldTestInterior(cellOrdinal,0,0)); FieldContainer<double> rhsTestCell(oneTestDim, &rhsVectorTest(cellOrdinal,0)); FieldContainer<double> rhsTrialCell(1, fieldOrder->totalDofs()); SerialDenseWrapper::multiply(rhsTrialCell, rhsTestCell, trialTestCell, 'N', 'T'); for (int fieldIndex=0; fieldIndex<fieldOrder->totalDofs(); fieldIndex++) { int stiffIndex = stiffnessIndexForFieldIndex[fieldIndex]; rhsVector(cellOrdinal,stiffIndex) = rhsTrialCell(0, fieldIndex); } } } FieldContainer<double> ipMatrixTraceIncludingInterior(numCells,numTestTraceDofsIncludingInterior,numTestTraceDofsIncludingInterior); int numTestTerms = _virtualTerms.getTestNormOperators().size(); for (int i=0; i<numTestTerms; i++) { LinearTermPtr testTerm = _virtualTerms.getTestNormOperators()[i]; LinearTermPtr boundaryTerm = _virtualTerms.getTestNormBoundaryOperators()[i]; testTerm->integrate(ipMatrixTraceIncludingInterior,testOrderTrace,boundaryTerm,testOrderTrace,ipBasisCache,ipBasisCache->isSideCache()); } FieldContainer<double> ipMatrixTrace(numCells,numTestTraceDofs,numTestTraceDofs); for (int cellOrdinal=0; cellOrdinal<numCells; cellOrdinal++) { for (int i_dofIndex=0; i_dofIndex<numTestTraceDofsIncludingInterior; i_dofIndex++) { if (remappedTraceIndices.find(i_dofIndex) == remappedTraceIndices.end()) { continue; } int i_remapped = remappedTraceIndices[i_dofIndex]; for (int j_dofIndex=0; j_dofIndex<numTestTraceDofsIncludingInterior; j_dofIndex++) { if (remappedTraceIndices.find(j_dofIndex) == remappedTraceIndices.end()) { continue; } int j_remapped = remappedTraceIndices[j_dofIndex]; ipMatrixTrace(cellOrdinal,i_remapped,j_remapped) = ipMatrixTraceIncludingInterior(cellOrdinal,i_dofIndex,j_dofIndex); } } } testMatrixAssemblyTime += timer.ElapsedTime(); // cout << "ipMatrix:\n" << ipMatrix; timer.ResetStartTime(); cout << "NOTE: we do not yet enforce continuity on the trace test space.\n"; // I *think* this is fine, but I'm not dead certain -- we do of course in the end enforce continuity in GDAMinimumRule // now, determine the trace part of the bilinear form matrix FieldContainer<double> bfMatrixTraceTraceIncludingTestInterior(numCells,testOrderTrace->totalDofs(),traceOrder->totalDofs()); FieldContainer<double> bfMatrixFieldTraceIncludingTestInterior(numCells,testOrderTrace->totalDofs(),fieldOrder->totalDofs()); for (int eqn=0; eqn<numEquations; eqn++) { VarPtr traceVar = _virtualTerms.getTraceVars()[eqn]; LinearTermPtr termTraced = traceVar->termTraced(); LinearTermPtr strongOperator = _virtualTerms.getFieldOperators()[eqn]; VarPtr testVar = _virtualTerms.getFieldTestVars()[eqn]; // want to determine \hat{C}(\hat{e}_i, \phi_j) for \phi_j with support on the boundary // the \phi_j's with support on the boundary are the ones associated with the trace LinearTermPtr trialTerm = 1.0 * traceVar; LinearTermPtr testTerm; if (traceVar->varType() == TRACE) { testTerm = Function::normal() * testVar; } else { testTerm = 1.0 * testVar; } // trialTerm->integrate(bfMatrixTrace,traceOrder,testTerm,testOrderTrace,basisCache,basisCache->isSideCache()); trialTerm->integrate(bfMatrixTraceTraceIncludingTestInterior,traceOrder,testTerm,testOrderTrace,basisCache,basisCache->isSideCache()); termTraced->integrate(bfMatrixFieldTraceIncludingTestInterior,fieldOrder,-testTerm,testOrderTrace,basisCache,basisCache->isSideCache()); } FieldContainer<double> bfMatrixFieldTrace(numCells,numTestTraceDofs,bfMatrixFieldTraceIncludingTestInterior.dimension(2)); FieldContainer<double> bfMatrixTraceTrace(numCells,numTestTraceDofs,bfMatrixTraceTraceIncludingTestInterior.dimension(2)); for (int cellOrdinal=0; cellOrdinal<numCells; cellOrdinal++) { for (int i_dofIndex=0; i_dofIndex<numTestTraceDofsIncludingInterior; i_dofIndex++) { if (remappedTraceIndices.find(i_dofIndex) == remappedTraceIndices.end()) { continue; } int i_remapped = remappedTraceIndices[i_dofIndex]; for (int j_dofIndex=0; j_dofIndex<bfMatrixFieldTrace.dimension(2); j_dofIndex++) { bfMatrixFieldTrace(cellOrdinal,i_remapped,j_dofIndex) = bfMatrixFieldTraceIncludingTestInterior(cellOrdinal,i_dofIndex,j_dofIndex); } for (int j_dofIndex=0; j_dofIndex<bfMatrixTraceTrace.dimension(2); j_dofIndex++) { bfMatrixTraceTrace(cellOrdinal,i_remapped,j_dofIndex) = bfMatrixTraceTraceIncludingTestInterior(cellOrdinal,i_dofIndex,j_dofIndex); } } } Teuchos::Array<int> ipMatrixDim(2), bfMatrixTraceTraceDim(2), bfMatrixFieldTraceDim(2); Teuchos::Array<int> traceTraceStiffDim(2), fieldTraceStiffDim(2), fieldFieldStiffDim(2); ipMatrixDim[0] = ipMatrixTrace.dimension(1); ipMatrixDim[1] = ipMatrixTrace.dimension(2); bfMatrixTraceTraceDim[0] = bfMatrixTraceTrace.dimension(1); bfMatrixTraceTraceDim[1] = bfMatrixTraceTrace.dimension(2); bfMatrixFieldTraceDim[0] = bfMatrixFieldTrace.dimension(1); bfMatrixFieldTraceDim[1] = bfMatrixFieldTrace.dimension(2); traceTraceStiffDim[0] = traceOrder->totalDofs(); traceTraceStiffDim[1] = traceTraceStiffDim[0]; fieldTraceStiffDim[0] = fieldOrder->totalDofs(); fieldTraceStiffDim[1] = traceOrder->totalDofs(); // rectangular fieldFieldStiffDim[0] = fieldOrder->totalDofs(); fieldFieldStiffDim[1] = fieldOrder->totalDofs(); FieldContainer<double> traceTraceStiffCell(traceTraceStiffDim); FieldContainer<double> fieldTraceStiffCell(fieldTraceStiffDim); FieldContainer<double> fieldFieldStiffCell(fieldFieldStiffDim); for (int cellOrdinal=0; cellOrdinal<numCells; cellOrdinal++) { FieldContainer<double> ipMatrixCell(ipMatrixDim,&ipMatrixTrace(cellOrdinal,0,0)); FieldContainer<double> optTestCoeffsTraceTrace(numTestTraceDofs,traceOrder->totalDofs()); FieldContainer<double> bfMatrixTraceTraceCell(bfMatrixTraceTraceDim,&bfMatrixTraceTrace(cellOrdinal,0,0)); int result = SerialDenseWrapper::solveSystemUsingQR(optTestCoeffsTraceTrace, ipMatrixCell, bfMatrixTraceTraceCell); SerialDenseWrapper::multiply(traceTraceStiffCell, bfMatrixTraceTraceCell, optTestCoeffsTraceTrace, 'T', 'N'); // copy into the appropriate spot in localStiffness: for (int i=0; i<traceTraceStiffDim[0]; i++) { int i_stiff = stiffnessIndexForTraceIndex[i]; for (int j=0; j<traceTraceStiffDim[1]; j++) { int j_stiff = stiffnessIndexForTraceIndex[j]; localStiffness(cellOrdinal,i_stiff,j_stiff) = traceTraceStiffCell(i,j); } } // because of the way the matrix blocks line up, we actually don't have to do a second inversion of ipMatrixCell for this part FieldContainer<double> bfMatrixFieldTraceCell(bfMatrixFieldTraceDim,&bfMatrixFieldTrace(cellOrdinal,0,0)); SerialDenseWrapper::multiply(fieldTraceStiffCell, bfMatrixFieldTraceCell, optTestCoeffsTraceTrace, 'T', 'N'); // copy into the appropriate spots in localStiffness (taking advantage of symmetry): for (int i=0; i<fieldTraceStiffDim[0]; i++) { int i_stiff = stiffnessIndexForFieldIndex[i]; for (int j=0; j<fieldTraceStiffDim[1]; j++) { int j_stiff = stiffnessIndexForTraceIndex[j]; localStiffness(cellOrdinal,i_stiff,j_stiff) = fieldTraceStiffCell(i,j); localStiffness(cellOrdinal,j_stiff,i_stiff) = fieldTraceStiffCell(i,j); } } // because of the way the matrix blocks line up, we do have some trace contributions in the (field, field) portion of the matrix // these get added to the field contributions (hence the +=) FieldContainer<double> optTestCoeffsFieldTrace(numTestTraceDofs,fieldOrder->totalDofs()); result = SerialDenseWrapper::solveSystemUsingQR(optTestCoeffsFieldTrace, ipMatrixCell, bfMatrixFieldTraceCell); SerialDenseWrapper::multiply(fieldFieldStiffCell, bfMatrixFieldTraceCell, optTestCoeffsFieldTrace, 'T', 'N'); for (int i=0; i<fieldFieldStiffDim[0]; i++) { int i_stiff = stiffnessIndexForFieldIndex[i]; for (int j=0; j<fieldFieldStiffDim[1]; j++) { int j_stiff = stiffnessIndexForFieldIndex[j]; localStiffness(cellOrdinal,i_stiff,j_stiff) += fieldFieldStiffCell(i,j); } } } testMatrixInversionTime += timer.ElapsedTime(); // cout << "optTestCoeffs:\n" << optTestCoeffs; if (printTimings) { cout << "testMatrixAssemblyTime: " << testMatrixAssemblyTime << " seconds.\n"; cout << "testMatrixInversionTime: " << testMatrixInversionTime << " seconds.\n"; cout << "localStiffnessDeterminationFromTestsTime: " << localStiffnessDeterminationFromTestsTime << " seconds.\n"; } }