void Boundary::singletonBCsToImpose(std::map<GlobalIndexType,Scalar> &dofIndexToValue, TBC<Scalar> &bc, DofInterpreter* dofInterpreter) { // first, let's check for any singletons (one-point BCs) map<IndexType, set < pair<int, unsigned> > > singletonsForCell; const set<GlobalIndexType>* rankLocalCells = &_mesh->cellIDsInPartition(); vector< int > trialIDs = _mesh->bilinearForm()->trialIDs(); for (int trialID : trialIDs) { if (bc.singlePointBC(trialID)) { auto knownActiveCells = &_mesh->getTopology()->getLocallyKnownActiveCellIndices(); vector<double> spatialVertex = bc.pointForSpatialPointBC(trialID); vector<IndexType> matchingVertices = _mesh->getTopology()->getVertexIndicesMatching(spatialVertex); unsigned vertexDim = 0; for (IndexType vertexIndex : matchingVertices) { set< pair<IndexType, unsigned> > cellsForVertex = _mesh->getTopology()->getCellsContainingEntity(vertexDim, vertexIndex); for (pair<IndexType, unsigned> cellForVertex : cellsForVertex) { // active cell IndexType matchingCellID = cellForVertex.first; if (rankLocalCells->find(matchingCellID) != rankLocalCells->end()) // we own this cell, so we're responsible for imposing the singleton BC { CellPtr cell = _mesh->getTopology()->getCell(matchingCellID); unsigned vertexOrdinal = cell->findSubcellOrdinal(vertexDim, vertexIndex); TEUCHOS_TEST_FOR_EXCEPTION(vertexOrdinal == -1, std::invalid_argument, "Internal error: vertexOrdinal not found for cell to which it supposedly belongs"); singletonsForCell[matchingCellID].insert(make_pair(trialID, vertexOrdinal)); } } } } } for (auto cellEntry : singletonsForCell) { GlobalIndexType cellID = cellEntry.first; auto singletons = cellEntry.second; ElementTypePtr elemType = _mesh->getElementType(cellID); map<int, vector<unsigned> > vertexOrdinalsForTrialID; for (pair<int, unsigned> trialVertexPair : singletons) { vertexOrdinalsForTrialID[trialVertexPair.first].push_back(trialVertexPair.second); } for (auto trialVertexOrdinals : vertexOrdinalsForTrialID) { int trialID = trialVertexOrdinals.first; vector<unsigned> vertexOrdinalsInCell = trialVertexOrdinals.second; CellTopoPtr cellTopo = elemType->cellTopoPtr; CellTopoPtr spatialCellTopo; bool spaceTime; int vertexOrdinalInSpatialCell; if (vertexOrdinalsInCell.size() == 2) { // we'd better be doing space-time in this case, and the vertices should be the same spatially spaceTime = (cellTopo->getTensorialDegree() > 0); TEUCHOS_TEST_FOR_EXCEPTION(!spaceTime, std::invalid_argument, "multiple vertices for spatial point only supported for space-time"); spatialCellTopo = cellTopo->getTensorialComponent(); vertexOrdinalInSpatialCell = -1; for (unsigned spatialVertexOrdinal = 0; spatialVertexOrdinal < spatialCellTopo->getNodeCount(); spatialVertexOrdinal++) { vector<unsigned> tensorComponentNodes = {spatialVertexOrdinal,0}; unsigned spaceTimeVertexOrdinal_t0 = cellTopo->getNodeFromTensorialComponentNodes(tensorComponentNodes); if ((spaceTimeVertexOrdinal_t0 == vertexOrdinalsInCell[0]) || (spaceTimeVertexOrdinal_t0 == vertexOrdinalsInCell[1])) { // then this should be our match. Confirm this: tensorComponentNodes = {spatialVertexOrdinal,1}; unsigned spaceTimeVertexOrdinal_t1 = cellTopo->getNodeFromTensorialComponentNodes(tensorComponentNodes); bool t1VertexMatches = (spaceTimeVertexOrdinal_t1 == vertexOrdinalsInCell[0]) || (spaceTimeVertexOrdinal_t1 == vertexOrdinalsInCell[1]); TEUCHOS_TEST_FOR_EXCEPTION(!t1VertexMatches, std::invalid_argument, "Internal error: space-time vertices do not belong to the same spatial vertex"); vertexOrdinalInSpatialCell = spatialVertexOrdinal; break; } } TEUCHOS_TEST_FOR_EXCEPTION(vertexOrdinalInSpatialCell == -1, std::invalid_argument, "Internal error: spatial vertex ordinal not found"); } else if (vertexOrdinalsInCell.size() == 1) { spaceTime = false; spatialCellTopo = cellTopo; vertexOrdinalInSpatialCell = vertexOrdinalsInCell[0]; } else { TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "vertexOrdinalsInCell must have 1 or 2 vertices"); } set<GlobalIndexType> globalIndicesForVariable; DofOrderingPtr trialOrderingPtr = elemType->trialOrderPtr; int numSpatialSides = spatialCellTopo->getSideCount(); vector<unsigned> spatialSidesForVertex; vector<unsigned> sideVertexOrdinals; // same index in this container as spatialSidesForVertex: gets the node ordinal of the vertex in that side int sideDim = spatialCellTopo->getDimension() - 1; if (!_mesh->bilinearForm()->isFluxOrTrace(trialID)) { spatialSidesForVertex.push_back(VOLUME_INTERIOR_SIDE_ORDINAL); sideVertexOrdinals.push_back(vertexOrdinalInSpatialCell); } else { for (int spatialSideOrdinal=0; spatialSideOrdinal < numSpatialSides; spatialSideOrdinal++) { CellTopoPtr sideTopo = spatialCellTopo->getSide(spatialSideOrdinal); for (unsigned sideVertexOrdinal = 0; sideVertexOrdinal < sideTopo->getNodeCount(); sideVertexOrdinal++) { unsigned spatialVertexOrdinal = spatialCellTopo->getNodeMap(sideDim, spatialSideOrdinal, sideVertexOrdinal); if (spatialVertexOrdinal == vertexOrdinalInSpatialCell) { spatialSidesForVertex.push_back(spatialSideOrdinal); sideVertexOrdinals.push_back(sideVertexOrdinal); break; // this is the only match we should find on this side } } } if (spatialSidesForVertex.size() == 0) { cout << "ERROR: no spatial side for vertex found during singleton BC imposition.\n"; TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "no spatial side for vertex found during singleton BC imposition"); } } for (int i=0; i<spatialSidesForVertex.size(); i++) { unsigned spatialSideOrdinal = spatialSidesForVertex[i]; unsigned vertexOrdinalInSide = sideVertexOrdinals[i]; unsigned sideForImposition; BasisPtr spatialBasis, temporalBasis, spaceTimeBasis, basisForImposition; if (!spaceTime) { spatialBasis = trialOrderingPtr->getBasis(trialID,spatialSideOrdinal); sideForImposition = spatialSideOrdinal; } else { unsigned spaceTimeSideOrdinal; if (!_mesh->bilinearForm()->isFluxOrTrace(trialID)) { spaceTimeSideOrdinal = VOLUME_INTERIOR_SIDE_ORDINAL; } else { spaceTimeSideOrdinal = cellTopo->getSpatialSideOrdinal(spatialSideOrdinal); } spaceTimeBasis = trialOrderingPtr->getBasis(trialID,spaceTimeSideOrdinal); sideForImposition = spaceTimeSideOrdinal; TensorBasis<>* tensorBasis = dynamic_cast<TensorBasis<>*>(spaceTimeBasis.get()); TEUCHOS_TEST_FOR_EXCEPTION(!tensorBasis, std::invalid_argument, "space-time basis must be a subclass of TensorBasis"); if (tensorBasis) { spatialBasis = tensorBasis->getSpatialBasis(); temporalBasis = tensorBasis->getTemporalBasis(); } } bool constantSpatialBasis = false; // upgrade bases to continuous ones of the same cardinality, if they are discontinuous. if (spatialBasis->getDegree() == 0) { constantSpatialBasis = true; } else if ((spatialBasis->functionSpace() == Camellia::FUNCTION_SPACE_HVOL) || (spatialBasis->functionSpace() == Camellia::FUNCTION_SPACE_HVOL_DISC)) { spatialBasis = BasisFactory::basisFactory()->getBasis(spatialBasis->getDegree(), spatialBasis->domainTopology(), Camellia::FUNCTION_SPACE_HGRAD); } else if (Camellia::functionSpaceIsDiscontinuous(spatialBasis->functionSpace())) { Camellia::EFunctionSpace fsContinuous = Camellia::continuousSpaceForDiscontinuous((spatialBasis->functionSpace())); spatialBasis = BasisFactory::basisFactory()->getBasis(spatialBasis->getDegree(), spatialBasis->domainTopology(), fsContinuous, Camellia::FUNCTION_SPACE_HGRAD); } if (temporalBasis.get()) { if ((temporalBasis->functionSpace() == Camellia::FUNCTION_SPACE_HVOL) || (temporalBasis->functionSpace() == Camellia::FUNCTION_SPACE_HVOL_DISC)) { temporalBasis = BasisFactory::basisFactory()->getBasis(temporalBasis->getDegree(), temporalBasis->domainTopology(), Camellia::FUNCTION_SPACE_HGRAD); } else if (Camellia::functionSpaceIsDiscontinuous(temporalBasis->functionSpace())) { Camellia::EFunctionSpace fsContinuous = Camellia::continuousSpaceForDiscontinuous((temporalBasis->functionSpace())); temporalBasis = BasisFactory::basisFactory()->getBasis(temporalBasis->getDegree(), temporalBasis->domainTopology(), fsContinuous, Camellia::FUNCTION_SPACE_HGRAD); } } if (spaceTime) { if (constantSpatialBasis) { // then use the original basis for imposition basisForImposition = spaceTimeBasis; } else { vector<int> H1Orders = {spatialBasis->getDegree(),temporalBasis->getDegree()}; spaceTimeBasis = BasisFactory::basisFactory()->getBasis(H1Orders, spaceTimeBasis->domainTopology(), spatialBasis->functionSpace(), temporalBasis->functionSpace()); basisForImposition = spaceTimeBasis; } } else { basisForImposition = spatialBasis; } vector<int> spatialDofOrdinalsForVertex = constantSpatialBasis ? vector<int>{0} : spatialBasis->dofOrdinalsForVertex(vertexOrdinalInSide); if (spatialDofOrdinalsForVertex.size() != 1) { cout << "ERROR: spatialDofOrdinalsForVertex.size() != 1 during singleton BC imposition.\n"; TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "spatialDofOrdinalsForVertex.size() != 1 during singleton BC imposition"); } int spatialDofOrdinalForVertex = spatialDofOrdinalsForVertex[0]; vector<int> basisDofOrdinals; if (!spaceTime) { basisDofOrdinals.push_back(spatialDofOrdinalForVertex); } else { int temporalBasisCardinality = temporalBasis->getCardinality(); TensorBasis<>* tensorBasis = dynamic_cast<TensorBasis<>*>(spaceTimeBasis.get()); for (int temporalBasisOrdinal=0; temporalBasisOrdinal<temporalBasisCardinality; temporalBasisOrdinal++) { basisDofOrdinals.push_back(tensorBasis->getDofOrdinalFromComponentDofOrdinals({spatialDofOrdinalForVertex, temporalBasisOrdinal})); } } for (int dofOrdinal : basisDofOrdinals) { FieldContainer<double> basisCoefficients(basisForImposition->getCardinality()); basisCoefficients[dofOrdinal] = 1.0; FieldContainer<double> globalCoefficients; FieldContainer<GlobalIndexType> globalDofIndices; dofInterpreter->interpretLocalBasisCoefficients(cellID, trialID, sideForImposition, basisCoefficients, globalCoefficients, globalDofIndices); double tol = 1e-14; int nonzeroEntryOrdinal = -1; for (int fieldOrdinal=0; fieldOrdinal < globalCoefficients.size(); fieldOrdinal++) { if (abs(globalCoefficients[fieldOrdinal]) > tol) { if (nonzeroEntryOrdinal != -1) { // previous nonzero entry found; this is a problem--it means we have multiple global coefficients that depend on this vertex // (could happen if user specified a hanging node) cout << "Error: vertex for single-point imposition has multiple global degrees of freedom.\n"; TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Error: vertex for single-point imposition has multiple global degrees of freedom."); } // nonzero entry: store the fact, and impose the constraint nonzeroEntryOrdinal = fieldOrdinal; bool isRankLocal = dofInterpreter->isLocallyOwnedGlobalDofIndex(globalDofIndices[fieldOrdinal]); if (isRankLocal) { dofIndexToValue[globalDofIndices[fieldOrdinal]] = bc.valueForSinglePointBC(trialID) * globalCoefficients[fieldOrdinal]; } else { cout << "ERROR: global dof index for single-point BC is not locally owned.\n"; TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "ERROR: global dof index for single-point BC is not locally owned"); } } } } } } } }