Exemplo n.º 1
0
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
    }
  }
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
0
void Boundary::bcsToImpose(FieldContainer<GlobalIndexType> &globalIndices,
                           FieldContainer<Scalar> &globalValues, TBC<Scalar> &bc,
                           DofInterpreter* dofInterpreter)
{
  set< GlobalIndexType > rankLocalCells = _mesh->cellIDsInPartition();
  map< GlobalIndexType, double> bcGlobalIndicesAndValues;

  for (GlobalIndexType cellID : rankLocalCells)
  {
    bcsToImpose(bcGlobalIndicesAndValues, bc, cellID, dofInterpreter);
  }
  singletonBCsToImpose(bcGlobalIndicesAndValues, bc, dofInterpreter);
  
  // ****** New, tag-based BC imposition follows ******
  map< GlobalIndexType, double> bcTagGlobalIndicesAndValues;
  
  map< int, vector<pair<VarPtr, TFunctionPtr<Scalar>>>> tagBCs = bc.getDirichletTagBCs(); // keys are tags
  
  MeshTopology* meshTopo = dynamic_cast<MeshTopology*>(_mesh->getTopology().get());
  
  TEUCHOS_TEST_FOR_EXCEPTION(!meshTopo, std::invalid_argument, "pure MeshTopologyViews are not yet supported by new tag-based BC imposition");
  
  for (auto tagBC : tagBCs)
  {
    int tagID = tagBC.first;
    
    vector<EntitySetPtr> entitySets = meshTopo->getEntitySetsForTagID(DIRICHLET_SET_TAG_NAME, tagID);
    for (EntitySetPtr entitySet : entitySets)
    {
      // get rank-local cells that match the entity set:
      set<IndexType> matchingCellIDs = entitySet->cellIDsThatMatch(_mesh->getTopology(), rankLocalCells);
      for (IndexType cellID : matchingCellIDs)
      {
        ElementTypePtr elemType = _mesh->getElementType(cellID);
        BasisCachePtr basisCache = BasisCache::basisCacheForCell(_mesh, cellID);
        
        for (auto varFunctionPair : tagBC.second)
        {
          VarPtr var = varFunctionPair.first;
          FunctionPtr f = varFunctionPair.second;
          
          vector<int> sideOrdinals = elemType->trialOrderPtr->getSidesForVarID(var->ID());
          
          for (int sideOrdinal : sideOrdinals)
          {
            BasisPtr basis = elemType->trialOrderPtr->getBasis(var->ID(), sideOrdinal);
            bool isVolume = basis->domainTopology()->getDimension() == _mesh->getDimension();
            for (int d=0; d<_mesh->getDimension(); d++)
            {
              vector<unsigned> matchingSubcells;
              if (isVolume)
                matchingSubcells = entitySet->subcellOrdinals(_mesh->getTopology(), cellID, d);
              else
              {
                CellTopoPtr cellTopo = elemType->cellTopoPtr;
                int sideDim = cellTopo->getDimension() - 1;
                vector<unsigned> matchingSubcellsOnSide = entitySet->subcellOrdinalsOnSide(_mesh->getTopology(), cellID, sideOrdinal, d);
                for (unsigned sideSubcellOrdinal : matchingSubcellsOnSide)
                {
                  unsigned cellSubcellOrdinal = CamelliaCellTools::subcellOrdinalMap(cellTopo, sideDim, sideOrdinal, d, sideSubcellOrdinal);
                  matchingSubcells.push_back(cellSubcellOrdinal);
                }
              }
              
              if (matchingSubcells.size() == 0) continue; // nothing to impose
              
              /*
               What follows - projecting the function onto the basis on the whole domain - is more expensive than necessary,
               in the general case: we can do the projection on just the matching subcells, and if we had a way of taking the
               restriction of a basis to a subcell of the domain, then we could avoid computing the whole basis as well.
               
               But for now, this should work, and it's simple to implement.
               */
              BasisCachePtr basisCacheForImposition = isVolume ? basisCache : basisCache->getSideBasisCache(sideOrdinal);
              int numCells = 1;
              FieldContainer<double> basisCoefficients(numCells,basis->getCardinality());
              Projector<double>::projectFunctionOntoBasisInterpolating(basisCoefficients, f, basis, basisCacheForImposition);
              basisCoefficients.resize(basis->getCardinality());
              
              set<GlobalIndexType> matchingGlobalIndices;
              for (unsigned matchingSubcell : matchingSubcells)
              {
                set<GlobalIndexType> subcellGlobalIndices = dofInterpreter->globalDofIndicesForVarOnSubcell(var->ID(),cellID,d,matchingSubcell);
                matchingGlobalIndices.insert(subcellGlobalIndices.begin(),subcellGlobalIndices.end());
              }
              
              FieldContainer<double> globalData;
              FieldContainer<GlobalIndexType> globalDofIndices;
//              dofInterpreter->interpretLocalBasisCoefficients(cellID, var->ID(), sideOrdinal, basisCoefficientsToImpose, globalData, globalDofIndices);
              dofInterpreter->interpretLocalBasisCoefficients(cellID, var->ID(), sideOrdinal, basisCoefficients, globalData, globalDofIndices);
              for (int globalDofOrdinal=0; globalDofOrdinal<globalDofIndices.size(); globalDofOrdinal++)
              {
                GlobalIndexType globalDofIndex = globalDofIndices(globalDofOrdinal);
                if (matchingGlobalIndices.find(globalDofIndex) != matchingGlobalIndices.end())
                  bcTagGlobalIndicesAndValues[globalDofIndex] = globalData(globalDofOrdinal);
              }
            }
          }
        }
      }
    }
  }
  
  // merge tag-based and legacy BC maps
  double tol = 1e-15;
  for (auto tagEntry : bcTagGlobalIndicesAndValues)
  {
    if (bcGlobalIndicesAndValues.find(tagEntry.first) != bcGlobalIndicesAndValues.end())
    {
      // then check that they match, within tolerance
      double diff = abs(bcGlobalIndicesAndValues[tagEntry.first] - tagEntry.second);
      TEUCHOS_TEST_FOR_EXCEPTION(diff > tol, std::invalid_argument, "Incompatible BC entries encountered");
    }
    else
    {
      bcGlobalIndicesAndValues[tagEntry.first] = tagEntry.second;
    }
  }
  
  globalIndices.resize(bcGlobalIndicesAndValues.size());
  globalValues.resize(bcGlobalIndicesAndValues.size());
  globalIndices.initialize(0);
  globalValues.initialize(0.0);
  int entryOrdinal = 0;
  for (auto bcEntry : bcGlobalIndicesAndValues)
  {
    globalIndices[entryOrdinal] = bcEntry.first;
    globalValues[entryOrdinal] = bcEntry.second;
    entryOrdinal++;
  }
}
Exemplo n.º 4
0
void Boundary::bcsToImpose( map<  GlobalIndexType, Scalar > &globalDofIndicesAndValues, TBC<Scalar> &bc,
                            GlobalIndexType cellID, DofInterpreter* dofInterpreter)
{
  // this is where we actually compute the BCs; the other bcsToImpose variants call this one.
  CellPtr cell = _mesh->getTopology()->getCell(cellID);

  // define a couple of important inner products:
  TIPPtr<Scalar> ipL2 = Teuchos::rcp( new TIP<Scalar> );
  TIPPtr<Scalar> ipH1 = Teuchos::rcp( new TIP<Scalar> );
  VarFactoryPtr varFactory = VarFactory::varFactory();
  VarPtr trace = varFactory->traceVar("trace");
  VarPtr flux = varFactory->traceVar("flux");
  ipL2->addTerm(flux);
  ipH1->addTerm(trace);
  ipH1->addTerm(trace->grad());
  ElementTypePtr elemType = _mesh->getElementType(cellID);
  DofOrderingPtr trialOrderingPtr = elemType->trialOrderPtr;
  vector< int > trialIDs = _mesh->bilinearForm()->trialIDs();

  vector<unsigned> boundarySides = cell->boundarySides();
  if (boundarySides.size() > 0)
  {
    BasisCachePtr basisCache = BasisCache::basisCacheForCell(_mesh, cellID);
    for (vector< int >::iterator trialIt = trialIDs.begin(); trialIt != trialIDs.end(); trialIt++)
    {
      int trialID = *(trialIt);
      if ( bc.bcsImposed(trialID) )
      {
//        // DEBUGGING: keep track of which sides we impose BCs on:
//        set<unsigned> bcImposedSides;
//
        // Determine global dof indices and values, in one pass per side
        for (int i=0; i<boundarySides.size(); i++)
        {
          unsigned sideOrdinal = boundarySides[i];
          // TODO: here, we need to treat the volume basis case.
          /*
           To do this:
           1. (Determine which dofs in the basis have support on the side.)
           2. (Probably should resize dirichletValues to match number of dofs with support on the side.)
           3. (Within coefficientsForBC, and the projection method it calls, when it's a side cache, check whether the basis being projected has a higher dimension.  If so, do the same determination regarding the support of basis on the side as #1.)
           4. DofInterpreter::interpretLocalBasisCoefficients() needs to handle the case that trialID has volume support, and in this case interpret the provided data appropriately.
           */
          
          BasisPtr basis;
          int numDofsSide;
          if (trialOrderingPtr->getSidesForVarID(trialID).size() == 1)
          {
            // volume basis
            basis = trialOrderingPtr->getBasis(trialID);
            // get the dof ordinals for the side (interpreted as a "continuous" basis)
            numDofsSide = basis->dofOrdinalsForSide(sideOrdinal).size();
          }
          else if (! trialOrderingPtr->hasBasisEntry(trialID, sideOrdinal))
          {
            continue;
          }
          else
          {
            basis = trialOrderingPtr->getBasis(trialID,sideOrdinal);
            numDofsSide = basis->getCardinality();
          }
          
          GlobalIndexType numCells = 1;
          if (numCells > 0)
          {
            FieldContainer<double> dirichletValues(numCells,numDofsSide);
            // project bc function onto side basis:
            BCPtr bcPtr = Teuchos::rcp(&bc, false);
            Teuchos::RCP<BCFunction<double>> bcFunction = BCFunction<double>::bcFunction(bcPtr, trialID);
            bcPtr->coefficientsForBC(dirichletValues, bcFunction, basis, basisCache->getSideBasisCache(sideOrdinal));
            dirichletValues.resize(numDofsSide);
            if (bcFunction->imposeOnCell(0))
            {
              FieldContainer<double> globalData;
              FieldContainer<GlobalIndexType> globalDofIndices;

              dofInterpreter->interpretLocalBasisCoefficients(cellID, trialID, sideOrdinal, dirichletValues, globalData, globalDofIndices);
              for (int globalDofOrdinal=0; globalDofOrdinal<globalDofIndices.size(); globalDofOrdinal++)
              {
                GlobalIndexType globalDofIndex = globalDofIndices(globalDofOrdinal);
                Scalar value = globalData(globalDofOrdinal);
                
                // sanity check: if this has been previously set, do the two values roughly agree?
                if (globalDofIndicesAndValues.find(globalDofIndex) != globalDofIndicesAndValues.end())
                {
                  double tol = 1e-10;
                  Scalar prevValue = globalDofIndicesAndValues[globalDofIndex];
                  double absDiff = abs(prevValue - value);
                  if (absDiff > tol)
                  {
                    double relativeDiff = absDiff / max(abs(prevValue),abs(value));
                    int rank = _mesh->Comm()->MyPID();
                    if (relativeDiff > tol)
                    {
                      cout << "WARNING: in Boundary::bcsToImpose(), inconsistent values for BC: " << prevValue << " and ";
                      cout << value << " prescribed for global dof index " << globalDofIndex;
                      cout << " on rank " << rank << endl;
                    }
                  }
                }
                globalDofIndicesAndValues[globalDofIndex] = value;
              }
            }
          }
        }
      }
    }
  }
}
Exemplo n.º 5
0
bool MeshTestUtility::neighborBasesAgreeOnSides(Teuchos::RCP<Mesh> mesh, Epetra_MultiVector &globalSolutionCoefficients)
{
  bool success = true;
  MeshTopologyViewPtr meshTopo = mesh->getTopology();
  int spaceDim = meshTopo->getDimension();

  set<IndexType> activeCellIndices = meshTopo->getActiveCellIndices();
  for (set<IndexType>::iterator cellIt=activeCellIndices.begin(); cellIt != activeCellIndices.end(); cellIt++)
  {
    IndexType cellIndex = *cellIt;
    CellPtr cell = meshTopo->getCell(cellIndex);

    BasisCachePtr fineCellBasisCache = BasisCache::basisCacheForCell(mesh, cellIndex);
    ElementTypePtr fineElemType = mesh->getElementType(cellIndex);
    DofOrderingPtr fineElemTrialOrder = fineElemType->trialOrderPtr;

    FieldContainer<double> fineSolutionCoefficients(fineElemTrialOrder->totalDofs());
    mesh->globalDofAssignment()->interpretGlobalCoefficients(cellIndex, fineSolutionCoefficients, globalSolutionCoefficients);
//    if ((cellIndex==0) || (cellIndex==2)) {
//      cout << "MeshTestUtility: local coefficients for cell " << cellIndex << ":\n" << fineSolutionCoefficients;
//    }

    unsigned sideCount = cell->getSideCount();
    for (unsigned sideOrdinal=0; sideOrdinal<sideCount; sideOrdinal++)
    {
      FieldContainer<double> fineSideRefPoints, fineCellRefPoints, coarseSideRefPoints, coarseCellRefPoints;
      bool hasCoarserNeighbor = determineRefTestPointsForNeighbors(meshTopo, cell, sideOrdinal, fineSideRefPoints, fineCellRefPoints, coarseSideRefPoints, coarseCellRefPoints);
      if (!hasCoarserNeighbor) continue;

      pair<GlobalIndexType, unsigned> neighborInfo = cell->getNeighborInfo(sideOrdinal, meshTopo);

      CellPtr neighborCell = meshTopo->getCell(neighborInfo.first);

      unsigned numTestPoints = coarseCellRefPoints.dimension(0);

      //        cout << "testing neighbor agreement between cell " << cellIndex << " and " << neighborCell->cellIndex() << endl;

      // if we get here, the cell has a neighbor on this side, and is at least as fine as that neighbor.

      BasisCachePtr fineSideBasisCache = fineCellBasisCache->getSideBasisCache(sideOrdinal);

      fineCellBasisCache->setRefCellPoints(fineCellRefPoints);

      BasisCachePtr coarseCellBasisCache = BasisCache::basisCacheForCell(mesh, neighborInfo.first);
      BasisCachePtr coarseSideBasisCache = coarseCellBasisCache->getSideBasisCache(neighborInfo.second);

      coarseCellBasisCache->setRefCellPoints(coarseCellRefPoints);

      bool hasSidePoints = (fineSideRefPoints.size() > 0);
      if (hasSidePoints)
      {
        fineSideBasisCache->setRefCellPoints(fineSideRefPoints);
        coarseSideBasisCache->setRefCellPoints(coarseSideRefPoints);
      }

      // sanity check: do physical points match?

      FieldContainer<double> fineCellPhysicalCubaturePoints = fineCellBasisCache->getPhysicalCubaturePoints();
      FieldContainer<double> coarseCellPhysicalCubaturePoints = coarseCellBasisCache->getPhysicalCubaturePoints();

      double tol = 1e-14;
      double maxDiff = 0;
      if (! fcsAgree(coarseCellPhysicalCubaturePoints, fineCellPhysicalCubaturePoints, tol, maxDiff) )
      {
        cout << "ERROR: MeshTestUtility::neighborBasesAgreeOnSides internal error: fine and coarse cell cubature points do not agree.\n";
        success = false;
        continue;
      }

      if (hasSidePoints)
      {
        FieldContainer<double> fineSidePhysicalCubaturePoints = fineSideBasisCache->getPhysicalCubaturePoints();
        FieldContainer<double> coarseSidePhysicalCubaturePoints = coarseSideBasisCache->getPhysicalCubaturePoints();

        double tol = 1e-14;
        double maxDiff = 0;
        if (! fcsAgree(fineSidePhysicalCubaturePoints, fineCellPhysicalCubaturePoints, tol, maxDiff) )
        {
          cout << "ERROR: MeshTestUtility::neighborBasesAgreeOnSides internal error: fine side and cell cubature points do not agree.\n";
          success = false;
          continue;
        }
        if (! fcsAgree(coarseSidePhysicalCubaturePoints, coarseCellPhysicalCubaturePoints, tol, maxDiff) )
        {
          cout << "ERROR: MeshTestUtility::neighborBasesAgreeOnSides internal error: coarse side and cell cubature points do not agree.\n";
          success = false;
          continue;
        }
        if (! fcsAgree(coarseSidePhysicalCubaturePoints, fineSidePhysicalCubaturePoints, tol, maxDiff) )
        {
          cout << "ERROR: MeshTestUtility::neighborBasesAgreeOnSides internal error: fine and coarse side cubature points do not agree.\n";
          success = false;
          continue;
        }
      }

      ElementTypePtr coarseElementType = mesh->getElementType(neighborInfo.first);
      DofOrderingPtr coarseElemTrialOrder = coarseElementType->trialOrderPtr;

      FieldContainer<double> coarseSolutionCoefficients(coarseElemTrialOrder->totalDofs());
      mesh->globalDofAssignment()->interpretGlobalCoefficients(neighborInfo.first, coarseSolutionCoefficients, globalSolutionCoefficients);

      set<int> varIDs = fineElemTrialOrder->getVarIDs();
      for (set<int>::iterator varIt = varIDs.begin(); varIt != varIDs.end(); varIt++)
      {
        int varID = *varIt;
//        cout << "MeshTestUtility: varID " << varID << ":\n";
        bool isTraceVar = mesh->bilinearForm()->isFluxOrTrace(varID);
        BasisPtr fineBasis, coarseBasis;
        BasisCachePtr fineCache, coarseCache;
        if (isTraceVar)
        {
          if (! hasSidePoints) continue; // then nothing to do for traces
          fineBasis = fineElemTrialOrder->getBasis(varID, sideOrdinal);
          coarseBasis = coarseElemTrialOrder->getBasis(varID, neighborInfo.second);
          fineCache = fineSideBasisCache;
          coarseCache = coarseSideBasisCache;
        }
        else
        {
          fineBasis = fineElemTrialOrder->getBasis(varID);
          coarseBasis = coarseElemTrialOrder->getBasis(varID);
          fineCache = fineCellBasisCache;
          coarseCache = coarseCellBasisCache;

          Camellia::EFunctionSpace fs = fineBasis->functionSpace();
          if ((fs == Camellia::FUNCTION_SPACE_HVOL)
              || (fs == Camellia::FUNCTION_SPACE_VECTOR_HVOL)
              || (fs == Camellia::FUNCTION_SPACE_TENSOR_HVOL))
          {
            // volume L^2 basis: no continuities expected...
            continue;
          }
        }
        FieldContainer<double> localValuesFine = *fineCache->getTransformedValues(fineBasis, OP_VALUE);
        FieldContainer<double> localValuesCoarse = *coarseCache->getTransformedValues(coarseBasis, OP_VALUE);

        bool scalarValued = (localValuesFine.rank() == 3);

        // the following used if vector or tensor-valued:
        Teuchos::Array<int> valueDim;
        unsigned componentsPerValue = 1;
        FieldContainer<double> valueContainer; // just used for enumeration computation...
        if (!scalarValued)
        {
          localValuesFine.dimensions(valueDim);
          // clear first three:
          valueDim.erase(valueDim.begin());
          valueDim.erase(valueDim.begin());
          valueDim.erase(valueDim.begin());
          valueContainer.resize(valueDim);
          componentsPerValue = valueContainer.size();
        }

        //          if (localValuesFine.rank() != 3) {
        //            cout << "WARNING: MeshTestUtility::neighborBasesAgreeOnSides() only supports scalar-valued bases right now.  Skipping check for varID " << varID << endl;
        //            continue;
        //          }

        FieldContainer<double> localPointValuesFine(fineElemTrialOrder->totalDofs());
        FieldContainer<double> localPointValuesCoarse(coarseElemTrialOrder->totalDofs());

        for (int valueComponentOrdinal=0; valueComponentOrdinal<componentsPerValue; valueComponentOrdinal++)
        {
          Teuchos::Array<int> valueMultiIndex(valueContainer.rank());

          if (!scalarValued)
            valueContainer.getMultiIndex(valueMultiIndex, valueComponentOrdinal);

          Teuchos::Array<int> localValuesMultiIndex(localValuesFine.rank());

          for (int r=0; r<valueMultiIndex.size(); r++)
          {
            localValuesMultiIndex[r+3] = valueMultiIndex[r];
          }

          for (int ptOrdinal=0; ptOrdinal<numTestPoints; ptOrdinal++)
          {
            localPointValuesCoarse.initialize(0);
            localPointValuesFine.initialize(0);
            localValuesMultiIndex[2] = ptOrdinal;

            double fineSolutionValue = 0, coarseSolutionValue = 0;

            for (int basisOrdinal=0; basisOrdinal < fineBasis->getCardinality(); basisOrdinal++)
            {
              int fineDofIndex;
              if (isTraceVar)
                fineDofIndex = fineElemTrialOrder->getDofIndex(varID, basisOrdinal, sideOrdinal);
              else
                fineDofIndex = fineElemTrialOrder->getDofIndex(varID, basisOrdinal);
              if (scalarValued)
              {
                localPointValuesFine(fineDofIndex) = localValuesFine(0,basisOrdinal,ptOrdinal);
              }
              else
              {
                localValuesMultiIndex[1] = basisOrdinal;
                localPointValuesFine(fineDofIndex) = localValuesFine.getValue(localValuesMultiIndex);
              }

              fineSolutionValue += fineSolutionCoefficients(fineDofIndex) * localPointValuesFine(fineDofIndex);
            }
            for (int basisOrdinal=0; basisOrdinal < coarseBasis->getCardinality(); basisOrdinal++)
            {
              int coarseDofIndex;
              if (isTraceVar)
                coarseDofIndex = coarseElemTrialOrder->getDofIndex(varID, basisOrdinal, neighborInfo.second);
              else
                coarseDofIndex = coarseElemTrialOrder->getDofIndex(varID, basisOrdinal);
              if (scalarValued)
              {
                localPointValuesCoarse(coarseDofIndex) = localValuesCoarse(0,basisOrdinal,ptOrdinal);
              }
              else
              {
                localValuesMultiIndex[1] = basisOrdinal;
                localPointValuesCoarse(coarseDofIndex) = localValuesCoarse.getValue(localValuesMultiIndex);
              }
              coarseSolutionValue += coarseSolutionCoefficients(coarseDofIndex) * localPointValuesCoarse(coarseDofIndex);
            }

            if (abs(coarseSolutionValue - fineSolutionValue) > 1e-13)
            {
              success = false;
              cout << "coarseSolutionValue (" << coarseSolutionValue << ") and fineSolutionValue (" << fineSolutionValue << ") differ by " << abs(coarseSolutionValue - fineSolutionValue);
              cout << " at point " << ptOrdinal << " for varID " << varID << ".  ";
              cout << "This may be an indication that something is amiss with the global-to-local map.\n";
            }
            else
            {
//              // DEBUGGING:
//              cout << "solution value at point (";
//              for (int d=0; d<spaceDim-1; d++) {
//                cout << fineSidePhysicalCubaturePoints(0,ptOrdinal,d) << ", ";
//              }
//              cout << fineSidePhysicalCubaturePoints(0,ptOrdinal,spaceDim-1) << "): ";
//              cout << coarseSolutionValue << endl;
            }

            FieldContainer<double> globalValuesFromFine, globalValuesFromCoarse;
            FieldContainer<GlobalIndexType> globalDofIndicesFromFine, globalDofIndicesFromCoarse;

            mesh->globalDofAssignment()->interpretLocalData(cellIndex, localPointValuesFine, globalValuesFromFine, globalDofIndicesFromFine);
            mesh->globalDofAssignment()->interpretLocalData(neighborInfo.first, localPointValuesCoarse, globalValuesFromCoarse, globalDofIndicesFromCoarse);

            std::map<GlobalIndexType, double> fineValuesMap;
            std::map<GlobalIndexType, double> coarseValuesMap;

            for (int i=0; i<globalDofIndicesFromCoarse.size(); i++)
            {
              GlobalIndexType globalDofIndex = globalDofIndicesFromCoarse[i];
              coarseValuesMap[globalDofIndex] = globalValuesFromCoarse[i];
            }

            double maxDiff = 0;
            for (int i=0; i<globalDofIndicesFromFine.size(); i++)
            {
              GlobalIndexType globalDofIndex = globalDofIndicesFromFine[i];
              fineValuesMap[globalDofIndex] = globalValuesFromFine[i];

              double diff = abs( fineValuesMap[globalDofIndex] - coarseValuesMap[globalDofIndex]);
              maxDiff = std::max(diff, maxDiff);
              if (diff > tol)
              {
                success = false;
                cout << "interpreted fine and coarse disagree at point (";
                for (int d=0; d<spaceDim; d++)
                {
                  cout << fineCellPhysicalCubaturePoints(0,ptOrdinal,d);
                  if (d==spaceDim-1)
                    cout <<  ").\n";
                  else
                    cout << ", ";
                }
              }
            }
            if (maxDiff > tol)
            {
              cout << "maxDiff: " << maxDiff << endl;
              cout << "globalValuesFromFine:\n" << globalValuesFromFine;
              cout << "globalValuesFromCoarse:\n" << globalValuesFromCoarse;

              cout << "globalDofIndicesFromFine:\n" << globalDofIndicesFromFine;
              cout <<  "globalDofIndicesFromCoarse:\n" << globalDofIndicesFromCoarse;

              continue; // only worth testing further if we passed the above
            }
          }
        }
      }
    }
  }

//  cout << "Completed neighborBasesAgreeOnSides.\n";
  return success;
}
Exemplo n.º 6
0
void ExactSolution::L2NormOfError(FieldContainer<double> &errorSquaredPerCell, Solution &solution, ElementTypePtr elemTypePtr, int trialID, int sideIndex, int cubDegree, double solutionLift) {
//  BasisCache(ElementTypePtr elemType, Teuchos::RCP<Mesh> mesh = Teuchos::rcp( (Mesh*) NULL ), bool testVsTest=false, int cubatureDegreeEnrichment = 0)

  DofOrdering dofOrdering = *(elemTypePtr->trialOrderPtr.get());
  BasisPtr basis = dofOrdering.getBasis(trialID,sideIndex);
  
  bool boundaryIntegral = solution.mesh()->bilinearForm()->isFluxOrTrace(trialID);
  
  BasisCachePtr basisCache;
  if (cubDegree <= 0) { // then take the default cub. degree
    basisCache = Teuchos::rcp( new BasisCache( elemTypePtr, solution.mesh() ) );
  } else {
    // we could eliminate the logic below if we just added BasisCache::setCubatureDegree()...
    // (the logic below is just to make the enriched cubature match the requested cubature degree...)
    int maxTrialDegree;
    if (!boundaryIntegral) {
      maxTrialDegree = elemTypePtr->trialOrderPtr->maxBasisDegreeForVolume();
    } else {
      maxTrialDegree = elemTypePtr->trialOrderPtr->maxBasisDegree(); // generally, this will be the trace degree
    }
    int maxTestDegree = elemTypePtr->testOrderPtr->maxBasisDegree();
    int cubDegreeEnrichment = max(cubDegree - (maxTrialDegree + maxTestDegree), 0);
    basisCache = Teuchos::rcp( new BasisCache( elemTypePtr, solution.mesh(), false, cubDegreeEnrichment) );
  }
  
  // much of this code is the same as what's in the volume integration in computeStiffness...
  FieldContainer<double> physicalCellNodes = solution.mesh()->physicalCellNodes(elemTypePtr);
  vector<GlobalIndexType> cellIDs = solution.mesh()->cellIDsOfType(elemTypePtr);
  basisCache->setPhysicalCellNodes(physicalCellNodes, cellIDs, true);
  
  if (boundaryIntegral) {
    basisCache = basisCache->getSideBasisCache(sideIndex);
  }
  
  FieldContainer<double> weightedMeasure = basisCache->getWeightedMeasures();
  FieldContainer<double> weightedErrorSquared;
  
  int numCells = basisCache->getPhysicalCubaturePoints().dimension(0);
  int numCubPoints = basisCache->getPhysicalCubaturePoints().dimension(1);
  int spaceDim = basisCache->getPhysicalCubaturePoints().dimension(2);
  
  Teuchos::Array<int> dimensions;
  dimensions.push_back(numCells);
  dimensions.push_back(numCubPoints);
  
  int basisRank = BasisFactory::basisFactory()->getBasisRank(basis);
  if (basisRank==1) {
    dimensions.push_back(spaceDim);
  }
  
  FieldContainer<double> computedValues(dimensions);
  FieldContainer<double> exactValues(dimensions);
  
  if (solutionLift != 0.0) {
    int size = computedValues.size();
    for (int i=0; i<size; i++) {
      computedValues[i] += solutionLift;
    }
  }
  
  solution.solutionValues(computedValues, trialID, basisCache);
  this->solutionValues(exactValues, trialID, basisCache);
  
//  cout << "ExactSolution: exact values:\n" << exactValues;
//  cout << "ExactSolution: computed values:\n" << computedValues;
  
  FieldContainer<double> errorSquared(numCells,numCubPoints);
  
  squaredDifference(errorSquared,computedValues,exactValues);
  
  weightedErrorSquared.resize(numCells,numCubPoints);
  for (int cellIndex=0; cellIndex<numCells; cellIndex++) {
    for (int ptIndex=0; ptIndex<numCubPoints; ptIndex++) {
      // following two lines for viewing in the debugger:
      double weight = weightedMeasure(cellIndex,ptIndex);
      double errorSquaredVal = errorSquared(cellIndex,ptIndex);
      weightedErrorSquared(cellIndex,ptIndex) = errorSquared(cellIndex,ptIndex) * weightedMeasure(cellIndex,ptIndex);
    }
  }
  
  // compute the integral
  errorSquaredPerCell.initialize(0.0);
  int numPoints = weightedErrorSquared.dimension(1);
  for (int cellIndex=0; cellIndex<numCells; cellIndex++) {
    for (int ptIndex=0; ptIndex<numPoints; ptIndex++) {
      errorSquaredPerCell(cellIndex) += weightedErrorSquared(cellIndex,ptIndex);
    }
  }
}