Exemplo n.º 1
0
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");
              }
            }
          }
        }
      }
    }
  }
}