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)); }
// 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]); } }