void ConstBCFunction::operator()(FArrayBox&           a_state,
                                 const Box&           a_valid,
                                 const ProblemDomain& a_domain,
                                 Real                 a_dx,
                                 bool                 a_homogeneous)
{
  const Box& domainBox = a_domain.domainBox();

  for (int idir = 0; idir < SpaceDim; idir++)
  {
    if (!a_domain.isPeriodic(idir))
    {
      for (SideIterator sit; sit.ok(); ++sit)
      {
        Side::LoHiSide side = sit();

        if (a_valid.sideEnd(side)[idir] == domainBox.sideEnd(side)[idir])
        {
          int  bcType;
          Real bcValue;

          if (side == Side::Lo)
          {
            bcType  = m_loSideType [idir];
            bcValue = m_loSideValue[idir];
          }
          else
          {
            bcType  = m_hiSideType [idir];
            bcValue = m_hiSideValue[idir];
          }

          if (bcType == 0)
          {
            // Neumann BC
            int isign = sign(side);

            Box toRegion = adjCellBox(a_valid, idir, side, 1);
            toRegion &= a_state.box();

            Box fromRegion = toRegion;
            fromRegion.shift(idir, -isign);

            a_state.copy(a_state, fromRegion, 0, toRegion, 0, a_state.nComp());

            if (!a_homogeneous)
            {
              for (BoxIterator bit(toRegion); bit.ok(); ++bit)
              {
                const IntVect& ivTo = bit();
                // IntVect ivClose = ivTo - isign*BASISV(idir);

                for (int icomp = 0; icomp < a_state.nComp(); icomp++)
                {
                  a_state(ivTo, icomp) += Real(isign)*a_dx*bcValue;
                }
              }
            }
          }
          else if (bcType == 1)
          {
            // Dirichlet BC
            int isign = sign(side);

            Box toRegion = adjCellBox(a_valid, idir, side, 1);
            toRegion &= a_state.box();

            for (BoxIterator bit(toRegion); bit.ok(); ++bit)
            {
              const IntVect& ivTo = bit();

              IntVect ivClose = ivTo -   isign*BASISV(idir);
              // IntVect ivFar   = ivTo - 2*isign*BASISV(idir);

              Real inhomogVal = 0.0;

              if (!a_homogeneous)
              {
                inhomogVal = bcValue;
              }

              for (int icomp = 0; icomp < a_state.nComp(); icomp++)
              {
                Real nearVal = a_state(ivClose, icomp);
                // Real farVal  = a_state(ivFar,   icomp);

                Real ghostVal = linearInterp(inhomogVal, nearVal);

                a_state(ivTo, icomp) = ghostVal;
              }
            }
          }
          else
          {
            MayDay::Abort("ConstBCFunction::operator() - unknown BC type");
          }
        } // if ends match
      } // end loop over sides
    } // if not periodic in this direction
  } // end loop over directions
}
void
LevelFluxRegisterEdge::incrementFine(
                                     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());
  CH_assert(!a_fineFlux.box().isEmpty());
  CH_assert(a_srcInterval.size() == a_dstInterval.size());
  CH_assert(a_srcInterval.begin() >= 0);
  CH_assert(a_srcInterval.end() < a_fineFlux.nComp());
  CH_assert(a_dstInterval.begin() >= 0);
  CH_assert(a_dstInterval.end() < m_nComp);

  CH_assert(a_dir >= 0);
  CH_assert(a_dir < SpaceDim);
  CH_assert((a_sd == Side::Lo)||(a_sd == Side::Hi));
  //
  //
  //denom is the number of fine faces per coarse face
  //this is intrinsically dimension-dependent
#if (CH_SPACEDIM == 2)
  Real denom = 1;
#elif (CH_SPACEDIM == 3)
  Real denom = m_nRefine;
#else
  // This code doesn't make any sense in 1D, and hasn't been implemented
  // for DIM > 3
  Real denom = -1.0;
  MayDay::Error("LevelFluxRegisterEdge -- bad SpaceDim");
#endif

  Real scale = a_scale/denom;

  // need which fluxbox face we're doing this for
  Box thisBox = a_fineFlux.box();
  int fluxComp = -1;
  for (int sideDir=0; sideDir<SpaceDim; sideDir++)
  {
    // we do nothing in the direction normal to face
    if (sideDir != a_dir)
    {
      if (thisBox.type(sideDir) == IndexType::CELL)
      {
        fluxComp = sideDir;
      }
    }
  }
  CH_assert (fluxComp >= 0);
  int regcomp = getRegComp(a_dir, fluxComp);

  FluxBox& thisReg = m_fabFine[index(a_dir, a_sd)][a_fineDataIndex];
  FArrayBox& reg = thisReg[regcomp];

  a_fineFlux.shiftHalf(a_dir, sign(a_sd));

  // this is a way of geting a face-centered domain
  // box which we can then use to intersect with things
  // to screen out cells outside the physical domain
  // (nothing is screened out in periodic case)
  Box shiftedValidDomain = m_domainCoarse.domainBox();
  shiftedValidDomain.grow(2);
  shiftedValidDomain &= m_domainCoarse;
  shiftedValidDomain.surroundingNodes(regcomp);

  BoxIterator regIt(reg.box() & shiftedValidDomain);
  for (regIt.begin(); regIt.ok(); ++regIt)
    {
      const IntVect& coarseIndex = regIt();
      // create a cell-centered box, then shift back to face-centered
      Box box(coarseIndex, coarseIndex);
      box.shiftHalf(regcomp,-1);
      // to avoid adding in edges which do not overlie coarse-grid
      // edges, will refine only in non-fluxComp directions to
      // determine box from which to grab fluxes.
      IntVect refineVect(m_nRefine*IntVect::Unit);
      //refineVect.setVal(fluxComp,1);
      box.refine(refineVect);
      if (a_sd == Side::Lo) box.growLo(a_dir,-(m_nRefine-1));
      else                 box.growHi(a_dir,-(m_nRefine-1));
      BoxIterator fluxIt(box);
      for (fluxIt.begin(); fluxIt.ok(); ++fluxIt)
        {
          int src = a_srcInterval.begin();
          int dest =  a_dstInterval.begin();
          for ( ; src <=a_srcInterval.end(); ++src,++dest)
            reg(coarseIndex, dest) += scale*a_fineFlux(fluxIt(), src);
        }
    }
  a_fineFlux.shiftHalf(a_dir, -sign(a_sd));
}
Example #3
0
// Compute the time-centered values of the primitive variable on the
// interior cell faces of the cell-centered box a_box.
void PatchGodunov::computeWHalf(FluxBox&         a_WHalf,
                                const FArrayBox& a_U,
                                const FArrayBox& a_S,
                                const Real&      a_dt,
                                const Box&       a_box)
{
  CH_assert(isDefined());
  CH_assert(a_box == m_currentBox);

  // Get the number of various variables
  int numPrim = m_gdnvPhysics->numPrimitives();

  // The current box of valid cells
  Box curBox = m_currentBox;

  // Boxes for face-centered state - used for the riemann() and
  // artificialViscosity() calls
  Box faceBox[SpaceDim];

  // Boxes for face-centered fluxes
  Box fluxBox[SpaceDim];

  // Boxes for cell-centered state - used for the updatePrim() calls
  Box ccBox[SpaceDim];

  for (int dir1 = 0; dir1 < SpaceDim; ++dir1)
    {
      // faceBox[dir1] is face-centered in direction "dir1",
      // is valid "curBox" grown by 1 in all directions except "dir1",
      // and stays one cell away, in "dir1", from the domain boundary.
      faceBox[dir1] = curBox; // valid cell-centered box
      faceBox[dir1].grow(1);
      faceBox[dir1] &= m_domain;
      faceBox[dir1].grow(dir1, -1);
      faceBox[dir1].surroundingNodes(dir1);

      // ccBox[dir1] is cell-centered,
      // is valid "curBox" grown by 1 in all directions except "dir1",
      // but only within the domain, "m_domain".
      ccBox[dir1] = curBox;
      ccBox[dir1].grow(1);
      ccBox[dir1].grow(dir1, -1);
      ccBox[dir1] &= m_domain;

      // fluxBox[dir1] is face-centered in direction "dir1",
      // consisting of all those faces of cells of "ccBox[dir1]".
      fluxBox[dir1] = ccBox[dir1];
      fluxBox[dir1].surroundingNodes(dir1);

      // The difference between faceBox[dir1] and fluxBox[dir1] is:
      // if curBox abuts the boundary of the domain in direction "dir1",
      // then fluxBox[dir1] contains faces along that boundary,
      // but faceBox[dir1] does not.
    }

  // cell-centered box:  but restrict it to within domain
  Box WBox = a_U.box();
  WBox &= m_domain;

  // Primitive variables
  FArrayBox W(WBox,numPrim);

  // Calculate the primitive variables W from the conserved variables a_U,
  // on cell-centered WBox.
  m_gdnvPhysics->consToPrim(W, a_U, WBox);

  // slopeBox is the cell-centered box where slopes will be needed:
  // it is one larger than the final update box "curBox" of valid cells,
  // but within domain.
  // On slopeBox we define the FABs flattening, WMinus, and WPlus.
  Box slopeBox = curBox;
  slopeBox.grow(1);
  slopeBox &= m_domain;

  // Compute flattening once for all slopes if needed
  FArrayBox flattening(slopeBox, 1); // cell-centered
  if (m_useFlattening)
    {
      Interval velInt    = m_gdnvPhysics->velocityInterval();
      int pressureIndex  = m_gdnvPhysics->pressureIndex();
      Real smallPressure = m_gdnvPhysics->smallPressure();
      int bulkIndex      = m_gdnvPhysics->bulkModulusIndex();

      m_util.computeFlattening(flattening,
                               W,
                               velInt,
                               pressureIndex,
                               smallPressure,
                               bulkIndex,
                               slopeBox);
    }

  // Intermediate, extrapolated primitive variables
  FArrayBox WMinus[SpaceDim];
  FArrayBox WPlus [SpaceDim];

  // Initial fluxes
  FArrayBox WHalf1[SpaceDim];

  // Source term computed from current state
  FArrayBox localSource;

  // If the source term is valid, make a local copy, increment it, and scale
  // it by 1/2 the timestep
  if (!a_S.box().isEmpty())
    {
      localSource.define(a_S.box(), a_S.nComp());
      localSource.copy(a_S);

      m_gdnvPhysics->incrementSource(localSource,W,slopeBox);

      localSource *= 0.5 * a_dt;
    }

  // Compute initial fluxes
  for (int dir1 = 0; dir1 < SpaceDim; dir1++)
    {
      // Size the intermediate, extrapolated primitive variables
      WMinus[dir1].resize(slopeBox,numPrim); // cell-centered
      WPlus [dir1].resize(slopeBox,numPrim); // cell-centered

      // Compute predictor step to obtain extrapolated primitive variables
      if (m_normalPredOrder == 0)
        {
          CTUNormalPred(WMinus[dir1],WPlus[dir1],a_dt,m_dx,W,
                        flattening,dir1,slopeBox);
        }
      else if (m_normalPredOrder == 1)
        {
          PLMNormalPred(WMinus[dir1],WPlus[dir1],a_dt,m_dx,W,
                        flattening,dir1,slopeBox);
        }
      else if (m_normalPredOrder == 2)
        {
          PPMNormalPred(WMinus[dir1],WPlus[dir1],a_dt,m_dx,W,
                        flattening,dir1,slopeBox);
        }
      else
        {
          MayDay::Error("PatchGodunov::computeWHalf: Normal predictor order must be 1 (PLM) or 2 (PPM)");
        }

      // If the source term is valid add it to the primitive quantities
      if (!localSource.box().isEmpty())
        {
          WMinus[dir1] += localSource;
          WPlus [dir1] += localSource;
        }

      // Solve the Riemann problem
      WHalf1[dir1].resize(fluxBox[dir1],numPrim); // face-centered
      m_gdnvPhysics->riemann(WHalf1[dir1],WPlus[dir1],WMinus[dir1],W,
                             m_currentTime,dir1,faceBox[dir1]);
    }

#if (CH_SPACEDIM == 3)
  // In 3D, compute some additional intermediate fluxes
  //
  // NOTE:  The diagonal entries of this array of fluxes are not
  // used and will not be defined.
  FArrayBox WHalf2[SpaceDim][SpaceDim];

  // Compute the intermediate, corrected fluxes in each direction
  for (int dir1 = 0; dir1 < SpaceDim; dir1++)
    {
      // Correct fluxes using fluxes from a different direction
      for (int dir2 = 0; dir2 < SpaceDim; dir2++)
        {
          // A different direction has been found
          if (dir2 != dir1)
            {
              // Temporary primitive variables
              FArrayBox WTempMinus(WMinus[dir1].box(),numPrim);
              FArrayBox WTempPlus (WPlus [dir1].box(),numPrim);
              FArrayBox AdWdx(WPlus[dir1].box(),numPrim);

              // preventing uninitialized memory reads which cause
              // FPE's on some machines
              // AdWdx.setVal(666.666);

              // Copy data for in place modification
              WTempMinus.copy(WMinus[dir1]);
              WTempPlus .copy(WPlus [dir1]);

              // Update the current, extrapolated primitive variable using a flux
              // in a different direction

              m_gdnvPhysics->quasilinearUpdate(AdWdx,
                                               WHalf1[dir2],
                                               WTempMinus,
                                               -(1.0/3.0) * a_dt / m_dx,
                                               dir2,
                                               ccBox[dir2]);
              WTempMinus += AdWdx;

              m_gdnvPhysics->quasilinearUpdate(AdWdx,
                                               WHalf1[dir2],
                                               WTempPlus,
                                               -(1.0/3.0) * a_dt / m_dx,
                                               dir2,
                                               ccBox[dir2]);
              WTempPlus  += AdWdx;

        // Solve the Riemann problem.

        WHalf2[dir1][dir2].resize(fluxBox[dir1],numPrim);
        m_gdnvPhysics->riemann(WHalf2[dir1][dir2],
                               WTempPlus,
                               WTempMinus,
                               W,
                               m_currentTime,
                               dir1,
                               faceBox[dir1]);
            }
        }
    }
#endif

  // faceBox and fluxBox are now a bit smaller for the final corrections
  for (int dir1 = 0; dir1 < SpaceDim; ++dir1)
    {
      faceBox[dir1] = curBox;
      faceBox[dir1].grow(dir1,1);
      faceBox[dir1] &= m_domain;
      faceBox[dir1].grow(dir1,-1);
      faceBox[dir1].surroundingNodes(dir1);

      fluxBox[dir1] = curBox;
      fluxBox[dir1].surroundingNodes(dir1);
    }

  // Do the final corrections to the fluxes
  for (int dir1 = 0; dir1 < SpaceDim; dir1++)
    {
      // Correct the flux using fluxes in the remaining direction(s)
      for (int dir2 = 0; dir2 < SpaceDim; dir2++)
        {
          // A different direction has been found
          if (dir2 != dir1)
            {
#if (CH_SPACEDIM == 2)
              // In 2D, the current primitive state is updated by a flux in
              // the other direction
              FArrayBox AdWdx(WPlus[dir1].box(),numPrim);

              m_gdnvPhysics->quasilinearUpdate(AdWdx,
                                               WHalf1[dir2],
                                               WMinus[dir1],
                                               -(1.0/2.0) * a_dt / m_dx,
                                               dir2,
                                               ccBox[dir2]);
              WMinus[dir1] += AdWdx;

              m_gdnvPhysics->quasilinearUpdate(AdWdx,
                                               WHalf1[dir2],
                                               WPlus [dir1],
                                               -(1.0/2.0) * a_dt / m_dx,
                                               dir2,
                                               ccBox[dir2]);
              WPlus[dir1] += AdWdx;

#elif (CH_SPACEDIM == 3)
              // In 3D, find a direction different from the two above
              int dir3 = 3 - dir1 - dir2;

              // Update the conservative state using both corrected fluxes in
              // the other two directions
              FArrayBox AdWdx(WPlus[dir1].box(),numPrim);

              m_gdnvPhysics->quasilinearUpdate(AdWdx,
                                               WHalf2[dir2][dir3],
                                               WMinus[dir1],
                                               -(1.0/2.0) * a_dt / m_dx,
                                               dir2,
                                               ccBox[dir2]);
              WMinus[dir1].plus(AdWdx,0,0,numPrim);

              m_gdnvPhysics->quasilinearUpdate(AdWdx,
                                               WHalf2[dir2][dir3],
                                               WPlus [dir1],
                                               -(1.0/2.0) * a_dt / m_dx,
                                               dir2,
                                               ccBox[dir2]);
              WPlus [dir1].plus(AdWdx,0,0,numPrim);
#else
              // Only 2D and 3D should be possible
              MayDay::Error("PatchGodunov::computeWHalf: CH_SPACEDIM not 2 or 3!");
#endif
            }
        }

      // Solve the Riemann problem to obtain time-centered face values.
      // be returned
      FArrayBox& WHalf = a_WHalf[dir1];
      m_gdnvPhysics->riemann(WHalf,
                             WPlus[dir1],
                             WMinus[dir1],
                             W,
                             m_currentTime,
                             dir1,
                             faceBox[dir1]);
    }
}