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); }
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); }
// 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); }
void NewPoissonOp::assign( FArrayBox& a_lhs, const FArrayBox& a_rhs) { a_lhs.copy(a_rhs); }
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 }
// 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]); } }