/* ********************************************************************* */ void Boundary (const Data *d, int idim, Grid *grid) /*! * Set boundary conditions on one or more sides of the computational * domain. * * \param [in,out] d pointer to PLUTO Data structure containing the * solution array (including centered and staggered * fields) * \param [in] idim specifies on which side(s) of the computational * domain boundary conditions must be set. Possible values * are * - idim = IDIR first dimension (x1) * - idim = JDIR second dimenson (x2) * - idim = KDIR third dimension (x3) * - idim = ALL_DIR all dimensions * * \param [in] grid pointer to an array of grid structures. ******************************************************************* */ { int is, nv, fargo_velocity_has_changed; int side[6] = {X1_BEG, X1_END, X2_BEG, X2_END, X3_BEG, X3_END}; int type[6], sbeg, send, vsign[NVAR]; int par_dim[3] = {0, 0, 0}; static int first_call = 1; double ***q; static RBox center[8], x1face[8], x2face[8], x3face[8]; /* ----------------------------------------------------- Set the boundary boxes on the six domain sides ----------------------------------------------------- */ #ifndef CH_SPACEDIM if (first_call){ SetRBox(center, x1face, x2face, x3face); first_call = 0; } #else /* -- with dynamic grids we need to re-define the RBox at each time -- */ SetRBox(center, x1face, x2face, x3face); #endif /* --------------------------------------------------- Check the number of processors in each direction --------------------------------------------------- */ D_EXPAND(par_dim[0] = grid[IDIR].nproc > 1; ,
// Advance the solution by "a_dt" by using an unsplit method. // "a_finerFluxRegister" is the flux register with the next finer level. // "a_coarseFluxRegister" is flux register with the next coarser level. // If source terms do not exist, "a_S" should be null constructed and not // defined (i.e. its define() should not be called). Real LevelPluto::step(LevelData<FArrayBox>& a_U, LevelData<FArrayBox> a_flux[CH_SPACEDIM], LevelFluxRegister& a_finerFluxRegister, LevelFluxRegister& a_coarserFluxRegister, LevelData<FArrayBox>& a_split_tags, const LevelData<FArrayBox>& a_UCoarseOld, const Real& a_TCoarseOld, const LevelData<FArrayBox>& a_UCoarseNew, const Real& a_TCoarseNew, const Real& a_time, const Real& a_dt, const Real& a_cfl) { CH_TIMERS("LevelPluto::step"); CH_TIMER("LevelPluto::step::setup" ,timeSetup); CH_TIMER("LevelPluto::step::update" ,timeUpdate); CH_TIMER("LevelPluto::step::reflux" ,timeReflux); CH_TIMER("LevelPluto::step::conclude",timeConclude); // Make sure everything is defined CH_assert(m_isDefined); CH_START(timeSetup); // Clear flux registers with next finer level if (m_hasFiner && (g_intStage == 1)) { a_finerFluxRegister.setToZero(); } // Setup an interval corresponding to the conserved variables Interval UInterval(0,m_numCons-1); { CH_TIME("setup::localU"); for (DataIterator dit = m_U.dataIterator(); dit.ok(); ++dit) { m_U[dit].setVal(0.0); // Gets rid of denormalized crap. m_U[dit].copy(a_U[dit]); } m_U.exchange(m_exchangeCopier); } // Fill m_U's ghost cells using fillInterp if (m_hasCoarser) { // Fraction "a_time" falls between the old and the new coarse times Real alpha = (a_time - a_TCoarseOld) / (a_TCoarseNew - a_TCoarseOld); // Truncate the fraction to the range [0,1] to remove floating-point // subtraction roundoff effects Real eps = 0.04 * a_dt / m_refineCoarse; if (Abs(alpha) < eps) alpha = 0.0; if (Abs(1.0-alpha) < eps) alpha = 1.0; // Current time before old coarse time if (alpha < 0.0) { MayDay::Error( "LevelPluto::step: alpha < 0.0"); } // Current time after new coarse time if (alpha > 1.0) { MayDay::Error( "LevelPluto::step: alpha > 1.0"); } // Interpolate ghost cells from next coarser level using both space // and time interpolation m_patcher.fillInterp(m_U, a_UCoarseOld, a_UCoarseNew, alpha, 0,0,m_numCons); } // Potentially used in boundary conditions m_patchPluto->setCurrentTime(a_time); // Use to restrict maximum wave speed away from zero Real maxWaveSpeed = 1.e-12; Real minDtCool = 1.e38; // The grid structure Grid *grid; static Time_Step Dts; Real inv_dt; #ifdef GLM_MHD glm_ch = g_coeff_dl_min*m_dx/(a_dt + 1.e-16)*a_cfl; // glm_ch = g_coeff_dl_min/(a_dt + 1.e-16)*a_cfl; /* If subcycling is turned off */ glm_ch = MIN(glm_ch,glm_ch_max*g_coeff_dl_min); #endif CH_STOP(timeSetup); g_level_dx = m_dx; // Beginning of loop through patches/grids. for (DataIterator dit = m_grids.dataIterator(); dit.ok(); ++dit){ CH_START(timeUpdate); // The current box Box curBox = m_grids.get(dit()); // The current grid of conserved variables FArrayBox& curU = m_U[dit]; // The current grid of volumes #if GEOMETRY != CARTESIAN const FArrayBox& curdV = m_dV[dit()]; #else const FArrayBox curdV; #endif #ifdef SKIP_SPLIT_CELLS // The current grid of split/unsplit tags FArrayBox& split_tags = a_split_tags[dit]; #else FArrayBox split_tags; #endif #if (TIME_STEPPING == RK2) // The current storage for flags (RK2 only) BaseFab<unsigned char>& flags = m_Flags[dit]; // Local temporary storage for conserved variables FArrayBox& curUtmp = m_Utmp[dit]; #else BaseFab<unsigned char> flags; FArrayBox curUtmp; #endif // The fluxes computed for this grid - used for refluxing and returning // other face centered quantities FluxBox flux; // Set the current box for the patch integrator m_patchPluto->setCurrentBox(curBox); Real minDtCoolGrid; grid = m_structs_grid[dit].getGrid(); IBEG = grid[IDIR].lbeg; IEND = grid[IDIR].lend; JBEG = grid[JDIR].lbeg; JEND = grid[JDIR].lend; KBEG = grid[KDIR].lbeg; KEND = grid[KDIR].lend; NX1 = grid[IDIR].np_int; NX2 = grid[JDIR].np_int; NX3 = grid[KDIR].np_int; NX1_TOT = grid[IDIR].np_tot; NX2_TOT = grid[JDIR].np_tot; NX3_TOT = grid[KDIR].np_tot; SetRBox(); /* RBox structures must be redefined for each patch */ g_dt = a_dt; g_time = a_time; g_maxRiemannIter = 0; PLM_CoefficientsSet (grid); /* -- these may be needed by shock flattening algorithms */ #if RECONSTRUCTION == PARABOLIC PPM_CoefficientsSet (grid); #endif // reset time step coefficients if (Dts.cmax == NULL) Dts.cmax = ARRAY_1D(NMAX_POINT, double); int id; Dts.inv_dta = 1.e-18; Dts.inv_dtp = 1.e-18; Dts.dt_cool = 1.e18; Dts.cfl = a_cfl; Where(-1, grid); /* -- store grid for subsequent calls -- */ // Take one step m_patchPluto->advanceStep (curU, curUtmp, curdV, split_tags, flags, flux, &Dts, curBox, grid); inv_dt = Dts.inv_dta + 2.0*Dts.inv_dtp; maxWaveSpeed = Max(maxWaveSpeed, inv_dt); // Now the inverse of the timestep minDtCool = Min(minDtCool, Dts.dt_cool/a_cfl); CH_STOP(timeUpdate); CH_START(timeReflux); // Do flux register updates for (int idir = 0; idir < SpaceDim; idir++) { // Increment coarse flux register between this level and the next // finer level - this level is the next coarser level with respect // to the next finer level if (m_hasFiner) { a_finerFluxRegister.incrementCoarse(flux[idir],a_dt,dit(), UInterval, UInterval,idir); } // Increment fine flux registers between this level and the next // coarser level - this level is the next finer level with respect // to the next coarser level if (m_hasCoarser) { a_coarserFluxRegister.incrementFine(flux[idir],a_dt,dit(), UInterval, UInterval,idir); } } CH_STOP(timeReflux); } CH_START(timeConclude); { CH_TIME("conclude::copyU"); // Now that we have completed the updates of all the patches, we copy the // contents of temporary storage, U, into the permanent storage, a_U. for(DataIterator dit = m_U.dataIterator(); dit.ok(); ++dit){ a_U[dit].copy(m_U[dit]); } } // Find the minimum of dt's over this level Real local_dtNew = 1. / maxWaveSpeed; local_dtNew = Min(local_dtNew,minDtCool); Real dtNew; { CH_TIME("conclude::getDt"); #ifdef CH_MPI #if (TIME_STEPPING == RK2) && (COOLING == NO) if (g_intStage == 1) { #endif int result = MPI_Allreduce(&local_dtNew, &dtNew, 1, MPI_CH_REAL, MPI_MIN, Chombo_MPI::comm); if(result != MPI_SUCCESS){ //bark!!! MayDay::Error("sorry, but I had a communcation error on new dt"); } #if (TIME_STEPPING == RK2) && (COOLING == NO) } else { dtNew = local_dtNew; } #endif #else dtNew = local_dtNew; #endif } CH_STOP(timeConclude); // Return the maximum stable time step return dtNew; }