예제 #1
0
void NewPoissonOp::axby( FArrayBox& a_lhs, const FArrayBox& a_x,
                         const FArrayBox& a_y, Real a_a, Real a_b)
{
  a_lhs.copy(a_x);
  a_lhs*=a_a;
  a_lhs.plus(a_y, a_b);
}
예제 #2
0
void PatchGodunov::CTUNormalPred(FArrayBox&       a_WMinus,
                                 FArrayBox&       a_WPlus,
                                 const Real&      a_dt,
                                 const Real&      a_dx,
                                 const FArrayBox& a_W,
                                 const FArrayBox& a_flat,
                                 const int&       a_dir,
                                 const Box&       a_box)
{
  // for CTU, increments are 0 -- straight copy from cells to faces
  a_WMinus.copy(a_W);
  a_WPlus.copy(a_W);

  // Apply a physics-dependent post-normal predictor step:
  // For example:
  //   - adjust/bound delta's so constraints on extrapolated primitive
  //     quantities are enforced (density and pressure > 0).
  //   - compute source terms that depend on the spatially varying
  //     coefficients.
  m_gdnvPhysics->postNormalPred(a_WMinus,a_WPlus,a_W,a_dt,a_dx,a_dir,a_box);
}
예제 #3
0
// this preconditioner first initializes phihat to (IA)phihat = rhshat
// (diagonization of L -- A is the matrix version of L)
// then smooths with a couple of passes of levelGSRB
void NewPoissonOp::preCond(   FArrayBox& a_phi, const FArrayBox& a_rhs)
{
    // diagonal term of this operator is 4/h/h in 2D, 6/h/h in 3D,
  // so inverse of this is our initial multiplier
  Real mult = -m_dx[0]*m_dx[0]/(2.0*SpaceDim);
  Interval comps = a_phi.interval();
  CH_assert(a_phi.nComp() == a_rhs.nComp());

  a_phi.copy(a_rhs.box(), comps,
             a_rhs.box(), a_rhs,
             comps);

  a_phi *= mult;

  relax(a_phi, a_rhs, 2);
}
예제 #4
0
void NewPoissonOp::assign(    FArrayBox& a_lhs, const FArrayBox& a_rhs)
{
  a_lhs.copy(a_rhs);
}
예제 #5
0
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
}
예제 #6
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]);
    }
}