Exemplo n.º 1
0
void
MappedLevelFluxRegister::incrementFine(const FArrayBox& a_fineFlux,
                                 Real a_scale,
                                 const DataIndex& a_fineDataIndex,
                                 const Interval& a_srcInterval,
                                 const Interval& a_dstInterval,
                                 int a_dir,
                                 Side::LoHiSide a_sd)
{
    CH_assert(isDefined());
    if (!(m_isDefined & FluxRegFineDefined)) return;
    CH_assert(a_srcInterval.size() == a_dstInterval.size());

    CH_TIME("MappedLevelFluxRegister::incrementFine");

    // We cast away the constness in a_coarseFlux for the scope of this function. This
    // should be acceptable, since at the end of the day there is no change to it. -JNJ
    FArrayBox& fineFlux = const_cast<FArrayBox&>(a_fineFlux); // Muhahaha.
    fineFlux.shiftHalf(a_dir, sign(a_sd));
    Real denom = 1.0;

    if (m_scaleFineFluxes) {
        denom = m_nRefine.product() / m_nRefine[a_dir];
    }

    Real scale = sign(a_sd) * a_scale / denom;

    FArrayBox& cFine = m_fineFlux[a_fineDataIndex];
    //  FArrayBox  cFineFortran(cFine.box(), cFine.nComp());
    //  cFineFortran.copy(cFine);

    Box clipBox = m_fineFlux.box(a_fineDataIndex);
    clipBox.refine(m_nRefine);
    Box fineBox;
    if (a_sd == Side::Lo) {
        fineBox = adjCellLo(clipBox, a_dir, 1);
        fineBox &= fineFlux.box();
    } else {
        fineBox = adjCellHi(clipBox, a_dir, 1);
        fineBox &= fineFlux.box();
    }
#if 0
    for (BoxIterator b(fineBox); b.ok(); ++b) {
        int s = a_srcInterval.begin();
        int d = a_dstInterval.begin();
        for (; s <= a_srcInterval.end(); ++s, ++d) {
            cFine(coarsen(b(), m_nRefine), d) += scale * fineFlux(b(), s);
        }
    }
#else
    // shifting to ensure fineBox is in the positive quadrant, so IntVect coarening
    // is just integer division.

    const Box& box = coarsen(fineBox, m_nRefine);
    Vector<Real> regbefore(cFine.nComp());
    Vector<Real>  regafter(cFine.nComp());
    if (s_verbose && (a_dir == debugdir) && box.contains(ivdebnoeb)) {
        for (int ivar = 0; ivar < cFine.nComp(); ivar++) {
            regbefore[ivar] = cFine(ivdebnoeb, ivar);
        }
    }


    const IntVect& iv = fineBox.smallEnd();
    IntVect civ = coarsen(iv, m_nRefine);
    int srcComp = a_srcInterval.begin();
    int destComp = a_dstInterval.begin();
    int ncomp = a_srcInterval.size();
    FORT_MAPPEDINCREMENTFINE(CHF_CONST_FRA_SHIFT(fineFlux, iv),
                             CHF_FRA_SHIFT(cFine, civ),
                             CHF_BOX_SHIFT(fineBox, iv),
                             CHF_CONST_INTVECT(m_nRefine),
                             CHF_CONST_REAL(scale),
                             CHF_CONST_INT(srcComp),
                             CHF_CONST_INT(destComp),
                             CHF_CONST_INT(ncomp));


    if (s_verbose && (a_dir == debugdir) && box.contains(ivdebnoeb)) {
        for (int ivar = 0; ivar < cFine.nComp(); ivar++) {
            regafter[ivar] = cFine(ivdebnoeb, ivar);
        }
    }

    if (s_verbose && (a_dir == debugdir) && box.contains(ivdebnoeb)) {

        pout() << "levelfluxreg::incrementFine: scale = " << scale << endl;
        Box refbox(ivdebnoeb, ivdebnoeb);
        refbox.refine(m_nRefine);
        refbox &= fineBox;
        if (!refbox.isEmpty()) {
            pout() << "fine fluxes = " << endl;
            for (BoxIterator  bit(refbox); bit.ok(); ++bit) {
                for (int ivar = 0; ivar < cFine.nComp(); ivar++) {
                    pout() << "iv = " << bit() << "(";
                    for (int ivar = 0; ivar < cFine.nComp(); ivar++) {
                        pout() << fineFlux(bit(), ivar);
                    }
                    pout() << ")" << endl;
                }
            }
        }

        for (int ivar = 0; ivar < cFine.nComp(); ivar++) {
            pout() << " reg before = " <<               regbefore[ivar] << ", ";
            pout() << " reg after  = " <<                regafter[ivar] << ", ";
        }
        pout() << endl;

    }


    //fineBox.shift(-shift);
    // now, check that cFineFortran and cFine are the same
    //fineBox.coarsen(m_nRefine);
    //    for (BoxIterator b(fineBox); b.ok(); ++b)
    //      {
    //        if (cFineFortran(b(),0) != cFine(b(),0))
    //          {
    //            MayDay::Error("Fortran doesn't match C++");
    //          }
    //      }
    // need to shift boxes back to where they were on entry.

    //  cFine.shift(-shift/m_nRefine);
#endif
    fineFlux.shiftHalf(a_dir, - sign(a_sd));
}
Exemplo n.º 2
0
EBCellFAB&
EBCellFAB::axby(const EBCellFAB& a_X, const EBCellFAB& a_Y,
                const Real& a_A, const Real& a_B)
{
  CH_assert(isDefined());
  CH_assert(a_X.isDefined());
  CH_assert(a_Y.isDefined());
  // Dan G. feels strongly that the assert below should NOT be commented out
  // Brian feels that a weaker version of the CH_assert (if possible) is needed
  // Terry is just trying to get his code to work
  //CH_assert(m_ebisBox == a_X.m_ebisBox);
  CH_assert(a_X.m_nComp == m_nComp);
  CH_assert(a_Y.m_nComp == m_nComp);

  bool sameRegBox = (a_X.m_regFAB.box() == a_Y.m_regFAB.box()) && (a_X.m_regFAB.box() ==  m_regFAB.box());
  Box locRegion = a_X.m_region & m_region & a_Y.m_region;
  if (!locRegion.isEmpty())
    {
      int srccomp = 0;
      int destcomp = 0;
      FORT_AXBYFAB(CHF_FRA(m_regFAB),
                   CHF_CONST_FRA(a_X.m_regFAB),
                   CHF_CONST_FRA(a_Y.m_regFAB),
                   CHF_CONST_REAL(a_A),
                   CHF_CONST_REAL(a_B),
                   CHF_BOX(locRegion),
                   CHF_INT(srccomp),
                   CHF_INT(destcomp),
                   CHF_INT(m_nComp));
      bool nvofTest   = false;
      bool regionTest = false;
      //CP: we do a thorough test here to see if all VoFs are the same, just being cautious
      const Vector<VolIndex>& vofs   = m_irrFAB.getVoFs();
      const Vector<VolIndex>& vofs_x = a_X.m_irrFAB.getVoFs();
      const Vector<VolIndex>& vofs_y = a_Y.m_irrFAB.getVoFs();
      if (vofs.size() == vofs_x.size() && vofs.size()==vofs_y.size())
        {
          nvofTest = true;
          for (int i=0; i<vofs.size(); i++)
            {
              if (vofs[i] != vofs_x[i] || vofs[i] != vofs_y[i])
                {
                  nvofTest = false;
                  break;
                }
            }

        }
      if (locRegion == a_X.m_region && locRegion == a_Y.m_region && locRegion == m_region)
        regionTest = true;
      if (sameRegBox && regionTest && nvofTest)
        {
          const Real* l = a_X.m_irrFAB.dataPtr(destcomp);
          const Real* r = a_Y.m_irrFAB.dataPtr(destcomp);
          Real* c = m_irrFAB.dataPtr(destcomp);
          int nvof = a_X.m_irrFAB.numVoFs();
          for (int i=0; i<m_nComp*nvof; i++)
            c[i] = l[i] * a_A + r[i] * a_B;
        }
      else
        {

          IntVectSet ivsMulti = a_X.getMultiCells();
          ivsMulti &= a_Y.getMultiCells();
          ivsMulti &= getMultiCells();  // opt might be to take this out
          ivsMulti &= locRegion;
          IVSIterator ivsit(ivsMulti);
          for (ivsit.reset(); ivsit.ok(); ++ivsit)
            {
              const IntVect& iv = ivsit();
              Vector<VolIndex> vofs = m_ebisBox.getVoFs(iv);
              for (int ivof = 0; ivof < vofs.size(); ivof++)
                {
                  const VolIndex& vof = vofs[ivof];
                  for (int icomp = 0; icomp < m_nComp; ++icomp)
                    {
                      m_irrFAB(vof, icomp) = a_X.m_irrFAB(vof, icomp) * a_A
                        + a_Y.m_irrFAB(vof, icomp) * a_B;
                    }
                }
            }
        }
    }
  return *this;
}
Exemplo n.º 3
0
void
EBPlanarShockIBC::
setBndrySlopes(EBCellFAB&       a_deltaPrim,
               const EBCellFAB& a_primState,
               const EBISBox&   a_ebisBox,
               const Box&       a_box,
               const int&       a_dir)
{
  // don't want to deal with the periodic case
 CH_assert(!m_domain.isPeriodic(a_dir));
 CH_assert(m_isDefined);
 CH_assert(m_isFortranCommonSet);

  Box loBox,hiBox,centerBox,domain;
  int hasLo,hasHi;
  Box slopeBox = a_deltaPrim.getRegion()&m_domain;
  int numSlop = a_deltaPrim.nComp();
  // Generate the domain boundary boxes, loBox and hiBox, if there are
  // domain boundarys there
  eblohicenter(loBox,hasLo,hiBox,hasHi,centerBox,domain,
             slopeBox,m_domain,a_dir);

  // Set the boundary slopes if necessary
  if ((hasLo != 0) || (hasHi != 0))
    {
      BaseFab<Real>& regDeltaPrim = a_deltaPrim.getSingleValuedFAB();
      const BaseFab<Real>& regPrimState = a_primState.getSingleValuedFAB();
      /**/
      FORT_SLOPEBCS(CHF_FRA(regDeltaPrim),
                    CHF_CONST_FRA(regPrimState),
                    CHF_CONST_REAL(m_dx),
                    CHF_CONST_INT(a_dir),
                    CHF_BOX(loBox),
                    CHF_CONST_INT(hasLo),
                    CHF_BOX(hiBox),
                    CHF_CONST_INT(hasHi));
      /**/
    }
  for(SideIterator sit; sit.ok(); ++sit)
    {
      bool doThisSide;
      Box thisBox;
      if(sit() == Side::Lo)
        {
          doThisSide = (hasLo != 0);
          thisBox = loBox;
        }
      else
        {
          doThisSide = (hasHi != 0);
          thisBox = hiBox;
        }
      if(doThisSide)
        {

          // the cells for which the regular calculation
          //are incorrect are the grown set of the multivalued
          //cells intersected with the appropriate bndry box
          //and added to the irregular cells on the boundary.
          Box boxGrown = thisBox;
          boxGrown.grow(a_dir, 1);
          boxGrown &= m_domain;
          IntVectSet ivs = a_ebisBox.getMultiCells(boxGrown);
          ivs &= loBox;
          IntVectSet ivsIrreg = a_ebisBox.getIrregIVS(thisBox);
          ivs |= ivsIrreg;
          for(VoFIterator vofit(ivs, a_ebisBox.getEBGraph()); vofit.ok(); ++vofit)
            {
              const VolIndex& vof = vofit();
              //all slopes at boundary get set to zero
              //except normal velocity.  just following the
              //fortran here
              int inormVelVar = a_dir + QVELX;
              for(int ivar = 0; ivar < numSlop; ivar++)
                {
                  if(ivar != inormVelVar)
                    {
                      a_deltaPrim(vof, ivar) = 0.0;
                    }
                }

              //for normal velocity
              //do strangely limited slope
              //just lifted from the fortran.
              Side::LoHiSide otherSide = flip(sit());
              Vector<FaceIndex> faces =
                a_ebisBox.getFaces(vof, a_dir, otherSide);

              Real thisVel = a_primState(vof, inormVelVar);
              Real otherVel = 0.;
              for(int iface = 0; iface < faces.size(); iface++)
                {
                  VolIndex otherVoF = faces[iface].getVoF(otherSide);
                  otherVel += a_primState(otherVoF,inormVelVar);
                }
              if(faces.size() > 0)
                {
                  otherVel /= Real(faces.size());
                  Real slope;
                  if(sit() == Side::Lo)
                    {
                      slope = otherVel - thisVel;
                    }
                  else
                    {
                      slope = thisVel  - otherVel;
                    }
                  //trick to make sure state will not change sign
                  if(slope*thisVel < 0)
                    {
                      a_deltaPrim(vof, inormVelVar) = 0.0;
                    }
                  else
                    { //slope and vel same sign
                      Real rsign = 1.0;
                      if(thisVel < 0.0)
                        rsign = -1.0;
                      //told you this was odd.
                      Real dvmin = Min(Abs(slope), Abs((Real)2.*thisVel));
                      a_deltaPrim(vof, inormVelVar) = rsign*dvmin;
                    }
                }
              else //no faces on high side of low boundary vof
                {
                  a_deltaPrim(vof, inormVelVar) = 0.0;
                }
            } //end loop over irregular vofs at boundary
        }
    } //end loop over boundary sides
}
Exemplo n.º 4
0
// -----------------------------------------------------------------------------
// Adds coarse cell values directly to all overlying fine cells,
// then removes the average from the fine result.
// -----------------------------------------------------------------------------
void ZeroAvgConstInterpPS::prolongIncrement (LevelData<FArrayBox>&       a_phiThisLevel,
                                             const LevelData<FArrayBox>& a_correctCoarse)
{
    CH_TIME("ZeroAvgConstInterpPS::prolongIncrement");

    // Gather grids, domains, refinement ratios...
    const DisjointBoxLayout& fineGrids = a_phiThisLevel.getBoxes();
    const DisjointBoxLayout& crseGrids = a_correctCoarse.getBoxes();
    CH_assert(fineGrids.compatible(crseGrids));

    const ProblemDomain& fineDomain = fineGrids.physDomain();
    const ProblemDomain& crseDomain = crseGrids.physDomain();

    const IntVect mgRefRatio = fineDomain.size() / crseDomain.size();
    CH_assert(mgRefRatio.product() > 1);

    // These will accumulate averaging data.
    Real localSum = 0.0;
    Real localVol = 0.0;
    CH_assert(!m_CCJinvPtr.isNull());
    CH_assert(m_dxProduct > 0.0);

    DataIterator dit = fineGrids.dataIterator();
    for (dit.reset(); dit.ok(); ++dit) {
        // Create references for convenience
        FArrayBox& fineFAB = a_phiThisLevel[dit];
        const FArrayBox& crseFAB = a_correctCoarse[dit];
        const Box& fineValid = fineGrids[dit];
        const FArrayBox& JinvFAB = (*m_CCJinvPtr)[dit];

        // To make things easier, we will offset the
        // coarse and fine data boxes to zero.
        const IntVect& fiv = fineValid.smallEnd();
        const IntVect civ = coarsen(fiv, mgRefRatio);

        // Correct the fine data
        FORT_CONSTINTERPWITHAVGPS (
            CHF_FRA_SHIFT(fineFAB, fiv),
            CHF_CONST_FRA_SHIFT(crseFAB, civ),
            CHF_BOX_SHIFT(fineValid, fiv),
            CHF_CONST_INTVECT(mgRefRatio),
            CHF_CONST_FRA1_SHIFT(JinvFAB,0,fiv),
            CHF_CONST_REAL(m_dxProduct),
            CHF_REAL(localVol),
            CHF_REAL(localSum));
    }

    // Compute global sum (this is where the MPI communication happens)
#ifdef CH_MPI
    Real globalSum = 0.0;
    int result = MPI_Allreduce(&localSum, &globalSum, 1, MPI_CH_REAL, MPI_SUM, Chombo_MPI::comm);

    if (result != MPI_SUCCESS) {
        MayDay::Error("Sorry, but I had a communication error in ZeroAvgConstInterpPS::prolongIncrement");
    }

    Real globalVol = 0.0;
    result = MPI_Allreduce(&localVol, &globalVol, 1, MPI_CH_REAL, MPI_SUM, Chombo_MPI::comm);

    if (result != MPI_SUCCESS) {
        MayDay::Error("Sorry, but I had a communication error in ZeroAvgConstInterpPS::prolongIncrement");
    }

#else
    Real globalSum = localSum;
    Real globalVol = localVol;
#endif

    // Remove the average from phi.
    Real avgPhi = globalSum / globalVol;
    for (dit.reset(); dit.ok(); ++dit) {
        a_phiThisLevel[dit] -= avgPhi;
    }
}
Exemplo n.º 5
0
void
kappaDivergence(EBCellFAB&             a_divF,
                const EBFluxFAB&       a_flux,
                const EBISBox&         a_ebisBox,
                const Box&             a_box,
                const Real&            a_dx)
{
    //set the divergence initially to zero
    //then loop through directions and increment the divergence
    //with each directions flux difference.
    a_divF.setVal(0.0);
    BaseFab<Real>&       regDivF = a_divF.getSingleValuedFAB();
    regDivF.setVal(0.);
    for (int idir = 0; idir < SpaceDim; idir++)
    {
        //update for the regular vofs in the nonconservative
        //case  works for all single valued vofs.
        /* do the regular vofs */
        /**/
        const EBFaceFAB& fluxDir = a_flux[idir];
        const BaseFab<Real>& regFluxDir = fluxDir.getSingleValuedFAB();
        int ncons = 1;
        FORT_DIVERGEF( CHF_BOX(a_box),
                       CHF_FRA(regDivF),
                       CHF_CONST_FRA(regFluxDir),
                       CHF_CONST_INT(idir),
                       CHF_CONST_INT(ncons),
                       CHF_CONST_REAL(a_dx));
        /**/
    }
    //update the irregular vofs using conservative diff
    IntVectSet ivsIrreg = a_ebisBox.getIrregIVS(a_box);
    for (VoFIterator vofit(ivsIrreg, a_ebisBox.getEBGraph()); vofit.ok(); ++vofit)
    {
        const VolIndex& vof = vofit();
        //divergence was set in regular update.  we reset it
        // to zero and recalc.
        Real update = 0.;
        for ( int idir = 0; idir < SpaceDim; idir++)
        {
            const EBFaceFAB& fluxDir = a_flux[idir];
            for (SideIterator sit; sit.ok(); ++sit)
            {
                int isign = sign(sit());
                Vector<FaceIndex> faces =
                    a_ebisBox.getFaces(vof, idir, sit());
                for (int iface = 0; iface < faces.size(); iface++)
                {
                    const FaceIndex& face = faces[iface];
                    Real areaFrac = a_ebisBox.areaFrac(face);
                    Real faceFlux =fluxDir(face, 0);
                    update += isign*areaFrac*faceFlux;

                }
            }
        }
        //add EB boundary condtions in divergence
        const IntVect& iv = vof.gridIndex();
        Real bndryArea = a_ebisBox.bndryArea(vof);
        RealVect bndryCent = a_ebisBox.bndryCentroid(vof);
        RealVect normal = a_ebisBox.normal(vof);
        RealVect bndryLoc;
        RealVect exactF;
        for (int idir = 0; idir < SpaceDim; idir++)
        {
            bndryLoc[idir] = a_dx*(iv[idir] + 0.5 + bndryCent[idir]);
        }
        for (int idir = 0; idir < SpaceDim; idir++)
        {
            exactF[idir] = exactFlux(bndryLoc, idir);
        }
        Real bndryFlux = PolyGeom::dot(exactF, normal);

        update -= bndryFlux*bndryArea;
        update /= a_dx; //note NOT divided by volfrac

        a_divF(vof, 0) = update;
    }
}
Exemplo n.º 6
0
void
EBPlanarShockIBC::
fluxBC(EBFluxFAB&            a_flux,
       const EBCellFAB&      a_primCenter,
       const EBCellFAB&      a_primExtrap,
       const Side::LoHiSide& a_side,
       const Real&           a_time,
       const EBISBox&        a_ebisBox,
       const DataIndex&      a_dit,
       const Box&            a_box,
       const Box&            a_faceBox,
       const int&            a_dir)
{
 CH_assert(m_isDefined);
 CH_assert(m_isFortranCommonSet);
 CH_assert(!m_domain.isPeriodic(a_dir));

  Box FBox = a_flux[a_dir].getSingleValuedFAB().box();
  Box cellBox = FBox;
  int numFlux = a_flux[a_dir].nComp();

  // Determine which side and thus shifting directions
  int isign = sign(a_side);
  cellBox.shiftHalf(a_dir,isign);

  // Is there a domain boundary next to this grid
  if (!m_domain.contains(cellBox))
    {
      cellBox &= m_domain;
      // Find the strip of cells next to the domain boundary
      Box boundaryBox = bdryBox(cellBox, a_dir, a_side, 1);

      // Shift things to all line up correctly
      boundaryBox.shiftHalf(a_dir,-isign);
      BaseFab<Real>& regFlux = a_flux[a_dir].getSingleValuedFAB();
      const BaseFab<Real>& regPrimExtrap = a_primExtrap.getSingleValuedFAB();

      // Set the boundary fluxes
      bool inbackofshock =
        (!m_shockbackward && a_side == Side::Lo) ||
        ( m_shockbackward && a_side == Side::Hi);
      if(a_dir == m_shocknorm && inbackofshock)
        {
          regFlux.shiftHalf(a_dir,-isign);

          // Set the boundary fluxes
          /**/
          FORT_EXTRAPBC(CHF_FRA(regFlux),
                        CHF_CONST_FRA(regPrimExtrap),
                        CHF_CONST_REAL(m_dx),
                        CHF_CONST_INT(a_dir),
                        CHF_BOX(boundaryBox));
          /**/

          // Shift returned fluxes to be face centered
          regFlux.shiftHalf(a_dir,isign);
          //now for the multivalued cells.  Since it is pointwise,
          //the regular calc is correct for all single-valued cells.
          IntVectSet ivs = a_ebisBox.getMultiCells(boundaryBox);
          for(VoFIterator vofit(ivs, a_ebisBox.getEBGraph()); vofit.ok(); ++vofit)
            {
              const VolIndex& vof = vofit();
              Vector<Real> qgdnv(QNUM);
              Vector<Real> fluxv(FNUM);
              for(int ivar = 0; ivar < QNUM; ivar++)
                {
                  qgdnv[ivar] = a_primExtrap(vof, ivar);
                }
              Vector<FaceIndex> bndryFaces =
                a_ebisBox.getFaces(vof, a_dir, a_side);
              for(int iface= 0; iface < bndryFaces.size(); iface++)
                {
                  /**/
                  FORT_POINTGETFLUX(CHF_VR(fluxv),
                                    CHF_VR(qgdnv),
                                    CHF_CONST_INT(a_dir));
                  /**/
                  const FaceIndex& face = bndryFaces[iface];
                  for(int ivar = 0; ivar < FNUM; ivar++)
                    {
                      a_flux[a_dir](face, ivar) = fluxv[ivar];
                    }
                }
            }
        } //end if on the back side of the shock
      else
        {
          regFlux.shiftHalf(a_dir,-isign);
          //solid wall bcs
          FORT_SLIPWALLSOLIDBC(CHF_FRA(regFlux),
                               CHF_CONST_FRA(regPrimExtrap),
                               CHF_CONST_INT(isign),
                               CHF_CONST_REAL(m_dx),
                               CHF_CONST_INT(a_dir),
                               CHF_BOX(boundaryBox));

          // Shift returned fluxes to be face centered
          regFlux.shiftHalf(a_dir,isign);
          int inormMomVar = CMOMX + a_dir;
          int inormVelVar = QVELX + a_dir;
          //now for the multivalued cells.  Since it is pointwise,
          //the regular calc is correct for all single-valued cells.
          IntVectSet ivs = a_ebisBox.getMultiCells(boundaryBox);
          for(VoFIterator vofit(ivs, a_ebisBox.getEBGraph()); vofit.ok(); ++vofit)
            {
              const VolIndex& vof = vofit();
              //set all fluxes except normal momentum  to zero.
              //set normal momemtum flux to sign(normal)*pressure
              Vector<FaceIndex> bndryFaces = a_ebisBox.getFaces(vof, a_dir, a_side);
              for(int iface= 0; iface < bndryFaces.size(); iface++)
                {
                  const FaceIndex& face = bndryFaces[iface];
                  //set all fluxes to zero then fix normal momentum
                  for(int ivar = 0; ivar < numFlux; ivar++)
                    {
                      a_flux[a_dir](face, ivar) = 0;
                    }
                  Real press = a_primExtrap(vof, QPRES);
                  Real dense = a_primExtrap(vof, QRHO);
                  Real unorm = a_primExtrap(vof, inormVelVar);
                  Real speed = sqrt(m_gamma*press/dense);

                  
                  a_flux[a_dir](face, inormMomVar) =
                    press + isign*dense*unorm*speed;

                }
            }
        }
    }
}
Exemplo n.º 7
0
void VCAMRPoissonOp2::looseGSRB(LevelData<FArrayBox>&       a_phi,
                               const LevelData<FArrayBox>& a_rhs)
{
  CH_TIME("VCAMRPoissonOp2::looseGSRB");
#if 1
  MayDay::Abort("VCAMRPoissonOp2::looseGSRB - Not implemented");
#else
  // This implementation converges at half the rate of "levelGSRB" in
  // multigrid solves
  CH_assert(a_phi.isDefined());
  CH_assert(a_rhs.isDefined());
  CH_assert(a_phi.ghostVect() >= IntVect::Unit);
  CH_assert(a_phi.nComp() == a_rhs.nComp());

  // Recompute the relaxation coefficient if needed.
  resetLambda();

  const DisjointBoxLayout& dbl = a_phi.disjointBoxLayout();

  DataIterator dit = a_phi.dataIterator();

  // fill in intersection of ghostcells and a_phi's boxes
  {
    CH_TIME("VCAMRPoissonOp2::looseGSRB::homogeneousCFInterp");
    homogeneousCFInterp(a_phi);
  }

  {
    CH_TIME("VCAMRPoissonOp2::looseGSRB::exchange");
    a_phi.exchange(a_phi.interval(), m_exchangeCopier);
  }

  // now step through grids...
  for (dit.begin(); dit.ok(); ++dit)
  {
    // invoke physical BC's where necessary
    {
      CH_TIME("VCAMRPoissonOp2::looseGSRB::BCs");
      m_bc(a_phi[dit], dbl[dit()], m_domain, m_dx, true);
    }

    const Box& region = dbl.get(dit());
    const FluxBox& thisBCoef  = (*m_bCoef)[dit];

    int whichPass = 0;

#if CH_SPACEDIM == 1
    FORT_GSRBHELMHOLTZVC1D
#elif CH_SPACEDIM == 2
    FORT_GSRBHELMHOLTZVC2D
#elif CH_SPACEDIM == 3
    FORT_GSRBHELMHOLTZVC3D
#else
    This_will_not_compile!
#endif
                          (CHF_FRA(a_phi[dit]),
                           CHF_CONST_FRA(a_rhs[dit]),
                           CHF_BOX(region),
                           CHF_CONST_REAL(m_dx),
                           CHF_CONST_REAL(m_alpha),
                           CHF_CONST_FRA((*m_aCoef)[dit]),
                           CHF_CONST_REAL(m_beta),
#if CH_SPACEDIM >= 1
                           CHF_CONST_FRA(thisBCoef[0]),
#endif
#if CH_SPACEDIM >= 2
                           CHF_CONST_FRA(thisBCoef[1]),
#endif
#if CH_SPACEDIM >= 3
                           CHF_CONST_FRA(thisBCoef[2]),
#endif
#if CH_SPACEDIM >= 4
                           This_will_not_compile!
#endif
                           CHF_CONST_FRA(m_lambda[dit]),
                           CHF_CONST_INT(whichPass));

    whichPass = 1;

#if CH_SPACEDIM == 1
    FORT_GSRBHELMHOLTZVC1D
#elif CH_SPACEDIM == 2
    FORT_GSRBHELMHOLTZVC2D
#elif CH_SPACEDIM == 3
    FORT_GSRBHELMHOLTZVC3D
#else
    This_will_not_compile!
#endif
                          (CHF_FRA(a_phi[dit]),
                           CHF_CONST_FRA(a_rhs[dit]),
                           CHF_BOX(region),
                           CHF_CONST_REAL(m_dx),
                           CHF_CONST_REAL(m_alpha),
                           CHF_CONST_FRA((*m_aCoef)[dit]),
                           CHF_CONST_REAL(m_beta),
#if CH_SPACEDIM >= 1
                           CHF_CONST_FRA(thisBCoef[0]),
#endif
#if CH_SPACEDIM >= 2
                           CHF_CONST_FRA(thisBCoef[1]),
#endif
#if CH_SPACEDIM >= 3
                           CHF_CONST_FRA(thisBCoef[2]),
#endif
#if CH_SPACEDIM >= 4
                           This_will_not_compile!
#endif
                           CHF_CONST_FRA(m_lambda[dit]),
                           CHF_CONST_INT(whichPass));
  } // end loop through grids
#endif
}
Exemplo n.º 8
0
// Set boundary fluxes
void VelIBC::primBC(FArrayBox&            a_WGdnv,
                    const FArrayBox&      a_Wextrap,
                    const FArrayBox&      a_W,
                    const int&            a_dir,
                    const Side::LoHiSide& a_side,
                    const Real&           a_time)
{
  CH_assert(m_isDefined == true);

  // In periodic case, this doesn't do anything
  if (!m_domain.isPeriodic(a_dir))
    {
      // This needs to be fixed
      // CH_assert(m_isBCvalSet);

      int lohisign;
      Box tmp = a_WGdnv.box() & m_domain;
      Real bcVal;

      // Determine which side and thus shifting directions
      if (a_side == Side::Lo)
        {
          lohisign = -1;
          bcVal = m_bcVal[a_dir][0];
        }
      else
        {
          lohisign = 1;
          bcVal = m_bcVal[a_dir][1];
        }

      tmp.shiftHalf(a_dir,lohisign);

      // Is there a domain boundary next to this grid
      if (!m_domain.contains(tmp))
        {
          tmp &= m_domain;

          Box boundaryBox;

          // Find the strip of cells next to the domain boundary
          if (a_side == Side::Lo)
            {
              boundaryBox = bdryLo(tmp,a_dir);
            }
          else
            {
              boundaryBox = bdryHi(tmp,a_dir);
            }

          // Set the boundary fluxes
          FORT_SOLIDVELBCF(CHF_FRA(a_WGdnv),
                           CHF_CONST_FRA(a_Wextrap),
                           CHF_CONST_REAL(bcVal),
                           CHF_CONST_INT(lohisign),
                           CHF_CONST_REAL(m_dx),
                           CHF_CONST_INT(a_dir),
                           CHF_BOX(boundaryBox));
        }
    }
}
Exemplo n.º 9
0
// -----------------------------------------------------------------------------
// Interpolate ghosts at CF interface using zeros on coarser grids.
// Only do one face.
// -----------------------------------------------------------------------------
void homogeneousCFInterp (LevelData<FArrayBox>& a_phif,
                          const DataIndex&      a_index,
                          const int             a_dir,
                          const Side::LoHiSide  a_side,
                          const Real            a_fineDxDir,
                          const Real            a_crseDxDir,
                          const CFRegion&       a_cfRegion)
{
    CH_TIME("homogeneousCFInterp (single grid)");

    // Sanity checks
    CH_assert((a_dir >= 0) && (a_dir < SpaceDim));
    CH_assert(a_phif.ghostVect()[a_dir] >= 1);

    // Get the C/F region
    const CFIVS* cfivs_ptr = NULL;
    if (a_side == Side::Lo) {
        CFRegion& castCFRegion = (CFRegion&)a_cfRegion;
        cfivs_ptr = &(castCFRegion.loCFIVS(a_index, a_dir));
    } else {
        CFRegion& castCFRegion = (CFRegion&)a_cfRegion;
        cfivs_ptr = &(castCFRegion.hiCFIVS(a_index, a_dir));
    }

    if (cfivs_ptr->isPacked()) {
        // The C/F region is a box.
        // Iterate over the box and interpolate.
        int ihiorlo = sign(a_side);
        FArrayBox& phiFab = a_phif[a_index];
        const Box region = cfivs_ptr->packedBox();

        CH_assert(a_crseDxDir > 0.0 || region.isEmpty());

        if (phiFab.box().size(a_dir) == 3) {
            // Linear interpolation of fine ghosts assuming
            // all zeros on coarser level.
            FORTNT_INTERPHOMOLINEAR(
                CHF_FRA(phiFab),
                CHF_BOX(region),
                CHF_CONST_REAL(a_fineDxDir),
                CHF_CONST_REAL(a_crseDxDir),
                CHF_CONST_INT(a_dir),
                CHF_CONST_INT(ihiorlo));
        } else {
            // Quadratic interpolation of fine ghosts assuming
            // all zeros on coarser level.
            FORTNT_INTERPHOMO(
                CHF_FRA(phiFab),
                CHF_BOX(region),
                CHF_CONST_REAL(a_fineDxDir),
                CHF_CONST_REAL(a_crseDxDir),
                CHF_CONST_INT(a_dir),
                CHF_CONST_INT(ihiorlo));
        }
    } else {
        // The C/F region is sparse.
        // Iterate over the IVS and interpolate.
        const IntVectSet& interp_ivs = cfivs_ptr->getFineIVS();

        if (!interp_ivs.isEmpty()) {
            CH_assert(a_crseDxDir > 0.0);
            interpOnIVSHomo(a_phif,
                            a_index,
                            a_dir,
                            a_side,
                            interp_ivs,
                            a_fineDxDir,
                            a_crseDxDir);
        }
    }
}
Exemplo n.º 10
0
void VCAMRPoissonOp2::restrictResidual(LevelData<FArrayBox>&       a_resCoarse,
                                      LevelData<FArrayBox>&       a_phiFine,
                                      const LevelData<FArrayBox>& a_rhsFine)
{
  CH_TIME("VCAMRPoissonOp2::restrictResidual");

  homogeneousCFInterp(a_phiFine);
  const DisjointBoxLayout& dblFine = a_phiFine.disjointBoxLayout();
  for (DataIterator dit = a_phiFine.dataIterator(); dit.ok(); ++dit)
    {
      FArrayBox& phi = a_phiFine[dit];
      m_bc(phi, dblFine[dit()], m_domain, m_dx, true);
    }

  a_phiFine.exchange(a_phiFine.interval(), m_exchangeCopier);

  for (DataIterator dit = a_phiFine.dataIterator(); dit.ok(); ++dit)
    {
      FArrayBox&       phi = a_phiFine[dit];
      const FArrayBox& rhs = a_rhsFine[dit];
      FArrayBox&       res = a_resCoarse[dit];

      const FArrayBox& thisACoef = (*m_aCoef)[dit];
      const FluxBox&   thisBCoef = (*m_bCoef)[dit];

      Box region = dblFine.get(dit());
      const IntVect& iv = region.smallEnd();
      IntVect civ = coarsen(iv, 2);

      res.setVal(0.0);

#if CH_SPACEDIM == 1
      FORT_RESTRICTRESVC1D
#elif CH_SPACEDIM == 2
      FORT_RESTRICTRESVC2D
#elif CH_SPACEDIM == 3
      FORT_RESTRICTRESVC3D
#else
      This_will_not_compile!
#endif
                          (CHF_FRA_SHIFT(res, civ),
                           CHF_CONST_FRA_SHIFT(phi, iv),
                           CHF_CONST_FRA_SHIFT(rhs, iv),
                           CHF_CONST_REAL(m_alpha),
                           CHF_CONST_FRA_SHIFT(thisACoef, iv),
                           CHF_CONST_REAL(m_beta),
#if CH_SPACEDIM >= 1
                           CHF_CONST_FRA_SHIFT(thisBCoef[0], iv),
#endif
#if CH_SPACEDIM >= 2
                           CHF_CONST_FRA_SHIFT(thisBCoef[1], iv),
#endif
#if CH_SPACEDIM >= 3
                           CHF_CONST_FRA_SHIFT(thisBCoef[2], iv),
#endif
#if CH_SPACEDIM >= 4
                           This_will_not_compile!
#endif
                           CHF_BOX_SHIFT(region, iv),
                           CHF_CONST_REAL(m_dx));
    }
}
Exemplo n.º 11
0
void
EBPoissonOp::
applyDomainFlux(Box * a_loBox,
                Box * a_hiBox,
                int * a_hasLo,
                int * a_hasHi,
                Box & a_dblBox,
                int a_nComps,
                BaseFab<Real> & a_phiFAB,
                bool a_homogeneousPhysBC,
                const DataIndex& a_dit,
                const Real& a_beta)
{
  CH_TIME("EBPoissonOp::applyDomainFlux");
  CH_assert(m_domainBC != NULL);

  for (int idir=0; idir<SpaceDim; idir++)
    {

      EBArith::loHi(a_loBox[idir], a_hasLo[idir],
                             a_hiBox[idir], a_hasHi[idir],
                             m_eblg.getDomain(), a_dblBox, idir);

      for (int comp = 0; comp<a_nComps; comp++)
        {

          if (a_hasLo[idir] == 1)
            {
              Box lbox=a_loBox[idir];
              lbox.shift(idir,-1);
              BaseFab<Real> loFaceFlux(a_loBox[idir],a_nComps);
              int side = -1;

              m_domainBC->getFaceFlux(loFaceFlux,a_phiFAB,m_origin,m_dx,idir,Side::Lo,a_dit,m_time,a_homogeneousPhysBC);

              FORT_REGAPPLYDOMAINFLUX_INPLACE(CHF_FRA1(a_phiFAB,comp),
                                              CHF_CONST_FRA1(loFaceFlux,comp),
                                              CHF_CONST_REAL(m_dx[idir]),
                                              CHF_CONST_INT(side),
                                              CHF_CONST_INT(idir),
                                              CHF_BOX(lbox));
            }

          if (a_hasHi[idir] == 1)
            {
              Box hbox=a_hiBox[idir];
              hbox.shift(idir,1);
              BaseFab<Real> hiFaceFlux(a_hiBox[idir],a_nComps);
              int side = 1;

              m_domainBC->getFaceFlux(hiFaceFlux,a_phiFAB,m_origin,m_dx,idir,Side::Hi,a_dit,m_time,a_homogeneousPhysBC);

              FORT_REGAPPLYDOMAINFLUX_INPLACE(CHF_FRA1(a_phiFAB,comp),
                                              CHF_CONST_FRA1(hiFaceFlux,comp),
                                              CHF_CONST_REAL(m_dx[idir]),
                                              CHF_CONST_INT(side),
                                              CHF_CONST_INT(idir),
                                              CHF_BOX(hbox));
            }

        }
    }
}
Exemplo n.º 12
0
// ---------------------------------------------------------
void
AMRNavierStokes::computeVorticity(LevelData<FArrayBox>& a_vorticity) const
{
  // this breaks the "const"-ness of the function,
  // but is necessary to ensure that boundary
  // conditions are properly set.
  LevelData<FArrayBox>& vel =
    *(const_cast<LevelData<FArrayBox>*>(m_vel_new_ptr));

  const DisjointBoxLayout& grids = vel.getBoxes();

  if (m_level > 0)
    {
      // do quadratic C/F BC's
      // for now, assume that BC's are with new velocity
      // (may need to be changed for fine-level regridding)
      LevelData<FArrayBox>& crseVel = crseNSPtr()->newVel();
      const DisjointBoxLayout& crseGrids = crseVel.getBoxes();
      int nRefCrse = crseNSPtr()->refRatio();

      QuadCFInterp interpolator(grids, &crseGrids, m_dx, nRefCrse,
                                SpaceDim, m_problem_domain);

      interpolator.coarseFineInterp(vel, crseVel);
    }

  Interval velComps(0,SpaceDim-1);
  vel.exchange(velComps);

  DataIterator dit = vel.dataIterator();

  // at the moment, do extrap at physical boundaries
  // (same effect as one-sided differencing)
  BCHolder vortVelBC = m_physBCPtr->extrapFuncBC(1);

  for (dit.reset(); dit.ok(); ++dit)
    {
      // apply physical BC's
      vortVelBC(vel[dit], grids[dit],
                m_problem_domain, m_dx,
                true); // homogeneous
      if (SpaceDim == 3)
        {
          for (int dir=0; dir<SpaceDim; dir++)
            {
              // and then compute vorticity
              FORT_COMPUTEVORT(CHF_FRA1(a_vorticity[dit],dir),
                               CHF_CONST_FRA(vel[dit]),
                               CHF_BOX(grids[dit]),
                               CHF_CONST_REAL(m_dx),
                               CHF_CONST_INT(dir));
            }
        }
      else if (SpaceDim == 2)
        {
          int dir = 2;
          FORT_COMPUTEVORT(CHF_FRA1(a_vorticity[dit],0),
                           CHF_CONST_FRA(vel[dit]),
                           CHF_BOX(grids[dit]),
                           CHF_CONST_REAL(m_dx),
                           CHF_CONST_INT(dir));
        } // end dimensionality choice
    } // end loop over grids
}
Exemplo n.º 13
0
// Adjust boundary fluxes to account for artificial viscosity
void RampIBC::artViscBC(FArrayBox&       a_F,
                        const FArrayBox& a_U,
                        const FArrayBox& a_divVel,
                        const int&       a_dir,
                        const Real&      a_time)
{
  CH_assert(m_isFortranCommonSet == true);
  CH_assert(m_isDefined == true);

  FArrayBox &divVel = (FArrayBox &)a_divVel;

  Box fluxBox = divVel.box();
  fluxBox.enclosedCells(a_dir);
  fluxBox.grow(a_dir,1);

  Box loBox,hiBox,centerBox,entireBox;
  int hasLo,hasHi;
  loHiCenterFace(loBox,hasLo,hiBox,hasHi,centerBox,entireBox,
                 fluxBox,m_domain,a_dir);

  if (hasLo == 1)
    {
      loBox.shiftHalf(a_dir,1);
      divVel.shiftHalf(a_dir,1);
      a_F.shiftHalf(a_dir,1);

      int loHiSide = -1;

      FORT_RAMPARTVISCF(CHF_FRA(a_F),
                        CHF_CONST_FRA(a_U),
                        CHF_CONST_FRA1(divVel,0),
                        CHF_CONST_INT(loHiSide),
                        CHF_CONST_REAL(m_dx),
                        CHF_CONST_INT(a_dir),
                        CHF_BOX(loBox));

      loBox.shiftHalf(a_dir,-1);
      divVel.shiftHalf(a_dir,-1);
      a_F.shiftHalf(a_dir,-1);
    }

  if (hasHi == 1)
    {
      hiBox.shiftHalf(a_dir,-1);
      divVel.shiftHalf(a_dir,-1);
      a_F.shiftHalf(a_dir,-1);

      int loHiSide = 1;

      FORT_RAMPARTVISCF(CHF_FRA(a_F),
                        CHF_CONST_FRA(a_U),
                        CHF_CONST_FRA1(divVel,0),
                        CHF_CONST_INT(loHiSide),
                        CHF_CONST_REAL(m_dx),
                        CHF_CONST_INT(a_dir),
                        CHF_BOX(hiBox));

      hiBox.shiftHalf(a_dir,1);
      divVel.shiftHalf(a_dir,1);
      a_F.shiftHalf(a_dir,1);
    }
}
Exemplo n.º 14
0
void
EBGradDivFilter::
cellGradient(EBCellFAB&             a_gradDiv,
             const EBCellFAB&       a_gradVel,
             const  EBCellFAB&      a_vel,
             const EBFluxFAB&       a_fluxVel,
             const EBFluxFAB&       a_div,
             const Box&             a_grid,
             const EBISBox&         a_ebisBox,
             const DataIndex&       a_dataIndex,
             bool a_multiplyByLambda,
             bool a_noExtrapToCovered)
{
  CH_TIME("EBGradDivFilter::cellGradient");
  int icomp = 0;
  EBCellFAB& lambdaFAB = m_lambda[a_dataIndex];
  IntVectSet irregIVS = a_ebisBox.getIrregIVS(a_grid);

  for (int faceDir = 0; faceDir < SpaceDim; faceDir++)
    {
      const EBFaceFAB&  faceDiv       =  a_div[faceDir];
      const BaseFab<Real>& regFaceDiv =   faceDiv.getSingleValuedFAB();
      const BaseFab<Real>& regLambda =   lambdaFAB.getSingleValuedFAB();
      BaseFab<Real>& regGradDiv       = a_gradDiv.getSingleValuedFAB();

      int imultByLambda = 0;
      if (a_multiplyByLambda)
        {
          imultByLambda = 1;
        }
      FORT_EBGDFCELLGRAD(CHF_FRA1(regGradDiv, faceDir),
                         CHF_CONST_FRA1(regFaceDiv, icomp),
                         CHF_CONST_FRA1(regLambda, icomp),
                         CHF_BOX(a_grid),
                         CHF_CONST_REAL(m_dxFine[faceDir]),
                         CHF_CONST_INT(faceDir),
                         CHF_CONST_INT(imultByLambda));

      //nonconservative gradient
      for (VoFIterator vofit(irregIVS, a_ebisBox.getEBGraph()); vofit.ok(); ++vofit)
        {
          const VolIndex& vof = vofit();
          Real gradVal = 0.0;

          Vector<FaceIndex> facesHi = a_ebisBox.getFaces(vof, faceDir, Side::Hi);
          Vector<FaceIndex> facesLo = a_ebisBox.getFaces(vof, faceDir, Side::Lo);

          bool zeroGrad = a_noExtrapToCovered && ((facesHi.size() == 0) || (facesLo.size() == 0));
          if (zeroGrad)
            {
              gradVal = 0;
            }
          else
            {
              Real valHi= 0;
              if (facesHi.size() > 0)
                {
                  for (int iface = 0; iface < facesHi.size(); iface++)
                    {
                      valHi += faceDiv(facesHi[iface], icomp);
                    }
                  valHi /= facesHi.size();
                }
              else
                {
                  valHi = ccpGetCoveredExtrapValue(vof, faceDir, Side::Hi,
                                                   faceDiv, a_ebisBox, a_grid,
                                                   m_domainFine, m_dxFine, icomp);
                }

              Real valLo= 0;
              if (facesLo.size() > 0)
                {
                  for (int iface = 0; iface < facesLo.size(); iface++)
                    {
                      valLo += faceDiv(facesLo[iface], 0);
                    }
                  valLo /= facesLo.size();
                }
              else
                {
                  valLo = ccpGetCoveredExtrapValue(vof, faceDir, Side::Lo ,
                                                   faceDiv, a_ebisBox, a_grid,
                                                   m_domainFine, m_dxFine, icomp);

                }
              gradVal = (valHi-valLo)/(m_dxFine[faceDir]);

              //multiply the lambda in since we have the area fractions lying about
              if (a_multiplyByLambda)
                {
                  Real lambda = lambdaFAB(vof, 0);
                  gradVal *= lambda;
                }
            }

          a_gradDiv(vof, faceDir) = gradVal;
        }
    }
}
Exemplo n.º 15
0
void
EBGradDivFilter::
gradVel(EBCellFAB&             a_gradVel,
        const  EBCellFAB&      a_vel,
        const Box&             a_grid,
        const EBISBox&         a_ebisBox,
        bool a_lowOrderOneSide)
{
  CH_TIME("EBGradDivFilter::gradVel");
  CH_assert(a_gradVel.nComp() == SpaceDim*SpaceDim);
  CH_assert(a_vel.nComp() == SpaceDim);

  int iLowOrderOneSide = 0;
  if (a_lowOrderOneSide)
    {
      iLowOrderOneSide = 1;
    }

  for (int derivDir = 0; derivDir < SpaceDim; derivDir++)
    {
      Box loBox, hiBox, centerBox;
      int hasLo, hasHi;
      EBArith::loHiCenter(loBox, hasLo, hiBox, hasHi, centerBox, m_domainFine, a_grid, derivDir);
      for (int velDir = 0; velDir < SpaceDim; velDir++)
        {
          BaseFab<Real>&   regGradVel  = a_gradVel.getSingleValuedFAB();
          const BaseFab<Real>& regVel  =     a_vel.getSingleValuedFAB();
          int gradcomp = getGradComp(velDir, derivDir);

          FORT_EBGDFGRADVEL(CHF_FRA1(regGradVel, gradcomp),
                            CHF_CONST_FRA1(regVel, velDir),
                            CHF_BOX(loBox),
                            CHF_INT(hasLo),
                            CHF_BOX(hiBox),
                            CHF_INT(hasHi),
                            CHF_BOX(centerBox),
                            CHF_CONST_REAL(m_dxFine[derivDir]),
                            CHF_CONST_INT(derivDir),
                            CHF_CONST_INT(iLowOrderOneSide));

          IntVectSet ivsIrreg = a_ebisBox.getIrregIVS(a_grid);
          if (!a_lowOrderOneSide)
            {
              ivsIrreg.grow(1);
              ivsIrreg &= a_grid;
            }
          for (VoFIterator vofit(ivsIrreg, a_ebisBox.getEBGraph()); vofit.ok(); ++vofit)
            {
              const VolIndex& vof = vofit();
              bool hasHi, hasLo;
              VolIndex vofHi, vofLo;
              Vector<FaceIndex> facesHi = a_ebisBox.getFaces(vof, derivDir, Side::Hi);
              Vector<FaceIndex> facesLo = a_ebisBox.getFaces(vof, derivDir, Side::Lo);

              hasHi = (facesHi.size() == 1) && (!facesHi[0].isBoundary());
              hasLo = (facesLo.size() == 1) && (!facesLo[0].isBoundary());
              if (hasLo)
                {
                  vofLo = facesLo[0].getVoF(Side::Lo);
                }
              if (hasHi)
                {
                  vofHi = facesHi[0].getVoF(Side::Hi);
                }

              Real gradVal;
              if (hasHi && hasLo)
                {
                  gradVal = (a_vel(vofHi, velDir) - a_vel(vofLo, velDir))/(2.*m_dxFine[derivDir]);
                }
              else if (hasHi || hasLo)
                {
                  //do one-sided diff
                  CH_assert(!(hasHi && hasLo));
                  Side::LoHiSide side;
                  VolIndex vofNear;
                  if (hasLo)
                    {
                      side = Side::Lo;
                      vofNear = vofLo;
                    }
                  else
                    {
                      side = Side::Hi;
                      vofNear = vofHi;
                    }
                  int isign = sign(side);

                  Vector<FaceIndex> facesFar = a_ebisBox.getFaces(vofNear, derivDir, side);
                  bool hasVoFFar = (facesFar.size()==1) && (!facesFar[0].isBoundary());
                  Real valStart = a_vel(vof,     velDir);
                  Real valNear  = a_vel(vofNear, velDir);
                  if (hasVoFFar && !a_lowOrderOneSide)
                    {
                      VolIndex vofFar = facesFar[0].getVoF(side);
                      Real valFar = a_vel(vofFar, velDir);
                      gradVal = (4*(valNear - valStart)- (valFar-valStart))/(2.*isign*m_dxFine[derivDir]);
                    }
                  else
                    {
                      //do not have another point for stencil or specified low order one-sided.
                      //drop order of derivative
                      gradVal = (valNear - valStart)/(isign*m_dxFine[derivDir]);
                    }
                }
              else
                {
                  //only have one point, can only set gradient to zero
                  gradVal = 0.0;
                }

              a_gradVel(vof, gradcomp) = gradVal;
            }
        }
    }
}