ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF Class Reference

#include <ERF.H>

Inheritance diagram for ERF:
Collaboration diagram for ERF:

Public Member Functions

 ERF ()
 
 ~ERF () override
 
void ERF_shared ()
 
 ERF (ERF &&) noexcept=delete
 
ERFoperator= (ERF &&other) noexcept=delete
 
 ERF (const ERF &other)=delete
 
ERFoperator= (const ERF &other)=delete
 
void Evolve ()
 
amrex::Real EvolveOneStep (amrex::Real time, amrex::Real dt_request)
 
void PackAtmosphericStates (amrex::Vector< amrex::MultiFab * > &states, amrex::Real time)
 
void ApplyOceanSurfaceState (const amrex::Vector< amrex::MultiFab * > &state, amrex::Real time)
 
void ErrorEst (int lev, amrex::TagBoxArray &tags, amrex::Real time, int ngrow) override
 
void HurricaneTracker (int lev, amrex::Real time, const amrex::MultiFab &cc_vel, const amrex::Real velmag_threshold, amrex::TagBoxArray *tags=nullptr)
 
bool FindInitialEye (int lev, const amrex::MultiFab &cc_vel, const amrex::Real velmag_threshold, amrex::Real &eye_x, amrex::Real &eye_y)
 
std::string MakeVTKFilename (int nstep)
 
std::string MakeVTKFilename_TrackerCircle (int nstep)
 
std::string MakeVTKFilename_EyeTracker_xy (int nstep)
 
std::string MakeFilename_EyeTracker_latlon (int nstep)
 
std::string MakeFilename_EyeTracker_maxvel (int nstep)
 
std::string MakeFilename_EyeTracker_minpressure (int nstep)
 
void WriteVTKPolyline (const std::string &filename, amrex::Vector< std::array< amrex::Real, 2 >> &points_xy)
 
void WriteLinePlot (const std::string &filename, amrex::Vector< std::array< amrex::Real, 2 >> &points_xy)
 
void InitData ()
 
void InitData_pre ()
 
void InitData_post ()
 
void Interp2DArrays (int lev, const amrex::BoxArray &my_ba2d, const amrex::DistributionMapping &my_dm)
 
void WriteMyEBSurface ()
 
void compute_divergence (int lev, amrex::MultiFab &rhs, amrex::Array< amrex::MultiFab const *, AMREX_SPACEDIM > rho0_u_const, amrex::Geometry const &geom_at_lev)
 
void project_initial_velocity (int lev, amrex::Real time, amrex::Real dt)
 
void project_momenta (int lev, amrex::Real l_time, amrex::Real l_dt, amrex::Vector< amrex::MultiFab > &vars)
 
void project_velocity_tb (int lev, amrex::Real dt, amrex::Vector< amrex::MultiFab > &vars)
 
void poisson_wall_dist (int lev)
 
void make_subdomains (const amrex::BoxList &ba, amrex::Vector< amrex::BoxArray > &bins)
 
void solve_with_gmres (int lev, const amrex::Box &subdomain, amrex::MultiFab &rhs, amrex::MultiFab &p, amrex::Array< amrex::MultiFab, AMREX_SPACEDIM > &fluxes, amrex::MultiFab &ax_sub, amrex::MultiFab &ay_sub, amrex::MultiFab &az_sub, amrex::MultiFab &, amrex::MultiFab &znd_sub)
 
void ImposeBCsOnPhi (int lev, amrex::MultiFab &phi, const amrex::Box &subdomain)
 
void init_only (int lev, amrex::Real time)
 
void restart ()
 
void check_state_for_nans (amrex::MultiFab const &S)
 
void check_vels_for_nans (amrex::MultiFab const &xvel, amrex::MultiFab const &yvel, amrex::MultiFab const &zvel)
 
void check_for_negative_theta (amrex::MultiFab &S)
 
void check_for_low_temp (amrex::MultiFab &S)
 
void compute_max_pressure_gradient_diagnostic (int lev)
 
bool writeNow (double cur_time, const int nstep, const int plot_int, const amrex::Real plot_per, const amrex::Real dt_0, amrex::Real &last_file_time)
 
void post_timestep (int nstep, double time, amrex::Real dt_lev)
 
void sum_integrated_quantities (double time)
 
void sum_derived_quantities (double time)
 
void sum_energy_quantities (double time)
 
void write_1D_profiles (double time)
 
void write_1D_profiles_stag (double time)
 
amrex::Real cloud_fraction (double time)
 
void FillBdyCCVels (amrex::MultiFab &mf_cc_vel, amrex::Geometry &lev_geom)
 
void sample_points (int lev, amrex::Real time, amrex::IntVect cell, amrex::MultiFab &mf)
 
void sample_lines (int lev, amrex::Real time, amrex::IntVect cell, amrex::MultiFab &mf)
 
void derive_diag_profiles (double time, amrex::Gpu::HostVector< amrex::Real > &h_avg_u, amrex::Gpu::HostVector< amrex::Real > &h_avg_v, amrex::Gpu::HostVector< amrex::Real > &h_avg_w, amrex::Gpu::HostVector< amrex::Real > &h_avg_rho, amrex::Gpu::HostVector< amrex::Real > &h_avg_th, amrex::Gpu::HostVector< amrex::Real > &h_avg_ksgs, amrex::Gpu::HostVector< amrex::Real > &h_avg_Kmv, amrex::Gpu::HostVector< amrex::Real > &h_avg_Khv, amrex::Gpu::HostVector< amrex::Real > &h_avg_qv, amrex::Gpu::HostVector< amrex::Real > &h_avg_qc, amrex::Gpu::HostVector< amrex::Real > &h_avg_qr, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqv, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqc, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqr, amrex::Gpu::HostVector< amrex::Real > &h_avg_qi, amrex::Gpu::HostVector< amrex::Real > &h_avg_qs, amrex::Gpu::HostVector< amrex::Real > &h_avg_qg, amrex::Gpu::HostVector< amrex::Real > &h_avg_uu, amrex::Gpu::HostVector< amrex::Real > &h_avg_uv, amrex::Gpu::HostVector< amrex::Real > &h_avg_uw, amrex::Gpu::HostVector< amrex::Real > &h_avg_vv, amrex::Gpu::HostVector< amrex::Real > &h_avg_vw, amrex::Gpu::HostVector< amrex::Real > &h_avg_ww, amrex::Gpu::HostVector< amrex::Real > &h_avg_uth, amrex::Gpu::HostVector< amrex::Real > &h_avg_vth, amrex::Gpu::HostVector< amrex::Real > &h_avg_wth, amrex::Gpu::HostVector< amrex::Real > &h_avg_thth, amrex::Gpu::HostVector< amrex::Real > &h_avg_ku, amrex::Gpu::HostVector< amrex::Real > &h_avg_kv, amrex::Gpu::HostVector< amrex::Real > &h_avg_kw, amrex::Gpu::HostVector< amrex::Real > &h_avg_p, amrex::Gpu::HostVector< amrex::Real > &h_avg_pu, amrex::Gpu::HostVector< amrex::Real > &h_avg_pv, amrex::Gpu::HostVector< amrex::Real > &h_avg_pw, amrex::Gpu::HostVector< amrex::Real > &h_avg_wthv)
 
void derive_diag_profiles_stag (double time, amrex::Gpu::HostVector< amrex::Real > &h_avg_u, amrex::Gpu::HostVector< amrex::Real > &h_avg_v, amrex::Gpu::HostVector< amrex::Real > &h_avg_w, amrex::Gpu::HostVector< amrex::Real > &h_avg_rho, amrex::Gpu::HostVector< amrex::Real > &h_avg_th, amrex::Gpu::HostVector< amrex::Real > &h_avg_ksgs, amrex::Gpu::HostVector< amrex::Real > &h_avg_Kmv, amrex::Gpu::HostVector< amrex::Real > &h_avg_Khv, amrex::Gpu::HostVector< amrex::Real > &h_avg_qv, amrex::Gpu::HostVector< amrex::Real > &h_avg_qc, amrex::Gpu::HostVector< amrex::Real > &h_avg_qr, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqv, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqc, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqr, amrex::Gpu::HostVector< amrex::Real > &h_avg_qi, amrex::Gpu::HostVector< amrex::Real > &h_avg_qs, amrex::Gpu::HostVector< amrex::Real > &h_avg_qg, amrex::Gpu::HostVector< amrex::Real > &h_avg_uu, amrex::Gpu::HostVector< amrex::Real > &h_avg_uv, amrex::Gpu::HostVector< amrex::Real > &h_avg_uw, amrex::Gpu::HostVector< amrex::Real > &h_avg_vv, amrex::Gpu::HostVector< amrex::Real > &h_avg_vw, amrex::Gpu::HostVector< amrex::Real > &h_avg_ww, amrex::Gpu::HostVector< amrex::Real > &h_avg_uth, amrex::Gpu::HostVector< amrex::Real > &h_avg_vth, amrex::Gpu::HostVector< amrex::Real > &h_avg_wth, amrex::Gpu::HostVector< amrex::Real > &h_avg_thth, amrex::Gpu::HostVector< amrex::Real > &h_avg_ku, amrex::Gpu::HostVector< amrex::Real > &h_avg_kv, amrex::Gpu::HostVector< amrex::Real > &h_avg_kw, amrex::Gpu::HostVector< amrex::Real > &h_avg_p, amrex::Gpu::HostVector< amrex::Real > &h_avg_pu, amrex::Gpu::HostVector< amrex::Real > &h_avg_pv, amrex::Gpu::HostVector< amrex::Real > &h_avg_pw, amrex::Gpu::HostVector< amrex::Real > &h_avg_wthv)
 
void derive_stress_profiles (amrex::Gpu::HostVector< amrex::Real > &h_avg_tau11, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau12, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau13, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau22, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau23, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau33, amrex::Gpu::HostVector< amrex::Real > &h_avg_hfx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_q1fx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_q2fx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_diss)
 
void derive_stress_profiles_stag (amrex::Gpu::HostVector< amrex::Real > &h_avg_tau11, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau12, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau13, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau22, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau23, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau33, amrex::Gpu::HostVector< amrex::Real > &h_avg_hfx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_q1fx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_q2fx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_diss)
 
amrex::Real volWgtSumMF (int lev, const amrex::MultiFab &mf, int comp, const amrex::MultiFab &dJ, const amrex::MultiFab &mfx, const amrex::MultiFab &mfy, bool finemask, bool local=true)
 
void volWgtColumnSum (int lev, const amrex::MultiFab &mf, int comp, amrex::MultiFab &mf_2d, const amrex::MultiFab &dJ)
 
void MakeNewLevelFromCoarse (int lev, amrex::Real time, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm) override
 
void RemakeLevel (int lev, amrex::Real time, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm) override
 
void ClearLevel (int lev) override
 
void MakeNewLevelFromScratch (int lev, amrex::Real time, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm) override
 
amrex::Real estTimeStep (int lev, long &dt_fast_ratio) const
 
void advance_dycore (int level, amrex::Vector< amrex::MultiFab > &state_old, amrex::Vector< amrex::MultiFab > &state_new, amrex::MultiFab &xvel_old, amrex::MultiFab &yvel_old, amrex::MultiFab &zvel_old, amrex::MultiFab &xvel_new, amrex::MultiFab &yvel_new, amrex::MultiFab &zvel_new, amrex::MultiFab &source, amrex::MultiFab &xmom_src, amrex::MultiFab &ymom_src, amrex::MultiFab &zmom_src, amrex::MultiFab &buoyancy, amrex::Geometry fine_geom, amrex::Real dt, amrex::Real time)
 
void advance_microphysics (int lev, amrex::MultiFab &cons_in, const amrex::Real &dt_advance, const int &iteration, const amrex::Real &time)
 
void advance_lsm (int lev, amrex::MultiFab &cons_in, amrex::MultiFab &xvel_in, amrex::MultiFab &yvel_in, const amrex::Real &time, const amrex::Real &dt_advance)
 
void advance_radiation (int lev, amrex::MultiFab &cons_in, const amrex::Real &dt_advance)
 
void build_fine_mask (int lev, amrex::MultiFab &fine_mask)
 
void MakeHorizontalAverages ()
 
void MakeDiagnosticAverage (amrex::Vector< amrex::Real > &h_havg, amrex::MultiFab &S, int n)
 
void derive_upwp (amrex::Vector< amrex::Real > &h_havg)
 
void Write3DPlotFile (int which, PlotFileType plotfile_type, amrex::Vector< std::string > plot_var_names)
 
void Write2DPlotFile (int which, PlotFileType plotfile_type, amrex::Vector< std::string > plot_var_names)
 
void WriteSubvolume (int isub, amrex::Vector< std::string > subvol_var_names)
 
void WriteMultiLevelPlotfileWithTerrain (const std::string &plotfilename, int nlevels, const amrex::Vector< const amrex::MultiFab * > &mf, const amrex::Vector< const amrex::MultiFab * > &mf_nd, const amrex::Vector< std::string > &varnames, const amrex::Vector< amrex::Geometry > &my_geom, amrex::Real time, const amrex::Vector< int > &level_steps, const amrex::Vector< amrex::IntVect > &my_ref_ratio, const std::string &versionName="HyperCLaw-V1.1", const std::string &levelPrefix="Level_", const std::string &mfPrefix="Cell", const amrex::Vector< std::string > &extra_dirs=amrex::Vector< std::string >()) const
 
void WriteGenericPlotfileHeaderWithTerrain (std::ostream &HeaderFile, int nlevels, const amrex::Vector< amrex::BoxArray > &bArray, const amrex::Vector< std::string > &varnames, const amrex::Vector< amrex::Geometry > &my_geom, amrex::Real time, const amrex::Vector< int > &level_steps, const amrex::Vector< amrex::IntVect > &my_ref_ratio, const std::string &versionName, const std::string &levelPrefix, const std::string &mfPrefix) const
 
void erf_enforce_hse (int lev, amrex::MultiFab &dens, amrex::MultiFab &pres, amrex::MultiFab &pi, amrex::MultiFab &th, amrex::MultiFab &qv, std::unique_ptr< amrex::MultiFab > &z_cc)
 
void init_from_input_sounding (int lev)
 
void init_immersed_forcing (int lev)
 
void input_sponge (int lev)
 
void init_from_hse (int lev)
 
void init_thin_body (int lev, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm)
 
void FillForecastStateMultiFabs (const int lev, const std::string &filename, const std::unique_ptr< amrex::MultiFab > &z_phys_nd, amrex::Vector< amrex::Vector< amrex::MultiFab >> &forecast_state)
 
void FillSurfaceStateMultiFabs (const int lev, const std::string &filename, amrex::Vector< amrex::MultiFab > &surface_state)
 
void WeatherDataInterpolation (const int nlevs, const amrex::Real time, amrex::Vector< std::unique_ptr< amrex::MultiFab >> &z_phys_nd, bool regrid_forces_file_read)
 
void SurfaceDataInterpolation (const int nlevs, const amrex::Real time, amrex::Vector< std::unique_ptr< amrex::MultiFab >> &z_phys_nd, bool regrid_forces_file_read)
 
void create_background_state_for_ensemble (int lev, amrex::MultiFab &mf_cc_pert, amrex::MultiFab &cons_pert, amrex::MultiFab &xvel_pert, amrex::MultiFab &yvel_pert, amrex::MultiFab &zvel_pert)
 
void create_random_perturbations (const int lev, amrex::MultiFab &mf_cc_pert)
 
void apply_gaussian_smoothing_to_perturbations (const int lev, amrex::MultiFab &mf_cc_pert)
 
void ComputeAndWriteEnsemblePerturbations ()
 
void PerformDataAssimilation (int da_iter)
 
void init_custom (int lev)
 
void fill_from_bndryregs (const amrex::Vector< amrex::MultiFab * > &mfs, amrex::Real time)
 
void MakeEBGeometry ()
 
void make_eb_box ()
 
void make_eb_regular ()
 
void AverageDownTo (int crse_lev, int scomp, int ncomp, bool do_perturbational_and_momenta=true)
 
void AverageDownMoistStateTo (int crse_lev)
 Conservation-preserving fine→coarse average of moist state components (RhoTheta and the contiguous moist q range) using detJ/mfac weighting, reusing AverageDownTo with perturbational/momenta handling disabled. More...
 
void WriteCheckpointFile () const
 
void ReadCheckpointFile ()
 
void ReadVelsOnlyFromCheckpointFile (int lev_to_fill, std::string &chkfile)
 
void ReadCheckpointFileSurfaceLayer ()
 
void init_zphys (int lev, amrex::Real elapsed_time)
 
void remake_zphys (int lev, std::unique_ptr< amrex::MultiFab > &temp_zphys_nd)
 
void update_terrain_arrays (int lev)
 
void writeJobInfo (const std::string &dir) const
 

Static Public Member Functions

static bool is_it_time_for_action (int nstep, double time, amrex::Real dt, int action_interval, amrex::Real action_per)
 
static void writeBuildInfo (std::ostream &os)
 
static void print_banner (MPI_Comm, std::ostream &)
 
static void print_usage (MPI_Comm, std::ostream &)
 
static void print_error (MPI_Comm, const std::string &msg)
 
static void print_summary (std::ostream &)
 
static void print_tpls (std::ostream &)
 

Public Attributes

amrex::Vector< std::array< amrex::Real, 2 > > hurricane_track_xy
 
amrex::Vector< std::array< amrex::Real, 2 > > hurricane_eye_track_xy
 
amrex::Vector< std::array< amrex::Real, 2 > > hurricane_eye_track_latlon
 
amrex::Vector< std::array< amrex::Real, 2 > > hurricane_maxvel_vs_time
 
amrex::Vector< std::array< amrex::Real, 2 > > hurricane_minpressure_vs_time
 
amrex::Vector< std::array< amrex::Real, 2 > > hurricane_tracker_circle
 
amrex::Vector< amrex::MultiFab > weather_forecast_data_1
 
amrex::Vector< amrex::MultiFab > weather_forecast_data_2
 
amrex::Vector< amrex::Vector< amrex::MultiFab > > forecast_state_1
 
amrex::Vector< amrex::Vector< amrex::MultiFab > > forecast_state_2
 
amrex::Vector< amrex::Vector< amrex::MultiFab > > forecast_state_interp
 
amrex::Vector< amrex::MultiFab > surface_state_1
 
amrex::Vector< amrex::MultiFab > surface_state_2
 
amrex::Vector< amrex::MultiFab > surface_state_interp
 
amrex::Vector< amrex::Vector< amrex::MultiFab > > bckgnd_state
 
std::string pp_prefix {"erf"}
 

Private Member Functions

void ReadParameters ()
 
void ParameterSanityChecks ()
 
void AverageDown ()
 
void update_diffusive_arrays (int lev, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm)
 
void Construct_ERFFillPatchers (int lev)
 
void Define_ERFFillPatchers (int lev)
 
void init1DArrays ()
 
void init_bcs ()
 
void init_phys_bcs (bool &rho_read, bool &read_prim_theta)
 
void init_stuff (int lev, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm, amrex::Vector< amrex::MultiFab > &lev_new, amrex::Vector< amrex::MultiFab > &lev_old, amrex::MultiFab &tmp_base_state, std::unique_ptr< amrex::MultiFab > &tmp_zphys_nd)
 
void turbPert_update (const int lev, const amrex::Real dt)
 
void turbPert_amplitude (const int lev)
 
void initialize_integrator (int lev, amrex::MultiFab &cons_mf, amrex::MultiFab &vel_mf)
 
void make_physbcs (int lev)
 
void initializeMicrophysics (const int &)
 
void FillPatchCrseLevel (int lev, double time, const amrex::Vector< amrex::MultiFab * > &mfs_vel, bool cons_only=false)
 
void FillPatchFineLevel (int lev, double time, const amrex::Vector< amrex::MultiFab * > &mfs_vel, const amrex::Vector< amrex::MultiFab * > &mfs_mom, const amrex::MultiFab &old_base_state, const amrex::MultiFab &new_base_state, bool fillset=true, bool cons_only=false)
 
void FillIntermediatePatch (int lev, amrex::Real time, const amrex::Vector< amrex::MultiFab * > &mfs_vel, const amrex::Vector< amrex::MultiFab * > &mfs_mom, int ng_cons, int ng_vel, bool cons_only, int icomp_cons, int ncomp_cons)
 
void FillCoarsePatch (int lev, amrex::Real time)
 
void timeStep (int lev, double time, int iteration)
 
void Advance (int lev, amrex::Real time, amrex::Real dt_lev, int iteration, int ncycle)
 
void initHSE ()
 Initialize HSE. More...
 
void initHSE (int lev)
 
void initRayleigh_at_level (const int &lev)
 Initialize Rayleigh damping profiles at a level. More...
 
void initSponge ()
 Initialize sponge profiles. More...
 
void setRayleighRefFromSounding (bool restarting)
 Set Rayleigh mean profiles from input sounding. More...
 
void setSpongeRefFromSounding (bool restarting)
 Set sponge mean profiles from input sounding. More...
 
void ComputeDt (int step=-1, double cur_time_d=0.0)
 
std::string PlotFileName (int lev) const
 
void setPlotVariables (const std::string &pp_plot_var_names, amrex::Vector< std::string > &plot_var_names)
 
void setPlotVariables2D (const std::string &pp_plot_var_names, amrex::Vector< std::string > &plot_var_names)
 
void appendPlotVariables (const std::string &pp_plot_var_names, amrex::Vector< std::string > &plot_var_names)
 
void setSubVolVariables (const std::string &pp_subvol_var_names, amrex::Vector< std::string > &subvol_var_names)
 
void init_Dirichlet_bc_data (const std::string input_file)
 
void InitializeFromFile ()
 
void InitializeLevelFromData (int lev, const amrex::MultiFab &initial_data)
 
void post_update (amrex::MultiFab &state_mf, amrex::Real time, const amrex::Geometry &geom)
 
void fill_rhs (amrex::MultiFab &rhs_mf, const amrex::MultiFab &state_mf, amrex::Real time, const amrex::Geometry &geom)
 
void init_geo_wind_profile (const std::string input_file, amrex::Vector< amrex::Real > &u_geos, amrex::Gpu::DeviceVector< amrex::Real > &u_geos_d, amrex::Vector< amrex::Real > &v_geos, amrex::Gpu::DeviceVector< amrex::Real > &v_geos_d, const amrex::Geometry &lgeom, const amrex::Vector< amrex::Real > &zlev_stag)
 
void refinement_criteria_setup ()
 
AMREX_FORCE_INLINE amrex::YAFluxRegister * getAdvFluxReg (int lev)
 
AMREX_FORCE_INLINE std::ostream & DataLog (int i)
 
AMREX_FORCE_INLINE std::ostream & DerDataLog (int i)
 
AMREX_FORCE_INLINE int NumDataLogs () noexcept
 
AMREX_FORCE_INLINE int NumDerDataLogs () noexcept
 
AMREX_FORCE_INLINE std::ostream & SamplePointLog (int i)
 
AMREX_FORCE_INLINE int NumSamplePointLogs () noexcept
 
AMREX_FORCE_INLINE std::ostream & SampleLineLog (int i)
 
AMREX_FORCE_INLINE int NumSampleLineLogs () noexcept
 
amrex::IntVect & SamplePoint (int i)
 
AMREX_FORCE_INLINE int NumSamplePoints () noexcept
 
amrex::IntVect & SampleLine (int i)
 
AMREX_FORCE_INLINE int NumSampleLines () noexcept
 
void setRecordDataInfo (int i, const std::string &filename)
 
void setRecordDerDataInfo (int i, const std::string &filename)
 
void setRecordEnergyDataInfo (int i, const std::string &filename)
 
void setRecordSamplePointInfo (int i, int lev, amrex::IntVect &cell, const std::string &filename)
 
void setRecordSampleLineInfo (int i, int lev, amrex::IntVect &cell, const std::string &filename)
 
std::string DataLogName (int i) const noexcept
 The filename of the ith datalog file. More...
 
std::string DerDataLogName (int i) const noexcept
 
std::string SamplePointLogName (int i) const noexcept
 The filename of the ith sampleptlog file. More...
 
std::string SampleLineLogName (int i) const noexcept
 The filename of the ith samplelinelog file. More...
 
eb_ const & get_eb (int lev) const noexcept
 
amrex::EBFArrayBoxFactory const & EBFactory (int lev) const noexcept
 

Static Private Member Functions

static amrex::Vector< std::string > PlotFileVarNames (amrex::Vector< std::string > plot_var_names)
 
static void GotoNextLine (std::istream &is)
 
static AMREX_FORCE_INLINE int ComputeGhostCells (const SolverChoice &sc)
 
static amrex::Real getCPUTime ()
 
static int nghost_eb_basic ()
 
static int nghost_eb_volume ()
 
static int nghost_eb_full ()
 

Private Attributes

amrex::Vector< std::unique_ptr< amrex::MultiFab > > lat_m
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > lon_m
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > sinPhi_m
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > cosPhi_m
 
InputSoundingData input_sounding_data
 
InputSpongeData input_sponge_data
 
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > xvel_bc_data
 
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > yvel_bc_data
 
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > zvel_bc_data
 
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > th_bc_data
 
std::unique_ptr< ProblemBaseprob = nullptr
 
amrex::Vector< int > num_boxes_at_level
 
amrex::Vector< int > num_files_at_level
 
amrex::Vector< amrex::Vector< amrex::Box > > boxes_at_level
 
amrex::Vector< int > istep
 
amrex::Vector< int > nsubsteps
 
amrex::Vector< amrex::Realt_new
 
amrex::Vector< amrex::Realt_old
 
amrex::Vector< amrex::Realdt
 
amrex::Vector< long > dt_mri_ratio
 
amrex::Vector< amrex::Vector< amrex::MultiFab > > vars_new
 
amrex::Vector< amrex::Vector< amrex::MultiFab > > vars_old
 
amrex::Vector< amrex::Vector< amrex::MultiFab > > gradp
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vel_t_avg
 
amrex::Vector< amrex::Realt_avg_cnt
 
amrex::Vector< std::unique_ptr< MRISplitIntegrator< amrex::Vector< amrex::MultiFab > > > > mri_integrator_mem
 
amrex::Vector< amrex::MultiFab > pp_inc
 
amrex::Vector< amrex::MultiFab > lagged_delta_rt
 
amrex::Vector< amrex::MultiFab > avg_xmom
 
amrex::Vector< amrex::MultiFab > avg_ymom
 
amrex::Vector< amrex::MultiFab > avg_zmom
 
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_cons > > physbcs_cons
 
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_u > > physbcs_u
 
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_v > > physbcs_v
 
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_w > > physbcs_w
 
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_base > > physbcs_base
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Theta_prim
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Qv_prim
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Qr_prim
 
amrex::Vector< amrex::MultiFab > rU_old
 
amrex::Vector< amrex::MultiFab > rU_new
 
amrex::Vector< amrex::MultiFab > rV_old
 
amrex::Vector< amrex::MultiFab > rV_new
 
amrex::Vector< amrex::MultiFab > rW_old
 
amrex::Vector< amrex::MultiFab > rW_new
 
amrex::Vector< amrex::MultiFab > zmom_crse_rhs
 
std::unique_ptr< Microphysicsmicro
 
amrex::Vector< amrex::Vector< amrex::MultiFab * > > qmoist
 
LandSurface lsm
 
amrex::Vector< std::string > lsm_data_name
 
amrex::Vector< amrex::Vector< amrex::MultiFab * > > lsm_data
 
amrex::Vector< std::string > lsm_flux_name
 
amrex::Vector< amrex::Vector< amrex::MultiFab * > > lsm_flux
 
amrex::Vector< std::unique_ptr< IRadiation > > rad
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > qheating_rates
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > rad_fluxes
 
bool plot_rad = false
 
int rad_datalog_int = -1
 
int cf_width {0}
 
int cf_set_width {0}
 
amrex::Vector< ERFFillPatcherFPr_c
 
amrex::Vector< ERFFillPatcherFPr_u
 
amrex::Vector< ERFFillPatcherFPr_v
 
amrex::Vector< ERFFillPatcherFPr_w
 
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > Tau
 
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > Tau_corr
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > eddyDiffs_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SmnSmn_lev
 
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > sst_lev
 
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > tsk_lev
 
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::iMultiFab > > > lmask_lev
 
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::iMultiFab > > > land_type_lev
 
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::iMultiFab > > > soil_type_lev
 
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > urb_frac_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_hfx1_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_hfx2_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_hfx3_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_diss_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q1fx1_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q1fx2_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q1fx3_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q2fx3_lev
 
amrex::Vector< amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > > Tau_EB
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > hfx3_EB
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > qfx3_EB
 
amrex::Vector< amrex::Vector< amrex::Real > > zlevels_stag
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_nd
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_cc
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > detJ_cc
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ax
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ay
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > az
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_nd_src
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_cc_src
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > detJ_cc_src
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ax_src
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ay_src
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > az_src
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_nd_new
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > detJ_cc_new
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_t_rk
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > terrain_blanking
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > walldist
 
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > mapfac
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > fine_mask
 
amrex::Vector< amrex::Vector< amrex::Real > > stretched_dz_h
 
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > stretched_dz_d
 
amrex::Vector< amrex::MultiFab > base_state
 
amrex::Vector< amrex::MultiFab > base_state_new
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Hwave
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Lwave
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Hwave_onegrid
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Lwave_onegrid
 
bool finished_wave = false
 
amrex::Vector< amrex::YAFluxRegister * > advflux_reg
 
amrex::Vector< amrex::BCRec > domain_bcs_type
 
amrex::Gpu::DeviceVector< amrex::BCRec > domain_bcs_type_d
 
amrex::Array< std::string, 2 *AMREX_SPACEDIM > domain_bc_type
 
amrex::Array< amrex::Array< amrex::Real, AMREX_SPACEDIM *2 >, AMREX_SPACEDIM+NBCVAR_maxm_bc_extdir_vals
 
amrex::Array< amrex::Array< amrex::Real, AMREX_SPACEDIM *2 >, AMREX_SPACEDIM+NBCVAR_maxm_bc_neumann_vals
 
amrex::Array< bool, AMREX_SPACEDIM *2 > m_bc_nonreflecting = {{false}}
 
amrex::GpuArray< ERF_BC, AMREX_SPACEDIM *2 > phys_bc_type
 
amrex::Vector< std::unique_ptr< amrex::iMultiFab > > xflux_imask
 
amrex::Vector< std::unique_ptr< amrex::iMultiFab > > yflux_imask
 
amrex::Vector< std::unique_ptr< amrex::iMultiFab > > zflux_imask
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > thin_xforce
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > thin_yforce
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > thin_zforce
 
amrex::Vector< int > last_subvol_step
 
amrex::Vector< amrex::Reallast_subvol_time
 
const int datwidth = 14
 
const int datprecision = 6
 
const int timeprecision = 13
 
int max_step = -1
 
bool use_datetime = false
 
const std::string datetime_format = "%Y-%m-%d %H:%M:%S"
 
std::string restart_chkfile = ""
 
amrex::Vector< amrex::Realfixed_dt
 
amrex::Vector< amrex::Realfixed_fast_dt
 
int regrid_int = -1
 
bool regrid_level_0_on_restart = false
 
std::string plot3d_file_1 {"plt_1_"}
 
std::string plot3d_file_2 {"plt_2_"}
 
std::string plot2d_file_1 {"plt2d_1_"}
 
std::string plot2d_file_2 {"plt2d_2_"}
 
std::string subvol_file {"subvol"}
 
bool m_expand_plotvars_to_unif_rr = false
 
int m_plot3d_int_1 = -1
 
int m_plot3d_int_2 = -1
 
int m_plot2d_int_1 = -1
 
int m_plot2d_int_2 = -1
 
amrex::Vector< int > m_subvol_int
 
amrex::Vector< amrex::Realm_subvol_per
 
amrex::Real m_plot3d_per_1 = -one
 
amrex::Real m_plot3d_per_2 = -one
 
amrex::Real m_plot2d_per_1 = -one
 
amrex::Real m_plot2d_per_2 = -one
 
bool m_plot_face_vels = false
 
bool plot_lsm = false
 
int profile_int = -1
 
bool destag_profiles = true
 
std::string check_file {"chk"}
 
int m_check_int = -1
 
amrex::Real m_check_per = -one
 
amrex::Vector< std::string > subvol3d_var_names
 
amrex::Vector< std::string > plot3d_var_names_1
 
amrex::Vector< std::string > plot3d_var_names_2
 
amrex::Vector< std::string > plot2d_var_names_1
 
amrex::Vector< std::string > plot2d_var_names_2
 
const amrex::Vector< std::string > cons_names
 
const amrex::Vector< std::string > derived_names
 
const amrex::Vector< std::string > derived_names_2d
 
const amrex::Vector< std::string > derived_subvol_names {"soundspeed", "temp", "theta", "KE", "scalar"}
 
TurbulentPerturbation turbPert
 
int file_name_digits = 5
 
bool use_real_time_in_pltname = false
 
int real_width {0}
 
bool real_extrap_w {true}
 
bool metgrid_debug_quiescent {false}
 
bool metgrid_debug_isothermal {false}
 
bool metgrid_debug_dry {false}
 
bool metgrid_debug_psfc {false}
 
bool metgrid_debug_msf {false}
 
bool metgrid_interp_theta {false}
 
bool metgrid_basic_linear {false}
 
bool metgrid_use_below_sfc {true}
 
bool metgrid_use_sfc {true}
 
bool metgrid_retain_sfc {false}
 
amrex::Real metgrid_proximity {amrex::Real(500.0)}
 
int metgrid_order {2}
 
int metgrid_force_sfc_k {6}
 
amrex::Vector< amrex::BoxArray > ba1d
 
amrex::Vector< amrex::BoxArray > ba2d
 
std::unique_ptr< amrex::MultiFab > wrf_C1H
 
std::unique_ptr< amrex::MultiFab > wrf_C2H
 
std::unique_ptr< amrex::MultiFab > wrf_MUB
 
std::unique_ptr< amrex::MultiFab > wrf_PHB
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > mf_PSFC
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > rhotheta_src
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > rhoqt_src
 
amrex::Vector< amrex::Vector< amrex::Real > > h_w_subsid
 
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_w_subsid
 
amrex::Vector< amrex::Vector< amrex::Real > > h_u_geos
 
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_u_geos
 
amrex::Vector< amrex::Vector< amrex::Real > > h_v_geos
 
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_v_geos
 
amrex::Vector< amrex::Vector< amrex::Vector< amrex::Real > > > h_rayleigh_ptrs
 
amrex::Vector< amrex::Vector< amrex::Vector< amrex::Real > > > h_sponge_ptrs
 
amrex::Vector< amrex::Vector< amrex::Real > > h_sinesq_ptrs
 
amrex::Vector< amrex::Vector< amrex::Real > > h_sinesq_stag_ptrs
 
amrex::Vector< amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > > d_rayleigh_ptrs
 
amrex::Vector< amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > > d_sponge_ptrs
 
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_sinesq_ptrs
 
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_sinesq_stag_ptrs
 
amrex::Vector< amrex::Realh_havg_density
 
amrex::Vector< amrex::Realh_havg_temperature
 
amrex::Vector< amrex::Realh_havg_pressure
 
amrex::Vector< amrex::Realh_havg_qv
 
amrex::Vector< amrex::Realh_havg_qc
 
amrex::Gpu::DeviceVector< amrex::Reald_havg_density
 
amrex::Gpu::DeviceVector< amrex::Reald_havg_temperature
 
amrex::Gpu::DeviceVector< amrex::Reald_havg_pressure
 
amrex::Gpu::DeviceVector< amrex::Reald_havg_qv
 
amrex::Gpu::DeviceVector< amrex::Reald_havg_qc
 
std::unique_ptr< WriteBndryPlanesm_w2d = nullptr
 
std::unique_ptr< ReadBndryPlanesm_r2d = nullptr
 
std::unique_ptr< SurfaceLayerm_SurfaceLayer = nullptr
 
amrex::Vector< std::unique_ptr< ForestDrag > > m_forest_drag
 
amrex::Vector< amrex::Vector< amrex::BoxArray > > subdomains
 
amrex::Vector< amrex::Realdz_min
 
int line_sampling_interval = -1
 
int plane_sampling_interval = -1
 
amrex::Real line_sampling_per = -one
 
amrex::Real plane_sampling_per = -one
 
std::unique_ptr< LineSamplerline_sampler = nullptr
 
std::unique_ptr< PlaneSamplerplane_sampler = nullptr
 
amrex::Vector< std::unique_ptr< std::fstream > > datalog
 
amrex::Vector< std::unique_ptr< std::fstream > > der_datalog
 
amrex::Vector< std::unique_ptr< std::fstream > > tot_e_datalog
 
amrex::Vector< std::string > datalogname
 
amrex::Vector< std::string > der_datalogname
 
amrex::Vector< std::string > tot_e_datalogname
 
amrex::Vector< std::unique_ptr< std::fstream > > sampleptlog
 
amrex::Vector< std::string > sampleptlogname
 
amrex::Vector< amrex::IntVect > samplepoint
 
amrex::Vector< std::unique_ptr< std::fstream > > samplelinelog
 
amrex::Vector< std::string > samplelinelogname
 
amrex::Vector< amrex::IntVect > sampleline
 
amrex::Vector< std::unique_ptr< eb_ > > eb
 

Static Private Attributes

static int last_plot3d_file_step_1 = -1
 
static int last_plot3d_file_step_2 = -1
 
static int last_plot2d_file_step_1 = -1
 
static int last_plot2d_file_step_2 = -1
 
static int last_check_file_step = -1
 
static amrex::Real last_plot3d_file_time_1 = zero
 
static amrex::Real last_plot3d_file_time_2 = zero
 
static amrex::Real last_plot2d_file_time_1 = zero
 
static amrex::Real last_plot2d_file_time_2 = zero
 
static amrex::Real last_check_file_time = zero
 
static bool plot_file_on_restart = true
 
static amrex::Real start_time = zero
 
static amrex::Real stop_time = std::numeric_limits<amrex::Real>::max()
 
static amrex::Real cfl = Real(0.8)
 
static amrex::Real sub_cfl = one
 
static amrex::Real init_shrink = one
 
static amrex::Real change_max = Real(1.1)
 
static amrex::Real dt_max_initial = Real(2.0e100)
 
static amrex::Real dt_max = Real(1.0e9)
 
static int fixed_mri_dt_ratio = 0
 
static SolverChoice solverChoice
 
static int verbose = 0
 
static int mg_verbose = 0
 
static bool use_fft = false
 
static int check_for_nans = 0
 
static int sum_interval = -1
 
static int pert_interval = -1
 
static amrex::Real sum_per = -one
 
static PlotFileType plotfile3d_type_1 = PlotFileType::None
 
static PlotFileType plotfile3d_type_2 = PlotFileType::None
 
static PlotFileType plotfile2d_type_1 = PlotFileType::None
 
static PlotFileType plotfile2d_type_2 = PlotFileType::None
 
static StateInterpType interpolation_type
 
static amrex::Vector< amrex::Vector< std::string > > nc_init_file = {{""}}
 
static amrex::Vector< amrex::Vector< int > > have_read_nc_init_file = {{0}}
 
static std::string nc_bdy_file
 
static std::string nc_low_file
 
static int output_1d_column = 0
 
static int column_interval = -1
 
static amrex::Real column_per = -one
 
static amrex::Real column_loc_x = zero
 
static amrex::Real column_loc_y = zero
 
static std::string column_file_name = "column_data.nc"
 
static int output_bndry_planes = 0
 
static int bndry_output_planes_interval = -1
 
static amrex::Real bndry_output_planes_per = -one
 
static amrex::Real bndry_output_planes_start_time = zero
 
static int input_bndry_planes = 0
 
static int ng_dens_hse
 
static int ng_pres_hse
 
static amrex::Vector< amrex::AMRErrorTag > ref_tags
 
static amrex::Real startCPUTime = zero
 
static amrex::Real previousCPUTimeUsed = zero
 

Detailed Description

Main class in ERF code, instantiated from main.cpp

Constructor & Destructor Documentation

◆ ERF() [1/3]

ERF::ERF ( )
143 {
144  int fix_random_seed = 0;
145  ParmParse pp("erf"); pp.query("fix_random_seed", fix_random_seed);
146  // Note that the value of 1024UL is not significant -- the point here is just to set the
147  // same seed for all MPI processes for the purpose of regression testing
148  if (fix_random_seed) {
149  Print() << "Fixing the random seed" << std::endl;
150  InitRandom(1024UL, ParallelDescriptor::NProcs(), 1024UL);
151  }
152 
153  ERF_shared();
154 }
ParmParse pp("prob")
void ERF_shared()
Definition: ERF.cpp:157
Here is the call graph for this function:

◆ ~ERF()

ERF::~ERF ( )
overridedefault

◆ ERF() [2/3]

ERF::ERF ( ERF &&  )
deletenoexcept

◆ ERF() [3/3]

ERF::ERF ( const ERF other)
delete

Member Function Documentation

◆ Advance()

void ERF::Advance ( int  lev,
amrex::Real  time,
amrex::Real  dt_lev,
int  iteration,
int  ncycle 
)
private

Function that advances the solution at one level for a single time step – this does some preliminaries then calls erf_advance

Parameters
[in]levlevel of refinement (coarsest level is 0)
[in]timestart time for time advance
[in]dt_levtime step for this time advance
21 {
22  BL_PROFILE("ERF::Advance()");
23 
24  // We must swap the pointers so the previous step's "new" is now this step's "old"
25  std::swap(vars_old[lev], vars_new[lev]);
26 
27  MultiFab& S_old = vars_old[lev][Vars::cons];
28  MultiFab& S_new = vars_new[lev][Vars::cons];
29 
30  MultiFab& U_old = vars_old[lev][Vars::xvel];
31  MultiFab& V_old = vars_old[lev][Vars::yvel];
32  MultiFab& W_old = vars_old[lev][Vars::zvel];
33 
34  MultiFab& U_new = vars_new[lev][Vars::xvel];
35  MultiFab& V_new = vars_new[lev][Vars::yvel];
36  MultiFab& W_new = vars_new[lev][Vars::zvel];
37 
38  // We need to set these because otherwise in the first call to erf_advance we may
39  // read uninitialized data on ghost values in setting the bc's on the velocities
40  U_new.setVal(Real(1.e34),U_new.nGrowVect());
41  V_new.setVal(Real(1.e34),V_new.nGrowVect());
42  W_new.setVal(Real(1.e34),W_new.nGrowVect());
43 
44  //
45  // NOTE: the momenta here are not fillpatched (they are only used as scratch space)
46  // If lev == 0 we have already FillPatched this in ERF::TimeStep
47  //
48  if (lev > 0) {
49  // Set ghost cells to bogus values so they aren't uninitialized
50  W_old.setBndry(Real(1.234e20));
51  FillPatchFineLevel(lev, time, {&S_old, &U_old, &V_old, &W_old},
52  {&S_old, &rU_old[lev], &rV_old[lev], &rW_old[lev]},
53  base_state[lev], base_state[lev]);
54  }
55 
56  //
57  // So we must convert the fillpatched to momenta, including the ghost values
58  //
59  const MultiFab* c_vfrac = nullptr;
60  if (solverChoice.terrain_type == TerrainType::EB) {
61  c_vfrac = &((get_eb(lev).get_const_factory())->getVolFrac());
62  }
63 
64  VelocityToMomentum(U_old, rU_old[lev].nGrowVect(),
65  V_old, rV_old[lev].nGrowVect(),
66  W_old, rW_old[lev].nGrowVect(),
67  S_old, rU_old[lev], rV_old[lev], rW_old[lev],
68  Geom(lev).Domain(),
69  domain_bcs_type, c_vfrac);
70 
71  // Update the inflow perturbation update time and amplitude
73  {
74  turbPert.calc_tpi_update(lev, dt_lev, U_old, V_old, S_old);
75  }
76 
77  // If PerturbationType::Direct or CPM is selected, directly add the computed perturbation
78  // on the conserved field
80  {
81  auto m_ixtype = S_old.boxArray().ixType(); // Conserved term
82  for (MFIter mfi(S_old,TileNoZ()); mfi.isValid(); ++mfi) {
83  Box bx = mfi.tilebox();
84  const Array4<Real> &cell_data = S_old.array(mfi);
85  const Array4<const Real> &pert_cell = turbPert.pb_cell[lev].array(mfi);
86  turbPert.apply_tpi(lev, bx, RhoTheta_comp, m_ixtype, cell_data, pert_cell);
87  }
88  }
89 
90  // configure SurfaceLayer params if needed
91  if (phys_bc_type[Orientation(Direction::z,Orientation::low)] == ERF_BC::surface_layer) {
92  if (m_SurfaceLayer) {
93  IntVect ng = Theta_prim[lev]->nGrowVect();
94  MultiFab::Copy( *Theta_prim[lev], S_old, RhoTheta_comp, 0, 1, ng);
95  MultiFab::Divide(*Theta_prim[lev], S_old, Rho_comp , 0, 1, ng);
96  if (solverChoice.moisture_type != MoistureType::None) {
97  ng = Qv_prim[lev]->nGrowVect();
98 
99  MultiFab::Copy( *Qv_prim[lev], S_old, RhoQ1_comp, 0, 1, ng);
100  MultiFab::Divide(*Qv_prim[lev], S_old, Rho_comp , 0, 1, ng);
101 
102  if (solverChoice.moisture_indices.qr > -1) {
103  MultiFab::Copy( *Qr_prim[lev], S_old, solverChoice.moisture_indices.qr, 0, 1, ng);
104  MultiFab::Divide(*Qr_prim[lev], S_old, Rho_comp , 0, 1, ng);
105  } else {
106  Qr_prim[lev]->setVal(0);
107  }
108  }
109  // NOTE: std::swap above causes the field ptrs to be out of date.
110  // Reassign the field ptrs for MAC avg computation.
111  m_SurfaceLayer->update_mac_ptrs(lev, vars_old, Theta_prim, Qv_prim, Qr_prim);
112  m_SurfaceLayer->update_pblh(lev, vars_old, z_phys_cc[lev].get(),
114 
115 #ifdef ERF_USE_NETCDF
116  Real elapsed_time_since_start_low = time + (start_time - start_low_time);
117 #else
118  Real elapsed_time_since_start_low = time;
119 #endif
120  m_SurfaceLayer->update_fluxes(lev, time, elapsed_time_since_start_low,
121  S_old, z_phys_nd[lev], walldist[lev]);
122  }
123  }
124 
125 #if defined(ERF_USE_WINDFARM)
126  // **************************************************************************************
127  // Update the windfarm sources
128  // **************************************************************************************
129  if (solverChoice.windfarm_type != WindFarmType::None) {
130  advance_windfarm(Geom(lev), dt_lev, S_old,
131  U_old, V_old, W_old, vars_windfarm[lev],
132  Nturb[lev], SMark[lev], time);
133  }
134 
135 #endif
136 
137  // **************************************************************************************
138  // Update the radiation sources with the "old" state
139  // **************************************************************************************
140  advance_radiation(lev, S_old, dt_lev);
141 
142 #ifdef ERF_USE_SHOC
143  // **************************************************************************************
144  // Update the "old" state using SHOC
145  // **************************************************************************************
146  if (solverChoice.use_shoc) {
147  // Get SFC fluxes from SurfaceLayer
148  if (m_SurfaceLayer) {
149  Vector<const MultiFab*> mfs = {&S_old, &U_old, &V_old, &W_old};
150  m_SurfaceLayer->impose_SurfaceLayer_bcs(lev, mfs, Tau[lev],
151  SFS_hfx1_lev[lev].get() , SFS_hfx2_lev[lev].get() , SFS_hfx3_lev[lev].get(),
152  SFS_q1fx1_lev[lev].get(), SFS_q1fx2_lev[lev].get(), SFS_q1fx3_lev[lev].get(),
153  z_phys_nd[lev].get());
154  }
155 
156  // Get Shoc tendencies and update the state
157  Real* w_sub = (solverChoice.custom_w_subsidence) ? d_w_subsid[lev].data() : nullptr;
158  compute_shoc_tendencies(lev, &S_old, &U_old, &V_old, &W_old, w_sub,
159  Tau[lev][TauType::tau13].get(), Tau[lev][TauType::tau23].get(),
160  SFS_hfx3_lev[lev].get() , SFS_q1fx3_lev[lev].get() ,
161  eddyDiffs_lev[lev].get() , z_phys_nd[lev].get() ,
162  dt_lev);
163  }
164 #endif
165 
166  const BoxArray& ba = S_old.boxArray();
167  const DistributionMapping& dm = S_old.DistributionMap();
168 
169  int nvars = S_old.nComp();
170 
171  // Source array for conserved cell-centered quantities -- this will be filled
172  // in the call to make_sources in ERF_TI_slow_rhs_pre.H
173  MultiFab cc_source(ba,dm,nvars,1); cc_source.setVal(0);
174 
175  // Source arrays for momenta -- these will be filled
176  // in the call to make_mom_sources in ERF_TI_slow_rhs_pre.H
177  BoxArray ba_x(ba); ba_x.surroundingNodes(0);
178  MultiFab xmom_source(ba_x,dm,1,1); xmom_source.setVal(0);
179 
180  BoxArray ba_y(ba); ba_y.surroundingNodes(1);
181  MultiFab ymom_source(ba_y,dm,1,1); ymom_source.setVal(0);
182 
183  BoxArray ba_z(ba); ba_z.surroundingNodes(2);
184  MultiFab zmom_source(ba_z,dm,1,1); zmom_source.setVal(0);
185  MultiFab buoyancy(ba_z,dm,1,1); buoyancy.setVal(0);
186 
187  amrex::Vector<MultiFab> state_old;
188  amrex::Vector<MultiFab> state_new;
189 
190  // **************************************************************************************
191  // Here we define state_old and state_new which are to be advanced
192  // **************************************************************************************
193  // Initial solution
194  // Note that "old" and "new" here are relative to each RK stage.
195  state_old.push_back(MultiFab(S_old , amrex::make_alias, 0, nvars)); // cons
196  state_old.push_back(MultiFab(rU_old[lev], amrex::make_alias, 0, 1)); // xmom
197  state_old.push_back(MultiFab(rV_old[lev], amrex::make_alias, 0, 1)); // ymom
198  state_old.push_back(MultiFab(rW_old[lev], amrex::make_alias, 0, 1)); // zmom
199 
200  // Final solution
201  // state_new at the end of the last RK stage holds the t^{n+1} data
202  state_new.push_back(MultiFab(S_new , amrex::make_alias, 0, nvars)); // cons
203  state_new.push_back(MultiFab(rU_new[lev], amrex::make_alias, 0, 1)); // xmom
204  state_new.push_back(MultiFab(rV_new[lev], amrex::make_alias, 0, 1)); // ymom
205  state_new.push_back(MultiFab(rW_new[lev], amrex::make_alias, 0, 1)); // zmom
206 
207  // **************************************************************************************
208  // Tests on the reasonableness of the solution before the dycore
209  // **************************************************************************************
210  // Test for NaNs after dycore
211  if (check_for_nans > 1) {
212  if (verbose > 1) {
213  amrex::Print() << "Testing old state and vels for NaNs before dycore" << std::endl;
214  }
215  check_state_for_nans(S_old);
216  check_vels_for_nans(rU_old[lev],rV_old[lev],rW_old[lev]);
217  }
218 
219  // We only test on low temp if we have a moisture model because we are protecting against
220  // the test on low temp inside the moisture models
221  if (solverChoice.moisture_type != MoistureType::None) {
222  if (verbose > 1) {
223  amrex::Print() << "Testing on low temperature before dycore" << std::endl;
224  }
225  check_for_low_temp(S_old);
226  } else {
227  if (verbose > 1) {
228  amrex::Print() << "Testing on negative temperature before dycore" << std::endl;
229  }
231  }
232 
233  // **************************************************************************************
234  // Update the dycore
235  // **************************************************************************************
236  advance_dycore(lev, state_old, state_new,
237  U_old, V_old, W_old,
238  U_new, V_new, W_new,
239  cc_source, xmom_source, ymom_source, zmom_source, buoyancy,
240  Geom(lev), dt_lev, time);
241 
242  // **************************************************************************************
243  // Tests on the reasonableness of the solution after the dycore
244  // **************************************************************************************
245  // Test for NaNs after dycore
246  if (check_for_nans > 0) {
247  if (verbose > 1) {
248  amrex::Print() << "Testing new state and vels for NaNs after dycore" << std::endl;
249  }
250  check_state_for_nans(S_new);
251  check_vels_for_nans(rU_new[lev],rV_new[lev],rW_new[lev]);
252  }
253 
254  // We only test on low temp if we have a moisture model because we are protecting against
255  // the test on low temp inside the moisture models
256  if (solverChoice.moisture_type != MoistureType::None) {
257  if (verbose > 1) {
258  amrex::Print() << "Testing on low temperature after dycore" << std::endl;
259  }
260  check_for_low_temp(S_new);
261  } else {
262  // Otherwise we will test on negative (rhotheta) coming out of the dycore
263  if (verbose > 1) {
264  amrex::Print() << "Testing on negative temperature after dycore" << std::endl;
265  }
267  }
268 
269  // **************************************************************************************
270  // Update the microphysics (moisture)
271  // **************************************************************************************
273  {
274  advance_microphysics(lev, S_new, dt_lev, iteration, time);
275 
276  // Test for NaNs after microphysics
277  if (check_for_nans > 0) {
278  amrex::Print() << "Testing new state for NaNs after advance_microphysics" << std::endl;
279  check_state_for_nans(S_new);
280  }
281  }
282 
283  // **************************************************************************************
284  // Update the land surface model
285  // **************************************************************************************
286  Real time_at_end_of_step = time+dt_lev;
287  advance_lsm(lev, S_new, U_new, V_new, time_at_end_of_step, dt_lev);
288 
289 #ifdef ERF_USE_PARTICLES
290  // **************************************************************************************
291  // Update the particle positions
292  // **************************************************************************************
293  evolveTracers(lev, dt_lev, vars_new, z_phys_nd);
294 #endif
295 
296  // ***********************************************************************************************
297  // Impose domain boundary conditions here so that in FillPatching the fine data we won't
298  // need to re-fill these
299  // ***********************************************************************************************
300  if (lev < finest_level) {
301  IntVect ngvect_vels = vars_new[lev][Vars::xvel].nGrowVect();
303  0,vars_new[lev][Vars::cons].nComp(),
304  vars_new[lev][Vars::cons].nGrowVect(),time,BCVars::cons_bc,true);
305  (*physbcs_u[lev])(vars_new[lev][Vars::xvel], vars_new[lev][Vars::xvel], vars_new[lev][Vars::yvel],
306  ngvect_vels,time,BCVars::xvel_bc,true);
307  (*physbcs_v[lev])(vars_new[lev][Vars::yvel], vars_new[lev][Vars::xvel], vars_new[lev][Vars::yvel],
308  ngvect_vels,time,BCVars::yvel_bc,true);
309  (*physbcs_w[lev])(vars_new[lev][Vars::zvel], vars_new[lev][Vars::xvel], vars_new[lev][Vars::yvel],
310  ngvect_vels,time,BCVars::zvel_bc,true);
311  }
312 
313  // **************************************************************************************
314  // Register old and new coarse data if we are at a level less than the finest level
315  // **************************************************************************************
316  if (lev < finest_level) {
317  if (cf_width > 0) {
318  // We must fill the ghost cells of these so that the parallel copy works correctly
319  state_old[IntVars::cons].FillBoundary(geom[lev].periodicity());
320  state_new[IntVars::cons].FillBoundary(geom[lev].periodicity());
321  FPr_c[lev].RegisterCoarseData({&state_old[IntVars::cons], &state_new[IntVars::cons]},
322  {time, time+dt_lev});
323  }
324 
325  if (cf_width >= 0) {
326  // We must fill the ghost cells of these so that the parallel copy works correctly
327  state_old[IntVars::xmom].FillBoundary(geom[lev].periodicity());
328  state_new[IntVars::xmom].FillBoundary(geom[lev].periodicity());
329  FPr_u[lev].RegisterCoarseData({&state_old[IntVars::xmom], &state_new[IntVars::xmom]},
330  {time, time+dt_lev});
331 
332  state_old[IntVars::ymom].FillBoundary(geom[lev].periodicity());
333  state_new[IntVars::ymom].FillBoundary(geom[lev].periodicity());
334  FPr_v[lev].RegisterCoarseData({&state_old[IntVars::ymom], &state_new[IntVars::ymom]},
335  {time, time+dt_lev});
336 
337  state_old[IntVars::zmom].FillBoundary(geom[lev].periodicity());
338  state_new[IntVars::zmom].FillBoundary(geom[lev].periodicity());
339  FPr_w[lev].RegisterCoarseData({&state_old[IntVars::zmom], &state_new[IntVars::zmom]},
340  {time, time+dt_lev});
341  }
342 
343  //
344  // Now create a MultiFab that holds (S_new - S_old) / dt from the coarse level interpolated
345  // on to the coarse/fine boundary at the fine resolution
346  //
347  Interpolater* mapper_f = &face_cons_linear_interp;
348 
349  // PhysBCFunctNoOp null_bc;
350  // MultiFab tempx(vars_new[lev+1][Vars::xvel].boxArray(),vars_new[lev+1][Vars::xvel].DistributionMap(),1,0);
351  // tempx.setVal(0);
352  // xmom_crse_rhs[lev+1].setVal(0);
353  // FPr_u[lev].FillSet(tempx , time , null_bc, domain_bcs_type);
354  // FPr_u[lev].FillSet(xmom_crse_rhs[lev+1], time+dt_lev, null_bc, domain_bcs_type);
355  // MultiFab::Subtract(xmom_crse_rhs[lev+1],tempx,0,0,1,IntVect{0});
356  // xmom_crse_rhs[lev+1].mult(one/dt_lev,0,1,0);
357 
358  // MultiFab tempy(vars_new[lev+1][Vars::yvel].boxArray(),vars_new[lev+1][Vars::yvel].DistributionMap(),1,0);
359  // tempy.setVal(0);
360  // ymom_crse_rhs[lev+1].setVal(0);
361  // FPr_v[lev].FillSet(tempy , time , null_bc, domain_bcs_type);
362  // FPr_v[lev].FillSet(ymom_crse_rhs[lev+1], time+dt_lev, null_bc, domain_bcs_type);
363  // MultiFab::Subtract(ymom_crse_rhs[lev+1],tempy,0,0,1,IntVect{0});
364  // ymom_crse_rhs[lev+1].mult(one/dt_lev,0,1,0);
365 
366  MultiFab temp_state(zmom_crse_rhs[lev+1].boxArray(),zmom_crse_rhs[lev+1].DistributionMap(),1,0);
367  InterpFromCoarseLevel(temp_state, IntVect{0}, IntVect{0}, state_old[IntVars::zmom], 0, 0, 1,
368  geom[lev], geom[lev+1], refRatio(lev), mapper_f, domain_bcs_type, BCVars::zvel_bc);
369  InterpFromCoarseLevel(zmom_crse_rhs[lev+1], IntVect{0}, IntVect{0}, state_new[IntVars::zmom], 0, 0, 1,
370  geom[lev], geom[lev+1], refRatio(lev), mapper_f, domain_bcs_type, BCVars::zvel_bc);
371  MultiFab::Subtract(zmom_crse_rhs[lev+1],temp_state,0,0,1,IntVect{0});
372  zmom_crse_rhs[lev+1].mult(one/dt_lev,0,1,0);
373  }
374 
375  // ***********************************************************************************************
376  // Update the time averaged velocities if they are requested
377  // ***********************************************************************************************
379  Time_Avg_Vel_atCC(dt[lev], t_avg_cnt[lev], vel_t_avg[lev].get(), U_new, V_new, W_new);
380  }
381 }
constexpr amrex::Real one
Definition: ERF_Constants.H:7
@ tau23
Definition: ERF_DataStruct.H:32
@ tau13
Definition: ERF_DataStruct.H:32
@ nvars
Definition: ERF_DataStruct.H:98
#define Rho_comp
Definition: ERF_IndexDefines.H:36
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:37
#define RhoQ1_comp
Definition: ERF_IndexDefines.H:42
@ surface_layer
pp get("wavelength", wavelength)
amrex::Real Real
Definition: ERF_ShocInterface.H:19
AMREX_FORCE_INLINE amrex::IntVect TileNoZ()
Definition: ERF_TileNoZ.H:11
void Time_Avg_Vel_atCC(const Real &dt, Real &t_avg_cnt, MultiFab *vel_t_avg, MultiFab &xvel, MultiFab &yvel, MultiFab &zvel)
Definition: ERF_TimeAvgVel.cpp:9
void VelocityToMomentum(const amrex::MultiFab &xvel_in, const amrex::IntVect &xvel_ngrow, const amrex::MultiFab &yvel_in, const amrex::IntVect &yvel_ngrow, const amrex::MultiFab &zvel_in, const amrex::IntVect &zvel_ngrow, const amrex::MultiFab &cons_in, amrex::MultiFab &xmom_out, amrex::MultiFab &ymom_out, amrex::MultiFab &zmom_out, const amrex::Box &domain, const amrex::Vector< amrex::BCRec > &domain_bcs_type_h, const amrex::MultiFab *c_vfrac=nullptr)
amrex::Vector< amrex::MultiFab > rU_new
Definition: ERF.H:882
amrex::Vector< std::unique_ptr< amrex::MultiFab > > walldist
Definition: ERF.H:992
static amrex::Real start_time
Definition: ERF.H:1078
void check_vels_for_nans(amrex::MultiFab const &xvel, amrex::MultiFab const &yvel, amrex::MultiFab const &zvel)
Definition: ERF.cpp:3257
amrex::Vector< ERFFillPatcher > FPr_u
Definition: ERF.H:932
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q1fx3_lev
Definition: ERF.H:955
amrex::Vector< amrex::Vector< amrex::MultiFab > > vars_new
Definition: ERF.H:847
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_hfx3_lev
Definition: ERF.H:953
amrex::Vector< ERFFillPatcher > FPr_v
Definition: ERF.H:933
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_hfx1_lev
Definition: ERF.H:953
eb_ const & get_eb(int lev) const noexcept
Definition: ERF.H:1670
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_cons > > physbcs_cons
Definition: ERF.H:869
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_cc
Definition: ERF.H:969
amrex::Vector< std::unique_ptr< amrex::MultiFab > > eddyDiffs_lev
Definition: ERF.H:939
static SolverChoice solverChoice
Definition: ERF.H:1213
amrex::Vector< ERFFillPatcher > FPr_c
Definition: ERF.H:931
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > Tau
Definition: ERF.H:937
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vel_t_avg
Definition: ERF.H:854
static int verbose
Definition: ERF.H:1248
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_w > > physbcs_w
Definition: ERF.H:872
amrex::Vector< amrex::MultiFab > base_state
Definition: ERF.H:1003
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Qv_prim
Definition: ERF.H:877
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q1fx2_lev
Definition: ERF.H:955
amrex::Vector< amrex::MultiFab > rV_new
Definition: ERF.H:884
amrex::Vector< amrex::BCRec > domain_bcs_type
Definition: ERF.H:1019
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Qr_prim
Definition: ERF.H:878
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_u > > physbcs_u
Definition: ERF.H:870
amrex::Vector< amrex::Real > t_avg_cnt
Definition: ERF.H:855
amrex::Vector< amrex::MultiFab > rU_old
Definition: ERF.H:881
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Theta_prim
Definition: ERF.H:876
static int check_for_nans
Definition: ERF.H:1252
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_v > > physbcs_v
Definition: ERF.H:871
void check_state_for_nans(amrex::MultiFab const &S)
Definition: ERF.cpp:3238
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_nd
Definition: ERF.H:968
void advance_dycore(int level, amrex::Vector< amrex::MultiFab > &state_old, amrex::Vector< amrex::MultiFab > &state_new, amrex::MultiFab &xvel_old, amrex::MultiFab &yvel_old, amrex::MultiFab &zvel_old, amrex::MultiFab &xvel_new, amrex::MultiFab &yvel_new, amrex::MultiFab &zvel_new, amrex::MultiFab &source, amrex::MultiFab &xmom_src, amrex::MultiFab &ymom_src, amrex::MultiFab &zmom_src, amrex::MultiFab &buoyancy, amrex::Geometry fine_geom, amrex::Real dt, amrex::Real time)
Definition: ERF_AdvanceDycore.cpp:38
amrex::Vector< amrex::MultiFab > rW_new
Definition: ERF.H:886
amrex::Vector< amrex::MultiFab > zmom_crse_rhs
Definition: ERF.H:890
void check_for_low_temp(amrex::MultiFab &S)
Definition: ERF.cpp:3284
TurbulentPerturbation turbPert
Definition: ERF.H:1216
amrex::Vector< amrex::MultiFab > rW_old
Definition: ERF.H:885
void check_for_negative_theta(amrex::MultiFab &S)
Definition: ERF.cpp:3319
std::unique_ptr< SurfaceLayer > m_SurfaceLayer
Definition: ERF.H:1383
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_w_subsid
Definition: ERF.H:1334
amrex::Vector< ERFFillPatcher > FPr_w
Definition: ERF.H:934
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_hfx2_lev
Definition: ERF.H:953
amrex::Vector< amrex::Real > dt
Definition: ERF.H:841
void advance_radiation(int lev, amrex::MultiFab &cons_in, const amrex::Real &dt_advance)
Definition: ERF_AdvanceRadiation.cpp:5
void advance_microphysics(int lev, amrex::MultiFab &cons_in, const amrex::Real &dt_advance, const int &iteration, const amrex::Real &time)
Definition: ERF_AdvanceMicrophysics.cpp:5
int cf_width
Definition: ERF.H:929
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q1fx1_lev
Definition: ERF.H:955
amrex::GpuArray< ERF_BC, AMREX_SPACEDIM *2 > phys_bc_type
Definition: ERF.H:1035
amrex::Vector< amrex::MultiFab > rV_old
Definition: ERF.H:883
void FillPatchFineLevel(int lev, double time, const amrex::Vector< amrex::MultiFab * > &mfs_vel, const amrex::Vector< amrex::MultiFab * > &mfs_mom, const amrex::MultiFab &old_base_state, const amrex::MultiFab &new_base_state, bool fillset=true, bool cons_only=false)
Definition: ERF_FillPatch.cpp:20
void advance_lsm(int lev, amrex::MultiFab &cons_in, amrex::MultiFab &xvel_in, amrex::MultiFab &yvel_in, const amrex::Real &time, const amrex::Real &dt_advance)
Definition: ERF_AdvanceLSM.cpp:5
amrex::Vector< amrex::Vector< amrex::MultiFab > > vars_old
Definition: ERF.H:848
const std::unique_ptr< amrex::EBFArrayBoxFactory > & get_const_factory() const noexcept
Definition: ERF_EB.H:46
@ zvel_bc
Definition: ERF_IndexDefines.H:104
@ yvel_bc
Definition: ERF_IndexDefines.H:103
@ cons_bc
Definition: ERF_IndexDefines.H:86
@ xvel_bc
Definition: ERF_IndexDefines.H:102
@ ymom
Definition: ERF_IndexDefines.H:194
@ cons
Definition: ERF_IndexDefines.H:192
@ zmom
Definition: ERF_IndexDefines.H:195
@ xmom
Definition: ERF_IndexDefines.H:193
@ ng
Definition: ERF_Morrison.H:48
@ xvel
Definition: ERF_IndexDefines.H:175
@ cons
Definition: ERF_IndexDefines.H:174
@ zvel
Definition: ERF_IndexDefines.H:177
@ yvel
Definition: ERF_IndexDefines.H:176
int qr
Definition: ERF_DataStruct.H:110
bool use_shoc
Definition: ERF_DataStruct.H:1241
bool moisture_tight_coupling
Definition: ERF_DataStruct.H:1306
bool custom_w_subsidence
Definition: ERF_DataStruct.H:1225
bool use_perturbation(int lev) const
Definition: ERF_DataStruct.H:1249
bool use_direct_perturbation(int lev) const
Definition: ERF_DataStruct.H:1256
MoistureType moisture_type
Definition: ERF_DataStruct.H:1287
static TerrainType terrain_type
Definition: ERF_DataStruct.H:1114
WindFarmType windfarm_type
Definition: ERF_DataStruct.H:1288
MoistureComponentIndices moisture_indices
Definition: ERF_DataStruct.H:1304
bool time_avg_vel
Definition: ERF_DataStruct.H:1247
amrex::Vector< amrex::MultiFab > pb_cell
Definition: ERF_TurbPertStruct.H:667
void calc_tpi_update(const int lev, const amrex::Real dt, amrex::MultiFab &mf_xvel, amrex::MultiFab &mf_yvel, amrex::MultiFab &mf_cons)
Definition: ERF_TurbPertStruct.H:250
void apply_tpi(const int &lev, const amrex::Box &vbx, const int &comp, const amrex::IndexType &m_ixtype, const amrex::Array4< amrex::Real > &src_arr, const amrex::Array4< amrex::Real const > &pert_cell)
Definition: ERF_TurbPertStruct.H:351
Here is the call graph for this function:

◆ advance_dycore()

void ERF::advance_dycore ( int  level,
amrex::Vector< amrex::MultiFab > &  state_old,
amrex::Vector< amrex::MultiFab > &  state_new,
amrex::MultiFab &  xvel_old,
amrex::MultiFab &  yvel_old,
amrex::MultiFab &  zvel_old,
amrex::MultiFab &  xvel_new,
amrex::MultiFab &  yvel_new,
amrex::MultiFab &  zvel_new,
amrex::MultiFab &  source,
amrex::MultiFab &  xmom_src,
amrex::MultiFab &  ymom_src,
amrex::MultiFab &  zmom_src,
amrex::MultiFab &  buoyancy,
amrex::Geometry  fine_geom,
amrex::Real  dt,
amrex::Real  time 
)

Function that advances the solution at one level for a single time step – this sets up the multirate time integrator and calls the integrator's advance function

Parameters
[in]levellevel of refinement (coarsest level is 0)
[in]state_oldold-time conserved variables
[in]state_newnew-time conserved variables
[in]xvel_oldold-time x-component of velocity
[in]yvel_oldold-time y-component of velocity
[in]zvel_oldold-time z-component of velocity
[in]xvel_newnew-time x-component of velocity
[in]yvel_newnew-time y-component of velocity
[in]zvel_newnew-time z-component of velocity
[in]cc_srcsource term for conserved variables
[in]xmom_srcsource term for x-momenta
[in]ymom_srcsource term for y-momenta
[in]zmom_srcsource term for z-momenta
[in]fine_geomcontainer for geometry information at current level
[in]dt_advancetime step for this time advance
[in]old_timeold time for this time advance
48 {
49  BL_PROFILE_VAR("erf_advance_dycore()",erf_advance_dycore);
50 
51  const Box& domain = fine_geom.Domain();
52 
55 
56  MultiFab r_hse (base_state[level], make_alias, BaseState::r0_comp , 1);
57  MultiFab p_hse (base_state[level], make_alias, BaseState::p0_comp , 1);
58  MultiFab pi_hse(base_state[level], make_alias, BaseState::pi0_comp, 1);
59 
60  // These pointers are used in the MRI utility functions
61  MultiFab* r0 = &r_hse;
62  MultiFab* p0 = &p_hse;
63  MultiFab* pi0 = &pi_hse;
64 
65  MultiFab* rhotheta_src_ptr = solverChoice.custom_rhotheta_forcing ? rhotheta_src[level].get() : nullptr;
66  MultiFab* rhoqt_src_ptr = solverChoice.custom_moisture_forcing ? rhoqt_src[level].get() : nullptr;
67  Real* dptr_wbar_sub = solverChoice.custom_w_subsidence ? d_w_subsid[level].data() : nullptr;
68 
69  // Turbulent Perturbation Pointer
70  //Real* dptr_rhotheta_src = solverChoice.pert_type ? d_rhotheta_src[level].data() : nullptr;
71 
72  Vector<Real*> d_rayleigh_ptrs_at_lev;
73  d_rayleigh_ptrs_at_lev.resize(Rayleigh::nvars);
74  d_rayleigh_ptrs_at_lev[Rayleigh::ubar] = solverChoice.dampingChoice.rayleigh_damp_U ? d_rayleigh_ptrs[level][Rayleigh::ubar].data() : nullptr;
75  d_rayleigh_ptrs_at_lev[Rayleigh::vbar] = solverChoice.dampingChoice.rayleigh_damp_V ? d_rayleigh_ptrs[level][Rayleigh::vbar].data() : nullptr;
76  d_rayleigh_ptrs_at_lev[Rayleigh::wbar] = solverChoice.dampingChoice.rayleigh_damp_W ? d_rayleigh_ptrs[level][Rayleigh::wbar].data() : nullptr;
77  d_rayleigh_ptrs_at_lev[Rayleigh::thetabar] = solverChoice.dampingChoice.rayleigh_damp_T ? d_rayleigh_ptrs[level][Rayleigh::thetabar].data() : nullptr;
78 
79  bool use_rayleigh =
82  Real* d_sinesq_at_lev = (use_rayleigh) ? d_sinesq_ptrs[level].data() : nullptr;
83  Real* d_sinesq_stag_at_lev = (use_rayleigh) ? d_sinesq_stag_ptrs[level].data() : nullptr;
84 
85  Vector<Real*> d_sponge_ptrs_at_lev;
86  if (SpongeChoice::sponge_type == SpongeType::Input_Sponge)
87  {
88  d_sponge_ptrs_at_lev.resize(Sponge::nvars_sponge);
89  d_sponge_ptrs_at_lev[Sponge::ubar_sponge] = d_sponge_ptrs[level][Sponge::ubar_sponge].data();
90  d_sponge_ptrs_at_lev[Sponge::vbar_sponge] = d_sponge_ptrs[level][Sponge::vbar_sponge].data();
91  }
92 
93  bool l_use_terrain_fitted_coords = (solverChoice.mesh_type != MeshType::ConstantDz);
94  bool l_use_kturb = tc.use_kturb;
95  bool l_use_diff = ( (dc.molec_diff_type != MolecDiffType::None) ||
96  l_use_kturb );
97 
98  const bool use_SurfLayer = (m_SurfaceLayer != nullptr);
99  const MultiFab* z_0 = (use_SurfLayer) ? m_SurfaceLayer->get_z0(level) : nullptr;
100 
101  const BoxArray& ba = state_old[IntVars::cons].boxArray();
102  const BoxArray& ba_z = zvel_old.boxArray();
103  const DistributionMapping& dm = state_old[IntVars::cons].DistributionMap();
104 
105  int num_prim = state_old[IntVars::cons].nComp() - 1;
106 
107  MultiFab S_prim (ba , dm, num_prim, state_old[IntVars::cons].nGrowVect());
108  MultiFab pi_stage (ba , dm, 1, 1);
109  MultiFab fast_coeffs(ba_z, dm, 5, 0);
110 
111  MultiFab* eddyDiffs = eddyDiffs_lev[level].get();
112  MultiFab* SmnSmn = SmnSmn_lev[level].get();
113 
114  // **************************************************************************************
115  // Compute strain for use in slow RHS and Smagorinsky model
116  // **************************************************************************************
117  {
118  BL_PROFILE("erf_advance_strain");
119  if (l_use_diff) {
120 
121  const BCRec* bc_ptr_h = domain_bcs_type.data();
122  const GpuArray<Real, AMREX_SPACEDIM> dxInv = fine_geom.InvCellSizeArray();
123 
124 #ifdef _OPENMP
125 #pragma omp parallel if (Gpu::notInLaunchRegion())
126 #endif
127  for ( MFIter mfi(state_new[IntVars::cons],TileNoZ()); mfi.isValid(); ++mfi)
128  {
129  Box bxcc = mfi.growntilebox(IntVect(1,1,0));
130  Box tbxxy = mfi.tilebox(IntVect(1,1,0),IntVect(1,1,0));
131  Box tbxxz = mfi.tilebox(IntVect(1,0,1),IntVect(1,1,0));
132  Box tbxyz = mfi.tilebox(IntVect(0,1,1),IntVect(1,1,0));
133 
134  if (bxcc.smallEnd(2) != domain.smallEnd(2)) {
135  bxcc.growLo(2,1);
136  tbxxy.growLo(2,1);
137  tbxxz.growLo(2,1);
138  tbxyz.growLo(2,1);
139  }
140 
141  if (bxcc.bigEnd(2) != domain.bigEnd(2)) {
142  bxcc.growHi(2,1);
143  tbxxy.growHi(2,1);
144  tbxxz.growHi(2,1);
145  tbxyz.growHi(2,1);
146  }
147 
148  const Array4<const Real> & u = xvel_old.array(mfi);
149  const Array4<const Real> & v = yvel_old.array(mfi);
150  const Array4<const Real> & w = zvel_old.array(mfi);
151 
152  Array4<Real> tau11 = Tau[level][TauType::tau11].get()->array(mfi);
153  Array4<Real> tau22 = Tau[level][TauType::tau22].get()->array(mfi);
154  Array4<Real> tau33 = Tau[level][TauType::tau33].get()->array(mfi);
155  Array4<Real> tau12 = Tau[level][TauType::tau12].get()->array(mfi);
156  Array4<Real> tau13 = Tau[level][TauType::tau13].get()->array(mfi);
157  Array4<Real> tau23 = Tau[level][TauType::tau23].get()->array(mfi);
158 
159  Array4<Real> tau21 = l_use_terrain_fitted_coords ? Tau[level][TauType::tau21].get()->array(mfi) : Array4<Real>{};
160  Array4<Real> tau31 = l_use_terrain_fitted_coords ? Tau[level][TauType::tau31].get()->array(mfi) : Array4<Real>{};
161  Array4<Real> tau32 = l_use_terrain_fitted_coords ? Tau[level][TauType::tau32].get()->array(mfi) : Array4<Real>{};
162  const Array4<const Real>& z_nd = z_phys_nd[level]->const_array(mfi);
163 
164  const Array4<const Real> mf_mx = mapfac[level][MapFacType::m_x]->const_array(mfi);
165  const Array4<const Real> mf_ux = mapfac[level][MapFacType::u_x]->const_array(mfi);
166  const Array4<const Real> mf_vx = mapfac[level][MapFacType::v_x]->const_array(mfi);
167  const Array4<const Real> mf_my = mapfac[level][MapFacType::m_y]->const_array(mfi);
168  const Array4<const Real> mf_uy = mapfac[level][MapFacType::u_y]->const_array(mfi);
169  const Array4<const Real> mf_vy = mapfac[level][MapFacType::v_y]->const_array(mfi);
170 
171  // We update Tau_corr[level] in erf_make_tau_terms, not here
172  Array4<Real> no_tau_corr_update_here{};
173 
174  if (solverChoice.mesh_type == MeshType::StretchedDz) {
175  ComputeStrain_S(bxcc, tbxxy, tbxxz, tbxyz, domain,
176  u, v, w,
177  tau11, tau22, tau33,
178  tau12, tau21,
179  tau13, tau31,
180  tau23, tau32,
181  stretched_dz_d[level], dxInv,
182  mf_mx, mf_ux, mf_vx, mf_my, mf_uy, mf_vy, bc_ptr_h,
183  no_tau_corr_update_here, no_tau_corr_update_here);
184  } else if (l_use_terrain_fitted_coords) {
185  ComputeStrain_T(bxcc, tbxxy, tbxxz, tbxyz, domain,
186  u, v, w,
187  tau11, tau22, tau33,
188  tau12, tau21,
189  tau13, tau31,
190  tau23, tau32,
191  z_nd, detJ_cc[level]->const_array(mfi), dxInv,
192  mf_mx, mf_ux, mf_vx, mf_my, mf_uy, mf_vy, bc_ptr_h,
193  no_tau_corr_update_here, no_tau_corr_update_here);
194  } else {
195  if (solverChoice.terrain_type == TerrainType::EB) {
196  ComputeStrain_EB(mfi, bxcc, tbxxy, tbxxz, tbxyz, domain,
197  u, v, w,
198  tau11, tau22, tau33,
199  tau12, tau13, tau23,
200  dxInv,
201  bc_ptr_h,
202  get_eb(level),
203  no_tau_corr_update_here, no_tau_corr_update_here);
204  } else {
205  ComputeStrain_N(bxcc, tbxxy, tbxxz, tbxyz, domain,
206  u, v, w,
207  tau11, tau22, tau33,
208  tau12, tau13, tau23,
209  dxInv,
210  mf_mx, mf_ux, mf_vx, mf_my, mf_uy, mf_vy, bc_ptr_h,
211  no_tau_corr_update_here, no_tau_corr_update_here);
212  }
213  }
214  } // mfi
215  } // l_use_diff
216  } // profile
217 
218 #include "ERF_TI_utils.H"
219 
220  // Additional SFS quantities, calculated once per timestep
221  MultiFab* Hfx1 = SFS_hfx1_lev[level].get();
222  MultiFab* Hfx2 = SFS_hfx2_lev[level].get();
223  MultiFab* Hfx3 = SFS_hfx3_lev[level].get();
224  MultiFab* Q1fx1 = SFS_q1fx1_lev[level].get();
225  MultiFab* Q1fx2 = SFS_q1fx2_lev[level].get();
226  MultiFab* Q1fx3 = SFS_q1fx3_lev[level].get();
227  MultiFab* Q2fx3 = SFS_q2fx3_lev[level].get();
228  MultiFab* Diss = SFS_diss_lev[level].get();
229 
230  MultiFab* Hfx3_EB = nullptr;
231  if (solverChoice.terrain_type == TerrainType::EB) {
232  Hfx3_EB = hfx3_EB[level].get();
233  }
234 
235  // *************************************************************************
236  // Calculate cell-centered eddy viscosity & diffusivities
237  //
238  // Notes -- we fill all the data in ghost cells before calling this so
239  // that we can fill the eddy viscosity in the ghost regions and
240  // not have to call a boundary filler on this data itself
241  //
242  // LES - updates both horizontal and vertical eddy viscosity components
243  // PBL - only updates vertical eddy viscosity components so horizontal
244  // components come from the LES model or are left as zero.
245  // *************************************************************************
246  if (l_use_kturb)
247  {
248  // NOTE: state_new transfers to state_old for PBL (due to ptr swap in advance)
249  bool l_use_moisture = ( solverChoice.moisture_type != MoistureType::None );
250  const BCRec* bc_ptr_h = domain_bcs_type.data();
251  ComputeTurbulentViscosity(dt_advance, xvel_old, yvel_old,Tau[level],
252  state_old[IntVars::cons],
253  *walldist[level].get(),
254  *eddyDiffs, *Hfx1, *Hfx2, *Hfx3, *Diss, // to be updated
255  fine_geom, mapfac[level],
256  z_phys_nd[level], solverChoice,
257  m_SurfaceLayer, z_0, l_use_terrain_fitted_coords,
258  l_use_moisture, level,
259  bc_ptr_h,
260  get_eb(level));
261  }
262 
263  // ***********************************************************************************************
264  // Update user-defined source terms -- these are defined once per time step (not per RK stage)
265  // ***********************************************************************************************
267  prob->update_rhotheta_sources(old_time,
268  rhotheta_src_ptr,
269  fine_geom, z_phys_cc[level]);
270  }
271 
273  prob->update_rhoqt_sources(old_time,
274  rhoqt_src_ptr,
275  fine_geom, z_phys_cc[level]);
276  }
277 
279  prob->update_geostrophic_profile(old_time,
280  h_u_geos[level], d_u_geos[level],
281  h_v_geos[level], d_v_geos[level],
282  fine_geom, z_phys_cc[level]);
283  }
284 
286  prob->update_w_subsidence(old_time,
287  h_w_subsid[level], d_w_subsid[level],base_state[level],
288  fine_geom, z_phys_nd[level]);
289  }
290 
291  // ***********************************************************************************************
292  // Convert old velocity available on faces to old momentum on faces to be used in time integration
293  // ***********************************************************************************************
294  MultiFab density(state_old[IntVars::cons], make_alias, Rho_comp, 1);
295 
296  //
297  // This is an optimization since we won't need more than one ghost
298  // cell of momentum in the integrator if not using numerical diffusion
299  //
300  IntVect ngu = (!solverChoice.use_num_diff) ? IntVect(1,1,1) : xvel_old.nGrowVect();
301  IntVect ngv = (!solverChoice.use_num_diff) ? IntVect(1,1,1) : yvel_old.nGrowVect();
302  IntVect ngw = (!solverChoice.use_num_diff) ? IntVect(1,1,0) : zvel_old.nGrowVect();
303 
304  const MultiFab* c_vfrac = nullptr;
305  if (solverChoice.terrain_type == TerrainType::EB) {
306  c_vfrac = &((get_eb(level).get_const_factory())->getVolFrac());
307  }
308 
309  VelocityToMomentum(xvel_old, ngu, yvel_old, ngv, zvel_old, ngw, density,
310  state_old[IntVars::xmom],
311  state_old[IntVars::ymom],
312  state_old[IntVars::zmom],
313  domain, domain_bcs_type, c_vfrac);
314 
315  MultiFab::Copy(xvel_new,xvel_old,0,0,1,xvel_old.nGrowVect());
316  MultiFab::Copy(yvel_new,yvel_old,0,0,1,yvel_old.nGrowVect());
317  MultiFab::Copy(zvel_new,zvel_old,0,0,1,zvel_old.nGrowVect());
318 
319  bool fast_only = false;
320  bool vel_and_mom_synced = true;
321 
322  apply_bcs(state_old, old_time,
323  state_old[IntVars::cons].nGrow(), state_old[IntVars::xmom].nGrow(),
324  fast_only, vel_and_mom_synced);
325 
326  cons_to_prim(state_old[IntVars::cons], S_prim, state_old[IntVars::cons].nGrow());
327 
328  make_pi_stage(state_old[IntVars::cons]);
329 
330  // ***********************************************************************************************
331  // Define a new MultiFab that holds q_total and fill it by summing the moisture components --
332  // to be used in buoyancy calculation and as part of the inertial weighting in the
333  // ***********************************************************************************************
334 
335  const bool l_eb_terrain = (solverChoice.terrain_type == TerrainType::EB);
336  MultiFab qt(grids[level], dmap[level], 1, (l_eb_terrain) ? 2 : 1);
337  qt.setVal(0);
338 
339 #include "ERF_TI_no_substep_fun.H"
340 #include "ERF_TI_substep_fun.H"
341 #include "ERF_TI_slow_rhs_pre.H"
342 #include "ERF_TI_slow_rhs_post.H"
343 
344  // ***************************************************************************************
345  // Setup the integrator and integrate for a single timestep
346  // **************************************************************************************
347  MRISplitIntegrator<Vector<MultiFab> >& mri_integrator = *mri_integrator_mem[level];
348 
349  // Define rhs and 'post update' utility function that is called after calculating
350  // any state data (e.g. at RK stages or at the end of a timestep)
351  mri_integrator.set_slow_rhs_pre(slow_rhs_fun_pre);
352  mri_integrator.set_slow_rhs_post(slow_rhs_fun_post);
353 
356  mri_integrator.set_no_substep(no_substep_fun);
357 
358  mri_integrator.advance(state_old, state_new, old_time, dt_advance);
359 
360  if (verbose) Print() << "Done with advance_dycore at level " << level << std::endl;
361 }
void ComputeStrain_EB(const MFIter &mfi, Box bxcc, Box tbxxy, Box tbxxz, Box tbxyz, Box domain, const Array4< const Real > &u, const Array4< const Real > &v, const Array4< const Real > &w, Array4< Real > &tau11, Array4< Real > &tau22, Array4< Real > &tau33, Array4< Real > &tau12, Array4< Real > &tau13, Array4< Real > &tau23, const GpuArray< Real, AMREX_SPACEDIM > &dxInv, const BCRec *bc_ptr, const eb_ &ebfact, Array4< Real > &tau13i, Array4< Real > &tau23i)
Definition: ERF_ComputeStrain_EB.cpp:28
void ComputeStrain_N(Box bxcc, Box tbxxy, Box tbxxz, Box tbxyz, Box domain, const Array4< const Real > &u, const Array4< const Real > &v, const Array4< const Real > &w, Array4< Real > &tau11, Array4< Real > &tau22, Array4< Real > &tau33, Array4< Real > &tau12, Array4< Real > &tau13, Array4< Real > &tau23, const GpuArray< Real, AMREX_SPACEDIM > &dxInv, const Array4< const Real > &mf_mx, const Array4< const Real > &mf_ux, const Array4< const Real > &mf_vx, const Array4< const Real > &mf_my, const Array4< const Real > &mf_uy, const Array4< const Real > &mf_vy, const BCRec *bc_ptr, Array4< Real > &tau13i, Array4< Real > &tau23i)
Definition: ERF_ComputeStrain_N.cpp:31
void ComputeStrain_S(Box bxcc, Box tbxxy, Box tbxxz, Box tbxyz, Box domain, const Array4< const Real > &u, const Array4< const Real > &v, const Array4< const Real > &w, Array4< Real > &tau11, Array4< Real > &tau22, Array4< Real > &tau33, Array4< Real > &tau12, Array4< Real > &tau21, Array4< Real > &tau13, Array4< Real > &tau31, Array4< Real > &tau23, Array4< Real > &tau32, const Gpu::DeviceVector< Real > &stretched_dz_d, const GpuArray< Real, AMREX_SPACEDIM > &dxInv, const Array4< const Real > &mf_mx, const Array4< const Real > &mf_ux, const Array4< const Real > &mf_vx, const Array4< const Real > &mf_my, const Array4< const Real > &mf_uy, const Array4< const Real > &mf_vy, const BCRec *bc_ptr, Array4< Real > &tau13i, Array4< Real > &tau23i)
Definition: ERF_ComputeStrain_S.cpp:39
void ComputeStrain_T(Box bxcc, Box tbxxy, Box tbxxz, Box tbxyz, Box domain, const Array4< const Real > &u, const Array4< const Real > &v, const Array4< const Real > &w, Array4< Real > &tau11, Array4< Real > &tau22, Array4< Real > &tau33, Array4< Real > &tau12, Array4< Real > &tau21, Array4< Real > &tau13, Array4< Real > &tau31, Array4< Real > &tau23, Array4< Real > &tau32, const Array4< const Real > &z_nd, const Array4< const Real > &detJ, const GpuArray< Real, AMREX_SPACEDIM > &dxInv, const Array4< const Real > &mf_mx, const Array4< const Real > &mf_ux, const Array4< const Real > &mf_vx, const Array4< const Real > &mf_my, const Array4< const Real > &mf_uy, const Array4< const Real > &mf_vy, const BCRec *bc_ptr, Array4< Real > &tau13i, Array4< Real > &tau23i)
Definition: ERF_ComputeStrain_T.cpp:39
void ComputeTurbulentViscosity(Real dt, const MultiFab &xvel, const MultiFab &yvel, Vector< std::unique_ptr< MultiFab >> &Tau_lev, MultiFab &cons_in, const MultiFab &wdist, MultiFab &eddyViscosity, MultiFab &Hfx1, MultiFab &Hfx2, MultiFab &Hfx3, MultiFab &Diss, const Geometry &geom, Vector< std::unique_ptr< MultiFab >> &mapfac, const std::unique_ptr< MultiFab > &z_phys_nd, const SolverChoice &solverChoice, std::unique_ptr< SurfaceLayer > &SurfLayer, const MultiFab *z_0, const bool &use_terrain_fitted_coords, const bool &use_moisture, int level, const BCRec *bc_ptr, const eb_ &ebfact, bool vert_only)
Definition: ERF_ComputeTurbulentViscosity.cpp:791
@ tau12
Definition: ERF_DataStruct.H:32
@ tau33
Definition: ERF_DataStruct.H:32
@ tau22
Definition: ERF_DataStruct.H:32
@ tau11
Definition: ERF_DataStruct.H:32
@ tau32
Definition: ERF_DataStruct.H:32
@ tau31
Definition: ERF_DataStruct.H:32
@ tau21
Definition: ERF_DataStruct.H:32
@ ubar
Definition: ERF_DataStruct.H:98
@ wbar
Definition: ERF_DataStruct.H:98
@ vbar
Definition: ERF_DataStruct.H:98
@ thetabar
Definition: ERF_DataStruct.H:98
@ nvars_sponge
Definition: ERF_DataStruct.H:103
@ vbar_sponge
Definition: ERF_DataStruct.H:103
@ ubar_sponge
Definition: ERF_DataStruct.H:103
@ v_x
Definition: ERF_DataStruct.H:24
@ u_y
Definition: ERF_DataStruct.H:25
@ v_y
Definition: ERF_DataStruct.H:25
@ m_y
Definition: ERF_DataStruct.H:25
@ u_x
Definition: ERF_DataStruct.H:24
@ m_x
Definition: ERF_DataStruct.H:24
amrex::GpuArray< Real, AMREX_SPACEDIM > dxInv
Definition: ERF_InitCustomPertVels_ParticleTests.H:17
auto no_substep_fun
Definition: ERF_TI_no_substep_fun.H:4
auto slow_rhs_fun_post
Definition: ERF_TI_slow_rhs_post.H:3
auto slow_rhs_fun_pre
Definition: ERF_TI_slow_rhs_pre.H:6
auto acoustic_substepping_fun
Definition: ERF_TI_substep_fun.H:6
auto make_pi_stage
Definition: ERF_TI_utils.H:4
auto apply_bcs
Definition: ERF_TI_utils.H:34
Real z_0
Definition: ERF_UpdateWSubsidence_Bomex.H:10
void cons_to_prim(const MultiFab &cons_state, MultiFab &S_prim, int ng)
Definition: ERF_Utils.cpp:6
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > mapfac
Definition: ERF.H:995
amrex::Vector< std::unique_ptr< MRISplitIntegrator< amrex::Vector< amrex::MultiFab > > > > mri_integrator_mem
Definition: ERF.H:857
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_sinesq_stag_ptrs
Definition: ERF.H:1365
amrex::Vector< amrex::Vector< amrex::Real > > h_w_subsid
Definition: ERF.H:1333
amrex::Vector< std::unique_ptr< amrex::MultiFab > > detJ_cc
Definition: ERF.H:971
amrex::Vector< std::unique_ptr< amrex::MultiFab > > hfx3_EB
Definition: ERF.H:961
amrex::Vector< amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > > d_sponge_ptrs
Definition: ERF.H:1361
amrex::Vector< long > dt_mri_ratio
Definition: ERF.H:842
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q2fx3_lev
Definition: ERF.H:956
std::unique_ptr< ProblemBase > prob
Definition: ERF.H:829
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > stretched_dz_d
Definition: ERF.H:1001
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_diss_lev
Definition: ERF.H:954
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_sinesq_ptrs
Definition: ERF.H:1364
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_v_geos
Definition: ERF.H:1340
amrex::Vector< amrex::Vector< amrex::Real > > h_v_geos
Definition: ERF.H:1339
amrex::Vector< std::unique_ptr< amrex::MultiFab > > rhotheta_src
Definition: ERF.H:1330
amrex::Vector< amrex::Vector< amrex::Real > > h_u_geos
Definition: ERF.H:1336
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SmnSmn_lev
Definition: ERF.H:940
amrex::Vector< std::unique_ptr< amrex::MultiFab > > rhoqt_src
Definition: ERF.H:1331
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_u_geos
Definition: ERF.H:1337
static int fixed_mri_dt_ratio
Definition: ERF.H:1098
amrex::Vector< amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > > d_rayleigh_ptrs
Definition: ERF.H:1360
Definition: ERF_MRI.H:16
void set_acoustic_substepping(std::function< void(int, int, int, T &, const T &, T &, T &, const amrex::Real, const amrex::Real, const amrex::Real, const amrex::Real, const amrex::Real)> F)
Definition: ERF_MRI.H:143
void set_no_substep(std::function< void(T &, T &, T &, amrex::Real, amrex::Real, int)> F)
Definition: ERF_MRI.H:161
void set_slow_rhs_post(std::function< void(T &, T &, T &, T &, const amrex::Real, const amrex::Real, const amrex::Real, const int)> F)
Definition: ERF_MRI.H:138
void set_slow_rhs_pre(std::function< void(T &, T &, T &, const amrex::Real, const amrex::Real, const amrex::Real, const int)> F)
Definition: ERF_MRI.H:134
void set_slow_fast_timestep_ratio(const int timestep_ratio=1)
Definition: ERF_MRI.H:151
amrex::Real advance(T &S_old, T &S_new, amrex::Real time, const amrex::Real time_step)
Definition: ERF_MRI.H:171
@ pi0_comp
Definition: ERF_IndexDefines.H:75
@ p0_comp
Definition: ERF_IndexDefines.H:74
@ r0_comp
Definition: ERF_IndexDefines.H:73
@ qt
Definition: ERF_Kessler.H:28
real(c_double), parameter p0
Definition: ERF_module_model_constants.F90:40
real(kind=kind_phys), parameter, private r0
Definition: ERF_module_mp_wsm6.F90:21
bool rayleigh_damp_V
Definition: ERF_DampingStruct.H:85
bool rayleigh_damp_T
Definition: ERF_DampingStruct.H:87
bool rayleigh_damp_W
Definition: ERF_DampingStruct.H:86
bool rayleigh_damp_U
Definition: ERF_DampingStruct.H:84
Definition: ERF_DiffStruct.H:19
MolecDiffType molec_diff_type
Definition: ERF_DiffStruct.H:84
static MeshType mesh_type
Definition: ERF_DataStruct.H:1123
DampingChoice dampingChoice
Definition: ERF_DataStruct.H:1133
DiffChoice diffChoice
Definition: ERF_DataStruct.H:1132
bool custom_rhotheta_forcing
Definition: ERF_DataStruct.H:1223
bool custom_geostrophic_profile
Definition: ERF_DataStruct.H:1228
bool use_num_diff
Definition: ERF_DataStruct.H:1283
bool custom_moisture_forcing
Definition: ERF_DataStruct.H:1224
amrex::Vector< TurbChoice > turbChoice
Definition: ERF_DataStruct.H:1135
static SpongeType sponge_type
Definition: ERF_SpongeStruct.H:81
Definition: ERF_TurbStruct.H:82
bool use_kturb
Definition: ERF_TurbStruct.H:465
Here is the call graph for this function:

◆ advance_lsm()

void ERF::advance_lsm ( int  lev,
amrex::MultiFab &  cons_in,
amrex::MultiFab &  xvel_in,
amrex::MultiFab &  yvel_in,
const amrex::Real time,
const amrex::Real dt_advance 
)
11 {
12  if (solverChoice.lsm_type != LandSurfaceType::None) {
13  if (solverChoice.lsm_type == LandSurfaceType::NOAHMP) {
14  lsm.Advance(lev, cons_in, xvel_in, yvel_in,
15  SFS_hfx3_lev[lev].get(), SFS_q1fx3_lev[lev].get(),
16  time, dt_advance, istep[0]);
17  } else {
18  lsm.Advance(lev, dt_advance);
19  }
20  }
21 }
LandSurface lsm
Definition: ERF.H:908
amrex::Vector< int > istep
Definition: ERF.H:835
void Advance(const int &lev, amrex::MultiFab &cons_in, amrex::MultiFab &xvel_in, amrex::MultiFab &yvel_in, amrex::MultiFab *hfx3_out, amrex::MultiFab *qfx3_out, const amrex::Real &time, const amrex::Real &dt_advance, const int &nstep)
Definition: ERF_LandSurface.H:53
LandSurfaceType lsm_type
Definition: ERF_DataStruct.H:1290
Here is the call graph for this function:

◆ advance_microphysics()

void ERF::advance_microphysics ( int  lev,
amrex::MultiFab &  cons_in,
const amrex::Real dt_advance,
const int &  iteration,
const amrex::Real time 
)
10 {
11  if (solverChoice.moisture_type != MoistureType::None) {
12  if (lev > 0) {
13  MultiFab& U_new = vars_new[lev][Vars::xvel];
14  MultiFab& V_new = vars_new[lev][Vars::yvel];
15  MultiFab& W_new = vars_new[lev][Vars::zvel];
16  FillPatchFineLevel(lev, time + dt_advance,
17  {&cons, &U_new, &V_new, &W_new},
18  {&cons, &rU_new[lev], &rV_new[lev], &rW_new[lev]},
19  base_state[lev], base_state[lev]);
20  } else {
21  cons.FillBoundary(geom[lev].periodicity());
22  }
23  micro->Update_Micro_Vars_Lev(lev, cons);
24  micro->Advance(lev, dt_advance, iteration, time, solverChoice, vars_new, z_phys_nd, phys_bc_type);
25  micro->Update_State_Vars_Lev(lev, cons, *z_phys_nd[lev]);
26 
27  // Sync cons[lev-1] covered cells with the moist state just written
28  // to cons[lev]. Without this, the next sub-cycle's FillPatchFineLevel
29  // for level lev would pull stale (latent-heat-less) values from
30  // cons[lev-1]'s coarse cells via cell-conservative interpolation,
31  // causing an artificial outward heat/q flux across the lev/(lev-1)
32  // boundary that drains the bubble interior.
33  if (lev > 0 && solverChoice.coupling_type == CouplingType::TwoWay &&
34  Microphysics::modelType(solverChoice.moisture_type) == MoistureModelType::Lagrangian) {
35  AverageDownMoistStateTo(lev - 1);
36  }
37  }
38 }
void AverageDownMoistStateTo(int crse_lev)
Conservation-preserving fine→coarse average of moist state components (RhoTheta and the contiguous mo...
Definition: ERF_AverageDown.cpp:243
std::unique_ptr< Microphysics > micro
Definition: ERF.H:892
static MoistureModelType modelType(const MoistureType a_moisture_type)
query if a specified moisture model is Eulerian or Lagrangian
Definition: ERF_Microphysics.H:102
CouplingType coupling_type
Definition: ERF_DataStruct.H:1286
Here is the call graph for this function:

◆ advance_radiation()

void ERF::advance_radiation ( int  lev,
amrex::MultiFab &  cons_in,
const amrex::Real dt_advance 
)
8 {
9  if (solverChoice.rad_type != RadiationType::None) {
10 #ifdef ERF_USE_NETCDF
11  MultiFab *lat_ptr = lat_m[lev].get();
12  MultiFab *lon_ptr = lon_m[lev].get();
13 #else
14  MultiFab *lat_ptr = nullptr;
15  MultiFab *lon_ptr = nullptr;
16 #endif
17  // T surf from SurfaceLayer if we have it
18  MultiFab* t_surf = (m_SurfaceLayer) ? m_SurfaceLayer->get_t_surf(lev) : nullptr;
19 
20  // RRTMGP inputs names and pointers
21  Vector<std::string> lsm_input_names = rad[lev]->get_lsm_input_varnames();
22  Vector<MultiFab*> lsm_input_ptrs(lsm_input_names.size(),nullptr);
23  for (int i(0); i<lsm_input_ptrs.size(); ++i) {
24  int varIdx = lsm.Get_DataIdx(lev,lsm_input_names[i]);
25  if (varIdx >= 0) { lsm_input_ptrs[i] = lsm.Get_Data_Ptr(lev,varIdx); }
26  }
27 
28  // RRTMGP output names and pointers
29  Vector<std::string> lsm_output_names = rad[lev]->get_lsm_output_varnames();
30  Vector<MultiFab*> lsm_output_ptrs(lsm_output_names.size(),nullptr);
31  for (int i(0); i<lsm_output_ptrs.size(); ++i) {
32  int varIdx = lsm.Get_DataIdx(lev,lsm_output_names[i]);
33  if (varIdx >= 0) { lsm_output_ptrs[i] = lsm.Get_Data_Ptr(lev,varIdx); }
34  }
35 
36  // Enter radiation class driver
37  amrex::Real time_for_rad = t_old[lev] + start_time;
38  rad[lev]->Run(lev, istep[lev], time_for_rad, dt_advance,
39  cons.boxArray(), geom[lev], &(cons),
40  lmask_lev[lev][0].get(), t_surf,
41  lsm_input_ptrs, lsm_output_ptrs,
42  qheating_rates[lev].get(), rad_fluxes[lev].get(),
43  z_phys_nd[lev].get() , lat_ptr, lon_ptr);
44  }
45 }
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::iMultiFab > > > lmask_lev
Definition: ERF.H:945
amrex::Vector< std::unique_ptr< IRadiation > > rad
Definition: ERF.H:914
amrex::Vector< amrex::Real > t_old
Definition: ERF.H:840
amrex::Vector< std::unique_ptr< amrex::MultiFab > > lon_m
Definition: ERF.H:792
amrex::Vector< std::unique_ptr< amrex::MultiFab > > lat_m
Definition: ERF.H:792
amrex::Vector< std::unique_ptr< amrex::MultiFab > > qheating_rates
Definition: ERF.H:915
amrex::Vector< std::unique_ptr< amrex::MultiFab > > rad_fluxes
Definition: ERF.H:916
int Get_DataIdx(const int &lev, std::string &varname)
Definition: ERF_LandSurface.H:110
amrex::MultiFab * Get_Data_Ptr(const int &lev, const int &varIdx)
Definition: ERF_LandSurface.H:92
RadiationType rad_type
Definition: ERF_DataStruct.H:1291

◆ appendPlotVariables()

void ERF::appendPlotVariables ( const std::string &  pp_plot_var_names,
amrex::Vector< std::string > &  plot_var_names 
)
private
233 {
234  ParmParse pp(pp_prefix);
235 
236  Vector<std::string> plot_var_names(0);
237  if (pp.contains(pp_plot_var_names.c_str())) {
238  std::string nm;
239  int nPltVars = pp.countval(pp_plot_var_names.c_str());
240  for (int i = 0; i < nPltVars; i++) {
241  pp.get(pp_plot_var_names.c_str(), nm, i);
242  // Add the named variable to our list of plot variables
243  // if it is not already in the list
244  if (!containerHasElement(plot_var_names, nm)) {
245  plot_var_names.push_back(nm);
246  }
247  }
248  }
249 
250  Vector<std::string> tmp_plot_names(0);
251 #ifdef ERF_USE_PARTICLES
252  Vector<std::string> particle_mesh_plot_names;
253  particleData.GetMeshPlotVarNames( particle_mesh_plot_names );
254  if (particle_mesh_plot_names.size() > 0) {
255  static bool first_call = true;
256  if (first_call) {
257  Print() << "ParticleData: the following additional Eulerian variables are available to plot:\n";
258  for (int i = 0; i < particle_mesh_plot_names.size(); i++) {
259  Print() << " " << particle_mesh_plot_names[i] << "\n";
260  }
261  first_call = false;
262  }
263  for (int i = 0; i < particle_mesh_plot_names.size(); i++) {
264  std::string tmp(particle_mesh_plot_names[i]);
265  if (containerHasElement(plot_var_names, tmp) ) {
266  tmp_plot_names.push_back(tmp);
267  }
268  }
269  }
270 #endif
271 
272  {
273  Vector<std::string> microphysics_plot_names;
274  micro->GetPlotVarNames(microphysics_plot_names);
275  if (microphysics_plot_names.size() > 0) {
276  static bool first_call = true;
277  if (first_call) {
278  Print() << getEnumNameString(solverChoice.moisture_type)
279  << ": the following additional variables are available to plot:\n";
280  for (int i = 0; i < microphysics_plot_names.size(); i++) {
281  Print() << " " << microphysics_plot_names[i] << "\n";
282  }
283  first_call = false;
284  }
285  for (auto& plot_name : microphysics_plot_names) {
286  if (containerHasElement(plot_var_names, plot_name)) {
287  tmp_plot_names.push_back(plot_name);
288  }
289  }
290  }
291  }
292 
293  for (int i = 0; i < tmp_plot_names.size(); i++) {
294  a_plot_var_names.push_back( tmp_plot_names[i] );
295  }
296 
297  // Finally, check to see if we found all the requested variables
298  for (const auto& plot_name : plot_var_names) {
299  if (!containerHasElement(a_plot_var_names, plot_name)) {
300  if (amrex::ParallelDescriptor::IOProcessor()) {
301  Warning("\nWARNING: Requested to plot variable '" + plot_name + "' but it is not available");
302  }
303  }
304  }
305 }
bool containerHasElement(const V &iterable, const T &query)
Definition: ERF_Container.H:5
std::string pp_prefix
Definition: ERF.H:562
@ tmp
Definition: ERF_AdvanceWSM6.cpp:114
Here is the call graph for this function:

◆ apply_gaussian_smoothing_to_perturbations()

void ERF::apply_gaussian_smoothing_to_perturbations ( const int  lev,
amrex::MultiFab &  mf_cc_pert 
)
88 {
89  const Geometry& gm = geom[lev];
90  const Real dx = gm.CellSize(0);
91  const Real dy = gm.CellSize(1);
92 
93  const Real dmesh = std::min(dx, dy);
94 
95  // ---- User choice ----
97  const int r = static_cast<int>(3.0 * sigma / dmesh);
98 
99  const int ncomp = mf_cc_pert.nComp();
100 
101  // ---- Precompute Gaussian weights ----
102  const int wsize = 2*r + 1;
103  Vector<Real> w_host(wsize * wsize);
104 
105  Real Z = zero;
106  for (int m = -r; m <= r; ++m) {
107  for (int n = -r; n <= r; ++n) {
108  Real val = std::exp(-(m*m*dx*dx + n*n*dy*dy)
109  /(two*sigma*sigma));
110  w_host[(m+r)*wsize + (n+r)] = val;
111  Z += val;
112  }
113  }
114 
115  for (auto& v : w_host) {
116  v /= Z;
117  }
118 
119  Gpu::DeviceVector<Real> w_dev(w_host.size());
120  Gpu::copy(Gpu::hostToDevice, w_host.begin(), w_host.end(), w_dev.begin());
121 
122  Real const* w = w_dev.data();
123 
124  // ---- Create a grown copy (for stencil access) ----
125  IntVect ngrow_big(AMREX_D_DECL(r, r, 0));
126 
127  MultiFab mf_copy(mf_cc_pert.boxArray(),
128  mf_cc_pert.DistributionMap(),
129  ncomp, ngrow_big);
130 
131  mf_copy.ParallelCopy(mf_cc_pert,
132  0, 0, ncomp,
133  IntVect(0), ngrow_big,
134  gm.periodicity());
135 
136  // ---- Apply smoothing ----
137  for (MFIter mfi(mf_cc_pert, TilingIfNotGPU()); mfi.isValid(); ++mfi)
138  {
139  const Box& bx = mfi.tilebox();
140 
141  auto const& in = mf_copy.const_array(mfi);
142  auto const& out = mf_cc_pert.array(mfi);
143 
144  ParallelFor(bx, ncomp,
145  [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
146  {
147  Real sum = zero;
148 
149  for (int m = -r; m <= r; ++m) {
150  for (int nn = -r; nn <= r; ++nn) {
151  Real wij = w[(m+r)*wsize + (nn+r)];
152  sum += wij * in(i+m, j+nn, k, n);
153  }
154  }
155 
156  out(i,j,k,n) = sum;
157  });
158  }
160 }
constexpr amrex::Real two
Definition: ERF_Constants.H:8
constexpr amrex::Real zero
Definition: ERF_Constants.H:6
struct @27 out
struct @27 in
const Real dy
Definition: ERF_InitCustomPert_ABL.H:24
const Real dx
Definition: ERF_InitCustomPert_ABL.H:23
amrex::Real sigma
Definition: ERF_InitCustomPert_DataAssimilation_ISV.H:11
void NormalizeMultiFabRMS_PerComponent(MultiFab &mf_cc_pert)
Definition: ERF_InitForEnsemble.cpp:40
ParallelFor(grown_box, [=] AMREX_GPU_DEVICE(int i, int j, int k) { qrcuten_arr(i, j, k)=Real(0);qscuten_arr(i, j, k)=Real(0);qicuten_arr(i, j, k)=Real(0);})
amrex::Real ens_pert_correlated_radius
Definition: ERF_DataStruct.H:1343
Here is the call graph for this function:

◆ ApplyOceanSurfaceState()

void ERF::ApplyOceanSurfaceState ( const amrex::Vector< amrex::MultiFab * > &  state,
amrex::Real  time 
)
271 {
272  amrex::ignore_unused(time);
273 
274  // Example (legacy state-passing): state[0] carries SST [K].
275  // We intentionally copy only one horizontal slab, derived from the
276  // interface face convention:
277  // - ocean/atmos interface face index on source: k_face = src.bigEnd(2) + 1
278  // - source cell below that face (ocean top cell): src_k = k_face - 1
279  // - destination LSM surface-facing slab uses its bottom-most k index
280  // (for current level-0 matched-grid tests this is the interface slab).
281  // This encodes the physical alignment note from coupled discussions:
282  // ERF k=0 atmospheric cell lies above REMORA k=nz-1 ocean cell.
283  // For initial matched-grid tests, require identical horizontal BoxArray/DM.
284  if (solverChoice.lsm_type == LandSurfaceType::None) {
285  return;
286  }
287 
288  if (!state.empty() && state[0] != nullptr && lsm.Get_Data_Ptr(0, 0) != nullptr) {
289  auto* dst = lsm.Get_Data_Ptr(0, 0);
290  const int dst_k = dst->boxArray().minimalBox().smallEnd(2);
291  const int src_k = state[0]->boxArray().minimalBox().bigEnd(2);
292  for (amrex::MFIter mfi(*dst, amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi) {
293  amrex::Box bx = amrex::makeSlab(mfi.validbox(), 2, dst_k);
294  auto dst_arr = dst->array(mfi);
295  auto src_arr = state[0]->const_array(mfi);
296  amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int) {
297  dst_arr(i,j,dst_k) = src_arr(i,j,src_k);
298  });
299  }
300  }
301 }
Here is the call graph for this function:

◆ AverageDown()

void ERF::AverageDown ( )
private
17 {
18  AMREX_ALWAYS_ASSERT(solverChoice.coupling_type == CouplingType::TwoWay);
19 
20  int src_comp, num_comp;
21  for (int lev = finest_level-1; lev >= 0; --lev)
22  {
23  // If anelastic we don't average down rho because rho == rho0.
24  if (solverChoice.anelastic[lev]) {
25  src_comp = 1;
26  } else {
27  src_comp = 0;
28  }
29  num_comp = vars_new[0][Vars::cons].nComp() - src_comp;
30  AverageDownTo(lev,src_comp,num_comp);
31  }
32 }
AMREX_ALWAYS_ASSERT(bx.length()[2]==khi+1)
void AverageDownTo(int crse_lev, int scomp, int ncomp, bool do_perturbational_and_momenta=true)
Definition: ERF_AverageDown.cpp:36
amrex::Vector< int > anelastic
Definition: ERF_DataStruct.H:1141
Here is the call graph for this function:

◆ AverageDownMoistStateTo()

void ERF::AverageDownMoistStateTo ( int  crse_lev)

Conservation-preserving fine→coarse average of moist state components (RhoTheta and the contiguous moist q range) using detJ/mfac weighting, reusing AverageDownTo with perturbational/momenta handling disabled.

244 {
245  AMREX_ALWAYS_ASSERT(solverChoice.coupling_type == CouplingType::TwoWay);
246  AMREX_ALWAYS_ASSERT(crse_lev >= 0 && crse_lev < finest_level);
247 
248  AverageDownTo(crse_lev, RhoTheta_comp, 1, false);
249 
250  const int n_moist = (micro) ? micro->Get_Qstate_Size() : 0;
251  if (n_moist > 0) {
252  AverageDownTo(crse_lev, RhoQ1_comp, n_moist, false);
253  }
254 }
Here is the call graph for this function:

◆ AverageDownTo()

void ERF::AverageDownTo ( int  crse_lev,
int  scomp,
int  ncomp,
bool  do_perturbational_and_momenta = true 
)
37 {
38  if (do_perturbational_and_momenta) {
39  if (solverChoice.anelastic[crse_lev]) {
40  AMREX_ALWAYS_ASSERT(scomp == 1);
41  } else {
42  AMREX_ALWAYS_ASSERT(scomp == 0);
43  }
44  AMREX_ALWAYS_ASSERT(ncomp == vars_new[crse_lev][Vars::cons].nComp() - scomp);
45  } else {
46  AMREX_ALWAYS_ASSERT(scomp >= 0);
47  AMREX_ALWAYS_ASSERT(ncomp > 0);
48  AMREX_ALWAYS_ASSERT(scomp + ncomp <= vars_new[crse_lev][Vars::cons].nComp());
49  }
50  AMREX_ALWAYS_ASSERT(solverChoice.coupling_type == CouplingType::TwoWay);
51 
52  // ******************************************************************************************
53  // First do cell-centered quantities
54  // The quantity that is conserved is not (rho S), but rather (rho S / m^2) where
55  // m is the map scale factor at cell centers
56  // Here we multiply (rho S) by detJ and divide (rho S) by m^2 before average down
57  // ******************************************************************************************
58  for (int lev = crse_lev; lev <= crse_lev+1; lev++) {
59  for (MFIter mfi(vars_new[lev][Vars::cons], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
60  const Box& bx = mfi.tilebox();
61  const Array4< Real> cons_arr = vars_new[lev][Vars::cons].array(mfi);
62  const Array4<const Real> mfx_arr = mapfac[lev][MapFacType::m_x]->const_array(mfi);
63  const Array4<const Real> mfy_arr = mapfac[lev][MapFacType::m_y]->const_array(mfi);
64  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
65  const Array4<const Real> detJ_arr = detJ_cc[lev]->const_array(mfi);
66  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
67  {
68  cons_arr(i,j,k,scomp+n) *= detJ_arr(i,j,k) / (mfx_arr(i,j,0)*mfy_arr(i,j,0));
69  });
70  } else {
71  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
72  {
73  cons_arr(i,j,k,scomp+n) /= (mfx_arr(i,j,0)*mfy_arr(i,j,0));
74  });
75  }
76  } // mfi
77  } // lev
78 
79  int fine_lev = crse_lev+1;
80 
81  if (do_perturbational_and_momenta && interpolation_type == StateInterpType::Perturbational) {
82  // Make the fine rho and (rho theta) be perturbational
83  MultiFab::Divide(vars_new[fine_lev][Vars::cons],vars_new[fine_lev][Vars::cons],
84  Rho_comp,RhoTheta_comp,1,IntVect{0});
85  MultiFab::Subtract(vars_new[fine_lev][Vars::cons],base_state[fine_lev],
86  BaseState::r0_comp,Rho_comp,1,IntVect{0});
87  MultiFab::Subtract(vars_new[fine_lev][Vars::cons],base_state[fine_lev],
88  BaseState::th0_comp,RhoTheta_comp,1,IntVect{0});
89 
90  // Make the crse rho and (rho theta) be perturbational
91  MultiFab::Divide(vars_new[crse_lev][Vars::cons],vars_new[crse_lev][Vars::cons],
92  Rho_comp,RhoTheta_comp,1,IntVect{0});
93  MultiFab::Subtract(vars_new[crse_lev][Vars::cons],base_state[crse_lev],
94  BaseState::r0_comp,Rho_comp,1,IntVect{0});
95  MultiFab::Subtract(vars_new[crse_lev][Vars::cons],base_state[crse_lev],
96  BaseState::th0_comp,RhoTheta_comp,1,IntVect{0});
97  }
98 
99  if (SolverChoice::terrain_type != TerrainType::EB) {
100  average_down(vars_new[crse_lev+1][Vars::cons],vars_new[crse_lev ][Vars::cons],
101  scomp, ncomp, refRatio(crse_lev));
102  } else {
103  // const auto dx = geom[fine_lev].CellSize();
104  // Setting cell_vol to the exact value may cause round-off errors in volume average.
105  // const Real cell_vol = dx[0]*dx[1]*dx[2];
106  constexpr Real cell_vol = one;
107  const BoxArray& ba = vars_new[fine_lev][IntVars::cons].boxArray();
108  const DistributionMapping& dm = vars_new[fine_lev][IntVars::cons].DistributionMap();
109  MultiFab vol_fine(ba, dm, 1, 0);
110  vol_fine.setVal(cell_vol);
111  EB_average_down(vars_new[fine_lev][Vars::cons],vars_new[crse_lev][Vars::cons],
112  vol_fine, *detJ_cc[fine_lev],
113  scomp, ncomp, refRatio(crse_lev));
114  }
115 
116  if (do_perturbational_and_momenta && interpolation_type == StateInterpType::Perturbational) {
117  // Restore the fine data to what it was
118  MultiFab::Add(vars_new[fine_lev][Vars::cons],base_state[fine_lev],
119  BaseState::r0_comp,Rho_comp,1,IntVect{0});
120  MultiFab::Add(vars_new[fine_lev][Vars::cons],base_state[fine_lev],
121  BaseState::th0_comp,RhoTheta_comp,1,IntVect{0});
122  MultiFab::Multiply(vars_new[fine_lev][Vars::cons],vars_new[fine_lev][Vars::cons],
123  Rho_comp,RhoTheta_comp,1,IntVect{0});
124 
125  // Make the crse data be full values not perturbational
126  MultiFab::Add(vars_new[crse_lev][Vars::cons],base_state[crse_lev],
127  BaseState::r0_comp,Rho_comp,1,IntVect{0});
128  MultiFab::Add(vars_new[crse_lev][Vars::cons],base_state[crse_lev],
129  BaseState::th0_comp,RhoTheta_comp,1,IntVect{0});
130  MultiFab::Multiply(vars_new[crse_lev][Vars::cons],vars_new[crse_lev][Vars::cons],
131  Rho_comp,RhoTheta_comp,1,IntVect{0});
132  }
133 
134  vars_new[crse_lev][Vars::cons].FillBoundary(geom[crse_lev].periodicity());
135 
136  // ******************************************************************************************
137  // Here we multiply (rho S) by m^2 and divide by detJ after average down
138  // ******************************************************************************************
139  for (int lev = crse_lev; lev <= crse_lev+1; lev++) {
140  for (MFIter mfi(vars_new[lev][Vars::cons], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
141  const Box& bx = mfi.tilebox();
142  const Array4< Real> cons_arr = vars_new[lev][Vars::cons].array(mfi);
143  const Array4<const Real> mfx_arr = mapfac[lev][MapFacType::m_x]->const_array(mfi);
144  const Array4<const Real> mfy_arr = mapfac[lev][MapFacType::m_y]->const_array(mfi);
145  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
146  const Array4<const Real> detJ_arr = detJ_cc[lev]->const_array(mfi);
147  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
148  {
149  cons_arr(i,j,k,scomp+n) *= (mfx_arr(i,j,0)*mfy_arr(i,j,0)) / detJ_arr(i,j,k);
150  });
151  } else { // MeshType::ConstantDz
152  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
153  {
154  cons_arr(i,j,k,scomp+n) *= (mfx_arr(i,j,0)*mfy_arr(i,j,0));
155  });
156  }
157  } // mfi
158  } // lev
159 
160  // Fill EB covered cells by old values
161  // (This won't be needed because EB_average_down copies the covered value.)
162  if (SolverChoice::terrain_type == TerrainType::EB) {
163  for (int lev = crse_lev; lev <= crse_lev+1; lev++) {
164  for (MFIter mfi(vars_new[lev][Vars::cons], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
165  const Box& bx = mfi.tilebox();
166  const Array4< Real> cons_new = vars_new[lev][Vars::cons].array(mfi);
167  const Array4<const Real> cons_old = vars_old[lev][Vars::cons].array(mfi);
168  const Array4<const Real> detJ_arr = detJ_cc[lev]->const_array(mfi);
169  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
170  {
171  if (detJ_arr(i,j,k) == zero) {
172  cons_new(i,j,k,scomp+n) = cons_old(i,j,k,scomp+n);
173  }
174  });
175  } // mfi
176  } // lev
177  }
178 
179  if (!do_perturbational_and_momenta) return;
180 
181  // ******************************************************************************************
182  // Now average down momenta.
183  // Note that vars_new holds velocities not momenta, but we want to do conservative
184  // averaging so we first convert to momentum, then average down, then convert
185  // back to velocities -- only on the valid region
186  // ******************************************************************************************
187  for (int lev = crse_lev; lev <= crse_lev+1; lev++)
188  {
189  // FillBoundary for density so we can go back and forth between velocity and momentum
190  vars_new[lev][Vars::cons].FillBoundary(geom[lev].periodicity());
191 
192  const MultiFab* c_vfrac = nullptr;
193  if (SolverChoice::terrain_type == TerrainType::EB) {
194  c_vfrac = &((get_eb(lev).get_const_factory())->getVolFrac());
195  }
196 
197  VelocityToMomentum(vars_new[lev][Vars::xvel], IntVect(0,0,0),
198  vars_new[lev][Vars::yvel], IntVect(0,0,0),
199  vars_new[lev][Vars::zvel], IntVect(0,0,0),
200  vars_new[lev][Vars::cons],
201  rU_new[lev],
202  rV_new[lev],
203  rW_new[lev],
204  Geom(lev).Domain(),
206  c_vfrac);
207  }
208 
209  if (SolverChoice::terrain_type != TerrainType::EB) {
210  average_down_faces(rU_new[crse_lev+1], rU_new[crse_lev], refRatio(crse_lev), geom[crse_lev]);
211  average_down_faces(rV_new[crse_lev+1], rV_new[crse_lev], refRatio(crse_lev), geom[crse_lev]);
212  average_down_faces(rW_new[crse_lev+1], rW_new[crse_lev], refRatio(crse_lev), geom[crse_lev]);
213  } else {
214  EB_average_down_faces({&rU_new[crse_lev+1], &rV_new[crse_lev+1], &rW_new[crse_lev+1]},
215  {&rU_new[crse_lev], &rV_new[crse_lev], &rW_new[crse_lev]},
216  refRatio(crse_lev), 0);
217  }
218 
219  for (int lev = crse_lev; lev <= crse_lev+1; lev++) {
220 
221  const MultiFab* c_vfrac = nullptr;
222  if (SolverChoice::terrain_type == TerrainType::EB) {
223  c_vfrac = &((get_eb(lev).get_const_factory())->getVolFrac());
224  }
225 
227  vars_new[lev][Vars::yvel],
228  vars_new[lev][Vars::zvel],
229  vars_new[lev][Vars::cons],
230  rU_new[lev],
231  rV_new[lev],
232  rW_new[lev],
233  Geom(lev).Domain(),
235  c_vfrac);
236  }
237 }
void MomentumToVelocity(MultiFab &xvel, MultiFab &yvel, MultiFab &zvel, const MultiFab &density, const MultiFab &xmom_in, const MultiFab &ymom_in, const MultiFab &zmom_in, const Box &domain, const Vector< BCRec > &domain_bcs_type_h, const MultiFab *c_vfrac)
Definition: ERF_MomentumToVelocity.cpp:25
static StateInterpType interpolation_type
Definition: ERF.H:1268
@ th0_comp
Definition: ERF_IndexDefines.H:76
Here is the call graph for this function:

◆ build_fine_mask()

void ERF::build_fine_mask ( int  lev,
amrex::MultiFab &  fine_mask 
)

Helper function for constructing a fine mask, that is, a MultiFab masking coarser data at a lower level by zeroing out covered cells in the fine mask MultiFab we compute.

Parameters
levelFine level index which masks underlying coarser data
126 {
127  // Mask for zeroing covered cells
128  AMREX_ASSERT(level > 0);
129 
130  BoxArray cba = grids[level-1];
131  DistributionMapping cdm = dmap[level-1];
132 
133  BoxArray fba = fine_mask_lev.boxArray();
134 
135  iMultiFab ifine_mask_lev = makeFineMask(cba, cdm, fba, ref_ratio[level-1], 1, 0);
136 
137  const auto fma = fine_mask_lev.arrays();
138  const auto ifma = ifine_mask_lev.arrays();
139  ParallelFor(fine_mask_lev, [=] AMREX_GPU_DEVICE(int bno, int i, int j, int k) noexcept
140  {
141  fma[bno](i,j,k) = ifma[bno](i,j,k);
142  });
143 }
Here is the call graph for this function:

◆ check_for_low_temp()

void ERF::check_for_low_temp ( amrex::MultiFab &  S)
3285 {
3286  // *****************************************************************************
3287  // Test for low temp (low is defined as beyond the microphysics range of validity)
3288  // *****************************************************************************
3289  //
3290  // This value is defined in erf_dtesati in Source/Utils/ERF_MicrophysicsUtils.H
3291  Real t_low = Real(273.16) - Real(85.);
3292  //
3293  for (MFIter mfi(S); mfi.isValid(); ++mfi)
3294  {
3295  Box bx = mfi.tilebox();
3296  const Array4<Real> &s_arr = S.array(mfi);
3297  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
3298  {
3299  const Real rho = s_arr(i, j, k, Rho_comp);
3300  const Real rhotheta = s_arr(i, j, k, RhoTheta_comp);
3301  const Real qv = s_arr(i, j, k, RhoQ1_comp) / rho;
3302 
3303  Real temp = getTgivenRandRTh(rho, rhotheta, qv);
3304 
3305  if (temp < t_low) {
3306 #ifdef AMREX_USE_GPU
3307  AMREX_DEVICE_PRINTF("Temperature too low in cell: %d %d %d %e \n", i,j,k,temp);
3308 #else
3309  printf("Temperature too low in cell: %d %d %d \n", i,j,k);
3310  printf("Based on temp / rhotheta / rho / qv %e %e %e %e \n", temp,rhotheta,rho,qv);
3311 #endif
3312  Abort();
3313  }
3314  });
3315  }
3316 }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getTgivenRandRTh(const amrex::Real rho, const amrex::Real rhotheta, const amrex::Real qv=amrex::Real(0))
Definition: ERF_EOS.H:46
rho
Definition: ERF_InitCustomPert_Bubble.H:106
@ qv
Definition: ERF_Kessler.H:29
Here is the call graph for this function:

◆ check_for_negative_theta()

void ERF::check_for_negative_theta ( amrex::MultiFab &  S)
3320 {
3321  // *****************************************************************************
3322  // Test for negative (rho theta)
3323  // *****************************************************************************
3324  for (MFIter mfi(S); mfi.isValid(); ++mfi)
3325  {
3326  Box bx = mfi.tilebox();
3327  const Array4<Real> &s_arr = S.array(mfi);
3328  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
3329  {
3330  const Real rho = s_arr(i, j, k, Rho_comp);
3331  const Real rhotheta = s_arr(i, j, k, RhoTheta_comp);
3332 
3333  if (rho <= zero) {
3334 #ifdef AMREX_USE_GPU
3335  AMREX_DEVICE_PRINTF("Rho is negative at %d %d %d %e \n", i,j,k,rho);
3336 #else
3337  printf("Rho is negative at %d %d %d %e \n", i,j,k,rho);
3338  Abort("Bad rho in check_for_negative_theta");
3339 #endif
3340  }
3341 
3342  if (rhotheta <= zero) {
3343 #ifdef AMREX_USE_GPU
3344  AMREX_DEVICE_PRINTF("RhoTheta is negative at %d %d %d %e \n", i,j,k,rhotheta);
3345 #else
3346  printf("RhoTheta is negative at %d %d %d %e \n", i,j,k,rhotheta);
3347  Abort("Bad theta in check_for_negative_theta");
3348 #endif
3349  }
3350 
3351  });
3352  } // mfi
3353 }
Here is the call graph for this function:

◆ check_state_for_nans()

void ERF::check_state_for_nans ( amrex::MultiFab const &  S)
3239 {
3240  bool any_have_nans = false;
3241 
3242  for (int i = 0; i < S.nComp(); i++) {
3243 
3244  if (S.contains_nan(i,1,0))
3245  {
3246  amrex::Print() << "Component " << i << " of conserved variables contains NaNs" << '\n';
3247  any_have_nans = true;
3248  }
3249  }
3250 
3251  if (any_have_nans) {
3252  exit(0);
3253  }
3254 }

◆ check_vels_for_nans()

void ERF::check_vels_for_nans ( amrex::MultiFab const &  xvel,
amrex::MultiFab const &  yvel,
amrex::MultiFab const &  zvel 
)
3258 {
3259  //
3260  // Test at the end of every full timestep whether the solution data contains NaNs
3261  //
3262  bool any_have_nans = false;
3263  if (xvel.contains_nan(0,1,0))
3264  {
3265  amrex::Print() << "x-velocity contains NaNs " << '\n';
3266  any_have_nans = true;
3267  }
3268  if (yvel.contains_nan(0,1,0))
3269  {
3270  amrex::Print() << "y-velocity contains NaNs" << '\n';
3271  any_have_nans = true;
3272  }
3273  if (zvel.contains_nan(0,1,0))
3274  {
3275  amrex::Print() << "z-velocity contains NaNs" << '\n';
3276  any_have_nans = true;
3277  }
3278  if (any_have_nans) {
3279  exit(0);
3280  }
3281 }

◆ ClearLevel()

void ERF::ClearLevel ( int  lev)
override
811 {
812  for (int var_idx = 0; var_idx < Vars::NumTypes; ++var_idx) {
813  vars_new[lev][var_idx].clear();
814  vars_old[lev][var_idx].clear();
815  }
816 
817  base_state[lev].clear();
818 
819  rU_new[lev].clear();
820  rU_old[lev].clear();
821  rV_new[lev].clear();
822  rV_old[lev].clear();
823  rW_new[lev].clear();
824  rW_old[lev].clear();
825 
826  if (lev > 0) {
827  zmom_crse_rhs[lev].clear();
828  }
829 
830  if ( (solverChoice.anelastic[lev] == 1) || (solverChoice.project_initial_velocity[lev] == 1) ) {
831  pp_inc[lev].clear();
832  }
833  if (solverChoice.anelastic[lev] == 0) {
834  lagged_delta_rt[lev].clear();
835  }
836  avg_xmom[lev].clear();
837  avg_ymom[lev].clear();
838  avg_zmom[lev].clear();
839 
840  // Clears the integrator memory
841  mri_integrator_mem[lev].reset();
842 
843  // Clears the physical boundary condition routines
844  physbcs_cons[lev].reset();
845  physbcs_u[lev].reset();
846  physbcs_v[lev].reset();
847  physbcs_w[lev].reset();
848  physbcs_base[lev].reset();
849 
850  // Clears the flux register array (only allocated for TwoWay coupling)
851  if (advflux_reg[lev]) {
852  advflux_reg[lev]->reset();
853  }
854 
855  // Clears the 2D arrays
856  if (sst_lev[lev][0]) {
857  for (int n = 0; n < sst_lev[lev].size(); n++) {
858  sst_lev[lev][n].reset();
859  }
860  }
861  if (tsk_lev[lev][0]) {
862  for (int n = 0; n < tsk_lev[lev].size(); n++) {
863  tsk_lev[lev][n].reset();
864  }
865  }
866  if (lat_m[lev]) {
867  lat_m[lev].reset();
868  }
869  if (lon_m[lev]) {
870  lon_m[lev].reset();
871  }
872  if (sinPhi_m[lev]) {
873  sinPhi_m[lev].reset();
874  }
875  if (cosPhi_m[lev]) {
876  cosPhi_m[lev].reset();
877  }
878 
879 #ifdef ERF_USE_FFT
880  // Clear any FFT solvers built at this level
881  if (m_3D_poisson.size() > lev) {
882  for (int n = 0; n < m_3D_poisson[lev].size(); n++) {
883  m_3D_poisson[lev][n].reset();
884  }
885  }
886  if (m_2D_poisson.size() > lev) {
887  for (int n = 0; n < m_2D_poisson[lev].size(); n++) {
888  m_2D_poisson[lev][n].reset();
889  }
890  }
891 #endif
892 }
amrex::Vector< amrex::MultiFab > avg_xmom
Definition: ERF.H:864
amrex::Vector< amrex::MultiFab > pp_inc
Definition: ERF.H:860
amrex::Vector< amrex::MultiFab > lagged_delta_rt
Definition: ERF.H:863
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > sst_lev
Definition: ERF.H:943
amrex::Vector< amrex::YAFluxRegister * > advflux_reg
Definition: ERF.H:1014
amrex::Vector< std::unique_ptr< amrex::MultiFab > > sinPhi_m
Definition: ERF.H:794
amrex::Vector< std::unique_ptr< amrex::MultiFab > > cosPhi_m
Definition: ERF.H:794
amrex::Vector< amrex::MultiFab > avg_ymom
Definition: ERF.H:865
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_base > > physbcs_base
Definition: ERF.H:873
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > tsk_lev
Definition: ERF.H:944
amrex::Vector< amrex::MultiFab > avg_zmom
Definition: ERF.H:866
@ NumTypes
Definition: ERF_IndexDefines.H:178
amrex::Vector< int > project_initial_velocity
Definition: ERF_DataStruct.H:1143

◆ cloud_fraction()

Real ERF::cloud_fraction ( double  time)
453 {
454  BL_PROFILE("ERF::cloud_fraction()");
455 
456  int lev = 0;
457  // This holds all of qc
458  MultiFab qc(vars_new[lev][Vars::cons],make_alias,RhoQ2_comp,1);
459 
460  int direction = 2; // z-direction
461  Box const& domain = geom[lev].Domain();
462 
463  auto const& qc_arr = qc.const_arrays();
464 
465  // qc_2d is an BaseFab<int> holding the max value over the column
466  auto qc_2d = ReduceToPlane<ReduceOpMax,int>(direction, domain, qc,
467  [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k) -> int
468  {
469  if (qc_arr[box_no](i,j,k) > 0) {
470  return 1;
471  } else {
472  return 0;
473  }
474  });
475 
476  auto* p = qc_2d.dataPtr();
477 
478  Long numpts = qc_2d.numPts();
479 
480  AMREX_ASSERT(numpts < Long(std::numeric_limits<int>::max));
481 
482 #if 1
483  if (ParallelDescriptor::UseGpuAwareMpi()) {
484  ParallelDescriptor::ReduceIntMax(p,static_cast<int>(numpts));
485  } else {
486  Gpu::PinnedVector<int> hv(numpts);
487  Gpu::copyAsync(Gpu::deviceToHost, p, p+numpts, hv.data());
488  Gpu::streamSynchronize();
489  ParallelDescriptor::ReduceIntMax(hv.data(),static_cast<int>(numpts));
490  Gpu::copyAsync(Gpu::hostToDevice, hv.data(), hv.data()+numpts, p);
491  }
492 
493  // Sum over component 0
494  Long num_cloudy = qc_2d.template sum<RunOn::Device>(0);
495 
496 #else
497  //
498  // We need this if we allow domain decomposition in the vertical
499  // but for now we leave it commented out
500  //
501  Long num_cloudy = Reduce::Sum<Long>(numpts,
502  [=] AMREX_GPU_DEVICE (Long i) -> Long {
503  if (p[i] == 1) {
504  return 1;
505  } else {
506  return 0;
507  }
508  });
509  ParallelDescriptor::ReduceLongSum(num_cloudy);
510 #endif
511 
512  Real num_total = Real(qc_2d.box().d_numPts());
513 
514  Real cloud_frac = num_cloudy / num_total;
515 
516  return cloud_frac;
517 }
#define RhoQ2_comp
Definition: ERF_IndexDefines.H:43
@ qc
Definition: ERF_SatAdj.H:40
@ p
Definition: ERF_WSM6.H:176

Referenced by PackAtmosphericStates().

Here is the caller graph for this function:

◆ compute_divergence()

void ERF::compute_divergence ( int  lev,
amrex::MultiFab &  rhs,
amrex::Array< amrex::MultiFab const *, AMREX_SPACEDIM >  rho0_u_const,
amrex::Geometry const &  geom_at_lev 
)

Project the single-level velocity field to enforce incompressibility Note that the level may or may not be level zero

11 {
12  BL_PROFILE("ERF::compute_divergence()");
13 
14  auto dxInv = geom_at_lev.InvCellSizeArray();
15 
16  // ****************************************************************************
17  // Compute divergence which will form RHS
18  // Note that we replace "rho0w" with the contravariant momentum, Omega
19  // ****************************************************************************
20  if (solverChoice.terrain_type == TerrainType::EB)
21  {
22  bool already_on_centroids = true;
23  EB_computeDivergence(rhs, rho0_u_const, geom_at_lev, already_on_centroids);
24  }
25  else if (SolverChoice::mesh_type == MeshType::ConstantDz)
26  {
27  computeDivergence(rhs, rho0_u_const, geom_at_lev);
28  }
29  else
30  {
31  for ( MFIter mfi(rhs,TilingIfNotGPU()); mfi.isValid(); ++mfi)
32  {
33  Box bx = mfi.tilebox();
34  const Array4<Real const>& rho0u_arr = rho0_u_const[0]->const_array(mfi);
35  const Array4<Real const>& rho0v_arr = rho0_u_const[1]->const_array(mfi);
36  const Array4<Real const>& rho0w_arr = rho0_u_const[2]->const_array(mfi);
37  const Array4<Real >& rhs_arr = rhs.array(mfi);
38 
39  const Array4<Real const>& mf_mx = mapfac[lev][MapFacType::m_x]->const_array(mfi);
40  const Array4<Real const>& mf_my = mapfac[lev][MapFacType::m_y]->const_array(mfi);
41  const Array4<Real const>& mf_vx = mapfac[lev][MapFacType::v_x]->const_array(mfi);
42  const Array4<Real const>& mf_uy = mapfac[lev][MapFacType::u_y]->const_array(mfi);
43 
44  if (SolverChoice::mesh_type == MeshType::StretchedDz)
45  {
46  Real* stretched_dz_d_ptr = stretched_dz_d[lev].data();
47  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
48  {
49  Real inv_dz = one/stretched_dz_d_ptr[k];
50  Real mfsq = mf_mx(i,j,0) * mf_my(i,j,0);
51  rhs_arr(i,j,k) = ( (rho0u_arr(i+1,j ,k )/mf_uy(i+1,j,0) - rho0u_arr(i,j,k)/mf_uy(i,j,0)) * dxInv[0]
52  +(rho0v_arr(i ,j+1,k )/mf_vx(i,j+1,0) - rho0v_arr(i,j,k)/mf_vx(i,j,0)) * dxInv[1]
53  +(rho0w_arr(i ,j ,k+1)/mfsq - rho0w_arr(i,j,k)/mfsq ) * inv_dz ) * mfsq;
54  });
55  }
56  else
57  {
58  //
59  // Note we compute the divergence using "rho0w" == Omega
60  //
61  const Array4<Real const>& ax_arr = ax[lev]->const_array(mfi);
62  const Array4<Real const>& ay_arr = ay[lev]->const_array(mfi);
63  const Array4<Real const>& dJ_arr = detJ_cc[lev]->const_array(mfi);
64 
65  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
66  {
67  Real mfsq = mf_mx(i,j,0) * mf_my(i,j,0);
68  rhs_arr(i,j,k) = ( ( ax_arr(i+1,j,k)*rho0u_arr(i+1,j,k)/mf_uy(i+1,j,0)
69  -ax_arr(i ,j,k)*rho0u_arr(i ,j,k)/mf_uy(i ,j,0) ) * dxInv[0]
70  + ( ay_arr(i,j+1,k)*rho0v_arr(i,j+1,k)/mf_vx(i,j+1,0)
71  -ay_arr(i,j ,k)*rho0v_arr(i,j ,k)/mf_vx(i,j ,0) ) * dxInv[1]
72  +( rho0w_arr(i,j,k+1)/mfsq
73  - rho0w_arr(i,j,k )/mfsq ) * dxInv[2] ) * mfsq / dJ_arr(i,j,k);
74  });
75  }
76  } // mfi
77  }
78 }
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ax
Definition: ERF.H:972
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ay
Definition: ERF.H:973
Here is the call graph for this function:

◆ compute_max_pressure_gradient_diagnostic()

void ERF::compute_max_pressure_gradient_diagnostic ( int  lev)
13 {
14  auto& lev_new = vars_new[lev];
15 
16  int ng = (solverChoice.terrain_type == TerrainType::EB) ? 3 : 1;
17 
18  Vector<MultiFab> gradp_temp; gradp_temp.resize(AMREX_SPACEDIM);
19  gradp_temp[0].define(vars_new[lev][Vars::xvel].boxArray(), lev_new[Vars::xvel].DistributionMap(), 1, 0);
20  gradp_temp[0].setVal(0.);
21  gradp_temp[1].define(vars_new[lev][Vars::yvel].boxArray(), lev_new[Vars::yvel].DistributionMap(), 1, 0);
22  gradp_temp[1].setVal(0.);
23  gradp_temp[2].define(vars_new[lev][Vars::zvel].boxArray(), lev_new[Vars::zvel].DistributionMap(), 1, 0);
24  gradp_temp[2].setVal(0.);
25 
26  int comp = 0;
27 
28  // Use this region to take max/min of gpx without including xlo,xhi if using real_bcs
29  Box xface_domain = surroundingNodes(geom[lev].Domain(), 0);
30  int ilo = xface_domain.smallEnd(0);
31  int ihi = xface_domain.bigEnd(0);
33  xface_domain.growLo(0,-1);
34  xface_domain.growHi(0,-1);
35  }
36 
37  // Use this region to take max/min of gpy without including ylo,yhi if using real_bcs
38  Box yface_domain = surroundingNodes(geom[lev].Domain(), 1);
39  int jlo = yface_domain.smallEnd(1);
40  int jhi = yface_domain.bigEnd(1);
42  yface_domain.growLo(1,-1);
43  yface_domain.growHi(1,-1);
44  }
45 
46 
47  // Use this region to take max/min of gpz without including top and bottom faces
48  Box zface_domain = surroundingNodes(geom[lev].Domain(), 2);
49  int klo = zface_domain.smallEnd(2);
50  int khi = zface_domain.bigEnd(2);
51 
52  zface_domain.growLo(2,-1);
53  zface_domain.growHi(2,-1);
54 
55  // *******************************************************************************
56  // First compute for base state pressure
57  // *******************************************************************************
58 
59  Print() << " " << std::endl;
60 
61  MultiFab r_hse(base_state[lev], make_alias, BaseState::r0_comp , 1);
62  MultiFab p_hse(base_state[lev], make_alias, BaseState::p0_comp , 1);
63 
64  compute_gradp(p_hse, geom[lev], *z_phys_nd[lev].get(), *z_phys_cc[lev].get(), mapfac[lev],
65  get_eb(lev), gradp_temp, solverChoice);
66 
67  Real min_gpx = gradp_temp[0].min(xface_domain,comp);
68  Real max_gpx = gradp_temp[0].max(xface_domain,comp);
69  if (max_gpx != zero || min_gpx != zero) {
70  Print() << "Min/Max value of x-gradient of base state pressure are " << min_gpx << " " << max_gpx;
71  IntVect min_loc = gradp_temp[0].minIndex(comp);
72  IntVect max_loc = gradp_temp[0].maxIndex(comp);
73  if (min_loc[0] != ilo && min_loc[0] != ihi) amrex::Print() << " with min at face " << min_loc;
74  if (max_loc[0] != ilo && max_loc[0] != ihi) amrex::Print() << " with max at face " << max_loc;
75  Print() << std::endl;
76  } else {
77  Print() << "Min/max value of x-gradient of base state pressure are zero " << std::endl;
78  }
79 
80  Real min_gpy = gradp_temp[1].min(yface_domain,comp);
81  Real max_gpy = gradp_temp[1].max(yface_domain,comp);
82  if (max_gpy != zero || min_gpy != zero) {
83  Print() << "Min/max value of y-gradient of base state pressure are " << min_gpy << " " << max_gpy;
84  IntVect min_loc = gradp_temp[1].minIndex(comp);
85  IntVect max_loc = gradp_temp[1].maxIndex(comp);
86  if (min_loc[1] != jlo && min_loc[1] != jhi) amrex::Print() << " with min at face " << min_loc;
87  if (max_loc[1] != jlo && max_loc[1] != jhi) amrex::Print() << " with max at face " << max_loc;
88  Print() << std::endl;
89  } else {
90  Print() << "Min/max value of y-gradient of base state pressure are zero " << std::endl;
91  }
92 
93  const Real grav = solverChoice.gravity;
94  for (MFIter mfi(gradp_temp[2]); mfi.isValid(); ++mfi) {
95  Box bx = mfi.validbox(); bx.growHi(2,-1);
96  if (bx.smallEnd(2) == 0) bx.growLo(2,-1);
97  auto gpz_arr = gradp_temp[2].array(mfi);
98  auto const rhse_arr = r_hse.const_array(mfi);
99  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
100  gpz_arr(i,j,k) += grav * myhalf * (rhse_arr(i,j,k) + rhse_arr(i,j,k-1));
101  });
102  }
103 
104  Real min_gpz = gradp_temp[2].min(zface_domain,comp);
105  Real max_gpz = gradp_temp[2].max(zface_domain,comp);
106  if (max_gpz != zero || min_gpz != zero) {
107  IntVect min_loc = gradp_temp[2].minIndex(comp);
108  IntVect max_loc = gradp_temp[2].maxIndex(comp);
109  Print() << "Min/max value of dp0/dz + rho0*|g| are " << min_gpz << " " << max_gpz;
110  if (min_loc[2] != klo && min_loc[2] != khi) amrex::Print() << " with min at face " << min_loc;
111  if (max_loc[2] != klo && max_loc[2] != khi) amrex::Print() << " with max at face " << max_loc;
112  Print() << std::endl;
113  } else {
114  Print() << "Min/max value of dp0/dz + rho0*|g| are zero " << std::endl;
115  }
116  Print() << " " << std::endl;
117 
118  if (!solverChoice.anelastic[lev]) {
119 
120  // *******************************************************************************
121  // Now compute for full (moist) pressure
122  // *******************************************************************************
123 
124  MultiFab p(p_hse.boxArray(), p_hse.DistributionMap(), 1, ng);
125  MultiFab rho(lev_new[Vars::cons], make_alias, Rho_comp , 1);
126 
127  if (solverChoice.moisture_type != MoistureType::None) {
128 
129  for (MFIter mfi(rho); mfi.isValid(); ++mfi)
130  {
131  Box gbx = mfi.tilebox();
132  gbx.grow(IntVect(ng,ng,ng));
133  if (gbx.smallEnd(2) < 0) gbx.setSmall(2,0);
134 
135  const Array4<const Real>& cell_data = lev_new[Vars::cons].array(mfi);
136  const Array4<const Real>& r_arr = rho.array(mfi);
137  const Array4< Real>& pp_arr = p.array(mfi);
138  ParallelFor(gbx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
139  {
140  Real qv_for_p = cell_data(i,j,k,RhoQ1_comp)/r_arr(i,j,k);
141  pp_arr(i,j,k) = getPgivenRTh(cell_data(i,j,k,RhoTheta_comp),qv_for_p);
142  });
143  }
144  compute_gradp(p, geom[lev], *z_phys_nd[lev].get(), *z_phys_cc[lev].get(), mapfac[lev],
145  get_eb(lev), gradp_temp, solverChoice);
146 
147  min_gpx = gradp_temp[0].min(xface_domain,comp);
148  max_gpx = gradp_temp[0].max(xface_domain,comp);
149  if (max_gpx != zero || min_gpx != zero) {
150  Print() << "Min/Max value of x-gradient of full (moist) pressure are " << min_gpx << " " << max_gpx;
151  IntVect min_loc = gradp_temp[0].minIndex(comp);
152  IntVect max_loc = gradp_temp[0].maxIndex(comp);
153  if (min_loc[0] != ilo && min_loc[0] != ihi) amrex::Print() << " with min at face " << min_loc;
154  if (max_loc[0] != ilo && max_loc[0] != ihi) amrex::Print() << " with max at face " << max_loc;
155  Print() << std::endl;
156  } else {
157  Print() << "Min/max value of x-gradient of full (moist) pressure are zero " << std::endl;
158  }
159 
160  Real min_gpy = gradp_temp[1].min(yface_domain,comp);
161  Real max_gpy = gradp_temp[1].max(yface_domain,comp);
162  if (max_gpy != zero || min_gpy != zero) {
163  Print() << "Min/Max value of y-gradient of full (moist) pressure are " << min_gpy << " " << max_gpy;
164  IntVect min_loc = gradp_temp[1].minIndex(comp);
165  IntVect max_loc = gradp_temp[1].maxIndex(comp);
166  if (min_loc[1] != jlo && min_loc[1] != jhi) amrex::Print() << " with min at face " << min_loc;
167  if (max_loc[1] != jlo && max_loc[1] != jhi) amrex::Print() << " with max at face " << max_loc;
168  Print() << std::endl;
169  } else {
170  Print() << "Min/max value of y-gradient of full (moist) pressure are zero " << std::endl;
171  }
172 
173  MultiFab qt(rho.boxArray(), rho.DistributionMap(), 1, 1);
174  int n_qstate_into_total = micro->Get_Qstate_Moist_Size() - micro->Get_Qstate_Moist_NumConc_Size();
175  make_qt(lev_new[Vars::cons], qt, n_qstate_into_total);
176 
177  const Real grav = solverChoice.gravity;
178  for (MFIter mfi(gradp_temp[2]); mfi.isValid(); ++mfi)
179  {
180  Box bx = mfi.validbox(); bx.growHi(2,-1);
181  if (bx.smallEnd(2) == 0) bx.growLo(2,-1);
182  auto gpz_arr = gradp_temp[2].array(mfi);
183  auto const r_arr = rho.const_array(mfi);
184  auto const qt_arr = qt.const_array(mfi);
185 
186  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
187  gpz_arr(i,j,k) += grav * myhalf * (r_arr(i,j,k )*(one+qt_arr(i,j,k )) +
188  r_arr(i,j,k-1)*(one+qt_arr(i,j,k-1)) );
189  });
190  }
191 
192  min_gpz = gradp_temp[2].min(zface_domain,comp);
193  max_gpz = gradp_temp[2].max(zface_domain,comp);
194  if (max_gpz != zero || min_gpz != zero) {
195  IntVect min_loc = gradp_temp[2].minIndex(comp);
196  IntVect max_loc = gradp_temp[2].maxIndex(comp);
197  Print() << "Min/max value of moist dp/dz + rho_m*|g| are " << min_gpz << " " << max_gpz;
198  if (min_loc[2] != klo && min_loc[2] != khi) amrex::Print() << " with min at face " << min_loc;
199  if (max_loc[2] != klo && max_loc[2] != khi) amrex::Print() << " with max at face " << max_loc;
200  Print() << std::endl;
201  } else {
202  Print() << "Min/max value of moist dp/dz + rho_m*|g| are zero " << std::endl;
203  }
204  Print() << " " << std::endl;
205  } // if moist
206  } // if !anelastic
207 }
constexpr amrex::Real myhalf
Definition: ERF_Constants.H:11
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getPgivenRTh(const amrex::Real rhotheta, const amrex::Real qv=amrex::Real(0))
Definition: ERF_EOS.H:81
const int khi
Definition: ERF_InitCustomPert_Bubble.H:21
void compute_gradp(const MultiFab &p, const Geometry &geom, const MultiFab &z_phys_nd, const MultiFab &z_phys_cc, Vector< std::unique_ptr< MultiFab >> &mapfac, const eb_ &ebfact, Vector< MultiFab > &gradp, const SolverChoice &solverChoice)
Definition: ERF_MakeGradP.cpp:113
void make_qt(const MultiFab &cons_state, MultiFab &qt, int n_qstate_into_total)
Definition: ERF_Utils.cpp:37
amrex::Real gravity
Definition: ERF_DataStruct.H:1208
static bool use_real_bcs
Definition: ERF_DataStruct.H:1120
Here is the call graph for this function:

◆ ComputeAndWriteEnsemblePerturbations()

void ERF::ComputeAndWriteEnsemblePerturbations ( )

◆ ComputeDt()

void ERF::ComputeDt ( int  step = -1,
double  cur_time_d = 0.0 
)
private

Function that calls estTimeStep for each level

12 {
13  Vector<Real> dt_tmp(finest_level+1);
14 
15  for (int lev = 0; lev <= finest_level; ++lev)
16  {
17  dt_tmp[lev] = estTimeStep(lev, dt_mri_ratio[lev]);
18  }
19 
20  ParallelDescriptor::ReduceRealMin(&dt_tmp[0], dt_tmp.size());
21 
22  Real dt_0 = dt_tmp[0];
23  int n_factor = 1;
24  for (int lev = 0; lev <= finest_level; ++lev) {
25  dt_tmp[lev] = amrex::min(dt_tmp[lev], change_max*dt[lev]);
26  n_factor *= nsubsteps[lev];
27  dt_0 = amrex::min(dt_0, n_factor*dt_tmp[lev]);
28 
29  }
30  // Limit level 0 time step if requested
31  if (step == 0) {
32  dt_0 *= init_shrink;
33  if (verbose && init_shrink != one) {
34  Print() << "Timestep 0: shrink level 0 initial dt by " << init_shrink << std::endl;
35  }
36  }
37  //
38  // Limit dt by the value of stop_time.
39  // Recall that stop_time is total time, but t_new is elapsed time,
40  // so we must add start_time to t_new
41  //
42  const Real eps = Real(1.e-3)*dt_0;
43  if (cur_time_d + static_cast<double>(dt_0) > static_cast<double>(stop_time - start_time) - static_cast<double>(eps)) {
44  dt_0 = static_cast<Real>(static_cast<double>(stop_time - start_time) - cur_time_d);
45  }
46 
47  dt[0] = dt_0;
48  for (int lev = 1; lev <= finest_level; ++lev) {
49  dt[lev] = dt[lev-1] / nsubsteps[lev];
50  }
51 }
amrex::Real estTimeStep(int lev, long &dt_fast_ratio) const
Definition: ERF_ComputeTimestep.cpp:60
static amrex::Real stop_time
Definition: ERF.H:1079
amrex::Vector< int > nsubsteps
Definition: ERF.H:836
static amrex::Real init_shrink
Definition: ERF.H:1090
static amrex::Real change_max
Definition: ERF.H:1091

Referenced by EvolveOneStep().

Here is the caller graph for this function:

◆ ComputeGhostCells()

static AMREX_FORCE_INLINE int ERF::ComputeGhostCells ( const SolverChoice sc)
inlinestaticprivate
1398  {
1399  int ngrow = 0;
1400 
1401  if (sc.use_num_diff)
1402  {
1403  ngrow = 3;
1404  } else {
1405  if (
1412  { ngrow = 3; }
1413  else if (
1420  { ngrow = 3; }
1421  else if (
1430  { ngrow = 3; }
1431  else if (
1440  { ngrow = 4; }
1441  else
1442  {
1443  if (sc.terrain_type == TerrainType::EB){
1444  ngrow = 4;
1445  } else {
1446  ngrow = 2;
1447  }
1448  }
1449  }
1450 
1451  return ngrow;
1452  }
@ Centered_6th
AdvType moistscal_horiz_adv_type
Definition: ERF_AdvStruct.H:423
AdvType dycore_vert_adv_type
Definition: ERF_AdvStruct.H:420
AdvType moistscal_vert_adv_type
Definition: ERF_AdvStruct.H:424
AdvType dryscal_horiz_adv_type
Definition: ERF_AdvStruct.H:421
AdvType dycore_horiz_adv_type
Definition: ERF_AdvStruct.H:419
AdvType dryscal_vert_adv_type
Definition: ERF_AdvStruct.H:422
AdvChoice advChoice
Definition: ERF_DataStruct.H:1131

◆ Construct_ERFFillPatchers()

void ERF::Construct_ERFFillPatchers ( int  lev)
private
3141 {
3142  auto& fine_new = vars_new[lev];
3143  auto& crse_new = vars_new[lev-1];
3144  auto& ba_fine = fine_new[Vars::cons].boxArray();
3145  auto& ba_crse = crse_new[Vars::cons].boxArray();
3146  auto& dm_fine = fine_new[Vars::cons].DistributionMap();
3147  auto& dm_crse = crse_new[Vars::cons].DistributionMap();
3148 
3149  int ncomp = vars_new[lev][Vars::cons].nComp();
3150 
3151  FPr_c.emplace_back(ba_fine, dm_fine, geom[lev] ,
3152  ba_crse, dm_crse, geom[lev-1],
3153  -cf_width, -cf_set_width, ncomp, &cell_cons_interp);
3154  FPr_u.emplace_back(convert(ba_fine, IntVect(1,0,0)), dm_fine, geom[lev] ,
3155  convert(ba_crse, IntVect(1,0,0)), dm_crse, geom[lev-1],
3156  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
3157  FPr_v.emplace_back(convert(ba_fine, IntVect(0,1,0)), dm_fine, geom[lev] ,
3158  convert(ba_crse, IntVect(0,1,0)), dm_crse, geom[lev-1],
3159  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
3160  FPr_w.emplace_back(convert(ba_fine, IntVect(0,0,1)), dm_fine, geom[lev] ,
3161  convert(ba_crse, IntVect(0,0,1)), dm_crse, geom[lev-1],
3162  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
3163 }
int cf_set_width
Definition: ERF.H:930

◆ create_background_state_for_ensemble()

void ERF::create_background_state_for_ensemble ( int  lev,
amrex::MultiFab &  mf_cc_pert,
amrex::MultiFab &  cons_pert,
amrex::MultiFab &  xvel_pert,
amrex::MultiFab &  yvel_pert,
amrex::MultiFab &  zvel_pert 
)
521 {
522 
523  ignore_unused(lev);
524  int nx_crse, ny_crse, nz_crse, ng_crse, ncomp_crse;
525  Vector<Vector<Real>> data_crse;
526  std::array<Real,3> problo_ext, probhi_ext;
527 
528  Vector<Real> data_rho, data_theta, data_xvel, data_yvel, data_zvel;
529 
531  nx_crse, ny_crse, nz_crse, ng_crse, ncomp_crse,
532  problo_ext, probhi_ext,
533  data_rho, data_theta, data_xvel, data_yvel, data_zvel);
534 
535  Geometry& geom_fine = geom[0];
536  // Create a cell-centered multifab on the fine mesh - ie. something with the same boxarray,
537  // distributed mapping, nGrow, but with 5 components
538  MultiFab mf_cc_fine;
539  const MultiFab& src = vars_new[0][0];
540  int ncomp = 5;
541  mf_cc_fine.define(src.boxArray(), src.DistributionMap(),
542  ncomp, src.nGrow());
543 
544  InterpolateToFineMF(data_rho, data_theta, data_xvel, data_yvel, data_zvel,
545  nx_crse, ny_crse, nz_crse,
546  problo_ext, probhi_ext,
547  mf_cc_fine,
548  geom_fine);
549 
550  ApplyNeumannBCs(geom_fine, mf_cc_fine);
551 
552  Vector<std::string> varnames = {"density","theta", "x_velocity","y_velocity","z_velocity"};
553 
554  // Add pertubrations stored in the "pert" variables in the function arguments
555  // (multiplied by the corresponding amplitude)
556  AddPertToBckgnd(mf_cc_fine, mf_cc_pert);
557  ApplyNeumannBCs(geom_fine, mf_cc_fine);
558  //WriteSingleLevelPlotfile("1_plt_final", mf_cc_fine, varnames, geom_fine, zero, 0);
559 
560  MakeFinalMultiFabs(mf_cc_fine, cons_pert, xvel_pert, yvel_pert, zvel_pert);
561 }
void InterpolateToFineMF(const Vector< Real > &data_rho, const Vector< Real > &data_theta, const Vector< Real > &data_xvel, const Vector< Real > &data_yvel, const Vector< Real > &data_zvel, int nx, int ny, int nz, const std::array< Real, 3 > &problo, const std::array< Real, 3 > &probhi, MultiFab &mf_fine, const Geometry &geom_fine)
Definition: ERF_InitForEnsemble.cpp:325
void ReadCustomDataFile(const std::string &filename_custom, int &nx, int &ny, int &nz, int &ng, int &ncomp, std::array< Real, 3 > &problo_ext, std::array< Real, 3 > &probhi_ext, Vector< Real > &data_rho, Vector< Real > &data_theta, Vector< Real > &data_xvel, Vector< Real > &data_yvel, Vector< Real > &data_zvel)
Definition: ERF_InitForEnsemble.cpp:208
void ApplyNeumannBCs(const Geometry &geom, MultiFab &mf_cc)
Definition: ERF_InitForEnsemble.cpp:162
void AddPertToBckgnd(MultiFab &mf_cc_fine, const MultiFab &mf_cc_pert)
Definition: ERF_InitForEnsemble.cpp:490
void MakeFinalMultiFabs(const MultiFab &mf_cc_fine, MultiFab &cons_pert, MultiFab &xvel_pert, MultiFab &yvel_pert, MultiFab &zvel_pert)
Definition: ERF_InitForEnsemble.cpp:426
std::string coarse_bckgnd_data_file
Definition: ERF_DataStruct.H:1345
Here is the call graph for this function:

◆ create_random_perturbations()

void ERF::create_random_perturbations ( const int  lev,
amrex::MultiFab &  mf_cc_pert 
)
16 {
17  const MultiFab& src = vars_new[lev][Vars::cons];
18 
19  int ncomp = 5;
20  mf_cc_pert.define(src.boxArray(), src.DistributionMap(),
21  ncomp, src.nGrow());
22 
23  // Loop over cell-centered boxes
24  for (MFIter mfi(mf_cc_pert, TilingIfNotGPU()); mfi.isValid(); ++mfi)
25  {
26  const Box& bx = mfi.tilebox();
27 
28  auto const& pert_arr = mf_cc_pert.array(mfi);
29 
30  // Loop over all 5 components
31  amrex::ParallelForRNG(bx, ncomp,
32  [=] AMREX_GPU_DEVICE (int i, int j, int k, int n,
33  const amrex::RandomEngine& engine) noexcept
34  {
35  pert_arr(i,j,k,n) = amrex::Random(engine);
36  });
37  }
38 }
ParallelForRNG(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k, const amrex::RandomEngine &engine) noexcept { const Real x=prob_lo_x+(i+myhalf) *dx;const Real y=prob_lo_y+(j+myhalf) *dy;const Real z=z_cc(i, j, k);const Real r=std::sqrt((x-xc) *(x-xc)+(y-yc) *(y-yc)+(z-zc) *(z-zc));if((z<=pert_ref_height) &&(T_0_Pert_Mag !=amrex::Real(0))) { Real rand_double=amrex::Random(engine);state_pert(i, j, k, RhoTheta_comp)=(rand_double *amrex::Real(2) - amrex::Real(1)) *T_0_Pert_Mag;if(!pert_rhotheta) { state_pert(i, j, k, RhoTheta_comp) *=r_hse(i, j, k);} } state_pert(i, j, k, RhoScalar_comp)=A_0 *std::exp(-amrex::Real(10.) *r *r);if(state_pert.nComp() > RhoKE_comp) { if(rhoKE_0 > 0) { state_pert(i, j, k, RhoKE_comp)=rhoKE_0;} else { state_pert(i, j, k, RhoKE_comp)=r_hse(i, j, k) *KE_0;} if(KE_decay_height > 0) { state_pert(i, j, k, RhoKE_comp) *=amrex::max(std::pow(1 - amrex::min(z/KE_decay_height, amrex::Real(1)), KE_decay_order), Real(1e-12));} } })
Here is the call graph for this function:

◆ DataLog()

AMREX_FORCE_INLINE std::ostream& ERF::DataLog ( int  i)
inlineprivate
1463  {
1464  return *datalog[i];
1465  }
amrex::Vector< std::unique_ptr< std::fstream > > datalog
Definition: ERF.H:1642

◆ DataLogName()

std::string ERF::DataLogName ( int  i) const
inlineprivatenoexcept

The filename of the ith datalog file.

1658 { return datalogname[i]; }
amrex::Vector< std::string > datalogname
Definition: ERF.H:1645

◆ Define_ERFFillPatchers()

void ERF::Define_ERFFillPatchers ( int  lev)
private
3167 {
3168  auto& fine_new = vars_new[lev];
3169  auto& crse_new = vars_new[lev-1];
3170  auto& ba_fine = fine_new[Vars::cons].boxArray();
3171  auto& ba_crse = crse_new[Vars::cons].boxArray();
3172  auto& dm_fine = fine_new[Vars::cons].DistributionMap();
3173  auto& dm_crse = crse_new[Vars::cons].DistributionMap();
3174 
3175  int ncomp = fine_new[Vars::cons].nComp();
3176 
3177  FPr_c[lev-1].Define(ba_fine, dm_fine, geom[lev] ,
3178  ba_crse, dm_crse, geom[lev-1],
3179  -cf_width, -cf_set_width, ncomp, &cell_cons_interp);
3180  FPr_u[lev-1].Define(convert(ba_fine, IntVect(1,0,0)), dm_fine, geom[lev] ,
3181  convert(ba_crse, IntVect(1,0,0)), dm_crse, geom[lev-1],
3182  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
3183  FPr_v[lev-1].Define(convert(ba_fine, IntVect(0,1,0)), dm_fine, geom[lev] ,
3184  convert(ba_crse, IntVect(0,1,0)), dm_crse, geom[lev-1],
3185  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
3186  FPr_w[lev-1].Define(convert(ba_fine, IntVect(0,0,1)), dm_fine, geom[lev] ,
3187  convert(ba_crse, IntVect(0,0,1)), dm_crse, geom[lev-1],
3188  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
3189 }

◆ DerDataLog()

AMREX_FORCE_INLINE std::ostream& ERF::DerDataLog ( int  i)
inlineprivate
1470  {
1471  return *der_datalog[i];
1472  }
amrex::Vector< std::unique_ptr< std::fstream > > der_datalog
Definition: ERF.H:1643

◆ DerDataLogName()

std::string ERF::DerDataLogName ( int  i) const
inlineprivatenoexcept
1659 { return der_datalogname[i]; }
amrex::Vector< std::string > der_datalogname
Definition: ERF.H:1646

◆ derive_diag_profiles()

void ERF::derive_diag_profiles ( double  time,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_u,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_v,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_w,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_rho,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_th,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_ksgs,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_Kmv,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_Khv,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_qv,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_qc,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_qr,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_wqv,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_wqc,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_wqr,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_qi,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_qs,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_qg,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_uu,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_uv,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_uw,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_vv,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_vw,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_ww,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_uth,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_vth,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_wth,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_thth,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_ku,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_kv,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_kw,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_p,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_pu,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_pv,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_pw,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_wthv 
)

Computes the profiles for diagnostic quantities.

Parameters
h_avg_uProfile for x-velocity on Host
h_avg_vProfile for y-velocity on Host
h_avg_wProfile for z-velocity on Host
h_avg_rhoProfile for density on Host
h_avg_thProfile for potential temperature on Host
h_avg_ksgsProfile for Kinetic Energy on Host
h_avg_uuProfile for x-velocity squared on Host
h_avg_uvProfile for x-velocity * y-velocity on Host
h_avg_uwProfile for x-velocity * z-velocity on Host
h_avg_vvProfile for y-velocity squared on Host
h_avg_vwProfile for y-velocity * z-velocity on Host
h_avg_wwProfile for z-velocity squared on Host
h_avg_uthProfile for x-velocity * potential temperature on Host
h_avg_uiuiuProfile for u_i*u_i*u triple product on Host
h_avg_uiuivProfile for u_i*u_i*v triple product on Host
h_avg_uiuiwProfile for u_i*u_i*w triple product on Host
h_avg_pProfile for pressure perturbation on Host
h_avg_puProfile for pressure perturbation * x-velocity on Host
h_avg_pvProfile for pressure perturbation * y-velocity on Host
h_avg_pwProfile for pressure perturbation * z-velocity on Host
205 {
206  // We assume that this is always called at level 0
207  int lev = 0;
208 
209  bool l_use_kturb = solverChoice.turbChoice[lev].use_kturb;
210  bool l_use_KE = solverChoice.turbChoice[lev].use_tke;
211  // This will hold rho, theta, ksgs, Kmh, Kmv, uu, uv, uw, vv, vw, ww, uth, vth, wth,
212  // 0 1 2 3 4 5 6 7 8 9 10 11 12 13
213  // thth, uiuiu, uiuiv, uiuiw, p, pu, pv, pw, qv, qc, qr, wqv, wqc, wqr,
214  // 14 15 16 17 18 19 20 21 22 23 24 25 26 27
215  // qi, qs, qg, wthv
216  // 28 29 30 31
217  MultiFab mf_out(grids[lev], dmap[lev], 32, 0);
218 
219  MultiFab mf_vels(grids[lev], dmap[lev], AMREX_SPACEDIM, 0);
220 
221  MultiFab u_cc(mf_vels, make_alias, 0, 1); // u at cell centers
222  MultiFab v_cc(mf_vels, make_alias, 1, 1); // v at cell centers
223  MultiFab w_cc(mf_vels, make_alias, 2, 1); // w at cell centers
224 
225  average_face_to_cellcenter(mf_vels,0,
226  Array<const MultiFab*,3>{&vars_new[lev][Vars::xvel],&vars_new[lev][Vars::yvel],&vars_new[lev][Vars::zvel]});
227 
228  int zdir = 2;
229  auto domain = geom[0].Domain();
230 
231  // Sum in the horizontal plane
232  h_avg_u = sumToLine(mf_vels ,0,1,domain,zdir);
233  h_avg_v = sumToLine(mf_vels ,1,1,domain,zdir);
234  h_avg_w = sumToLine(mf_vels ,2,1,domain,zdir);
235 
236  int hu_size = h_avg_u.size();
237 
238  // Divide by the total number of cells we are averaging over
239  Real area_z = static_cast<Real>(domain.length(0)*domain.length(1));
240  for (int k = 0; k < hu_size; ++k) {
241  h_avg_u[k] /= area_z; h_avg_v[k] /= area_z; h_avg_w[k] /= area_z;
242  }
243 
244  Gpu::DeviceVector<Real> d_avg_u(hu_size, zero);
245  Gpu::DeviceVector<Real> d_avg_v(hu_size, zero);
246  Gpu::DeviceVector<Real> d_avg_w(hu_size, zero);
247 
248 #if 0
249  auto* avg_u_ptr = d_avg_u.data();
250  auto* avg_v_ptr = d_avg_v.data();
251  auto* avg_w_ptr = d_avg_w.data();
252 #endif
253 
254  Gpu::copy(Gpu::hostToDevice, h_avg_u.begin(), h_avg_u.end(), d_avg_u.begin());
255  Gpu::copy(Gpu::hostToDevice, h_avg_v.begin(), h_avg_v.end(), d_avg_v.begin());
256  Gpu::copy(Gpu::hostToDevice, h_avg_w.begin(), h_avg_w.end(), d_avg_w.begin());
257 
258  int nvars = vars_new[lev][Vars::cons].nComp();
259  MultiFab mf_cons(vars_new[lev][Vars::cons], make_alias, 0, nvars);
260 
261  MultiFab p_hse (base_state[lev], make_alias, BaseState::p0_comp, 1);
262 
263  bool use_moisture = (solverChoice.moisture_type != MoistureType::None);
264 
265  for ( MFIter mfi(mf_cons,TilingIfNotGPU()); mfi.isValid(); ++mfi)
266  {
267  const Box& bx = mfi.tilebox();
268  const Array4<Real>& fab_arr = mf_out.array(mfi);
269  const Array4<Real>& u_cc_arr = u_cc.array(mfi);
270  const Array4<Real>& v_cc_arr = v_cc.array(mfi);
271  const Array4<Real>& w_cc_arr = w_cc.array(mfi);
272  const Array4<Real>& cons_arr = mf_cons.array(mfi);
273  const Array4<Real>& p0_arr = p_hse.array(mfi);
274  const Array4<const Real>& eta_arr = (l_use_kturb) ? eddyDiffs_lev[lev]->const_array(mfi) :
275  Array4<const Real>{};
276 
277  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
278  {
279  Real theta = cons_arr(i,j,k,RhoTheta_comp) / cons_arr(i,j,k,Rho_comp);
280  fab_arr(i, j, k, 0) = cons_arr(i,j,k,Rho_comp);
281  fab_arr(i, j, k, 1) = theta;
282  Real ksgs = zero;
283  if (l_use_KE) {
284  ksgs = cons_arr(i,j,k,RhoKE_comp) / cons_arr(i,j,k,Rho_comp);
285  }
286  fab_arr(i, j, k, 2) = ksgs;
287 #if 1
288  if (l_use_kturb) {
289  fab_arr(i, j, k, 3) = eta_arr(i,j,k,EddyDiff::Mom_v); // Kmv
290  fab_arr(i, j, k, 4) = eta_arr(i,j,k,EddyDiff::Theta_v); // Khv
291  } else {
292  fab_arr(i, j, k, 3) = zero;
293  fab_arr(i, j, k, 4) = zero;
294  }
295 #else
296  // Here we hijack the "Kturb" variable name to print out the resolved kinetic energy
297  Real upert = u_cc_arr(i,j,k) - avg_u_ptr[k];
298  Real vpert = v_cc_arr(i,j,k) - avg_v_ptr[k];
299  Real wpert = w_cc_arr(i,j,k) - avg_w_ptr[k];
300  fab_arr(i, j, k, 3) = myhalf * (upert*upert + vpert*vpert + wpert*wpert);
301 #endif
302  fab_arr(i, j, k, 5) = u_cc_arr(i,j,k) * u_cc_arr(i,j,k); // u*u
303  fab_arr(i, j, k, 6) = u_cc_arr(i,j,k) * v_cc_arr(i,j,k); // u*v
304  fab_arr(i, j, k, 7) = u_cc_arr(i,j,k) * w_cc_arr(i,j,k); // u*w
305  fab_arr(i, j, k, 8) = v_cc_arr(i,j,k) * v_cc_arr(i,j,k); // v*v
306  fab_arr(i, j, k, 9) = v_cc_arr(i,j,k) * w_cc_arr(i,j,k); // v*w
307  fab_arr(i, j, k,10) = w_cc_arr(i,j,k) * w_cc_arr(i,j,k); // w*w
308  fab_arr(i, j, k,11) = u_cc_arr(i,j,k) * theta; // u*th
309  fab_arr(i, j, k,12) = v_cc_arr(i,j,k) * theta; // v*th
310  fab_arr(i, j, k,13) = w_cc_arr(i,j,k) * theta; // w*th
311  fab_arr(i, j, k,14) = theta * theta; // th*th
312 
313  // if the number of fields is changed above, then be sure to update
314  // the following def!
315  Real uiui = fab_arr(i,j,k,5) + fab_arr(i,j,k,8) + fab_arr(i,j,k,10);
316  fab_arr(i, j, k,15) = uiui * u_cc_arr(i,j,k); // (ui*ui)*u
317  fab_arr(i, j, k,16) = uiui * v_cc_arr(i,j,k); // (ui*ui)*v
318  fab_arr(i, j, k,17) = uiui * w_cc_arr(i,j,k); // (ui*ui)*w
319 
320  if (!use_moisture) {
321  Real p = getPgivenRTh(cons_arr(i, j, k, RhoTheta_comp));
322  p -= p0_arr(i,j,k);
323  fab_arr(i, j, k,18) = p; // p
324  fab_arr(i, j, k,19) = p * u_cc_arr(i,j,k); // p*u
325  fab_arr(i, j, k,20) = p * v_cc_arr(i,j,k); // p*v
326  fab_arr(i, j, k,21) = p * w_cc_arr(i,j,k); // p*w
327  fab_arr(i, j, k,22) = zero; // qv
328  fab_arr(i, j, k,23) = zero; // qc
329  fab_arr(i, j, k,24) = zero; // qr
330  fab_arr(i, j, k,25) = zero; // w*qv
331  fab_arr(i, j, k,26) = zero; // w*qc
332  fab_arr(i, j, k,27) = zero; // w*qr
333  fab_arr(i, j, k,28) = zero; // qi
334  fab_arr(i, j, k,29) = zero; // qs
335  fab_arr(i, j, k,30) = zero; // qg
336  fab_arr(i, j, k,31) = zero; // w*thv
337  }
338  });
339  } // mfi
340 
341  if (use_moisture)
342  {
343  int n_qstate_moist = micro->Get_Qstate_Moist_Size();
344 
345  for ( MFIter mfi(mf_cons,TilingIfNotGPU()); mfi.isValid(); ++mfi)
346  {
347  const Box& bx = mfi.tilebox();
348  const Array4<Real>& fab_arr = mf_out.array(mfi);
349  const Array4<Real>& cons_arr = mf_cons.array(mfi);
350  const Array4<Real>& u_cc_arr = u_cc.array(mfi);
351  const Array4<Real>& v_cc_arr = v_cc.array(mfi);
352  const Array4<Real>& w_cc_arr = w_cc.array(mfi);
353  const Array4<Real>& p0_arr = p_hse.array(mfi);
354 
355  int rhoqr_comp = solverChoice.moisture_indices.qr;
356 
357  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
358  {
359  Real qv = cons_arr(i,j,k,RhoQ1_comp) / cons_arr(i,j,k,Rho_comp);
360  Real qc = cons_arr(i,j,k,RhoQ2_comp) / cons_arr(i,j,k,Rho_comp);
361  Real qr = (rhoqr_comp > -1) ? cons_arr(i,j,k,rhoqr_comp) / cons_arr(i,j,k,Rho_comp) :
362  zero;
363  Real p = getPgivenRTh(cons_arr(i, j, k, RhoTheta_comp), qv);
364 
365  p -= p0_arr(i,j,k);
366  fab_arr(i, j, k,18) = p; // p
367  fab_arr(i, j, k,19) = p * u_cc_arr(i,j,k); // p*u
368  fab_arr(i, j, k,20) = p * v_cc_arr(i,j,k); // p*v
369  fab_arr(i, j, k,21) = p * w_cc_arr(i,j,k); // p*w
370  fab_arr(i, j, k,22) = qv; // qv
371  fab_arr(i, j, k,23) = qc; // qc
372  fab_arr(i, j, k,24) = qr; // qr
373  fab_arr(i, j, k,25) = w_cc_arr(i,j,k) * qv; // w*qv
374  fab_arr(i, j, k,26) = w_cc_arr(i,j,k) * qc; // w*qc
375  fab_arr(i, j, k,27) = w_cc_arr(i,j,k) * qr; // w*qr
376  if (n_qstate_moist > 3) {
377  fab_arr(i, j, k,28) = cons_arr(i,j,k,RhoQ3_comp) / cons_arr(i,j,k,Rho_comp); // qi
378  fab_arr(i, j, k,29) = cons_arr(i,j,k,RhoQ5_comp) / cons_arr(i,j,k,Rho_comp); // qs
379  fab_arr(i, j, k,30) = cons_arr(i,j,k,RhoQ6_comp) / cons_arr(i,j,k,Rho_comp); // qg
380  } else {
381  fab_arr(i, j, k,28) = zero; // qi
382  fab_arr(i, j, k,29) = zero; // qs
383  fab_arr(i, j, k,30) = zero; // qg
384  }
385  Real ql = qc + qr;
386  Real theta = cons_arr(i,j,k,RhoTheta_comp) / cons_arr(i,j,k,Rho_comp);
387  Real thv = theta * (1 + Real(0.61)*qv - ql);
388  fab_arr(i, j, k,31) = w_cc_arr(i,j,k) * thv; // w*thv
389  });
390  } // mfi
391  } // use_moisture
392 
393  h_avg_rho = sumToLine(mf_out, 0,1,domain,zdir);
394  h_avg_th = sumToLine(mf_out, 1,1,domain,zdir);
395  h_avg_ksgs = sumToLine(mf_out, 2,1,domain,zdir);
396  h_avg_Kmv = sumToLine(mf_out, 3,1,domain,zdir);
397  h_avg_Khv = sumToLine(mf_out, 4,1,domain,zdir);
398  h_avg_uu = sumToLine(mf_out, 5,1,domain,zdir);
399  h_avg_uv = sumToLine(mf_out, 6,1,domain,zdir);
400  h_avg_uw = sumToLine(mf_out, 7,1,domain,zdir);
401  h_avg_vv = sumToLine(mf_out, 8,1,domain,zdir);
402  h_avg_vw = sumToLine(mf_out, 9,1,domain,zdir);
403  h_avg_ww = sumToLine(mf_out,10,1,domain,zdir);
404  h_avg_uth = sumToLine(mf_out,11,1,domain,zdir);
405  h_avg_vth = sumToLine(mf_out,12,1,domain,zdir);
406  h_avg_wth = sumToLine(mf_out,13,1,domain,zdir);
407  h_avg_thth = sumToLine(mf_out,14,1,domain,zdir);
408  h_avg_uiuiu = sumToLine(mf_out,15,1,domain,zdir);
409  h_avg_uiuiv = sumToLine(mf_out,16,1,domain,zdir);
410  h_avg_uiuiw = sumToLine(mf_out,17,1,domain,zdir);
411  h_avg_p = sumToLine(mf_out,18,1,domain,zdir);
412  h_avg_pu = sumToLine(mf_out,19,1,domain,zdir);
413  h_avg_pv = sumToLine(mf_out,20,1,domain,zdir);
414  h_avg_pw = sumToLine(mf_out,21,1,domain,zdir);
415  h_avg_qv = sumToLine(mf_out,22,1,domain,zdir);
416  h_avg_qc = sumToLine(mf_out,23,1,domain,zdir);
417  h_avg_qr = sumToLine(mf_out,24,1,domain,zdir);
418  h_avg_wqv = sumToLine(mf_out,25,1,domain,zdir);
419  h_avg_wqc = sumToLine(mf_out,26,1,domain,zdir);
420  h_avg_wqr = sumToLine(mf_out,27,1,domain,zdir);
421  h_avg_qi = sumToLine(mf_out,28,1,domain,zdir);
422  h_avg_qs = sumToLine(mf_out,29,1,domain,zdir);
423  h_avg_qg = sumToLine(mf_out,30,1,domain,zdir);
424  h_avg_wthv = sumToLine(mf_out,31,1,domain,zdir);
425 
426  // Divide by the total number of cells we are averaging over
427  int h_avg_u_size = static_cast<int>(h_avg_u.size());
428  for (int k = 0; k < h_avg_u_size; ++k) {
429  h_avg_rho[k] /= area_z;
430  h_avg_ksgs[k] /= area_z;
431  h_avg_Kmv[k] /= area_z;
432  h_avg_Khv[k] /= area_z;
433  h_avg_th[k] /= area_z;
434  h_avg_thth[k] /= area_z;
435  h_avg_uu[k] /= area_z;
436  h_avg_uv[k] /= area_z;
437  h_avg_uw[k] /= area_z;
438  h_avg_vv[k] /= area_z;
439  h_avg_vw[k] /= area_z;
440  h_avg_ww[k] /= area_z;
441  h_avg_uth[k] /= area_z;
442  h_avg_vth[k] /= area_z;
443  h_avg_wth[k] /= area_z;
444  h_avg_uiuiu[k] /= area_z;
445  h_avg_uiuiv[k] /= area_z;
446  h_avg_uiuiw[k] /= area_z;
447  h_avg_p[k] /= area_z;
448  h_avg_pu[k] /= area_z;
449  h_avg_pv[k] /= area_z;
450  h_avg_pw[k] /= area_z;
451  h_avg_qv[k] /= area_z;
452  h_avg_qc[k] /= area_z;
453  h_avg_qr[k] /= area_z;
454  h_avg_wqv[k] /= area_z;
455  h_avg_wqc[k] /= area_z;
456  h_avg_wqr[k] /= area_z;
457  h_avg_qi[k] /= area_z;
458  h_avg_qs[k] /= area_z;
459  h_avg_qg[k] /= area_z;
460  h_avg_wthv[k] /= area_z;
461  }
462 
463 #if 0
464  // Here we print the integrated total kinetic energy as computed in the 1D profile above
465  Real sum = zero;
466  Real dz = geom[0].ProbHi(2) / static_cast<Real>(h_avg_u_size);
467  for (int k = 0; k < h_avg_u_size; ++k) {
468  sum += h_avg_kturb[k] * h_avg_rho[k] * dz;
469  }
470  amrex::Print() << "ITKE " << time << " " << sum << " using " << h_avg_u_size << " " << dz << std::endl;
471 #endif
472 }
#define RhoQ3_comp
Definition: ERF_IndexDefines.H:44
#define RhoQ6_comp
Definition: ERF_IndexDefines.H:47
#define RhoQ5_comp
Definition: ERF_IndexDefines.H:46
#define RhoKE_comp
Definition: ERF_IndexDefines.H:38
const bool use_moisture
Definition: ERF_InitCustomPert_Bomex.H:14
@ Theta_v
Definition: ERF_IndexDefines.H:210
@ Mom_v
Definition: ERF_IndexDefines.H:209
@ theta
Definition: ERF_MM5.H:20
@ dz
Definition: ERF_AdvanceWSM6.cpp:104
@ qr
Definition: ERF_AdvanceWSM6.cpp:112
Here is the call graph for this function:

◆ derive_diag_profiles_stag()

void ERF::derive_diag_profiles_stag ( double  time,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_u,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_v,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_w,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_rho,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_th,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_ksgs,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_Kmv,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_Khv,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_qv,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_qc,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_qr,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_wqv,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_wqc,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_wqr,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_qi,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_qs,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_qg,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_uu,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_uv,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_uw,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_vv,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_vw,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_ww,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_uth,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_vth,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_wth,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_thth,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_ku,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_kv,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_kw,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_p,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_pu,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_pv,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_pw,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_wthv 
)

Computes the profiles for diagnostic quantities at staggered heights.

Parameters
h_avg_uProfile for x-velocity on Host
h_avg_vProfile for y-velocity on Host
h_avg_wProfile for z-velocity on Host
h_avg_rhoProfile for density on Host
h_avg_thProfile for potential temperature on Host
h_avg_ksgsProfile for Kinetic Energy on Host
h_avg_uuProfile for x-velocity squared on Host
h_avg_uvProfile for x-velocity * y-velocity on Host
h_avg_uwProfile for x-velocity * z-velocity on Host
h_avg_vvProfile for y-velocity squared on Host
h_avg_vwProfile for y-velocity * z-velocity on Host
h_avg_wwProfile for z-velocity squared on Host
h_avg_uthProfile for x-velocity * potential temperature on Host
h_avg_uiuiuProfile for u_i*u_i*u triple product on Host
h_avg_uiuivProfile for u_i*u_i*v triple product on Host
h_avg_uiuiwProfile for u_i*u_i*w triple product on Host
h_avg_pProfile for pressure perturbation on Host
h_avg_puProfile for pressure perturbation * x-velocity on Host
h_avg_pvProfile for pressure perturbation * y-velocity on Host
h_avg_pwProfile for pressure perturbation * z-velocity on Host
311 {
312  // We assume that this is always called at level 0
313  int lev = 0;
314 
315  bool l_use_kturb = solverChoice.turbChoice[lev].use_kturb;
316  bool l_use_KE = solverChoice.turbChoice[lev].use_tke;
317  // Note: "uiui" == u_i*u_i = u*u + v*v + w*w
318  // This will hold rho, theta, ksgs, Kmh, Kmv, uu, uv, vv, uth, vth,
319  // indices: 0 1 2 3 4 5 6 7 8 9
320  // thth, uiuiu, uiuiv, p, pu, pv, qv, qc, qr, qi, qs, qg
321  // 10 11 12 13 14 15 16 17 18 19 20 21
322  MultiFab mf_out(grids[lev], dmap[lev], 22, 0);
323 
324  // This will hold uw, vw, ww, wth, uiuiw, pw, wqv, wqc, wqr, wthv
325  // indices: 0 1 2 3 4 5 6 7 8 9
326  MultiFab mf_out_stag(convert(grids[lev], IntVect(0,0,1)), dmap[lev], 10, 0);
327 
328  // This is only used to average u and v; w is not averaged to cell centers
329  MultiFab mf_vels(grids[lev], dmap[lev], 2, 0);
330 
331  MultiFab u_cc(mf_vels, make_alias, 0, 1); // u at cell centers
332  MultiFab v_cc(mf_vels, make_alias, 1, 1); // v at cell centers
333  MultiFab w_fc(vars_new[lev][Vars::zvel], make_alias, 0, 1); // w at face centers (staggered)
334 
335  int zdir = 2;
336  auto domain = geom[0].Domain();
337  Box stag_domain = domain;
338  stag_domain.convert(IntVect(0,0,1));
339 
340  int nvars = vars_new[lev][Vars::cons].nComp();
341  MultiFab mf_cons(vars_new[lev][Vars::cons], make_alias, 0, nvars);
342 
343  MultiFab p_hse (base_state[lev], make_alias, BaseState::p0_comp, 1);
344 
345  bool use_moisture = (solverChoice.moisture_type != MoistureType::None);
346 
347  for ( MFIter mfi(mf_cons,TilingIfNotGPU()); mfi.isValid(); ++mfi)
348  {
349  const Box& bx = mfi.tilebox();
350  const Array4<Real>& fab_arr = mf_out.array(mfi);
351  const Array4<Real>& fab_arr_stag = mf_out_stag.array(mfi);
352  const Array4<Real>& u_arr = vars_new[lev][Vars::xvel].array(mfi);
353  const Array4<Real>& v_arr = vars_new[lev][Vars::yvel].array(mfi);
354  const Array4<Real>& u_cc_arr = u_cc.array(mfi);
355  const Array4<Real>& v_cc_arr = v_cc.array(mfi);
356  const Array4<Real>& w_fc_arr = w_fc.array(mfi);
357  const Array4<Real>& cons_arr = mf_cons.array(mfi);
358  const Array4<Real>& p0_arr = p_hse.array(mfi);
359  const Array4<const Real>& eta_arr = (l_use_kturb) ? eddyDiffs_lev[lev]->const_array(mfi) :
360  Array4<const Real>{};
361 
362  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
363  {
364  u_cc_arr(i,j,k) = myhalf * (u_arr(i,j,k) + u_arr(i+1,j ,k));
365  v_cc_arr(i,j,k) = myhalf * (v_arr(i,j,k) + v_arr(i ,j+1,k));
366 
367  Real theta = cons_arr(i,j,k,RhoTheta_comp) / cons_arr(i,j,k,Rho_comp);
368  fab_arr(i, j, k, 0) = cons_arr(i,j,k,Rho_comp);
369  fab_arr(i, j, k, 1) = theta;
370  Real ksgs = zero;
371  if (l_use_KE) {
372  ksgs = cons_arr(i,j,k,RhoKE_comp) / cons_arr(i,j,k,Rho_comp);
373  }
374  fab_arr(i, j, k, 2) = ksgs;
375  if (l_use_kturb) {
376  fab_arr(i, j, k, 3) = eta_arr(i,j,k,EddyDiff::Mom_v); // Kmv
377  fab_arr(i, j, k, 4) = eta_arr(i,j,k,EddyDiff::Theta_v); // Khv
378  } else {
379  fab_arr(i, j, k, 3) = zero;
380  fab_arr(i, j, k, 4) = zero;
381  }
382  fab_arr(i, j, k, 5) = u_cc_arr(i,j,k) * u_cc_arr(i,j,k); // u*u
383  fab_arr(i, j, k, 6) = u_cc_arr(i,j,k) * v_cc_arr(i,j,k); // u*v
384  fab_arr(i, j, k, 7) = v_cc_arr(i,j,k) * v_cc_arr(i,j,k); // v*v
385  fab_arr(i, j, k, 8) = u_cc_arr(i,j,k) * theta; // u*th
386  fab_arr(i, j, k, 9) = v_cc_arr(i,j,k) * theta; // v*th
387  fab_arr(i, j, k,10) = theta * theta; // th*th
388 
389  Real wcc = myhalf * (w_fc_arr(i,j,k) + w_fc_arr(i,j,k+1));
390 
391  // if the number of fields is changed above, then be sure to update
392  // the following def!
393  Real uiui = fab_arr(i,j,k,5) + fab_arr(i,j,k,7) + wcc*wcc;
394  fab_arr(i, j, k,11) = uiui * u_cc_arr(i,j,k); // (ui*ui)*u
395  fab_arr(i, j, k,12) = uiui * v_cc_arr(i,j,k); // (ui*ui)*v
396 
397  if (!use_moisture) {
398  Real p = getPgivenRTh(cons_arr(i, j, k, RhoTheta_comp));
399  p -= p0_arr(i,j,k);
400  fab_arr(i, j, k,13) = p; // p
401  fab_arr(i, j, k,14) = p * u_cc_arr(i,j,k); // p*u
402  fab_arr(i, j, k,15) = p * v_cc_arr(i,j,k); // p*v
403  fab_arr(i, j, k,16) = zero; // qv
404  fab_arr(i, j, k,17) = zero; // qc
405  fab_arr(i, j, k,18) = zero; // qr
406  fab_arr(i, j, k,19) = zero; // qi
407  fab_arr(i, j, k,20) = zero; // qs
408  fab_arr(i, j, k,21) = zero; // qg
409  }
410  });
411 
412  const Box& zbx = mfi.tilebox(IntVect(0,0,1));
413  ParallelFor(zbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
414  {
415  // average to z faces (first to cell centers, then in z)
416  Real uface = fourth * ( u_arr(i ,j,k) + u_arr(i ,j,k-1)
417  + u_arr(i+1,j,k) + u_arr(i+1,j,k-1));
418  Real vface = fourth * ( v_arr(i,j ,k) + v_arr(i,j ,k-1)
419  + v_arr(i,j+1,k) + v_arr(i,j+1,k-1));
420  Real theta0 = cons_arr(i,j,k ,RhoTheta_comp) / cons_arr(i,j,k ,Rho_comp);
421  Real theta1 = cons_arr(i,j,k-1,RhoTheta_comp) / cons_arr(i,j,k-1,Rho_comp);
422  Real thface = myhalf*(theta0 + theta1);
423  fab_arr_stag(i,j,k,0) = uface * w_fc_arr(i,j,k); // u*w
424  fab_arr_stag(i,j,k,1) = vface * w_fc_arr(i,j,k); // v*w
425  fab_arr_stag(i,j,k,2) = w_fc_arr(i,j,k) * w_fc_arr(i,j,k); // w*w
426  fab_arr_stag(i,j,k,3) = thface * w_fc_arr(i,j,k); // th*w
427  Real uiui = uface*uface + vface*vface + fab_arr_stag(i,j,k,2);
428  fab_arr_stag(i,j,k,4) = uiui * w_fc_arr(i,j,k); // (ui*ui)*w
429  if (!use_moisture) {
430  Real p0 = getPgivenRTh(cons_arr(i, j, k , RhoTheta_comp)) - p0_arr(i,j,k );
431  Real p1 = getPgivenRTh(cons_arr(i, j, k-1, RhoTheta_comp)) - p0_arr(i,j,k-1);
432  Real pface = myhalf * (p0 + p1);
433  fab_arr_stag(i,j,k,5) = pface * w_fc_arr(i,j,k); // p*w
434  fab_arr_stag(i,j,k,6) = zero; // w*qv
435  fab_arr_stag(i,j,k,7) = zero; // w*qc
436  fab_arr_stag(i,j,k,8) = zero; // w*qr
437  fab_arr_stag(i,j,k,9) = zero; // w*thv
438  }
439  });
440 
441  } // mfi
442 
443  if (use_moisture)
444  {
445  int n_qstate_moist = micro->Get_Qstate_Moist_Size();
446 
447  for ( MFIter mfi(mf_cons,TilingIfNotGPU()); mfi.isValid(); ++mfi)
448  {
449  const Box& bx = mfi.tilebox();
450  const Array4<Real>& fab_arr = mf_out.array(mfi);
451  const Array4<Real>& fab_arr_stag = mf_out_stag.array(mfi);
452  const Array4<Real>& cons_arr = mf_cons.array(mfi);
453  const Array4<Real>& u_cc_arr = u_cc.array(mfi);
454  const Array4<Real>& v_cc_arr = v_cc.array(mfi);
455  const Array4<Real>& w_fc_arr = w_fc.array(mfi);
456  const Array4<Real>& p0_arr = p_hse.array(mfi);
457 
458  int rhoqr_comp = solverChoice.moisture_indices.qr;
459 
460  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
461  {
462  Real qv = cons_arr(i,j,k,RhoQ1_comp) / cons_arr(i,j,k,Rho_comp);
463  Real qc = cons_arr(i,j,k,RhoQ2_comp) / cons_arr(i,j,k,Rho_comp);
464  Real qr = (rhoqr_comp > -1) ? cons_arr(i,j,k,rhoqr_comp) / cons_arr(i,j,k,Rho_comp) :
465  zero;
466  Real p = getPgivenRTh(cons_arr(i, j, k, RhoTheta_comp), qv);
467 
468  p -= p0_arr(i,j,k);
469  fab_arr(i, j, k,13) = p; // p
470  fab_arr(i, j, k,14) = p * u_cc_arr(i,j,k); // p*u
471  fab_arr(i, j, k,15) = p * v_cc_arr(i,j,k); // p*v
472  fab_arr(i, j, k,16) = qv; // qv
473  fab_arr(i, j, k,17) = qc; // qc
474  fab_arr(i, j, k,18) = qr; // qr
475  if (n_qstate_moist > 3) { // SAM model
476  fab_arr(i, j, k,19) = cons_arr(i,j,k,RhoQ3_comp) / cons_arr(i,j,k,Rho_comp); // qi
477  fab_arr(i, j, k,20) = cons_arr(i,j,k,RhoQ5_comp) / cons_arr(i,j,k,Rho_comp); // qs
478  fab_arr(i, j, k,21) = cons_arr(i,j,k,RhoQ6_comp) / cons_arr(i,j,k,Rho_comp); // qg
479  } else {
480  fab_arr(i, j, k,19) = zero; // qi
481  fab_arr(i, j, k,20) = zero; // qs
482  fab_arr(i, j, k,21) = zero; // qg
483  }
484  });
485 
486  const Box& zbx = mfi.tilebox(IntVect(0,0,1));
487  ParallelFor(zbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
488  {
489  Real qv0 = cons_arr(i,j,k ,RhoQ1_comp) / cons_arr(i,j,k ,Rho_comp);
490  Real qv1 = cons_arr(i,j,k-1,RhoQ1_comp) / cons_arr(i,j,k-1,Rho_comp);
491  Real qc0 = cons_arr(i,j,k ,RhoQ2_comp) / cons_arr(i,j,k ,Rho_comp);
492  Real qc1 = cons_arr(i,j,k-1,RhoQ2_comp) / cons_arr(i,j,k-1,Rho_comp);
493  Real qr0 = (rhoqr_comp > -1) ? cons_arr(i,j,k ,RhoQ3_comp) / cons_arr(i,j,k ,Rho_comp) :
494  zero;
495  Real qr1 = (rhoqr_comp > -1) ? cons_arr(i,j,k-1,RhoQ3_comp) / cons_arr(i,j,k-1,Rho_comp) :
496  zero;
497  Real qvface = myhalf * (qv0 + qv1);
498  Real qcface = myhalf * (qc0 + qc1);
499  Real qrface = myhalf * (qr0 + qr1);
500 
501  Real p0 = getPgivenRTh(cons_arr(i, j, k , RhoTheta_comp), qv0) - p0_arr(i,j,k );
502  Real p1 = getPgivenRTh(cons_arr(i, j, k-1, RhoTheta_comp), qv1) - p0_arr(i,j,k-1);
503  Real pface = myhalf * (p0 + p1);
504 
505  Real theta0 = cons_arr(i,j,k ,RhoTheta_comp) / cons_arr(i,j,k ,Rho_comp);
506  Real theta1 = cons_arr(i,j,k-1,RhoTheta_comp) / cons_arr(i,j,k-1,Rho_comp);
507  Real thface = myhalf*(theta0 + theta1);
508  Real ql = qcface + qrface;
509  Real thv = thface * (1 + Real(0.61)*qvface - ql);
510 
511  fab_arr_stag(i,j,k,5) = pface * w_fc_arr(i,j,k); // p*w
512  fab_arr_stag(i,j,k,6) = qvface * w_fc_arr(i,j,k); // w*qv
513  fab_arr_stag(i,j,k,7) = qcface * w_fc_arr(i,j,k); // w*qc
514  fab_arr_stag(i,j,k,8) = qrface * w_fc_arr(i,j,k); // w*qr
515  fab_arr_stag(i,j,k,9) = thv * w_fc_arr(i,j,k); // w*thv
516  });
517  } // mfi
518  } // use_moisture
519 
520  // Sum in the horizontal plane
521  h_avg_u = sumToLine(u_cc,0,1, domain,zdir);
522  h_avg_v = sumToLine(v_cc,0,1, domain,zdir);
523  h_avg_w = sumToLine(w_fc,0,1,stag_domain,zdir);
524 
525  h_avg_rho = sumToLine(mf_out, 0,1,domain,zdir);
526  h_avg_th = sumToLine(mf_out, 1,1,domain,zdir);
527  h_avg_ksgs = sumToLine(mf_out, 2,1,domain,zdir);
528  h_avg_Kmv = sumToLine(mf_out, 3,1,domain,zdir);
529  h_avg_Khv = sumToLine(mf_out, 4,1,domain,zdir);
530  h_avg_uu = sumToLine(mf_out, 5,1,domain,zdir);
531  h_avg_uv = sumToLine(mf_out, 6,1,domain,zdir);
532  h_avg_vv = sumToLine(mf_out, 7,1,domain,zdir);
533  h_avg_uth = sumToLine(mf_out, 8,1,domain,zdir);
534  h_avg_vth = sumToLine(mf_out, 9,1,domain,zdir);
535  h_avg_thth = sumToLine(mf_out,10,1,domain,zdir);
536  h_avg_uiuiu = sumToLine(mf_out,11,1,domain,zdir);
537  h_avg_uiuiv = sumToLine(mf_out,12,1,domain,zdir);
538  h_avg_p = sumToLine(mf_out,13,1,domain,zdir);
539  h_avg_pu = sumToLine(mf_out,14,1,domain,zdir);
540  h_avg_pv = sumToLine(mf_out,15,1,domain,zdir);
541  h_avg_qv = sumToLine(mf_out,16,1,domain,zdir);
542  h_avg_qc = sumToLine(mf_out,17,1,domain,zdir);
543  h_avg_qr = sumToLine(mf_out,18,1,domain,zdir);
544  h_avg_qi = sumToLine(mf_out,19,1,domain,zdir);
545  h_avg_qs = sumToLine(mf_out,20,1,domain,zdir);
546  h_avg_qg = sumToLine(mf_out,21,1,domain,zdir);
547 
548  h_avg_uw = sumToLine(mf_out_stag,0,1,stag_domain,zdir);
549  h_avg_vw = sumToLine(mf_out_stag,1,1,stag_domain,zdir);
550  h_avg_ww = sumToLine(mf_out_stag,2,1,stag_domain,zdir);
551  h_avg_wth = sumToLine(mf_out_stag,3,1,stag_domain,zdir);
552  h_avg_uiuiw = sumToLine(mf_out_stag,4,1,stag_domain,zdir);
553  h_avg_pw = sumToLine(mf_out_stag,5,1,stag_domain,zdir);
554  h_avg_wqv = sumToLine(mf_out_stag,6,1,stag_domain,zdir);
555  h_avg_wqc = sumToLine(mf_out_stag,7,1,stag_domain,zdir);
556  h_avg_wqr = sumToLine(mf_out_stag,8,1,stag_domain,zdir);
557  h_avg_wthv = sumToLine(mf_out_stag,9,1,stag_domain,zdir);
558 
559  // Divide by the total number of cells we are averaging over
560  Real area_z = static_cast<Real>(domain.length(0)*domain.length(1));
561  int unstag_size = h_avg_w.size() - 1; // _un_staggered heights
562  for (int k = 0; k < unstag_size; ++k) {
563  h_avg_u[k] /= area_z;
564  h_avg_v[k] /= area_z;
565  h_avg_rho[k] /= area_z;
566  h_avg_ksgs[k] /= area_z;
567  h_avg_Kmv[k] /= area_z;
568  h_avg_Khv[k] /= area_z;
569  h_avg_th[k] /= area_z;
570  h_avg_thth[k] /= area_z;
571  h_avg_uu[k] /= area_z;
572  h_avg_uv[k] /= area_z;
573  h_avg_vv[k] /= area_z;
574  h_avg_uth[k] /= area_z;
575  h_avg_vth[k] /= area_z;
576  h_avg_uiuiu[k] /= area_z;
577  h_avg_uiuiv[k] /= area_z;
578  h_avg_p[k] /= area_z;
579  h_avg_pu[k] /= area_z;
580  h_avg_pv[k] /= area_z;
581  h_avg_qv[k] /= area_z;
582  h_avg_qc[k] /= area_z;
583  h_avg_qr[k] /= area_z;
584  h_avg_qi[k] /= area_z;
585  h_avg_qs[k] /= area_z;
586  h_avg_qg[k] /= area_z;
587  }
588 
589  for (int k = 0; k < unstag_size+1; ++k) { // staggered heights
590  h_avg_w[k] /= area_z;
591  h_avg_uw[k] /= area_z;
592  h_avg_vw[k] /= area_z;
593  h_avg_ww[k] /= area_z;
594  h_avg_wth[k] /= area_z;
595  h_avg_uiuiw[k] /= area_z;
596  h_avg_pw[k] /= area_z;
597  h_avg_wqv[k] /= area_z;
598  h_avg_wqc[k] /= area_z;
599  h_avg_wqr[k] /= area_z;
600  h_avg_wthv[k] /= area_z;
601  }
602 }
constexpr amrex::Real fourth
Definition: ERF_Constants.H:12
const Box zbx
Definition: ERF_SetupDiff.H:9
real(kind=kind_phys), save qc0
Definition: ERF_module_mp_wsm6.F90:46
Here is the call graph for this function:

◆ derive_stress_profiles()

void ERF::derive_stress_profiles ( amrex::Gpu::HostVector< amrex::Real > &  h_avg_tau11,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_tau12,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_tau13,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_tau22,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_tau23,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_tau33,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_hfx3,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_q1fx3,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_q2fx3,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_diss 
)
480 {
481  int lev = 0;
482 
483  // This will hold the stress tensor components
484  MultiFab mf_out(grids[lev], dmap[lev], 10, 0);
485 
486  MultiFab mf_rho(vars_new[lev][Vars::cons], make_alias, 0, 1);
487 
488  bool l_use_moist = ( solverChoice.moisture_type != MoistureType::None );
489 
490  for ( MFIter mfi(mf_out,TilingIfNotGPU()); mfi.isValid(); ++mfi)
491  {
492  const Box& bx = mfi.tilebox();
493  const Array4<Real>& fab_arr = mf_out.array(mfi);
494 
495  const Array4<const Real>& rho_arr = mf_rho.const_array(mfi);
496 
497  // NOTE: These are from the last RK stage...
498  const Array4<const Real>& tau11_arr = Tau[lev][TauType::tau11]->const_array(mfi);
499  const Array4<const Real>& tau12_arr = Tau[lev][TauType::tau12]->const_array(mfi);
500  const Array4<const Real>& tau13_arr = Tau[lev][TauType::tau13]->const_array(mfi);
501  const Array4<const Real>& tau22_arr = Tau[lev][TauType::tau22]->const_array(mfi);
502  const Array4<const Real>& tau23_arr = Tau[lev][TauType::tau23]->const_array(mfi);
503  const Array4<const Real>& tau33_arr = Tau[lev][TauType::tau33]->const_array(mfi);
504 
505  // These should be re-calculated during ERF_slow_rhs_post
506  // -- just vertical SFS kinematic heat flux for now
507  //const Array4<const Real>& hfx1_arr = SFS_hfx1_lev[lev]->const_array(mfi);
508  //const Array4<const Real>& hfx2_arr = SFS_hfx2_lev[lev]->const_array(mfi);
509  const Array4<const Real>& hfx3_arr = SFS_hfx3_lev[lev]->const_array(mfi);
510  const Array4<const Real>& q1fx3_arr = (l_use_moist) ? SFS_q1fx3_lev[lev]->const_array(mfi) :
511  Array4<const Real>{};
512  const Array4<const Real>& q2fx3_arr = (l_use_moist) ? SFS_q2fx3_lev[lev]->const_array(mfi) :
513  Array4<const Real>{};
514  const Array4<const Real>& diss_arr = SFS_diss_lev[lev]->const_array(mfi);
515 
516  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
517  {
518  // rho averaging should follow Diffusion/ERF_ComputeStress_*.cpp
519  fab_arr(i, j, k, 0) = tau11_arr(i,j,k) / rho_arr(i,j,k);
520  fab_arr(i, j, k, 1) = ( tau12_arr(i,j ,k) + tau12_arr(i+1,j ,k)
521  + tau12_arr(i,j+1,k) + tau12_arr(i+1,j+1,k) )
522  / ( rho_arr(i,j ,k) + rho_arr(i+1,j ,k)
523  + rho_arr(i,j+1,k) + rho_arr(i+1,j+1,k) );
524  fab_arr(i, j, k, 2) = ( tau13_arr(i,j,k ) + tau13_arr(i+1,j,k )
525  + tau13_arr(i,j,k+1) + tau13_arr(i+1,j,k+1) )
526  / ( rho_arr(i,j,k ) + rho_arr(i+1,j,k )
527  + rho_arr(i,j,k+1) + rho_arr(i+1,j,k+1) );
528  fab_arr(i, j, k, 3) = tau22_arr(i,j,k) / rho_arr(i,j,k);
529  fab_arr(i, j, k, 4) = ( tau23_arr(i,j,k ) + tau23_arr(i,j+1,k )
530  + tau23_arr(i,j,k+1) + tau23_arr(i,j+1,k+1) )
531  / ( rho_arr(i,j,k ) + rho_arr(i,j+1,k )
532  + rho_arr(i,j,k+1) + rho_arr(i,j+1,k+1) );
533  fab_arr(i, j, k, 5) = tau33_arr(i,j,k) / rho_arr(i,j,k);
534  fab_arr(i, j, k, 6) = myhalf * ( hfx3_arr(i,j,k) + hfx3_arr(i,j,k+1) ) / rho_arr(i,j,k);
535  fab_arr(i, j, k, 7) = (l_use_moist) ? myhalf * ( q1fx3_arr(i,j,k) + q1fx3_arr(i,j,k+1) ) / rho_arr(i,j,k) : zero;
536  fab_arr(i, j, k, 8) = (l_use_moist) ? myhalf * ( q2fx3_arr(i,j,k) + q2fx3_arr(i,j,k+1) ) / rho_arr(i,j,k) : zero;
537  fab_arr(i, j, k, 9) = diss_arr(i,j,k) / rho_arr(i,j,k);
538  });
539  }
540 
541  int zdir = 2;
542  auto domain = geom[0].Domain();
543 
544  h_avg_tau11 = sumToLine(mf_out,0,1,domain,zdir);
545  h_avg_tau12 = sumToLine(mf_out,1,1,domain,zdir);
546  h_avg_tau13 = sumToLine(mf_out,2,1,domain,zdir);
547  h_avg_tau22 = sumToLine(mf_out,3,1,domain,zdir);
548  h_avg_tau23 = sumToLine(mf_out,4,1,domain,zdir);
549  h_avg_tau33 = sumToLine(mf_out,5,1,domain,zdir);
550  h_avg_hfx3 = sumToLine(mf_out,6,1,domain,zdir);
551  h_avg_q1fx3 = sumToLine(mf_out,7,1,domain,zdir);
552  h_avg_q2fx3 = sumToLine(mf_out,8,1,domain,zdir);
553  h_avg_diss = sumToLine(mf_out,9,1,domain,zdir);
554 
555  int ht_size = h_avg_tau11.size();
556 
557  // Divide by the total number of cells we are averaging over
558  Real area_z = static_cast<Real>(domain.length(0)*domain.length(1));
559  for (int k = 0; k < ht_size; ++k) {
560  h_avg_tau11[k] /= area_z;
561  h_avg_tau12[k] /= area_z;
562  h_avg_tau13[k] /= area_z;
563  h_avg_tau22[k] /= area_z;
564  h_avg_tau23[k] /= area_z;
565  h_avg_tau33[k] /= area_z;
566  h_avg_hfx3[k] /= area_z;
567  h_avg_q1fx3[k] /= area_z;
568  h_avg_q2fx3[k] /= area_z;
569  h_avg_diss[k] /= area_z;
570  }
571 }
auto rho_arr
Definition: ERF_UpdateWSubsidence_SineMassFlux.H:3
Here is the call graph for this function:

◆ derive_stress_profiles_stag()

void ERF::derive_stress_profiles_stag ( amrex::Gpu::HostVector< amrex::Real > &  h_avg_tau11,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_tau12,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_tau13,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_tau22,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_tau23,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_tau33,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_hfx3,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_q1fx3,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_q2fx3,
amrex::Gpu::HostVector< amrex::Real > &  h_avg_diss 
)
610 {
611  int lev = 0;
612 
613  // This will hold the stress tensor components
614  MultiFab mf_out(grids[lev], dmap[lev], 10, 0);
615 
616  // This will hold Tau13 and Tau23
617  MultiFab mf_out_stag(convert(grids[lev], IntVect(0,0,1)), dmap[lev], 5, 0);
618 
619  MultiFab mf_rho(vars_new[lev][Vars::cons], make_alias, 0, 1);
620 
621  bool l_use_moist = ( solverChoice.moisture_type != MoistureType::None );
622 
623  for ( MFIter mfi(mf_out,TilingIfNotGPU()); mfi.isValid(); ++mfi)
624  {
625  const Box& bx = mfi.tilebox();
626  const Array4<Real>& fab_arr = mf_out.array(mfi);
627  const Array4<Real>& fab_arr_stag = mf_out_stag.array(mfi);
628 
629  const Array4<const Real>& rho_arr = mf_rho.const_array(mfi);
630 
631  // NOTE: These are from the last RK stage...
632  const Array4<const Real>& tau11_arr = Tau[lev][TauType::tau11]->const_array(mfi);
633  const Array4<const Real>& tau12_arr = Tau[lev][TauType::tau12]->const_array(mfi);
634  const Array4<const Real>& tau13_arr = Tau[lev][TauType::tau13]->const_array(mfi);
635  const Array4<const Real>& tau22_arr = Tau[lev][TauType::tau22]->const_array(mfi);
636  const Array4<const Real>& tau23_arr = Tau[lev][TauType::tau23]->const_array(mfi);
637  const Array4<const Real>& tau33_arr = Tau[lev][TauType::tau33]->const_array(mfi);
638 
639  // These should be re-calculated during ERF_slow_rhs_post
640  // -- just vertical SFS kinematic heat flux for now
641  //const Array4<const Real>& hfx1_arr = SFS_hfx1_lev[lev]->const_array(mfi);
642  //const Array4<const Real>& hfx2_arr = SFS_hfx2_lev[lev]->const_array(mfi);
643  const Array4<const Real>& hfx3_arr = SFS_hfx3_lev[lev]->const_array(mfi);
644  const Array4<const Real>& q1fx3_arr = (l_use_moist) ? SFS_q1fx3_lev[lev]->const_array(mfi) :
645  Array4<const Real>{};
646  const Array4<const Real>& q2fx3_arr = (l_use_moist) ? SFS_q2fx3_lev[lev]->const_array(mfi) :
647  Array4<const Real>{};
648  const Array4<const Real>& diss_arr = SFS_diss_lev[lev]->const_array(mfi);
649 
650  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
651  {
652  // rho averaging should follow Diffusion/ERF_ComputeStress_*.cpp
653  fab_arr(i, j, k, 0) = tau11_arr(i,j,k) / rho_arr(i,j,k);
654  fab_arr(i, j, k, 1) = ( tau12_arr(i,j ,k) + tau12_arr(i+1,j ,k)
655  + tau12_arr(i,j+1,k) + tau12_arr(i+1,j+1,k) )
656  / ( rho_arr(i,j ,k) + rho_arr(i+1,j ,k)
657  + rho_arr(i,j+1,k) + rho_arr(i+1,j+1,k) );
658  fab_arr(i, j, k, 3) = tau22_arr(i,j,k) / rho_arr(i,j,k);
659  fab_arr(i, j, k, 5) = tau33_arr(i,j,k) / rho_arr(i,j,k);
660  fab_arr(i, j, k, 9) = diss_arr(i,j,k) / rho_arr(i,j,k);
661  });
662 
663  const Box& zbx = mfi.tilebox(IntVect(0,0,1));
664  ParallelFor(zbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
665  {
666  Real rho_face = myhalf * (rho_arr(i,j,k-1) + rho_arr(i,j,k));
667  // average from edge to face center
668  fab_arr_stag(i,j,k,0) = myhalf*(tau13_arr(i,j,k) + tau13_arr(i+1,j ,k)) / rho_face;
669  fab_arr_stag(i,j,k,1) = myhalf*(tau23_arr(i,j,k) + tau23_arr(i ,j+1,k)) / rho_face;
670 
671  fab_arr_stag(i,j,k,2) = hfx3_arr(i,j,k) / rho_face;
672  fab_arr_stag(i,j,k,3) = (l_use_moist) ? q1fx3_arr(i,j,k) / rho_face : zero;
673  fab_arr_stag(i,j,k,4) = (l_use_moist) ? q2fx3_arr(i,j,k) / rho_face : zero;
674  });
675  }
676 
677  int zdir = 2;
678  auto domain = geom[0].Domain();
679  Box stag_domain = domain;
680  stag_domain.convert(IntVect(0,0,1));
681 
682  h_avg_tau11 = sumToLine(mf_out,0,1,domain,zdir);
683  h_avg_tau12 = sumToLine(mf_out,1,1,domain,zdir);
684 // h_avg_tau13 = sumToLine(mf_out,2,1,domain,zdir);
685  h_avg_tau22 = sumToLine(mf_out,3,1,domain,zdir);
686 // h_avg_tau23 = sumToLine(mf_out,4,1,domain,zdir);
687  h_avg_tau33 = sumToLine(mf_out,5,1,domain,zdir);
688 // h_avg_hfx3 = sumToLine(mf_out,6,1,domain,zdir);
689 // h_avg_q1fx3 = sumToLine(mf_out,7,1,domain,zdir);
690 // h_avg_q2fx3 = sumToLine(mf_out,8,1,domain,zdir);
691  h_avg_diss = sumToLine(mf_out,9,1,domain,zdir);
692 
693  h_avg_tau13 = sumToLine(mf_out_stag,0,1,stag_domain,zdir);
694  h_avg_tau23 = sumToLine(mf_out_stag,1,1,stag_domain,zdir);
695  h_avg_hfx3 = sumToLine(mf_out_stag,2,1,stag_domain,zdir);
696  h_avg_q1fx3 = sumToLine(mf_out_stag,3,1,stag_domain,zdir);
697  h_avg_q2fx3 = sumToLine(mf_out_stag,4,1,stag_domain,zdir);
698 
699  int ht_size = h_avg_tau11.size(); // _un_staggered
700 
701  // Divide by the total number of cells we are averaging over
702  Real area_z = static_cast<Real>(domain.length(0)*domain.length(1));
703  for (int k = 0; k < ht_size; ++k) {
704  h_avg_tau11[k] /= area_z;
705  h_avg_tau12[k] /= area_z;
706  h_avg_tau13[k] /= area_z;
707  h_avg_tau22[k] /= area_z;
708  h_avg_tau23[k] /= area_z;
709  h_avg_tau33[k] /= area_z;
710  h_avg_hfx3[k] /= area_z;
711  h_avg_q1fx3[k] /= area_z;
712  h_avg_q2fx3[k] /= area_z;
713  h_avg_diss[k] /= area_z;
714  }
715  // staggered heights
716  h_avg_tau13[ht_size] /= area_z;
717  h_avg_tau23[ht_size] /= area_z;
718  h_avg_hfx3[ht_size] /= area_z;
719  h_avg_q1fx3[ht_size] /= area_z;
720  h_avg_q2fx3[ht_size] /= area_z;
721 }
Here is the call graph for this function:

◆ derive_upwp()

void ERF::derive_upwp ( amrex::Vector< amrex::Real > &  h_havg)

◆ EBFactory()

amrex::EBFArrayBoxFactory const& ERF::EBFactory ( int  lev) const
inlineprivatenoexcept
1676  {
1677  return *(eb[lev]->get_const_factory());
1678  }
amrex::Vector< std::unique_ptr< eb_ > > eb
Definition: ERF.H:1668

◆ erf_enforce_hse()

void ERF::erf_enforce_hse ( int  lev,
amrex::MultiFab &  dens,
amrex::MultiFab &  pres,
amrex::MultiFab &  pi,
amrex::MultiFab &  th,
amrex::MultiFab &  qv,
std::unique_ptr< amrex::MultiFab > &  z_cc 
)

Enforces hydrostatic equilibrium when using terrain.

Parameters
[in]levInteger specifying the current level
[out]densMultiFab storing base state density
[out]presMultiFab storing base state pressure
[out]piMultiFab storing base state Exner function
[in]z_ccPointer to MultiFab storing cell centered z-coordinates
213 {
214  Real l_gravity = solverChoice.gravity;
215  bool l_use_terrain = (solverChoice.mesh_type != MeshType::ConstantDz);
216 
217  const auto geomdata = geom[lev].data();
218  const Real dz = geomdata.CellSize(2);
219 
220  for ( MFIter mfi(dens, TileNoZ()); mfi.isValid(); ++mfi )
221  {
222  // Create a flat box with same horizontal extent but only one cell in vertical
223  const Box& tbz = mfi.nodaltilebox(2);
224  int klo = tbz.smallEnd(2);
225  int khi = tbz.bigEnd(2);
226 
227  // Note we only grow by 1 because that is how big z_cc is.
228  Box b2d = tbz; // Copy constructor
229  b2d.grow(0,1);
230  b2d.grow(1,1);
231  b2d.setRange(2,0);
232 
233  // Intersect this box with the domain
234  Box zdomain = convert(geom[lev].Domain(),tbz.ixType());
235  b2d &= zdomain;
236 
237  // We integrate to the first cell (and below) by using rho in this cell
238  // If gravity == 0 this is constant pressure
239  // If gravity != 0, hence this is a wall, this gives gp0 = dens[0] * gravity
240  // (dens_hse*gravity would also be dens[0]*gravity because we use foextrap for rho at k = -1)
241  // Note ng_pres_hse = 1
242 
243  // We start by assuming pressure on the ground is p_0 (in ERF_Constants.H)
244  // Note that gravity is positive
245 
246  Array4<Real> rho_arr = dens.array(mfi);
247  Array4<Real> pres_arr = pres.array(mfi);
248  Array4<Real> pi_arr = pi.array(mfi);
249  Array4<Real> th_arr = theta.array(mfi);
250  Array4<Real> zcc_arr;
251  if (l_use_terrain) {
252  zcc_arr = z_cc->array(mfi);
253  }
254 
255  const Real rdOcp = solverChoice.rdOcp;
256 
257  ParallelFor(b2d, [=] AMREX_GPU_DEVICE (int i, int j, int)
258  {
259  // Set value at surface from Newton iteration for rho
260  if (klo == 0)
261  {
262  // Physical height of the terrain at cell center
263  Real hz;
264  if (l_use_terrain) {
265  hz = zcc_arr(i,j,klo);
266  } else {
267  hz = myhalf*dz;
268  }
269 
270  pres_arr(i,j,klo) = p_0 - hz * rho_arr(i,j,klo) * l_gravity;
271  pi_arr(i,j,klo) = getExnergivenP(pres_arr(i,j,klo), rdOcp);
272  th_arr(i,j,klo) = getRhoThetagivenP(pres_arr(i,j,klo)) / rho_arr(i,j,klo);
273 
274  //
275  // Set ghost cell with dz and rho at boundary
276  // (We will set the rest of the ghost cells in the boundary condition routine)
277  //
278  pres_arr(i,j,klo-1) = p_0 + hz * rho_arr(i,j,klo) * l_gravity;
279  pi_arr(i,j,klo-1) = getExnergivenP(pres_arr(i,j,klo-1), rdOcp);
280  th_arr(i,j,klo-1) = getRhoThetagivenP(pres_arr(i,j,klo-1)) / rho_arr(i,j,klo-1);
281 
282  } else {
283 
284  // If level > 0 and klo > 0, we need to use the value of pres_arr(i,j,klo-1) which was
285  // filled from FillPatch-ing it.
286  Real dz_loc;
287  if (l_use_terrain) {
288  dz_loc = (zcc_arr(i,j,klo) - zcc_arr(i,j,klo-1));
289  } else {
290  dz_loc = dz;
291  }
292 
293  Real dens_interp = myhalf*(rho_arr(i,j,klo) + rho_arr(i,j,klo-1));
294  pres_arr(i,j,klo) = pres_arr(i,j,klo-1) - dz_loc * dens_interp * l_gravity;
295 
296  pi_arr(i,j,klo ) = getExnergivenP(pres_arr(i,j,klo ), rdOcp);
297  th_arr(i,j,klo ) = getRhoThetagivenP(pres_arr(i,j,klo )) / rho_arr(i,j,klo );
298 
299  pi_arr(i,j,klo-1) = getExnergivenP(pres_arr(i,j,klo-1), rdOcp);
300  th_arr(i,j,klo-1) = getRhoThetagivenP(pres_arr(i,j,klo-1)) / rho_arr(i,j,klo-1);
301  }
302 
303  Real dens_interp;
304  if (l_use_terrain) {
305  for (int k = klo+1; k <= khi; k++) {
306  Real dz_loc = (zcc_arr(i,j,k) - zcc_arr(i,j,k-1));
307  dens_interp = myhalf*(rho_arr(i,j,k) + rho_arr(i,j,k-1));
308  pres_arr(i,j,k) = pres_arr(i,j,k-1) - dz_loc * dens_interp * l_gravity;
309  pi_arr(i,j,k) = getExnergivenP(pres_arr(i,j,k), rdOcp);
310  th_arr(i,j,k) = getRhoThetagivenP(pres_arr(i,j,k)) / rho_arr(i,j,k);
311  }
312  } else {
313  for (int k = klo+1; k <= khi; k++) {
314  dens_interp = myhalf*(rho_arr(i,j,k) + rho_arr(i,j,k-1));
315  pres_arr(i,j,k) = pres_arr(i,j,k-1) - dz * dens_interp * l_gravity;
316  pi_arr(i,j,k) = getExnergivenP(pres_arr(i,j,k), rdOcp);
317  th_arr(i,j,k) = getRhoThetagivenP(pres_arr(i,j,k)) / rho_arr(i,j,k);
318  }
319  }
320  });
321 
322  } // mfi
323 
324  dens.FillBoundary(geom[lev].periodicity());
325  pres.FillBoundary(geom[lev].periodicity());
326  pi.FillBoundary(geom[lev].periodicity());
327  theta.FillBoundary(geom[lev].periodicity());
328  qv.FillBoundary(geom[lev].periodicity());
329 }
constexpr amrex::Real p_0
Definition: ERF_Constants.H:37
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getRhoThetagivenP(const amrex::Real p, const amrex::Real qv=amrex::Real(0))
Definition: ERF_EOS.H:172
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getExnergivenP(const amrex::Real P, const amrex::Real rdOcp)
Definition: ERF_EOS.H:141
const Real rdOcp
Definition: ERF_InitCustomPert_Bomex.H:16
@ pres
Definition: ERF_Kessler.H:26
real(c_double), parameter, private pi
Definition: ERF_module_mp_morr_two_moment.F90:100
real(kind=kind_phys), parameter, private dens
Definition: ERF_module_mp_wsm6.F90:39
amrex::Real rdOcp
Definition: ERF_DataStruct.H:1210
Here is the call graph for this function:

◆ ERF_shared()

void ERF::ERF_shared ( )
158 {
159  if (ParallelDescriptor::IOProcessor()) {
160  const char* erf_hash = buildInfoGetGitHash(1);
161  const char* amrex_hash = buildInfoGetGitHash(2);
162  const char* buildgithash = buildInfoGetBuildGitHash();
163  const char* buildgitname = buildInfoGetBuildGitName();
164 
165  if (strlen(erf_hash) > 0) {
166  Print() << "\n"
167  << "ERF git hash: " << erf_hash << "\n";
168  }
169  if (strlen(amrex_hash) > 0) {
170  Print() << "AMReX git hash: " << amrex_hash << "\n";
171  }
172  if (strlen(buildgithash) > 0) {
173  Print() << buildgitname << " git hash: " << buildgithash << "\n";
174  }
175 
176  Print() << "\n";
177  }
178 
179  int nlevs_max = max_level + 1;
180 
181 #ifdef ERF_USE_WINDFARM
182  Nturb.resize(nlevs_max);
183  vars_windfarm.resize(nlevs_max);
184  SMark.resize(nlevs_max);
185 #endif
186 
187  qheating_rates.resize(nlevs_max);
188  rad_fluxes.resize(nlevs_max);
189 
190  // NOTE: size lsm before readparams (chooses the model at all levels)
191  lsm.ReSize(nlevs_max);
192  lsm_data.resize(nlevs_max);
193  lsm_flux.resize(nlevs_max);
194 
195  rhotheta_src.resize(nlevs_max);
196  rhoqt_src.resize(nlevs_max);
197 
198  // NOTE: size canopy model before readparams (if file exists, we construct)
199  m_forest_drag.resize(nlevs_max);
200  for (int lev = 0; lev <= max_level; ++lev) { m_forest_drag[lev] = nullptr;}
201 
202  ReadParameters();
203  initializeMicrophysics(nlevs_max);
204 
205 #ifdef ERF_USE_WINDFARM
206  initializeWindFarm(nlevs_max);
207 #endif
208 
209 #ifdef ERF_USE_SHOC
210  shoc_interface.resize(nlevs_max);
211  if (solverChoice.use_shoc) {
212  for (int lev = 0; lev <= max_level; ++lev) {
213  shoc_interface[lev] = std::make_unique<SHOCInterface>(lev, solverChoice);
214  }
215  }
216 #endif
217 
218  rad.resize(nlevs_max);
219  for (int lev = 0; lev <= max_level; ++lev) {
220  if (solverChoice.rad_type == RadiationType::RRTMGP) {
221 #ifdef ERF_USE_RRTMGP
222  rad[lev] = std::make_unique<Radiation>(lev, solverChoice);
223  // pass radiation datalog frequency to model - RRTMGP needs to know when to save data for profiles
224  rad[lev]->setDataLogFrequency(rad_datalog_int);
225 #endif
226  } else if (solverChoice.rad_type != RadiationType::None) {
227  Abort("Don't know this radiation model!");
228  }
229  }
230  const std::string& pv3d_1 = "plot_vars_1" ; setPlotVariables(pv3d_1,plot3d_var_names_1);
231  const std::string& pv3d_2 = "plot_vars_2" ; setPlotVariables(pv3d_2,plot3d_var_names_2);
232  const std::string& pv2d_1 = "plot2d_vars_1"; setPlotVariables2D(pv2d_1,plot2d_var_names_1);
233  const std::string& pv2d_2 = "plot2d_vars_2"; setPlotVariables2D(pv2d_2,plot2d_var_names_2);
234 
235  // This is only used when we have mesh_type == MeshType::StretchedDz
236  stretched_dz_h.resize(nlevs_max);
237  stretched_dz_d.resize(nlevs_max);
238 
239  // Initialize staggered vertical levels for grid stretching or terrain, and
240  // to simplify Rayleigh damping layer calculations.
241  zlevels_stag.resize(max_level+1);
245  geom,
246  refRatio(),
249  solverChoice.dz0);
250 
251  if (SolverChoice::mesh_type == MeshType::StretchedDz ||
252  SolverChoice::mesh_type == MeshType::VariableDz) {
253  int nz = geom[0].Domain().length(2) + 1; // staggered
254  if (std::fabs(zlevels_stag[0][nz-1]-geom[0].ProbHi(2)) > Real(1.0e-4)) {
255  Print() << "Note: prob_hi[2]=" << geom[0].ProbHi(2)
256  << " does not match highest requested z level " << zlevels_stag[0][nz-1]
257  << std::endl;
258  }
259  if (std::fabs(zlevels_stag[0][0]-geom[0].ProbLo(2)) > Real(1.0e-4)) {
260  Print() << "Note: prob_lo[2]=" << geom[0].ProbLo(2)
261  << " does not match lowest requested level " << zlevels_stag[0][0]
262  << std::endl;
263  }
264 
265  // Redefine the problem domain here?
266  }
267 
268  // Get lo/hi indices for massflux calc
270  if (solverChoice.mesh_type == MeshType::ConstantDz) {
271  const bool zlo_unset = (solverChoice.const_massflux_layer_lo == amrex::Real(-1e34));
272  const bool zhi_unset = (solverChoice.const_massflux_layer_hi == amrex::Real( 1e34));
273  const Real massflux_zlo = solverChoice.const_massflux_layer_lo - geom[0].ProbLo(2);
274  const Real massflux_zhi = solverChoice.const_massflux_layer_hi - geom[0].ProbLo(2);
275  const Real dz = geom[0].CellSize(2);
276  if (zlo_unset) {
277  solverChoice.massflux_klo = geom[0].Domain().smallEnd(2);
278  } else {
279  solverChoice.massflux_klo = static_cast<int>(std::ceil(massflux_zlo / dz - myhalf));
280  }
281  if (zhi_unset) {
282  solverChoice.massflux_khi = geom[0].Domain().bigEnd(2);
283  } else {
284  solverChoice.massflux_khi = static_cast<int>(std::floor(massflux_zhi / dz - myhalf));
285  }
286  } else if (solverChoice.mesh_type == MeshType::StretchedDz) {
287  const Real massflux_zlo = solverChoice.const_massflux_layer_lo;
288  const Real massflux_zhi = solverChoice.const_massflux_layer_hi;
289  solverChoice.massflux_klo = geom[0].Domain().smallEnd(2);
290  solverChoice.massflux_khi = geom[0].Domain().bigEnd(2) + 1;
291  for (int k=0; k <= geom[0].Domain().bigEnd(2)+1; ++k) {
292  if (zlevels_stag[0][k] <= massflux_zlo) solverChoice.massflux_klo = k;
293  if (zlevels_stag[0][k] <= massflux_zhi) solverChoice.massflux_khi = k;
294  }
295  } else { // solverChoice.mesh_type == MeshType::VariableDz
296  Error("Const massflux with variable dz not supported -- planar averages are on k rather than constant-z planes");
297  }
298 
299  Print() << "Constant mass flux based on k in ["
300  << solverChoice.massflux_klo << ", " << solverChoice.massflux_khi << "]" << std::endl;
301  }
302 
303 #ifdef ERF_REMORA_FORCE_PROBINIT_LINK
304  extern void erf_probinit_link_anchor_func () noexcept;
305  erf_probinit_link_anchor_func();
306 #endif
307  prob = amrex_probinit(geom[0].ProbLo(),geom[0].ProbHi());
308 
309  // Geometry on all levels has been defined already.
310 
311  // No valid BoxArray and DistributionMapping have been defined.
312  // But the arrays for them have been resized.
313 
314  t_new.resize(nlevs_max, zero);
315  t_old.resize(nlevs_max, -Real(1.e100));
316  dt.resize(nlevs_max, std::min(Real(1.e100),dt_max_initial));
317  dt_mri_ratio.resize(nlevs_max, 1);
318 
319  vars_new.resize(nlevs_max);
320  vars_old.resize(nlevs_max);
321  gradp.resize(nlevs_max);
322 
323  // We resize this regardless in order to pass it without error
324  pp_inc.resize(nlevs_max);
325 
326  // Used in the fast substepping only
327  lagged_delta_rt.resize(nlevs_max);
328  avg_xmom.resize(nlevs_max);
329  avg_ymom.resize(nlevs_max);
330  avg_zmom.resize(nlevs_max);
331 
332  rU_new.resize(nlevs_max);
333  rV_new.resize(nlevs_max);
334  rW_new.resize(nlevs_max);
335 
336  rU_old.resize(nlevs_max);
337  rV_old.resize(nlevs_max);
338  rW_old.resize(nlevs_max);
339 
340  // xmom_crse_rhs.resize(nlevs_max);
341  // ymom_crse_rhs.resize(nlevs_max);
342  zmom_crse_rhs.resize(nlevs_max);
343 
344  for (int lev = 0; lev < nlevs_max; ++lev) {
345  vars_new[lev].resize(Vars::NumTypes);
346  vars_old[lev].resize(Vars::NumTypes);
347  gradp[lev].resize(AMREX_SPACEDIM);
348  }
349 
350  // Time integrator
351  mri_integrator_mem.resize(nlevs_max);
352 
353  // Physical boundary conditions
354  physbcs_cons.resize(nlevs_max);
355  physbcs_u.resize(nlevs_max);
356  physbcs_v.resize(nlevs_max);
357  physbcs_w.resize(nlevs_max);
358  physbcs_base.resize(nlevs_max);
359 
360  // Planes to hold Dirichlet values at boundaries
361  xvel_bc_data.resize(nlevs_max);
362  yvel_bc_data.resize(nlevs_max);
363  zvel_bc_data.resize(nlevs_max);
364  th_bc_data.resize(nlevs_max);
365 
366  advflux_reg.resize(nlevs_max);
367 
368  // Stresses
369  Tau.resize(nlevs_max);
370  Tau_corr.resize(nlevs_max);
371  SFS_hfx1_lev.resize(nlevs_max); SFS_hfx2_lev.resize(nlevs_max); SFS_hfx3_lev.resize(nlevs_max);
372  SFS_diss_lev.resize(nlevs_max);
373  SFS_q1fx1_lev.resize(nlevs_max); SFS_q1fx2_lev.resize(nlevs_max); SFS_q1fx3_lev.resize(nlevs_max);
374  SFS_q2fx3_lev.resize(nlevs_max);
375  eddyDiffs_lev.resize(nlevs_max);
376  SmnSmn_lev.resize(nlevs_max);
377  Tau_EB.resize(nlevs_max);
378  hfx3_EB.resize(nlevs_max);
379 
380  // Sea surface temps
381  sst_lev.resize(nlevs_max);
382  tsk_lev.resize(nlevs_max);
383  lmask_lev.resize(nlevs_max);
384 
385  // Land and soil grid type and urban fractions
386  land_type_lev.resize(nlevs_max);
387  soil_type_lev.resize(nlevs_max);
388  urb_frac_lev.resize(nlevs_max);
389 
390  // Metric terms
391  z_phys_nd.resize(nlevs_max);
392  z_phys_cc.resize(nlevs_max);
393  detJ_cc.resize(nlevs_max);
394  ax.resize(nlevs_max);
395  ay.resize(nlevs_max);
396  az.resize(nlevs_max);
397 
398  z_phys_nd_new.resize(nlevs_max);
399  detJ_cc_new.resize(nlevs_max);
400 
401  z_phys_nd_src.resize(nlevs_max);
402  z_phys_cc_src.resize(nlevs_max);
403  detJ_cc_src.resize(nlevs_max);
404  ax_src.resize(nlevs_max);
405  ay_src.resize(nlevs_max);
406  az_src.resize(nlevs_max);
407 
408  z_t_rk.resize(nlevs_max);
409 
410  terrain_blanking.resize(nlevs_max);
411 
412  // Wall distance
413  walldist.resize(nlevs_max);
414 
415  // BoxArrays to make MultiFabs needed to convert WRFBdy data
416  ba1d.resize(nlevs_max);
417  ba2d.resize(nlevs_max);
418 
419  // MultiFabs needed to convert WRFBdy data
420  mf_PSFC.resize(nlevs_max);
421 
422  // Map factors
423  mapfac.resize(nlevs_max);
424 
425  // Fine mask
426  fine_mask.resize(nlevs_max);
427 
428  // Thin immersed body
429  xflux_imask.resize(nlevs_max);
430  yflux_imask.resize(nlevs_max);
431  zflux_imask.resize(nlevs_max);
432  //overset_imask.resize(nlevs_max);
433  thin_xforce.resize(nlevs_max);
434  thin_yforce.resize(nlevs_max);
435  thin_zforce.resize(nlevs_max);
436 
437  // Base state
438  base_state.resize(nlevs_max);
439  base_state_new.resize(nlevs_max);
440 
441  // Wave coupling data
442  Hwave.resize(nlevs_max);
443  Lwave.resize(nlevs_max);
444  for (int lev = 0; lev < max_level; ++lev)
445  {
446  Hwave[lev] = nullptr;
447  Lwave[lev] = nullptr;
448  }
449  Hwave_onegrid.resize(nlevs_max);
450  Lwave_onegrid.resize(nlevs_max);
451  for (int lev = 0; lev < max_level; ++lev)
452  {
453  Hwave_onegrid[lev] = nullptr;
454  Lwave_onegrid[lev] = nullptr;
455  }
456 
457  // Theta prim for MOST
458  Theta_prim.resize(nlevs_max);
459 
460  // Qv prim for MOST
461  Qv_prim.resize(nlevs_max);
462 
463  // Qr prim for MOST
464  Qr_prim.resize(nlevs_max);
465 
466  // Time averaged velocity field
467  vel_t_avg.resize(nlevs_max);
468  t_avg_cnt.resize(nlevs_max);
469 
470  // Size lat long arrays and default to null pointers
471  lat_m.resize(nlevs_max);
472  lon_m.resize(nlevs_max);
473  for (int lev = 0; lev < max_level; ++lev) {
474  lat_m[lev] = nullptr;
475  lon_m[lev] = nullptr;
476  }
477 
478  // Variable coriolis
479  sinPhi_m.resize(nlevs_max);
480  cosPhi_m.resize(nlevs_max);
481  for (int lev = 0; lev < max_level; ++lev) {
482  sinPhi_m[lev] = nullptr;
483  cosPhi_m[lev] = nullptr;
484  }
485 
486  // Rayleigh damping
487  h_rayleigh_ptrs.resize(nlevs_max);
488  d_rayleigh_ptrs.resize(nlevs_max);
489  h_sinesq_ptrs.resize(nlevs_max);
490  d_sinesq_ptrs.resize(nlevs_max);
491  h_sinesq_stag_ptrs.resize(nlevs_max);
492  d_sinesq_stag_ptrs.resize(nlevs_max);
493 
494  // Initialize tagging criteria for mesh refinement
496 
497  for (int lev = 0; lev < max_level; ++lev)
498  {
499  Print() << "Refinement ratio at level " << lev+1 << " set to be " <<
500  ref_ratio[lev][0] << " " << ref_ratio[lev][1] << " " << ref_ratio[lev][2] << std::endl;
501  }
502 
503  // We will create each of these in MakeNewLevelFromScratch
504  eb.resize(max_level+1);
505  for (int lev = 0; lev < max_level + 1; lev++){
506  eb[lev] = std::make_unique<eb_>();
507  }
508 
509  //
510  // Construct the EB data structures and store in a separate class
511  //
512  // This is needed before initializing level MultiFabs
513  if ( solverChoice.terrain_type == TerrainType::EB ||
514  solverChoice.terrain_type == TerrainType::ImmersedForcing)
515  {
516  std::string geometry ="terrain";
517  ParmParse pp_eb2("eb2");
518  pp_eb2.queryAdd("geometry", geometry);
519 
520  constexpr int ngrow_for_eb = 4; // This is the default in amrex but we need to explicitly pass it here since
521  // we want to also pass the build_coarse_level_by_coarsening argument
522  const bool build_eb_for_multigrid = (solverChoice.terrain_type == TerrainType::EB &&
524  solverChoice.anelastic[0] == 1));
525  // Note this just needs to be an integer > number of V-cycles one might use
526  const int max_coarsening_level = (build_eb_for_multigrid) ? 100 : 0;
527  const bool build_coarse_level_by_coarsening(false);
528 
529  // Define GeometryShop using the implicit function
530  if (geometry == "terrain") {
531  Box terrain_bx(surroundingNodes(geom[max_level].Domain())); terrain_bx.grow(3);
532  FArrayBox terrain_fab(makeSlab(terrain_bx,2,0),1);
533  Real dummy_time = zero;
534  prob->init_terrain_surface(geom[max_level], terrain_fab, dummy_time);
535  TerrainIF implicit_fun(terrain_fab, geom[max_level], stretched_dz_d[max_level]);
536  auto gshop = EB2::makeShop(implicit_fun);
537  if (build_eb_for_multigrid) {
538  EB2::Build(gshop, geom[max_level], max_level, max_coarsening_level,
539  ngrow_for_eb, build_coarse_level_by_coarsening);
540  } else {
541  EB2::Build(gshop, this->Geom(), ngrow_for_eb);
542  }
543  } else if (geometry == "plane") {
544  RealArray plane_point{zero, zero, zero};
545  RealArray plane_normal{zero, zero, -one}; // pointing into the solid region
546  pp_eb2.query("plane_point", plane_point);
547  pp_eb2.query("plane_normal", plane_normal);
548  EB2::PlaneIF implicit_fun(plane_point, plane_normal, true);
549  auto gshop = EB2::makeShop(implicit_fun);
550  if (build_eb_for_multigrid) {
551  EB2::Build(gshop, geom[max_level], max_level, max_coarsening_level,
552  ngrow_for_eb, build_coarse_level_by_coarsening);
553  } else {
554  EB2::Build(gshop, this->Geom(), ngrow_for_eb);
555  }
556  } else if (geometry == "box") {
557  RealArray box_lo{zero, zero, zero};
558  RealArray box_hi{zero, zero, zero};
559  pp_eb2.query("box_lo", box_lo);
560  pp_eb2.query("box_hi", box_hi);
561  EB2::BoxIF implicit_fun(box_lo, box_hi, false);
562  auto gshop = EB2::makeShop(implicit_fun);
563  if (build_eb_for_multigrid) {
564  EB2::Build(gshop, geom[max_level], max_level, max_coarsening_level,
565  ngrow_for_eb, build_coarse_level_by_coarsening);
566  } else {
567  EB2::Build(gshop, this->Geom(), ngrow_for_eb);
568  }
569  } else if (geometry == "sphere") {
570  auto ProbLoArr = geom[max_level].ProbLoArray();
571  auto ProbHiArr = geom[max_level].ProbHiArray();
572  const Real xcen = myhalf * (ProbLoArr[0] + ProbHiArr[0]);
573  const Real ycen = myhalf * (ProbLoArr[1] + ProbHiArr[1]);
574  RealArray sphere_center = {xcen, ycen, zero};
575  EB2::SphereIF implicit_fun(myhalf, sphere_center, false);
576  auto gshop = EB2::makeShop(implicit_fun);
577  if (build_eb_for_multigrid) {
578  EB2::Build(gshop, geom[max_level], max_level, max_coarsening_level,
579  ngrow_for_eb, build_coarse_level_by_coarsening);
580  } else {
581  EB2::Build(gshop, this->Geom(), ngrow_for_eb);
582  }
583  }
584  }
585 
586  if ( solverChoice.buildings_type == BuildingsType::ImmersedForcing) {
587  constexpr int ngrow_for_eb = 4;
588  Box buildings_bx(surroundingNodes(geom[max_level].Domain())); buildings_bx.grow(3);
589  FArrayBox buildings_fab(makeSlab(buildings_bx,2,0),1);
590  Real dummy_time = zero;
591  prob->init_buildings_surface(geom[max_level], buildings_fab, dummy_time);
592  TerrainIF implicit_fun(buildings_fab, geom[max_level], stretched_dz_d[max_level]);
593  auto gshop = EB2::makeShop(implicit_fun);
594  EB2::Build(gshop, this->Geom(), ngrow_for_eb);
595  }
596 
597  forecast_state_1.resize(nlevs_max);
598  forecast_state_2.resize(nlevs_max);
599  forecast_state_interp.resize(nlevs_max);
600 
601  surface_state_1.resize(nlevs_max);
602  surface_state_2.resize(nlevs_max);
603  surface_state_interp.resize(nlevs_max);
604 }
void init_zlevels(Vector< Vector< Real >> &zlevels_stag, Vector< Vector< Real >> &stretched_dz_h, Vector< Gpu::DeviceVector< Real >> &stretched_dz_d, Vector< Geometry > const &geom, Vector< IntVect > const &ref_ratio, const Real grid_stretching_ratio, const Real zsurf, const Real dz0)
Definition: ERF_InitZLevels.cpp:11
std::unique_ptr< ProblemBase > amrex_probinit(const amrex_real *problo, const amrex_real *probhi) AMREX_ATTRIBUTE_WEAK
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Hwave_onegrid
Definition: ERF.H:1009
amrex::Vector< std::unique_ptr< amrex::MultiFab > > thin_yforce
Definition: ERF.H:1045
void setPlotVariables(const std::string &pp_plot_var_names, amrex::Vector< std::string > &plot_var_names)
Definition: ERF_Plotfile.cpp:28
amrex::Vector< amrex::BoxArray > ba2d
Definition: ERF.H:1298
amrex::Vector< amrex::Vector< amrex::MultiFab > > gradp
Definition: ERF.H:851
void ReadParameters()
Definition: ERF.cpp:2400
amrex::Vector< amrex::Vector< amrex::MultiFab > > forecast_state_interp
Definition: ERF.H:169
amrex::Vector< std::unique_ptr< amrex::MultiFab > > mf_PSFC
Definition: ERF.H:1307
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_nd_src
Definition: ERF.H:976
amrex::Vector< amrex::MultiFab > base_state_new
Definition: ERF.H:1004
amrex::Vector< std::unique_ptr< amrex::MultiFab > > az
Definition: ERF.H:974
amrex::Vector< std::unique_ptr< amrex::MultiFab > > terrain_blanking
Definition: ERF.H:989
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_nd_new
Definition: ERF.H:983
amrex::Vector< std::unique_ptr< amrex::MultiFab > > thin_zforce
Definition: ERF.H:1046
amrex::Vector< std::string > plot3d_var_names_2
Definition: ERF.H:1143
amrex::Vector< std::string > plot2d_var_names_1
Definition: ERF.H:1144
amrex::Vector< std::unique_ptr< amrex::MultiFab > > thin_xforce
Definition: ERF.H:1044
void setPlotVariables2D(const std::string &pp_plot_var_names, amrex::Vector< std::string > &plot_var_names)
Definition: ERF_Plotfile.cpp:190
amrex::Vector< amrex::Real > t_new
Definition: ERF.H:839
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > th_bc_data
Definition: ERF.H:806
amrex::Vector< amrex::MultiFab > surface_state_1
Definition: ERF.H:170
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_t_rk
Definition: ERF.H:986
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Lwave_onegrid
Definition: ERF.H:1010
amrex::Vector< amrex::Vector< amrex::Real > > h_sinesq_ptrs
Definition: ERF.H:1356
amrex::Vector< std::unique_ptr< amrex::MultiFab > > fine_mask
Definition: ERF.H:998
amrex::Vector< std::unique_ptr< ForestDrag > > m_forest_drag
Definition: ERF.H:1384
amrex::Vector< amrex::BoxArray > ba1d
Definition: ERF.H:1297
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > xvel_bc_data
Definition: ERF.H:803
int rad_datalog_int
Definition: ERF.H:926
amrex::Vector< amrex::MultiFab > surface_state_2
Definition: ERF.H:171
amrex::Vector< std::unique_ptr< amrex::MultiFab > > detJ_cc_src
Definition: ERF.H:978
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ay_src
Definition: ERF.H:980
amrex::Vector< std::unique_ptr< amrex::iMultiFab > > yflux_imask
Definition: ERF.H:1039
amrex::Vector< amrex::Vector< amrex::MultiFab * > > lsm_flux
Definition: ERF.H:912
amrex::Vector< std::string > plot3d_var_names_1
Definition: ERF.H:1142
void refinement_criteria_setup()
Definition: ERF_Tagging.cpp:464
amrex::Vector< std::string > plot2d_var_names_2
Definition: ERF.H:1145
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > Tau_corr
Definition: ERF.H:938
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ax_src
Definition: ERF.H:979
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > urb_frac_lev
Definition: ERF.H:950
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_cc_src
Definition: ERF.H:977
amrex::Vector< amrex::Vector< amrex::MultiFab > > forecast_state_2
Definition: ERF.H:168
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::iMultiFab > > > soil_type_lev
Definition: ERF.H:949
amrex::Vector< amrex::Vector< amrex::Real > > zlevels_stag
Definition: ERF.H:965
amrex::Vector< amrex::Vector< amrex::MultiFab * > > lsm_data
Definition: ERF.H:910
amrex::Vector< amrex::Vector< amrex::Real > > stretched_dz_h
Definition: ERF.H:1000
amrex::Vector< std::unique_ptr< amrex::MultiFab > > az_src
Definition: ERF.H:981
static amrex::Real dt_max_initial
Definition: ERF.H:1092
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Lwave
Definition: ERF.H:1008
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::iMultiFab > > > land_type_lev
Definition: ERF.H:948
amrex::Vector< amrex::Vector< amrex::MultiFab > > forecast_state_1
Definition: ERF.H:167
amrex::Vector< std::unique_ptr< amrex::iMultiFab > > zflux_imask
Definition: ERF.H:1040
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > zvel_bc_data
Definition: ERF.H:805
amrex::Vector< amrex::Vector< amrex::Real > > h_sinesq_stag_ptrs
Definition: ERF.H:1357
amrex::Vector< std::unique_ptr< amrex::MultiFab > > detJ_cc_new
Definition: ERF.H:984
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > yvel_bc_data
Definition: ERF.H:804
amrex::Vector< amrex::MultiFab > surface_state_interp
Definition: ERF.H:172
amrex::Vector< amrex::Vector< amrex::Vector< amrex::Real > > > h_rayleigh_ptrs
Definition: ERF.H:1352
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Hwave
Definition: ERF.H:1007
amrex::Vector< amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > > Tau_EB
Definition: ERF.H:960
amrex::Vector< std::unique_ptr< amrex::iMultiFab > > xflux_imask
Definition: ERF.H:1038
void initializeMicrophysics(const int &)
Definition: ERF.cpp:2176
void ReSize(const int &nlev)
Definition: ERF_LandSurface.H:25
Definition: ERF_EBIFTerrain.H:14
const char * buildInfoGetGitHash(int i)
amrex::Real dz0
Definition: ERF_DataStruct.H:1215
amrex::Real const_massflux_layer_lo
Definition: ERF_DataStruct.H:1325
amrex::Real const_massflux_v
Definition: ERF_DataStruct.H:1323
int massflux_klo
Definition: ERF_DataStruct.H:1327
amrex::Real grid_stretching_ratio
Definition: ERF_DataStruct.H:1213
amrex::Real const_massflux_u
Definition: ERF_DataStruct.H:1322
amrex::Real zsurf
Definition: ERF_DataStruct.H:1214
static BuildingsType buildings_type
Definition: ERF_DataStruct.H:1117
amrex::Real const_massflux_layer_hi
Definition: ERF_DataStruct.H:1326
int massflux_khi
Definition: ERF_DataStruct.H:1328
Here is the call graph for this function:

◆ ErrorEst()

void ERF::ErrorEst ( int  lev,
amrex::TagBoxArray &  tags,
amrex::Real  time,
int  ngrow 
)
override

Function to tag cells for refinement – this overrides the pure virtual function in AmrCore

Parameters
[in]levclevel of refinement at which we tag cells (0 is coarsest level)
[out]tagsarray of tagged cells
[in]timecurrent time
[in]ngrownumber of ghost cells (not used here)
27 {
28  const int clearval = TagBox::CLEAR;
29  const int tagval = TagBox::SET;
30 
31 #ifdef ERF_USE_NETCDF
32  if ((solverChoice.init_type == InitType::WRFInput) || (solverChoice.init_type == InitType::Metgrid)) {
33  int ratio;
34  Box subdomain;
35 
36  // This is the number of boxes that may have already been defined in the refinement_criteria_setup routine.
37  // If nb == 0 then no boxes have been specified in the inputs file, and we will use the boxes given in wrfinput_d*
38  // If nb > 0 then boxes have been specified in the inputs file, and we will use the specified boxes as long
39  // as we can ensure that they are contained inside the boxes given in wrfinput_d*
40  int nb_prespecified = num_boxes_at_level[levc+1];
41 
42  if (!nc_init_file[levc+1].empty())
43  {
44  Real levc_start_time = read_start_time_from_wrfinput(levc , nc_init_file[levc ][0]);
45  if (solverChoice.init_type == InitType::WRFInput) {
46  amrex::Print() << " WRFInput time at level " << levc << " is " << levc_start_time << std::endl;
47  } else if (solverChoice.init_type == InitType::Metgrid) {
48  amrex::Print() << " met_em time at level " << levc << " is " << levc_start_time << std::endl;
49  }
50 
51  for (int isub = 0; isub < nc_init_file[levc+1].size(); isub++) {
52  if (!have_read_nc_init_file[levc+1][isub])
53  {
54  Real levf_start_time = read_start_time_from_wrfinput(levc+1, nc_init_file[levc+1][isub]);
55  if (solverChoice.init_type == InitType::WRFInput) {
56  amrex::Print() << " WRFInput start_time at level " << levc+1 << " is " << levf_start_time << std::endl;
57  } else if (solverChoice.init_type == InitType::Metgrid) {
58  amrex::Print() << " met_em start time at level " << levc+1 << " is " << levf_start_time << std::endl;
59  }
60 
61  // We assume there is only one subdomain at levc; otherwise we don't know
62  // which one is the parent of the fine region we are trying to create
63  AMREX_ALWAYS_ASSERT(subdomains[levc].size() == 1);
64 
65  if ((solverChoice.init_type == InitType::WRFInput) && ((ref_ratio[levc][2]) != 1)) {
66  amrex::Abort("The ref_ratio specified in the inputs file must have 1 in the z direction; please use ref_ratio_vect rather than ref_ratio");
67  }
68 
69  if ( levf_start_time <= (levc_start_time + t_new[levc]) ) {
70  if (solverChoice.init_type == InitType::WRFInput) {
71  amrex::Print() << " WRFInput file to read: " << nc_init_file[levc+1][isub] << std::endl;
72  subdomain = read_subdomain_from_wrfinput(levc, nc_init_file[levc+1][isub], ratio);
73  amrex::Print() << " WRFInput subdomain " << isub << " at level " << levc+1 << " is " << subdomain << std::endl;
74  } else if (solverChoice.init_type == InitType::Metgrid) {
75  amrex::Print() << "met_em file to read: " << nc_init_file[levc+1][0] << std::endl;
76  const Box& domain = geom[levc].Domain();
77  int klo = domain.smallEnd(2);
78  int khi = domain.bigEnd(2);
79  subdomain = read_subdomain_from_metgrid(levc, nc_init_file[levc+1][0], ratio, klo, khi);
80  amrex::Print() << " met_em subdomain at level " << levc+1 << " is " << subdomain << std::endl;
81  }
82 
83  if ( (ratio != ref_ratio[levc][0]) || (ratio != ref_ratio[levc][1]) ) {
84  amrex::Print() << "File " << nc_init_file[levc+1][0] << " has refinement ratio = " << ratio << std::endl;
85  amrex::Print() << "The inputs file has refinement ratio = " << ref_ratio[levc] << std::endl;
86  amrex::Abort("These must be the same -- please edit your inputs file and try again.");
87  }
88 
89  subdomain.coarsen(ref_ratio[levc]);
90 
91  // Recall we asserted that there is only one box at level levc
92  Box coarser_level(subdomains[levc][0].minimalBox());
93  subdomain.shift(coarser_level.smallEnd());
94 
95  if (verbose > 0) {
96  amrex::Print() << " Crse version of subdomain available for tagging is" << subdomain << std::endl;
97  }
98 
99  Box new_fine(subdomain);
100  if (solverChoice.init_type == InitType::WRFInput) {
101  new_fine.refine(IntVect(ratio,ratio,1));
102  } else if (solverChoice.init_type == InitType::Metgrid) {
103  new_fine.refine(ref_ratio[levc]);
104  }
105  if (nb_prespecified == 0) {
106  num_boxes_at_level[levc+1] += 1;
107  boxes_at_level[levc+1].push_back(new_fine);
108  } else {
109  if (!new_fine.contains(boxes_at_level[levc+1][isub])) {
110  amrex::Print() << "\n";
111  amrex::Print() << "Box available in wrfinputs file " << new_fine << std::endl;
112  amrex::Print() << "Box requested for refinement in inputs file " << boxes_at_level[levc+1][isub] << std::endl;
113  amrex::Abort("Specified boxes must be contained within boxes specified in wrfinput at this level");
114  }
115  }
116 
117  Box coarsened_bx(boxes_at_level[levc+1][isub]); coarsened_bx.coarsen(ref_ratio[levc]);
118 
119  for (MFIter mfi(tags); mfi.isValid(); ++mfi)
120  {
121  auto tag_arr = tags.array(mfi); // Get device-accessible array
122 
123  Box bx = mfi.validbox() & coarsened_bx;
124 
125  if (!bx.isEmpty()) {
126  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
127  tag_arr(i,j,k) = TagBox::SET;
128  });
129  }
130  }
131  } // time is right
132  } else {
133  // Re-tag this region
134  for (MFIter mfi(tags); mfi.isValid(); ++mfi)
135  {
136  auto tag_arr = tags.array(mfi); // Get device-accessible array
137 
138  Box existing_bx_coarsened(boxes_at_level[levc+1][isub]);
139  existing_bx_coarsened.coarsen(ref_ratio[levc]);
140 
141  Box bx = mfi.validbox(); bx &= existing_bx_coarsened;
142 
143  if (!bx.isEmpty()) {
144  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
145  tag_arr(i,j,k) = TagBox::SET;
146  });
147  }
148  }
149  } // has file been read?
150  } // isub
151  return;
152  } // file not empty
153  }
154 #endif
155 
156  //
157  // Make sure the ghost cells of the level we are tagging at are filled
158  // in case we take differences that require them
159  // NOTE: We are Fillpatching only the cell-centered variables here
160  //
161  MultiFab& S_new = vars_new[levc][Vars::cons];
162  MultiFab& U_new = vars_new[levc][Vars::xvel];
163  MultiFab& V_new = vars_new[levc][Vars::yvel];
164  MultiFab& W_new = vars_new[levc][Vars::zvel];
165  //
166  if (levc == 0) {
167  FillPatchCrseLevel(levc, time, {&S_new, &U_new, &V_new, &W_new});
168  } else {
169  FillPatchFineLevel(levc, time, {&S_new, &U_new, &V_new, &W_new},
170  {&S_new, &rU_new[levc], &rV_new[levc], &rW_new[levc]},
171  base_state[levc], base_state[levc],
172  false, true);
173  }
174 
175  for (int t=0; t < ref_tags.size(); ++t)
176  {
177  //
178  // This mf must have ghost cells because we may take differences between adjacent values
179  //
180  std::unique_ptr<MultiFab> mf = std::make_unique<MultiFab>(grids[levc], dmap[levc], 1, 1);
181  mf->setVal(0.0);
182 
183  // This allows dynamic refinement based on the value of the density
184  if (ref_tags[t].Field() == "density")
185  {
186  MultiFab::Copy(*mf,vars_new[levc][Vars::cons],Rho_comp,0,1,1);
187 
188  // Refinement based on a moisture mixing ratio (qv, qc, qi, qr, qs, qg).
189  // The map from name to RhoQ component depends on the moisture model and
190  // is held in solverChoice.moisture_indices.
191  } else if ( (ref_tags[t].Field() == "qv") ||
192  (ref_tags[t].Field() == "qc") ||
193  (ref_tags[t].Field() == "qi") ||
194  (ref_tags[t].Field() == "qr") ||
195  (ref_tags[t].Field() == "qs") ||
196  (ref_tags[t].Field() == "qg") )
197  {
198  const auto& mi = solverChoice.moisture_indices;
199  int qcomp = -1;
200  if (ref_tags[t].Field() == "qv") { qcomp = mi.qv; }
201  else if (ref_tags[t].Field() == "qc") { qcomp = mi.qc; }
202  else if (ref_tags[t].Field() == "qi") { qcomp = mi.qi; }
203  else if (ref_tags[t].Field() == "qr") { qcomp = mi.qr; }
204  else if (ref_tags[t].Field() == "qs") { qcomp = mi.qs; }
205  else if (ref_tags[t].Field() == "qg") { qcomp = mi.qg; }
206  AMREX_ALWAYS_ASSERT(qcomp >= 0);
207  MultiFab::Copy( *mf, vars_new[levc][Vars::cons], qcomp, 0, 1, 1);
208  MultiFab::Divide(*mf, vars_new[levc][Vars::cons], Rho_comp, 0, 1, 1);
209 
210  // qt = total condensed water mixing ratio (qc + qi + qr + qs + qg).
211  // Excludes qv by convention here.
212  } else if (ref_tags[t].Field() == "qt") {
213  const auto& mi = solverChoice.moisture_indices;
214  const int idx_qc = mi.qc, idx_qi = mi.qi, idx_qr = mi.qr,
215  idx_qs = mi.qs, idx_qg = mi.qg;
216  AMREX_ALWAYS_ASSERT(idx_qc >= 0 || idx_qi >= 0 || idx_qr >= 0 ||
217  idx_qs >= 0 || idx_qg >= 0);
218  mf->setVal(0.0);
219  for (MFIter mfi(*mf, TilingIfNotGPU()); mfi.isValid(); ++mfi)
220  {
221  const Box& bx = mfi.growntilebox();
222  auto qt_arr = mf->array(mfi);
223  auto cons_arr = vars_new[levc][Vars::cons].const_array(mfi);
224  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
225  const Real rho_inv = Real(1.0) / cons_arr(i,j,k,Rho_comp);
226  Real q = Real(0.0);
227  if (idx_qc >= 0) { q += cons_arr(i,j,k,idx_qc) * rho_inv; }
228  if (idx_qi >= 0) { q += cons_arr(i,j,k,idx_qi) * rho_inv; }
229  if (idx_qr >= 0) { q += cons_arr(i,j,k,idx_qr) * rho_inv; }
230  if (idx_qs >= 0) { q += cons_arr(i,j,k,idx_qs) * rho_inv; }
231  if (idx_qg >= 0) { q += cons_arr(i,j,k,idx_qg) * rho_inv; }
232  qt_arr(i,j,k) = q;
233  });
234  }
235 
236  // This allows dynamic refinement based on the value of the z-component of vorticity
237  } else if (ref_tags[t].Field() == "vorticity" ) {
238  MultiFab mf_cc_vel(grids[levc], dmap[levc], AMREX_SPACEDIM, IntVect(1,1,1));
239  average_face_to_cellcenter(mf_cc_vel,0,Array<const MultiFab*,3>{&U_new, &V_new, &W_new}, 1);
240 
241  for (MFIter mfi(*mf, TilingIfNotGPU()); mfi.isValid(); ++mfi)
242  {
243  const Box& bx = mfi.tilebox();
244  auto& dfab = (*mf)[mfi];
245  auto& sfab = mf_cc_vel[mfi];
246  auto& zfab = (*z_phys_cc[levc])[mfi];
247  derived::erf_dervortz(bx, dfab, 0, 1, sfab, zfab, Geom(levc), time, nullptr, levc);
248  }
249 
250  // This allows dynamic refinement based on the value of the scalar/theta
251  } else if ( (ref_tags[t].Field() == "scalar" ) ||
252  (ref_tags[t].Field() == "theta" ) )
253  {
254  for (MFIter mfi(*mf, TilingIfNotGPU()); mfi.isValid(); ++mfi)
255  {
256  const Box& bx = mfi.tilebox();
257  auto& dfab = (*mf)[mfi];
258  auto& sfab = vars_new[levc][Vars::cons][mfi];
259  auto& zfab = (*z_phys_cc[levc])[mfi];
260  if (ref_tags[t].Field() == "scalar") {
261  derived::erf_derscalar(bx, dfab, 0, 1, sfab, zfab, Geom(levc), time, nullptr, levc);
262  } else if (ref_tags[t].Field() == "theta") {
263  derived::erf_dertheta(bx, dfab, 0, 1, sfab, zfab, Geom(levc), time, nullptr, levc);
264  }
265  } // mfi
266  // This allows dynamic refinement based on the value of updraft helicity
267  } else if (ref_tags[t].Field() == "helicity")
268  {
269  MultiFab mf_cc_vel(grids[levc], dmap[levc], AMREX_SPACEDIM, IntVect(1,1,1));
270  average_face_to_cellcenter(mf_cc_vel,0,Array<const MultiFab*,3>{&U_new, &V_new, &W_new}, 1);
271 
272  for (MFIter mfi(*mf, TilingIfNotGPU()); mfi.isValid(); ++mfi)
273  {
274  const Box& bx = mfi.tilebox();
275  auto& dfab = (*mf)[mfi];
276  auto& sfab = mf_cc_vel[mfi];
277  auto& zfab = (*z_phys_cc[levc])[mfi];
278 
279  derived::erf_derhelicity(bx, dfab, 0, 1, sfab, zfab, Geom(levc), time, nullptr, levc);
280  }
281  } else if (ref_tags[t].Field() == "max_reflectivity")
282  {
283  if (solverChoice.moisture_type == MoistureType::Morrison ||
284  solverChoice.moisture_type == MoistureType::SAM) {
285  for (MFIter mfi(*mf, TilingIfNotGPU()); mfi.isValid(); ++mfi)
286  {
287  const Box& bx = mfi.tilebox();
288  auto& dfab = (*mf)[mfi];
289  auto& sfab = vars_new[levc][Vars::cons][mfi];
290  auto& zfab = (*z_phys_cc[levc])[mfi];
291 
292  derived::erf_dermaxreflectivity(bx, dfab, 0, 1, sfab, zfab, Geom(levc), time, nullptr, levc);
293  }
294  } else {
295  Abort("Max reflectivity is only available with Morrison and SAM microphysics.");
296  }
297  // This allows dynamic refinement based on the terrain blanking
298  } else if ( (SolverChoice::terrain_type == TerrainType::ImmersedForcing) &&
299  (ref_tags[t].Field() == "terrain_blanking") )
300  {
301  MultiFab::Copy(*mf,*terrain_blanking[levc],0,0,1,1);
302  }
303  else if (ref_tags[t].Field() == "velmag")
304  {
305  ParmParse pp(pp_prefix);
306  Vector<std::string> refinement_indicators;
307  pp.queryarr("refinement_indicators",refinement_indicators,0,pp.countval("refinement_indicators"));
308  Real velmag_threshold;
309  bool is_hurricane_tracker = false;
310  for (int i=0; i<refinement_indicators.size(); ++i)
311  {
312  if (refinement_indicators[i]=="hurricane_tracker") {
313  is_hurricane_tracker = true;
314  std::string ref_prefix = pp_prefix + "." + refinement_indicators[i];
315  ParmParse ppr(ref_prefix);
316  ppr.get("value_greater", velmag_threshold);
317  break;
318  }
319  }
320 
321  Vector<MultiFab> mf_cc_vel(1);
322  mf_cc_vel[0].define(grids[levc], dmap[levc], AMREX_SPACEDIM, IntVect(0,0,0));
323  average_face_to_cellcenter(mf_cc_vel[0],0,Array<const MultiFab*,3>{&U_new, &V_new, &W_new});
324 
325  if (is_hurricane_tracker) {
326  HurricaneTracker(levc, time, mf_cc_vel[0], velmag_threshold, &tags);
327  } else {
328  for (MFIter mfi(*mf, TilingIfNotGPU()); mfi.isValid(); ++mfi)
329  {
330  const Box& bx = mfi.tilebox();
331  auto& dfab = (*mf)[mfi];
332  auto& sfab = mf_cc_vel[0][mfi];
333  auto& zfab = (*z_phys_cc[levc])[mfi];
334  derived::erf_dermagvel(bx, dfab, 0, 1, sfab, zfab, Geom(levc), time, nullptr, levc);
335  }
336  }
337 
338 #ifdef ERF_USE_PARTICLES
339  } else {
340  //
341  // Particle-derived refinement. Two forms of `field_name` are
342  // supported:
343  // <species>_count : particle count per cell
344  // <species>_<mesh_var> : Eulerian mesh variable provided
345  // by the species' `meshPlotVarNames()`
346  // (e.g. `super_droplets_moisture_mass_density`,
347  // `tracer_particles_mass_density`).
348  //
349  // In both cases the field is deposited at every level in
350  // [levc, finest_level] and averaged down level-by-level so that
351  // a signal present only on a finer level still triggers
352  // refinement at the coarser level being tagged. Without this,
353  // particles localised at level 1 would not register at level 0
354  // and the fine grid would disappear at the next regrid.
355  //
356  const auto& particles_namelist( particleData.getNames() );
357  mf->setVal(0.0);
358  for (ParticlesNamesVector::size_type i = 0; i < particles_namelist.size(); i++)
359  {
360  auto* pc = particleData[particles_namelist[i]];
361  const std::string& sp_name = particles_namelist[i];
362  const std::string& field = ref_tags[t].Field();
363 
364  const std::string count_str = sp_name + "_count";
365  const std::string prefix = sp_name + "_";
366  std::string mesh_var;
367  if (field != count_str
368  && field.size() > prefix.size()
369  && field.compare(0, prefix.size(), prefix) == 0)
370  {
371  const std::string suffix = field.substr(prefix.size());
372  for (const auto& v : pc->meshPlotVarNames()) {
373  if (v == suffix) { mesh_var = v; break; }
374  }
375  }
376  if (field != count_str && mesh_var.empty()) { continue; }
377 
378  pc->resizeData();
379  const int pc_nlevs = static_cast<int>(pc->GetParticles().size());
380 
381  // Deposit at each level into per-level MultiFabs.
382  Vector<MultiFab> per_lev(finest_level+1);
383  for (int lev = levc; lev <= finest_level; lev++) {
384  per_lev[lev].define(grids[lev], dmap[lev], 1, 0);
385  per_lev[lev].setVal(0);
386  if (field == count_str) {
387  if (lev < pc_nlevs) {
388  pc->IncrementWithTotal(per_lev[lev], lev);
389  }
390  } else {
391  pc->computeMeshVar(mesh_var, per_lev[lev],
392  *z_phys_nd[lev], lev);
393  }
394  }
395 
396  // Average down level-by-level from finest to levc. This
397  // avoids multi-level coarsening (e.g. L2->L0 with ratio
398  // (4,1,4)) which can fail when fine-level boxes are not
399  // aligned to the composite refinement ratio.
400  for (int lev = finest_level; lev > levc; lev--) {
401  MultiFab temp_crse(grids[lev-1], dmap[lev-1], 1, 0);
402  temp_crse.setVal(0);
403  average_down(per_lev[lev], temp_crse,
404  0, 1, ref_ratio[lev-1]);
405  MultiFab::Add(per_lev[lev-1], temp_crse, 0, 0, 1, 0);
406  }
407 
408  MultiFab::Copy(*mf, per_lev[levc], 0, 0, 1, 0);
409  }
410 #endif
411  }
412 
413  ref_tags[t](tags,mf.get(),clearval,tagval,time,levc,geom[levc]);
414  } // loop over t
415 
416  // ********************************************************************************************
417  // Refinement based on 2d distance from the "eye" which is defined here as the (x,y) location of
418  // the integrated qv
419  // ********************************************************************************************
420  ParmParse pp(pp_prefix);
421  Vector<std::string> refinement_indicators;
422  pp.queryarr("refinement_indicators",refinement_indicators,0,pp.countval("refinement_indicators"));
423  for (int i=0; i<refinement_indicators.size(); ++i)
424  {
425  if ( (refinement_indicators[i]=="storm_tracker") && (solverChoice.moisture_type != MoistureType::None) )
426  {
427  std::string ref_prefix = pp_prefix + "." + refinement_indicators[i];
428  ParmParse ppr(ref_prefix);
429 
430  Real ref_start_time = -one;
431  ppr.query("start_time",ref_start_time);
432 
433  if (time >= ref_start_time) {
434 
435  Real max_radius = -one;
436  ppr.get("max_radius", max_radius);
437 
438  // Create the volume-weighted sum of (rho qv) in each column
439  MultiFab mf_qv_int(ba2d[levc], dmap[levc], 1, 0); mf_qv_int.setVal(0.);
440 
441  // Define the 2D MultiFab holding the column-integrated (rho qv)
442  volWgtColumnSum(levc, S_new, RhoQ1_comp, mf_qv_int, *detJ_cc[levc]);
443 
444  // Find the max value in the domain
445  IntVect eye = mf_qv_int.maxIndex(0);
446 
447  const auto dx = geom[levc].CellSizeArray();
448  const auto prob_lo = geom[levc].ProbLoArray();
449 
450  Real eye_x = prob_lo[0] + (eye[0] + myhalf) * dx[0];
451  Real eye_y = prob_lo[1] + (eye[1] + myhalf) * dx[1];
452 
453  tag_on_distance_from_eye(geom[levc], &tags, eye_x, eye_y, max_radius);
454  }
455  }
456  }
457 }
const amrex::Real * prob_lo
Definition: ERF_InitCustomPert_DataAssimilation_ISV.H:16
void tag_on_distance_from_eye(const Geometry &cgeom, TagBoxArray *tags, const Real eye_x, const Real eye_y, const Real rad_tag)
Definition: ERF_Tagging.cpp:951
amrex::Vector< amrex::Vector< amrex::Box > > boxes_at_level
Definition: ERF.H:833
void volWgtColumnSum(int lev, const amrex::MultiFab &mf, int comp, amrex::MultiFab &mf_2d, const amrex::MultiFab &dJ)
Definition: ERF_VolWgtSum.cpp:82
void HurricaneTracker(int lev, amrex::Real time, const amrex::MultiFab &cc_vel, const amrex::Real velmag_threshold, amrex::TagBoxArray *tags=nullptr)
Definition: ERF_Tagging.cpp:980
static amrex::Vector< amrex::Vector< std::string > > nc_init_file
Definition: ERF.H:1271
amrex::Vector< amrex::Vector< amrex::BoxArray > > subdomains
Definition: ERF.H:1391
void FillPatchCrseLevel(int lev, double time, const amrex::Vector< amrex::MultiFab * > &mfs_vel, bool cons_only=false)
Definition: ERF_FillPatch.cpp:290
static amrex::Vector< amrex::Vector< int > > have_read_nc_init_file
Definition: ERF.H:1272
static amrex::Vector< amrex::AMRErrorTag > ref_tags
Definition: ERF.H:1389
amrex::Vector< int > num_boxes_at_level
Definition: ERF.H:831
@ q
Definition: ERF_WSM6.H:169
@ t
Definition: ERF_WSM6.H:168
void erf_derhelicity(const Box &bx, FArrayBox &derfab, int dcomp, int, const FArrayBox &datfab, const FArrayBox &zcc_fab, const Geometry &geomdata, Real, const int *, const int)
Definition: ERF_Derive.cpp:645
void erf_dermagvel(const Box &bx, FArrayBox &derfab, int dcomp, int ncomp, const FArrayBox &datfab, const FArrayBox &, const Geometry &, Real, const int *, const int)
Definition: ERF_Derive.cpp:480
void erf_dervortz(const Box &bx, FArrayBox &derfab, int dcomp, int ncomp, const FArrayBox &datfab, const FArrayBox &, const Geometry &geomdata, Real, const int *, const int)
Definition: ERF_Derive.cpp:415
void erf_derscalar(const Box &bx, FArrayBox &derfab, int, int, const FArrayBox &datfab, const FArrayBox &, const Geometry &, Real, const int *, const int)
Definition: ERF_Derive.cpp:320
void erf_dertheta(const Box &bx, FArrayBox &derfab, int, int, const FArrayBox &datfab, const FArrayBox &, const Geometry &, Real, const int *, const int)
Definition: ERF_Derive.cpp:298
void erf_dermaxreflectivity(const Box &bx, FArrayBox &derfab, int dcomp, int, const FArrayBox &datfab, const FArrayBox &, const Geometry &, Real, const int *, const int)
Definition: ERF_Derive.cpp:566
integer, private isub
Definition: ERF_module_mp_morr_two_moment.F90:164
int qv
Definition: ERF_DataStruct.H:107
int qc
Definition: ERF_DataStruct.H:108
static InitType init_type
Definition: ERF_DataStruct.H:1108
Here is the call graph for this function:

◆ estTimeStep()

Real ERF::estTimeStep ( int  level,
long &  dt_fast_ratio 
) const

Function that calls estTimeStep for each level

Parameters
[in]levellevel of refinement (coarsest level i 0)
[out]dt_fast_ratioratio of slow to fast time step
61 {
62  BL_PROFILE("ERF::estTimeStep()");
63 
64  Real estdt_comp = Real(1.e20);
65  Real estdt_lowM = Real(1.e20);
66 
67  // We intentionally use the level 0 domain to compute whether to use this direction in the dt calculation
68  const int nxc = geom[0].Domain().length(0);
69  const int nyc = geom[0].Domain().length(1);
70 
71  auto const dxinv = geom[level].InvCellSizeArray();
72  auto const dzinv = one / dz_min[level];
73 
74  MultiFab const& S_new = vars_new[level][Vars::cons];
75 
76  MultiFab ccvel(grids[level],dmap[level],3,0);
77 
78  average_face_to_cellcenter(ccvel,0,
79  Array<const MultiFab*,3>{&vars_new[level][Vars::xvel],
80  &vars_new[level][Vars::yvel],
81  &vars_new[level][Vars::zvel]});
82 
83  bool l_substepping = (solverChoice.substepping_type[level] == SubsteppingType::Implicit);
84  int l_anelastic = solverChoice.anelastic[level];
85 
86  bool l_comp_substepping_diag = (verbose && l_substepping && !l_anelastic && solverChoice.substepping_diag);
87 
88  Real estdt_comp_inv;
89  Real estdt_vert_comp_inv;
90  Real estdt_vert_lowM_inv;
91 
92  if (l_substepping && (nxc==1) && (nyc==1)) {
93  // SCM -- should not depend on dx or dy; force minimum number of substeps
94  estdt_comp_inv = std::numeric_limits<Real>::min();
95  }
96  else if (solverChoice.terrain_type == TerrainType::EB)
97  {
98  const eb_& eb_lev = get_eb(level);
99  const MultiFab& detJ = (eb_lev.get_const_factory())->getVolFrac();
100 
101  estdt_comp_inv = ReduceMax(S_new, ccvel, detJ, 0,
102  [=] AMREX_GPU_HOST_DEVICE (Box const& b,
103  Array4<Real const> const& s,
104  Array4<Real const> const& u,
105  Array4<Real const> const& vf) -> Real
106  {
107  Real new_comp_dt = -Real(1.e100);
108  amrex::Loop(b, [=,&new_comp_dt] (int i, int j, int k) noexcept
109  {
110  if (vf(i,j,k) > zero)
111  {
112  const Real rho = s(i, j, k, Rho_comp);
113  const Real rhotheta = s(i, j, k, RhoTheta_comp);
114 
115  // NOTE: even when moisture is present,
116  // we only use the partial pressure of the dry air
117  // to compute the soundspeed
118  Real pressure = getPgivenRTh(rhotheta);
119  Real c = std::sqrt(Gamma * pressure / rho);
120 
121  // If we are doing implicit acoustic substepping, then the z-direction does not contribute
122  // to the computation of the time step
123  if (l_substepping) {
124  if ((nxc > 1) && (nyc==1)) {
125  // 2-D in x-z
126  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]), new_comp_dt);
127  } else if ((nyc > 1) && (nxc==1)) {
128  // 2-D in y-z
129  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,1))+c)*dxinv[1]), new_comp_dt);
130  } else {
131  // 3-D
132  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]),
133  ((amrex::Math::abs(u(i,j,k,1))+c)*dxinv[1]), new_comp_dt);
134  }
135 
136  // If we are not doing implicit acoustic substepping, then the z-direction contributes
137  // to the computation of the time step
138  } else {
139  if (nxc > 1 && nyc > 1) {
140  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]),
141  ((amrex::Math::abs(u(i,j,k,1))+c)*dxinv[1]),
142  ((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
143  } else if (nxc > 1) {
144  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]),
145  ((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
146  } else if (nyc > 1) {
147  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,1))+c)*dxinv[1]),
148  ((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
149  } else {
150  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
151  }
152 
153  }
154  }
155  });
156  return new_comp_dt;
157  });
158 
159  } else {
160  const MultiFab& detJ = *detJ_cc[level];
161  estdt_comp_inv = ReduceMax(S_new, ccvel, detJ, 0,
162  [=] AMREX_GPU_HOST_DEVICE (Box const& b,
163  Array4<Real const> const& s,
164  Array4<Real const> const& u,
165  Array4<Real const> const& dJ) -> Real
166  {
167  Real new_comp_dt = -Real(1.e100);
168  amrex::Loop(b, [=,&new_comp_dt] (int i, int j, int k) noexcept
169  {
170  {
171  const Real rho = s(i, j, k, Rho_comp);
172  const Real rhotheta = s(i, j, k, RhoTheta_comp);
173 
174  Real idz_loc = dxinv[2] / dJ(i,j,k);
175 
176  // NOTE: even when moisture is present,
177  // we only use the partial pressure of the dry air
178  // to compute the soundspeed
179  Real pressure = getPgivenRTh(rhotheta);
180  Real c = std::sqrt(Gamma * pressure / rho);
181 
182  // If we are doing implicit acoustic substepping, then the z-direction is not constrained
183  // by the speed of sound for the computation of the time step
184  if (l_substepping) {
185  if ((nxc > 1) && (nyc==1)) {
186  // 2-D in x-z
187  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]), new_comp_dt);
188  } else if ((nyc > 1) && (nxc==1)) {
189  // 2-D in y-z
190  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,1))+c)*dxinv[1]), new_comp_dt);
191  } else {
192  // 3-D
193  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]),
194  ((amrex::Math::abs(u(i,j,k,1))+c)*dxinv[1]),
195  ((amrex::Math::abs(u(i,j,k,2)) )*idz_loc ),new_comp_dt);
196  }
197 
198  // If we are not doing implicit acoustic substepping, then the z-direction contributes
199  // to the computation of the time step
200  } else {
201  if (nxc > 1 && nyc > 1) {
202  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]),
203  ((amrex::Math::abs(u(i,j,k,1))+c)*dxinv[1]),
204  ((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
205  } else if (nxc > 1) {
206  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]),
207  ((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
208  } else if (nyc > 1) {
209  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,1))+c)*dxinv[1]),
210  ((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
211  } else {
212  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
213  }
214 
215  }
216  }
217  });
218  return new_comp_dt;
219  });
220  } // not EB
221 
222  ParallelDescriptor::ReduceRealMax(estdt_comp_inv);
223  // Globally empty level -> ReduceMax = lowest(); treat level as non-constraining.
224  estdt_comp = (estdt_comp_inv > Real(0.0)) ? (cfl / estdt_comp_inv) : Real(1.e20);
225 
226  Real estdt_lowM_inv = ReduceMax(ccvel, 0,
227  [=] AMREX_GPU_HOST_DEVICE (Box const& b,
228  Array4<Real const> const& u) -> Real
229  {
230  Real new_lm_dt = -Real(1.e100);
231  Loop(b, [=,&new_lm_dt] (int i, int j, int k) noexcept
232  {
233  new_lm_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0)))*dxinv[0]),
234  ((amrex::Math::abs(u(i,j,k,1)))*dxinv[1]),
235  ((amrex::Math::abs(u(i,j,k,2)))*dxinv[2]), new_lm_dt);
236  });
237  return new_lm_dt;
238  });
239 
240  ParallelDescriptor::ReduceRealMax(estdt_lowM_inv);
241  if (estdt_lowM_inv > 0.0_rt)
242  estdt_lowM = cfl / estdt_lowM_inv;
243 
244  // Additional vertical diagnostics
245  if (l_comp_substepping_diag) {
246  estdt_vert_comp_inv = ReduceMax(S_new, ccvel, 0,
247  [=] AMREX_GPU_HOST_DEVICE (Box const& b,
248  Array4<Real const> const& s,
249  Array4<Real const> const& u) -> Real
250  {
251  Real new_comp_dt = -Real(1.e100);
252  amrex::Loop(b, [=,&new_comp_dt] (int i, int j, int k) noexcept
253  {
254  {
255  const Real rho = s(i, j, k, Rho_comp);
256  const Real rhotheta = s(i, j, k, RhoTheta_comp);
257 
258  // NOTE: even when moisture is present,
259  // we only use the partial pressure of the dry air
260  // to compute the soundspeed
261  Real pressure = getPgivenRTh(rhotheta);
262  Real c = std::sqrt(Gamma * pressure / rho);
263 
264  // Look at z-direction only
265  new_comp_dt = amrex::max((amrex::Math::abs(u(i,j,k,2)) + c) * dzinv, new_comp_dt);
266  }
267  });
268  return new_comp_dt;
269  });
270 
271  estdt_vert_lowM_inv = ReduceMax(ccvel, 0,
272  [=] AMREX_GPU_HOST_DEVICE (Box const& b,
273  Array4<Real const> const& u) -> Real
274  {
275  Real new_lowM_dt = -Real(1.e100);
276  amrex::Loop(b, [=,&new_lowM_dt] (int i, int j, int k) noexcept
277  {
278  new_lowM_dt = amrex::max((amrex::Math::abs(u(i,j,k,2))) * dzinv, new_lowM_dt);
279  });
280  return new_lowM_dt;
281  });
282 
283  ParallelDescriptor::ReduceRealMax(estdt_vert_comp_inv);
284  ParallelDescriptor::ReduceRealMax(estdt_vert_lowM_inv);
285  }
286 
287  if (verbose) {
288  if (fixed_dt[level] <= zero) {
289  Print() << "Using cfl = " << cfl << " and dx/dy/dz_min = " <<
290  one/dxinv[0] << " " << one/dxinv[1] << " " << dz_min[level] << std::endl;
291  Print() << "Compressible dt at level " << level << ": " << estdt_comp << std::endl;
292  if (estdt_lowM_inv > 0.0_rt) {
293  Print() << "Anelastic dt at level " << level << ": " << estdt_lowM << std::endl;
294  } else {
295  Print() << "Anelastic dt at level " << level << ": undefined " << std::endl;
296  }
297  }
298 
299  if (fixed_dt[level] > zero) {
300  Print() << "Based on cfl of one " << std::endl;
301  Print() << "Compressible dt at level " << level << " would be: " << estdt_comp/cfl << std::endl;
302  if (estdt_lowM_inv > 0.0_rt) {
303  Print() << "Anelastic dt at level " << level << " would be: " << estdt_lowM/cfl << std::endl;
304  } else {
305  Print() << "Anelastic dt at level " << level << " would be undefined " << std::endl;
306  }
307  Print() << "Fixed dt at level " << level << " is: " << fixed_dt[level] << std::endl;
308  if (fixed_fast_dt[level] > zero) {
309  Print() << "Fixed fast dt at level " << level << " is: " << fixed_fast_dt[level] << std::endl;
310  }
311  }
312  }
313 
314  if (solverChoice.substepping_type[level] != SubsteppingType::None) {
315  if (fixed_dt[level] > zero && fixed_fast_dt[level] > zero) {
316  dt_fast_ratio = static_cast<long>( fixed_dt[level] / fixed_fast_dt[level] );
317  if (dt_fast_ratio < 1) {
318  Abort("Invalid fixed_fast_dt: must be <= fixed_dt so mri_dt_ratio >= 1");
319  }
320  } else if (fixed_dt[level] > zero) {
321  // Max CFL_c = one for substeps by default, but we enforce a min of 4 substeps
322  auto dt_sub_max = (estdt_comp/cfl * sub_cfl);
323  dt_fast_ratio = static_cast<long>( std::max(fixed_dt[level]/dt_sub_max,Real(4.)) );
324  } else {
325  // auto dt_sub_max = (estdt_comp/cfl * sub_cfl);
326  // dt_fast_ratio = static_cast<long>( std::max(estdt_comp/dt_sub_max,Real(4.)) );
327  dt_fast_ratio = static_cast<long>( std::max(cfl / sub_cfl, Real(4.)) );
328  }
329 
330  // Force time step ratio to be an even value
332  if ( dt_fast_ratio%2 != 0) dt_fast_ratio += 1;
333  } else {
334  if ( dt_fast_ratio%6 != 0) {
335  Print() << "mri_dt_ratio = " << dt_fast_ratio
336  << " not divisible by 6 for N/3 substeps in stage 1" << std::endl;
337  dt_fast_ratio = static_cast<int>(std::ceil(dt_fast_ratio/Real(6.0)) * 6);
338  }
339  }
340 
341  if (verbose) {
342  Print() << "smallest even ratio is: " << dt_fast_ratio << std::endl;
343  }
344  } // if substepping
345 
346  // Print out some extra diagnostics -- dt calcs are repeated so as to not
347  // disrupt the overall code flow...
348  if (l_comp_substepping_diag) {
349  Real dt_diag = (fixed_dt[level] > zero) ? fixed_dt[level] : estdt_comp;
350  int ns = (fixed_mri_dt_ratio > zero) ? fixed_mri_dt_ratio : dt_fast_ratio;
351 
352  // horizontal acoustic CFL must be < 1 (fully explicit)
353  // vertical acoustic CFL may be > 1
354  Print() << "effective horiz,vert acoustic CFL with " << ns << " substeps : "
355  << (dt_diag / ns) * estdt_comp_inv << " "
356  << (dt_diag / ns) * estdt_vert_comp_inv << std::endl;
357 
358  // vertical advective CFL should be < 1, otherwise w-damping may be needed
359  Print() << "effective vert advective CFL : "
360  << dt_diag * estdt_vert_lowM_inv << std::endl;
361  }
362 
363  if (fixed_dt[level] > zero) {
364  return fixed_dt[level];
365  } else {
366  // Anelastic (substepping is not allowed)
367  if (l_anelastic) {
368 
369  // Make sure that timestep is less than the dt_max
370  estdt_lowM = amrex::min(estdt_lowM, dt_max);
371 
372  // On the first timestep enforce dt_max_initial
373  if (istep[level] == 0) {
374  return amrex::min(dt_max_initial, estdt_lowM);
375  } else {
376  return estdt_lowM;
377  }
378 
379 
380  // Compressible with or without substepping
381  } else {
382  return estdt_comp;
383  }
384  }
385 }
constexpr amrex::Real Gamma
Definition: ERF_Constants.H:38
amrex::Vector< amrex::Real > dz_min
Definition: ERF.H:1393
amrex::Vector< amrex::Real > fixed_dt
Definition: ERF.H:1096
static amrex::Real dt_max
Definition: ERF.H:1093
amrex::Vector< amrex::Real > fixed_fast_dt
Definition: ERF.H:1097
static amrex::Real cfl
Definition: ERF.H:1088
static amrex::Real sub_cfl
Definition: ERF.H:1089
Definition: ERF_EB.H:13
@ ns
Definition: ERF_Morrison.H:47
int force_stage1_single_substep
Definition: ERF_DataStruct.H:1138
amrex::Vector< SubsteppingType > substepping_type
Definition: ERF_DataStruct.H:1140
bool substepping_diag
Definition: ERF_DataStruct.H:1147
Here is the call graph for this function:

◆ Evolve()

void ERF::Evolve ( )
611 {
612  BL_PROFILE_VAR("ERF::Evolve()", evolve);
613 
614  //
615  // cur_time = t_new is elapsed time, not total time
616  // stop_time is total time
617  // Tracked in double to avoid float32 drift over many timesteps in single-precision builds.
618  double cur_time = static_cast<double>(t_new[0]);
619 
620  // Take one coarse timestep by calling timeStep -- which recursively calls timeStep
621  // for finer levels (with or without subcycling)
622  for (int step = istep[0]; (step < max_step) && (start_time+cur_time < stop_time); ++step)
623  {
624  if (use_datetime) {
625  Print() << "\n" << getTimestamp(start_time+cur_time, datetime_format)
626  << " (" << cur_time << " s elapsed)" << std::endl;
627  }
628  Print() << "\nCoarse STEP " << step+1 << " starts ..." << std::endl;
629 
630  ComputeDt(step, cur_time);
631 
632  // Make sure we have read enough of the boundary plane data to make it through this timestep
633  if (input_bndry_planes)
634  {
635  m_r2d->read_input_files(cur_time+start_time,dt[0],m_bc_extdir_vals);
636  }
637 
638 #ifdef ERF_USE_PARTICLES
639  // We call this every time step with the knowledge that the particles may be
640  // initialized at a later time than the simulation start time.
641  // The ParticleContainer carries a "start time" so the initialization will happen
642  // only when a) time > start_time, and b) particles have not yet been initialized
643  initializeTracers((ParGDBBase*)GetParGDB(),z_phys_nd,cur_time);
644 #endif
645 
646  if(solverChoice.init_type == InitType::HindCast and
648  for(int lev=0;lev<finest_level+1;lev++){
649  WeatherDataInterpolation(lev,cur_time,z_phys_nd,false);
650  }
651  }
652 
653  if(solverChoice.init_type == InitType::HindCast and
655  for(int lev=0;lev<finest_level+1;lev++){
656  SurfaceDataInterpolation(lev,cur_time,z_phys_nd,false);
657  }
658  }
659 
660  auto dEvolveTime0 = amrex::second();
661 
662  int iteration = 1;
663  timeStep(0, cur_time, iteration);
664 
665  cur_time += static_cast<double>(dt[0]);
666  // Sync t_new[0] from accurate double to prevent float32 accumulation drift in SP builds.
667  t_new[0] = static_cast<Real>(cur_time);
668 
669  Print() << "Coarse STEP " << step+1 << " ends." << " TIME = " << cur_time
670  << " DT = " << dt[0] << std::endl;
671 
672  if (check_for_nans > 0) {
673  amrex::Print() << "Testing new state and vels for NaNs at end of timestep" << std::endl;
674  for (int lev = 0; lev <= finest_level; ++lev) {
677  }
678  }
679 
680  if (verbose > 0)
681  {
682  auto dEvolveTime = amrex::second() - dEvolveTime0;
683  ParallelDescriptor::ReduceRealMax(dEvolveTime,ParallelDescriptor::IOProcessorNumber());
684  amrex::Print() << "Timestep time = " << dEvolveTime << " seconds." << '\n';
685  }
686 
687  post_timestep(step, cur_time, dt[0]);
688 
689  if (writeNow(cur_time, step+1, m_plot3d_int_1, m_plot3d_per_1, dt[0], last_plot3d_file_time_1)) {
690  last_plot3d_file_step_1 = step+1;
692  for (int lev = 0; lev <= finest_level; ++lev) {lsm.Plot(lev, step+1);}
694  }
695  if (writeNow(cur_time, step+1, m_plot3d_int_2, m_plot3d_per_2, dt[0], last_plot3d_file_time_2)) {
696  last_plot3d_file_step_2 = step+1;
698  for (int lev = 0; lev <= finest_level; ++lev) {lsm.Plot(lev, step+1);}
700  }
701 
702  if (writeNow(cur_time, step+1, m_plot2d_int_1, m_plot2d_per_1, dt[0], last_plot2d_file_time_1)) {
703  last_plot2d_file_step_1 = step+1;
706  }
707 
708  if (writeNow(cur_time, step+1, m_plot2d_int_2, m_plot2d_per_2, dt[0], last_plot2d_file_time_2)) {
709  last_plot2d_file_step_2 = step+1;
712  }
713 
714  for (int i = 0; i < m_subvol_int.size(); i++) {
715  if (writeNow(cur_time, step+1, m_subvol_int[i], m_subvol_per[i], dt[0], last_subvol_time[i])) {
716  last_subvol_step[i] = step+1;
718  if (m_subvol_per[i] > zero) {last_subvol_time[i] += m_subvol_per[i];}
719  }
720  }
721 
722  if (writeNow(cur_time, step+1, m_check_int, m_check_per, dt[0], last_check_file_time)) {
723  last_check_file_step = step+1;
726  }
727 
728 #ifdef AMREX_MEM_PROFILING
729  {
730  std::ostringstream ss;
731  ss << "[STEP " << step+1 << "]";
732  MemProfiler::report(ss.str());
733  }
734 #endif
735 
736  if (start_time+cur_time >= stop_time - Real(1.e-6)*dt[0]) break;
737  }
738 
739  // Write plotfiles at final time
743  }
747  }
751  }
755  }
756 
757  for (int i = 0; i < m_subvol_int.size(); i++) {
758  if ( (m_subvol_int[i] > 0 || m_subvol_per[i] > zero) && istep[0] > last_subvol_step[i]) {
760  if (m_subvol_per[i] > zero) {last_subvol_time[i] += m_subvol_per[i];}
761  }
762  }
763 
764  if ( (m_check_int > 0 || m_check_per > zero) && istep[0] > last_check_file_step) {
767  }
768 
769  BL_PROFILE_VAR_STOP(evolve);
770 }
AMREX_FORCE_INLINE std::string getTimestamp(const amrex::Real epoch_real, const std::string &datetime_format, bool add_long_frac=true)
Definition: ERF_EpochTime.H:103
void SurfaceDataInterpolation(const int nlevs, const amrex::Real time, amrex::Vector< std::unique_ptr< amrex::MultiFab >> &z_phys_nd, bool regrid_forces_file_read)
Definition: ERF_SurfaceDataInterpolation.cpp:142
static int last_check_file_step
Definition: ERF.H:1052
int max_step
Definition: ERF.H:1075
static amrex::Real last_plot2d_file_time_2
Definition: ERF.H:1057
amrex::Vector< std::string > subvol3d_var_names
Definition: ERF.H:1140
amrex::Real m_plot2d_per_1
Definition: ERF.H:1125
static amrex::Real last_plot2d_file_time_1
Definition: ERF.H:1056
static int last_plot2d_file_step_2
Definition: ERF.H:1051
amrex::Array< amrex::Array< amrex::Real, AMREX_SPACEDIM *2 >, AMREX_SPACEDIM+NBCVAR_max > m_bc_extdir_vals
Definition: ERF.H:1026
static amrex::Real last_plot3d_file_time_2
Definition: ERF.H:1055
int m_plot2d_int_2
Definition: ERF.H:1118
int m_plot3d_int_1
Definition: ERF.H:1115
static int last_plot3d_file_step_2
Definition: ERF.H:1049
amrex::Real m_plot2d_per_2
Definition: ERF.H:1126
bool writeNow(double cur_time, const int nstep, const int plot_int, const amrex::Real plot_per, const amrex::Real dt_0, amrex::Real &last_file_time)
Definition: ERF.cpp:3217
amrex::Real m_check_per
Definition: ERF.H:1138
int m_check_int
Definition: ERF.H:1137
static int input_bndry_planes
Definition: ERF.H:1324
void Write2DPlotFile(int which, PlotFileType plotfile_type, amrex::Vector< std::string > plot_var_names)
Definition: ERF_Plotfile.cpp:2033
const std::string datetime_format
Definition: ERF.H:1082
bool use_datetime
Definition: ERF.H:1081
amrex::Vector< amrex::Real > m_subvol_per
Definition: ERF.H:1121
void post_timestep(int nstep, double time, amrex::Real dt_lev)
Definition: ERF.cpp:774
void ComputeDt(int step=-1, double cur_time_d=0.0)
Definition: ERF_ComputeTimestep.cpp:11
void WeatherDataInterpolation(const int nlevs, const amrex::Real time, amrex::Vector< std::unique_ptr< amrex::MultiFab >> &z_phys_nd, bool regrid_forces_file_read)
Definition: ERF_WeatherDataInterpolation.cpp:347
void WriteSubvolume(int isub, amrex::Vector< std::string > subvol_var_names)
Definition: ERF_WriteSubvolume.cpp:145
amrex::Real m_plot3d_per_2
Definition: ERF.H:1124
amrex::Vector< int > last_subvol_step
Definition: ERF.H:1060
static PlotFileType plotfile3d_type_2
Definition: ERF.H:1261
static PlotFileType plotfile2d_type_2
Definition: ERF.H:1263
int m_plot2d_int_1
Definition: ERF.H:1117
void WriteCheckpointFile() const
Definition: ERF_Checkpoint.cpp:26
void Write3DPlotFile(int which, PlotFileType plotfile_type, amrex::Vector< std::string > plot_var_names)
Definition: ERF_Plotfile.cpp:321
static int last_plot2d_file_step_1
Definition: ERF.H:1050
amrex::Real m_plot3d_per_1
Definition: ERF.H:1123
std::unique_ptr< ReadBndryPlanes > m_r2d
Definition: ERF.H:1382
amrex::Vector< amrex::Real > last_subvol_time
Definition: ERF.H:1061
void timeStep(int lev, double time, int iteration)
Definition: ERF_TimeStep.cpp:17
static amrex::Real last_check_file_time
Definition: ERF.H:1058
static int last_plot3d_file_step_1
Definition: ERF.H:1048
static amrex::Real last_plot3d_file_time_1
Definition: ERF.H:1054
static PlotFileType plotfile2d_type_1
Definition: ERF.H:1262
static PlotFileType plotfile3d_type_1
Definition: ERF.H:1260
amrex::Vector< int > m_subvol_int
Definition: ERF.H:1120
int m_plot3d_int_2
Definition: ERF.H:1116
void Plot(const int &lev, const int &nstep)
Definition: ERF_LandSurface.H:74
bool hindcast_lateral_forcing
Definition: ERF_DataStruct.H:1332
bool hindcast_surface_bcs
Definition: ERF_DataStruct.H:1333

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ EvolveOneStep()

amrex::Real ERF::EvolveOneStep ( amrex::Real  time,
amrex::Real  dt_request 
)
14 {
15  amrex::Real cur_time = t_new[0];
16  const int step = istep[0];
17 
18  if (start_time + cur_time >= stop_time) {
19  return amrex::Real(0.0);
20  }
21 
22  ComputeDt(step);
23 
24  int iteration = 1;
25  timeStep(0, cur_time, iteration);
26  cur_time += dt[0];
27 
28  post_timestep(step, cur_time, dt[0]);
29 
30  if (writeNow(cur_time, step+1, m_plot3d_int_1, m_plot3d_per_1, dt[0], last_plot3d_file_time_1)) {
31  last_plot3d_file_step_1 = step+1;
33  for (int lev = 0; lev <= finest_level; ++lev) {lsm.Plot(lev, step+1);}
35  }
36  if (writeNow(cur_time, step+1, m_plot3d_int_2, m_plot3d_per_2, dt[0], last_plot3d_file_time_2)) {
37  last_plot3d_file_step_2 = step+1;
39  for (int lev = 0; lev <= finest_level; ++lev) {lsm.Plot(lev, step+1);}
41  }
42  if (writeNow(cur_time, step+1, m_plot2d_int_1, m_plot2d_per_1, dt[0], last_plot2d_file_time_1)) {
43  last_plot2d_file_step_1 = step+1;
46  }
47  if (writeNow(cur_time, step+1, m_plot2d_int_2, m_plot2d_per_2, dt[0], last_plot2d_file_time_2)) {
48  last_plot2d_file_step_2 = step+1;
51  }
52  for (int i = 0; i < m_subvol_int.size(); i++) {
53  if (writeNow(cur_time, step+1, m_subvol_int[i], m_subvol_per[i], dt[0], last_subvol_time[i])) {
54  last_subvol_step[i] = step+1;
56  if (m_subvol_per[i] > amrex::Real(0.0)) {last_subvol_time[i] += m_subvol_per[i];}
57  }
58  }
59  if (writeNow(cur_time, step+1, m_check_int, m_check_per, dt[0], last_check_file_time)) {
60  last_check_file_step = step+1;
63  }
64 
65  return dt[0];
66 }
Here is the call graph for this function:

◆ fill_from_bndryregs()

void ERF::fill_from_bndryregs ( const amrex::Vector< amrex::MultiFab * > &  mfs,
amrex::Real  time 
)
14 {
15  //
16  // We now assume that if we read in on one face, we read in on all faces
17  //
19 
20  int lev = 0;
21  const Box& domain = geom[lev].Domain();
22 
23  const auto& dom_lo = lbound(domain);
24  const auto& dom_hi = ubound(domain);
25 
26  // Boundary-plane files are indexed by absolute simulation time.
27  Vector<std::unique_ptr<PlaneVector>>& bndry_data = m_r2d->interp_in_time(time + start_time);
28 
29  const BCRec* bc_ptr = domain_bcs_type_d.data();
30 
31  // xlo: ori = 0
32  // ylo: ori = 1
33  // zlo: ori = 2
34  // xhi: ori = 3
35  // yhi: ori = 4
36  // zhi: ori = 5
37  const auto& bdatxlo = (*bndry_data[0])[lev].const_array();
38  const auto& bdatylo = (*bndry_data[1])[lev].const_array();
39  const auto& bdatxhi = (*bndry_data[3])[lev].const_array();
40  const auto& bdatyhi = (*bndry_data[4])[lev].const_array();
41 
42  int bccomp;
43 
44  for (int var_idx = 0; var_idx < Vars::NumTypes; ++var_idx)
45  {
46  MultiFab& mf = *mfs[var_idx];
47  const int icomp = 0;
48  const int ncomp = mf.nComp();
49 
50  if (var_idx == Vars::xvel) {
51  bccomp = BCVars::xvel_bc;
52  } else if (var_idx == Vars::yvel) {
53  bccomp = BCVars::yvel_bc;
54  } else if (var_idx == Vars::zvel) {
55  bccomp = BCVars::zvel_bc;
56  } else if (var_idx == Vars::cons) {
57  bccomp = BCVars::cons_bc;
58  }
59 
60 #ifdef AMREX_USE_OMP
61 #pragma omp parallel if (Gpu::notInLaunchRegion())
62 #endif
63  for (MFIter mfi(mf); mfi.isValid(); ++mfi)
64  {
65  const Array4<Real>& dest_arr = mf.array(mfi);
66  Box bx = mfi.growntilebox();
67 
68  // x-faces
69  {
70  Box bx_xlo(bx); bx_xlo.setBig(0,dom_lo.x-1);
71  if (var_idx == Vars::xvel) bx_xlo.setBig(0,dom_lo.x);
72 
73  Box bx_xhi(bx); bx_xhi.setSmall(0,dom_hi.x+1);
74 
76  bx_xlo, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) {
77  int bc_comp = (icomp+n >= RhoScalar_comp && icomp+n < RhoScalar_comp+NSCALARS) ?
78  BCVars::RhoScalar_bc_comp : icomp+n;
79  if (bc_ptr[bc_comp].lo(0) == ERFBCType::ext_dir_ingested) {
80  int jb = std::min(std::max(j,dom_lo.y),dom_hi.y);
81  int kb = std::min(std::max(k,dom_lo.z),dom_hi.z);
82  dest_arr(i,j,k,icomp+n) = bdatxlo(dom_lo.x-1,jb,kb,bccomp+n);
83  }
84  },
85  bx_xhi, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) {
86  int bc_comp = (icomp+n >= RhoScalar_comp && icomp+n < RhoScalar_comp+NSCALARS) ?
87  BCVars::RhoScalar_bc_comp : icomp+n;
88  if (bc_ptr[bc_comp].hi(0) == ERFBCType::ext_dir_ingested) {
89  int jb = std::min(std::max(j,dom_lo.y),dom_hi.y);
90  int kb = std::min(std::max(k,dom_lo.z),dom_hi.z);
91  dest_arr(i,j,k,icomp+n) = bdatxhi(dom_hi.x+1,jb,kb,bccomp+n);
92  }
93  }
94  );
95  } // x-faces
96 
97  // y-faces
98  {
99  Box bx_ylo(bx); bx_ylo.setBig (1,dom_lo.y-1);
100  if (var_idx == Vars::yvel) bx_ylo.setBig(1,dom_lo.y);
101 
102  Box bx_yhi(bx); bx_yhi.setSmall(1,dom_hi.y+1);
103 
104  ParallelFor(
105  bx_ylo, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) {
106  int bc_comp = (icomp+n >= RhoScalar_comp && icomp+n < RhoScalar_comp+NSCALARS) ?
107  BCVars::RhoScalar_bc_comp : icomp+n;
108  if (bc_ptr[bc_comp].lo(1) == ERFBCType::ext_dir_ingested) {
109  int ib = std::min(std::max(i,dom_lo.x),dom_hi.x);
110  int kb = std::min(std::max(k,dom_lo.z),dom_hi.z);
111  dest_arr(i,j,k,icomp+n) = bdatylo(ib,dom_lo.y-1,kb,bccomp+n);
112  }
113  },
114  bx_yhi, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) {
115  int bc_comp = (icomp+n >= RhoScalar_comp && icomp+n < RhoScalar_comp+NSCALARS) ?
116  BCVars::RhoScalar_bc_comp : icomp+n;
117  if (bc_ptr[bc_comp].hi(1) == ERFBCType::ext_dir_ingested) {
118  int ib = std::min(std::max(i,dom_lo.x),dom_hi.x);
119  int kb = std::min(std::max(k,dom_lo.z),dom_hi.z);
120  dest_arr(i,j,k,icomp+n) = bdatyhi(ib,dom_hi.y+1,kb,bccomp+n);
121  }
122  }
123  );
124  } // y-faces
125  } // mf
126  } // var_idx
127 }
#define RhoScalar_comp
Definition: ERF_IndexDefines.H:40
#define NSCALARS
Definition: ERF_IndexDefines.H:16
const auto & dom_hi
Definition: ERF_SetupVertDiff.H:2
const auto & dom_lo
Definition: ERF_SetupVertDiff.H:1
amrex::Gpu::DeviceVector< amrex::BCRec > domain_bcs_type_d
Definition: ERF.H:1020
@ RhoScalar_bc_comp
Definition: ERF_IndexDefines.H:90
@ ext_dir_ingested
Definition: ERF_IndexDefines.H:247
Here is the call graph for this function:

◆ fill_rhs()

void ERF::fill_rhs ( amrex::MultiFab &  rhs_mf,
const amrex::MultiFab &  state_mf,
amrex::Real  time,
const amrex::Geometry &  geom 
)
private

◆ FillBdyCCVels()

void ERF::FillBdyCCVels ( amrex::MultiFab &  mf_cc_vel,
amrex::Geometry &  lev_geom 
)
12 {
13  // Impose bc's at domain boundaries
14  Box domain(lev_geom.Domain());
15 
16  int ihi = domain.bigEnd(0);
17  int jhi = domain.bigEnd(1);
18  int khi = domain.bigEnd(2);
19 
20  // Impose periodicity first
21  mf_cc_vel.FillBoundary(lev_geom.periodicity());
22 
23  int jper = (lev_geom.isPeriodic(1));
24  int kper = (lev_geom.isPeriodic(2));
25 
26  for (MFIter mfi(mf_cc_vel, TilingIfNotGPU()); mfi.isValid(); ++mfi)
27  {
28  const Box& bx = mfi.tilebox();
29  const Array4<Real>& vel_arr = mf_cc_vel.array(mfi);
30 
31  if (!lev_geom.isPeriodic(0)) {
32  // Low-x side
33  if (bx.smallEnd(0) <= domain.smallEnd(0)) {
34  Real multn = ( (phys_bc_type[0] == ERF_BC::slip_wall ) ||
36  (phys_bc_type[0] == ERF_BC::symmetry ) ) ? -one : one;
37  Real multt = (phys_bc_type[0] == ERF_BC::no_slip_wall) ? -one : one;
38  Box gbx(bx); gbx.grow(1,jper); gbx.grow(2,kper);
39  ParallelFor(makeSlab(gbx,0,0), [=] AMREX_GPU_DEVICE(int , int j, int k) noexcept
40  {
41  vel_arr(-1,j,k,0) = multn*vel_arr(0,j,k,0); // u
42  vel_arr(-1,j,k,1) = multt*vel_arr(0,j,k,1); // v
43  vel_arr(-1,j,k,2) = multt*vel_arr(0,j,k,2); // w
44  });
45  }
46 
47  // High-x side
48  if (bx.bigEnd(0) >= domain.bigEnd(0)) {
49  Real multn = ( (phys_bc_type[3] == ERF_BC::slip_wall ) ||
51  (phys_bc_type[3] == ERF_BC::symmetry ) ) ? -one : one;
52  Real multt = (phys_bc_type[3] == ERF_BC::no_slip_wall) ? -one : one;
53  Box gbx(bx); gbx.grow(1,jper); gbx.grow(2,kper);
54  ParallelFor(makeSlab(gbx,0,0), [=] AMREX_GPU_DEVICE(int , int j, int k) noexcept
55  {
56  vel_arr(ihi+1,j,k,0) = multn*vel_arr(ihi,j,k,0); // u
57  vel_arr(ihi+1,j,k,1) = multt*vel_arr(ihi,j,k,1); // v
58  vel_arr(ihi+1,j,k,2) = multt*vel_arr(ihi,j,k,2); // w
59  });
60  }
61  } // !periodic
62 
63  if (!lev_geom.isPeriodic(1)) {
64  // Low-y side
65  if (bx.smallEnd(1) <= domain.smallEnd(1)) {
66  Real multn = ( (phys_bc_type[1] == ERF_BC::slip_wall ) ||
68  (phys_bc_type[1] == ERF_BC::symmetry ) ) ? -one : one;
69  Real multt = (phys_bc_type[1] == ERF_BC::no_slip_wall) ? -one : one;
70  Box gbx(bx); gbx.grow(0,1); gbx.grow(2,kper);
71  ParallelFor(makeSlab(gbx,1,0), [=] AMREX_GPU_DEVICE(int i, int , int k) noexcept
72  {
73  vel_arr(i,-1,k,0) = multt*vel_arr(i,0,k,0); // u
74  vel_arr(i,-1,k,1) = multn*vel_arr(i,0,k,1); // u
75  vel_arr(i,-1,k,2) = multt*vel_arr(i,0,k,2); // w
76  });
77  }
78 
79  // High-y side
80  if (bx.bigEnd(1) >= domain.bigEnd(1)) {
81  Real multn = ( (phys_bc_type[4] == ERF_BC::slip_wall ) ||
83  (phys_bc_type[4] == ERF_BC::symmetry ) ) ? -one : one;
84  Real multt = (phys_bc_type[4] == ERF_BC::no_slip_wall) ? -one : one;
85  Box gbx(bx); gbx.grow(0,1); gbx.grow(2,kper);
86  ParallelFor(makeSlab(gbx,1,0), [=] AMREX_GPU_DEVICE(int i, int , int k) noexcept
87  {
88  vel_arr(i,jhi+1,k,0) = multt*vel_arr(i,jhi,k,0); // u
89  vel_arr(i,jhi+1,k,1) = multn*vel_arr(i,jhi,k,1); // v
90  vel_arr(i,jhi+1,k,2) = multt*vel_arr(i,jhi,k,2); // w
91  });
92  }
93  } // !periodic
94 
95  if (!lev_geom.isPeriodic(2)) {
96  // Low-z side
97  if (bx.smallEnd(2) <= domain.smallEnd(2)) {
98  Real multn = ( (phys_bc_type[2] == ERF_BC::slip_wall ) ||
100  (phys_bc_type[2] == ERF_BC::symmetry ) ) ? -one : one;
101  Real multt = (phys_bc_type[2] == ERF_BC::no_slip_wall) ? -one : one;
102  Box gbx(bx); gbx.grow(0,1); gbx.grow(1,1);
103  ParallelFor(makeSlab(gbx,2,0), [=] AMREX_GPU_DEVICE(int i, int j, int) noexcept
104  {
105  vel_arr(i,j,-1,0) = multt*vel_arr(i,j,0,0); // u
106  vel_arr(i,j,-1,1) = multt*vel_arr(i,j,0,1); // v
107  vel_arr(i,j,-1,2) = multn*vel_arr(i,j,0,2); // w
108  });
109  }
110 
111  // High-z side
112  if (bx.bigEnd(2) >= domain.bigEnd(2)) {
113  Real multn = ( (phys_bc_type[5] == ERF_BC::slip_wall ) ||
115  (phys_bc_type[5] == ERF_BC::symmetry ) ) ? -one : one;
116  Real multt = (phys_bc_type[5] == ERF_BC::no_slip_wall) ? -one : one;
117  Box gbx(bx); gbx.grow(0,1); gbx.grow(1,1);
118  ParallelFor(makeSlab(gbx,2,0), [=] AMREX_GPU_DEVICE(int i, int j, int) noexcept
119  {
120  vel_arr(i,j,khi+1,0) = multt*vel_arr(i,j,khi,0); // u
121  vel_arr(i,j,khi+1,1) = multt*vel_arr(i,j,khi,1); // v
122  vel_arr(i,j,khi+1,2) = multn*vel_arr(i,j,khi,2); // w
123  });
124  }
125  } // !periodic
126  } // MFIter
127 
128  // Impose periodicity again
129  mf_cc_vel.FillBoundary(lev_geom.periodicity());
130 }
@ no_slip_wall
Here is the call graph for this function:

◆ FillCoarsePatch()

void ERF::FillCoarsePatch ( int  lev,
amrex::Real  time 
)
private
22 {
23  BL_PROFILE_VAR("FillCoarsePatch()",FillCoarsePatch);
24  AMREX_ASSERT(lev > 0);
25 
26  //
27  //****************************************************************************************************************
28  // First fill velocities and density at the COARSE level so we can convert velocity to momenta at the COARSE level
29  //****************************************************************************************************************
30  //
31  bool cons_only = false;
32  if (lev == 1) {
33  FillPatchCrseLevel(lev-1, time, {&vars_new[lev-1][Vars::cons], &vars_new[lev-1][Vars::xvel],
34  &vars_new[lev-1][Vars::yvel], &vars_new[lev-1][Vars::zvel]},
35  cons_only);
36  } else {
37  FillPatchFineLevel(lev-1, time, {&vars_new[lev-1][Vars::cons], &vars_new[lev-1][Vars::xvel],
38  &vars_new[lev-1][Vars::yvel], &vars_new[lev-1][Vars::zvel]},
39  {&vars_new[lev-1][Vars::cons],
40  &rU_new[lev-1], &rV_new[lev-1], &rW_new[lev-1]},
41  base_state[lev-1], base_state[lev-1],
42  false, cons_only);
43  }
44 
45  //
46  // ************************************************
47  // Convert velocity to momentum at the COARSE level
48  // ************************************************
49  //
50  const MultiFab* c_vfrac = nullptr;
51  if (solverChoice.terrain_type == TerrainType::EB) {
52  c_vfrac = &((get_eb(lev-1).get_const_factory())->getVolFrac());
53  }
54 
55  VelocityToMomentum(vars_new[lev-1][Vars::xvel], IntVect{0},
56  vars_new[lev-1][Vars::yvel], IntVect{0},
57  vars_new[lev-1][Vars::zvel], IntVect{0},
58  vars_new[lev-1][Vars::cons],
59  rU_new[lev-1],
60  rV_new[lev-1],
61  rW_new[lev-1],
62  Geom(lev-1).Domain(),
63  domain_bcs_type, c_vfrac);
64 
65  // Fill ghost cells of coarse momentum before interpolation to fine level.
66  // VelocityToMomentum above fills only valid cells (IntVect{0} grow). On restart
67  // from a non-AMR checkpoint, init_stuff initialises rU/rV/rW_new[lev-1] with large
68  // sentinel values for ALL cells including ghost cells; the checkpoint read then
69  // overwrites only valid cells. InterpFromCoarseLevel (see comments below) ASSUMES
70  // ghost cells at lev-1 are already filled and uses them in its stencil near periodic
71  // boundaries. Without this FillBoundary, those sentinel ghost cells contaminate the
72  // fine-level interpolation, producing unphysical velocities that blow up WENO5.
73  rU_new[lev-1].FillBoundary(geom[lev-1].periodicity());
74  rV_new[lev-1].FillBoundary(geom[lev-1].periodicity());
75  rW_new[lev-1].FillBoundary(geom[lev-1].periodicity());
76 
77  //
78  // *****************************************************************
79  // Interpolate all cell-centered variables from coarse to fine level
80  // *****************************************************************
81  //
82  Interpolater* mapper_c = &cell_cons_interp;
83  Interpolater* mapper_f = &face_cons_linear_interp;
84 
85  //
86  //************************************************************************************************
87  // Interpolate cell-centered data from coarse to fine level
88  // with InterpFromCoarseLevel which ASSUMES that all ghost cells at lev-1 have already been filled
89  // ************************************************************************************************
90  IntVect ngvect_cons = vars_new[lev][Vars::cons].nGrowVect();
91  int ncomp_cons = vars_new[lev][Vars::cons].nComp();
92 
93  InterpFromCoarseLevel(vars_new[lev ][Vars::cons], ngvect_cons, IntVect(0,0,0),
94  vars_new[lev-1][Vars::cons], 0, 0, ncomp_cons,
95  geom[lev-1], geom[lev],
96  refRatio(lev-1), mapper_c, domain_bcs_type, BCVars::cons_bc);
97 
98  // ***************************************************************************
99  // Physical bc's for cell centered variables at domain boundary
100  // ***************************************************************************
102  0,ncomp_cons,ngvect_cons,time,BCVars::cons_bc,true);
103 
104  //
105  //************************************************************************************************
106  // Interpolate x-momentum from coarse to fine level
107  // with InterpFromCoarseLevel which ASSUMES that all ghost cells at lev-1 have already been filled
108  // ************************************************************************************************
109  //
110  InterpFromCoarseLevel(rU_new[lev], IntVect{0}, IntVect{0}, rU_new[lev-1], 0, 0, 1,
111  geom[lev-1], geom[lev],
112  refRatio(lev-1), mapper_f, domain_bcs_type, BCVars::xvel_bc);
113 
114  //
115  //************************************************************************************************
116  // Interpolate y-momentum from coarse to fine level
117  // with InterpFromCoarseLevel which ASSUMES that all ghost cells at lev-1 have already been filled
118  // ************************************************************************************************
119  //
120  InterpFromCoarseLevel(rV_new[lev], IntVect{0}, IntVect{0}, rV_new[lev-1], 0, 0, 1,
121  geom[lev-1], geom[lev],
122  refRatio(lev-1), mapper_f, domain_bcs_type, BCVars::yvel_bc);
123 
124  //************************************************************************************************
125  // Interpolate z-momentum from coarse to fine level
126  // with InterpFromCoarseLevel which ASSUMES that all ghost cells at lev-1 have already been filled
127  // ************************************************************************************************
128  InterpFromCoarseLevel(rW_new[lev], IntVect{0}, IntVect{0}, rW_new[lev-1], 0, 0, 1,
129  geom[lev-1], geom[lev],
130  refRatio(lev-1), mapper_f, domain_bcs_type, BCVars::zvel_bc);
131  //
132  // *********************************************************
133  // After interpolation of momentum, convert back to velocity
134  // *********************************************************
135  //
136  for (int which_lev = lev-1; which_lev <= lev; which_lev++)
137  {
138  c_vfrac = nullptr;
139  if (solverChoice.terrain_type == TerrainType::EB) {
140  c_vfrac = &((get_eb(which_lev).get_const_factory())->getVolFrac());
141  }
142 
144  vars_new[which_lev][Vars::yvel],
145  vars_new[which_lev][Vars::zvel],
146  vars_new[which_lev][Vars::cons],
147  rU_new[which_lev],
148  rV_new[which_lev],
149  rW_new[which_lev],
150  Geom(which_lev).Domain(),
151  domain_bcs_type, c_vfrac);
152  }
153 
154  // ***************************************************************************
155  // Physical bc's at domain boundary
156  // ***************************************************************************
157  IntVect ngvect_vels = vars_new[lev][Vars::xvel].nGrowVect();
158 
160  ngvect_vels,time,BCVars::xvel_bc,true);
162  ngvect_vels,time,BCVars::yvel_bc,true);
164  ngvect_vels,time,BCVars::zvel_bc,true);
165 
166  // ***************************************************************************
167  // Since lev > 0 here we don't worry about m_r2d or wrfbdy data
168  // ***************************************************************************
169 }
void FillCoarsePatch(int lev, amrex::Real time)
Definition: ERF_FillCoarsePatch.cpp:21
Here is the call graph for this function:

◆ FillForecastStateMultiFabs()

void ERF::FillForecastStateMultiFabs ( const int  lev,
const std::string &  filename,
const std::unique_ptr< amrex::MultiFab > &  z_phys_nd,
amrex::Vector< amrex::Vector< amrex::MultiFab >> &  forecast_state 
)
68 {
69 
70  Vector<Real> latvec_h, lonvec_h, xvec_h, yvec_h, zvec_h;
71  Vector<Real> rho_h, uvel_h, vvel_h, wvel_h, theta_h, qv_h, qc_h, qr_h;
72 
73  ReadCustomBinaryIC(filename, latvec_h, lonvec_h,
74  xvec_h, yvec_h, zvec_h, rho_h,
75  uvel_h, vvel_h, wvel_h,
76  theta_h, qv_h, qc_h, qr_h);
77 
78  Real zmax = *std::max_element(zvec_h.begin(), zvec_h.end());
79 
80  const auto prob_lo_erf = geom[lev].ProbLoArray();
81  const auto prob_hi_erf = geom[lev].ProbHiArray();
82  const auto dx_erf = geom[lev].CellSizeArray();
83 
84  if (prob_hi_erf[2] >= zmax) {
85  Abort("ERROR: the maximum z of the domain (" + std::to_string(prob_hi_erf[2]) +
86  ") should be less than the maximum z in the forecast data (" + std::to_string(zmax) +
87  "). Change geometry.prob_hi[2] in the inputs to be less than " + std::to_string(zmax) + "."
88  );
89  }
90 
91  if(prob_lo_erf[0] < xvec_h.front() + 4*dx_erf[0]){
92  amrex::Abort("The xlo value of the domain has to be greater than " + std::to_string(xvec_h.front() + 4*dx_erf[0]));
93  }
94  if(prob_hi_erf[0] > xvec_h.back() - 4*dx_erf[0]){
95  amrex::Abort("The xhi value of the domain has to be less than " + std::to_string(xvec_h.back() - 4*dx_erf[0]));
96  }
97  if(prob_lo_erf[1] < yvec_h.front() + 4*dx_erf[1]){
98  amrex::Abort("The ylo value of the domain has to be greater than " + std::to_string(yvec_h.front() + 4*dx_erf[1]));
99  }
100  if(prob_hi_erf[1] > yvec_h.back() - 4*dx_erf[1]){
101  amrex::Abort("The yhi value of the domain has to be less than " + std::to_string(yvec_h.back() - 4*dx_erf[1]));
102  }
103 
104 
105  int nx = static_cast<int>(xvec_h.size());
106  int ny = static_cast<int>(yvec_h.size());
107  int nz = static_cast<int>(zvec_h.size());
108 
109  amrex::Real dxvec = (xvec_h[nx-1]-xvec_h[0])/(nx-1);
110  amrex::Real dyvec = (yvec_h[ny-1]-yvec_h[0])/(ny-1);
111 
112  amrex::Gpu::DeviceVector<Real> latvec_d(nx*ny), lonvec_d(nx*ny), zvec_d(nz);
113  amrex::Gpu::DeviceVector<Real> xvec_d(nx*ny*nz), yvec_d(nx*ny*nz);
114  amrex::Gpu::DeviceVector<Real> rho_d(nx*ny*nz), uvel_d(nx*ny*nz), vvel_d(nx*ny*nz), wvel_d(nx*ny*nz),
115  theta_d(nx*ny*nz), qv_d(nx*ny*nz), qc_d(nx*ny*nz), qr_d(nx*ny*nz);
116 
117  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, latvec_h.begin(), latvec_h.end(), latvec_d.begin());
118  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, lonvec_h.begin(), lonvec_h.end(), lonvec_d.begin());
119 
120  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, xvec_h.begin(), xvec_h.end(), xvec_d.begin());
121  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, yvec_h.begin(), yvec_h.end(), yvec_d.begin());
122  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, zvec_h.begin(), zvec_h.end(), zvec_d.begin());
123  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, rho_h.begin(), rho_h.end(), rho_d.begin());
124  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, theta_h.begin(), theta_h.end(), theta_d.begin());
125  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, uvel_h.begin(), uvel_h.end(), uvel_d.begin());
126  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, vvel_h.begin(), vvel_h.end(), vvel_d.begin());
127  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, wvel_h.begin(), wvel_h.end(), wvel_d.begin());
128  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, qv_h.begin(), qv_h.end(), qv_d.begin());
129  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, qc_h.begin(), qc_h.end(), qc_d.begin());
130  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, qr_h.begin(), qr_h.end(), qr_d.begin());
131 
132  amrex::Gpu::streamSynchronize();
133 
134  Real* latvec_d_ptr = latvec_d.data();
135  Real* lonvec_d_ptr = lonvec_d.data();
136  Real* xvec_d_ptr = xvec_d.data();
137  Real* yvec_d_ptr = yvec_d.data();
138  Real* zvec_d_ptr = zvec_d.data();
139  Real* rho_d_ptr = rho_d.data();
140  Real* uvel_d_ptr = uvel_d.data();
141  Real* vvel_d_ptr = vvel_d.data();
142  Real* wvel_d_ptr = wvel_d.data();
143  Real* theta_d_ptr = theta_d.data();
144  Real* qv_d_ptr = qv_d.data();
145  Real* qc_d_ptr = qc_d.data();
146  Real* qr_d_ptr = qr_d.data();
147 
148  MultiFab& erf_mf_cons = forecast_state[lev][Vars::cons];
149  MultiFab& erf_mf_xvel = forecast_state[lev][Vars::xvel];
150  MultiFab& erf_mf_yvel = forecast_state[lev][Vars::yvel];
151  MultiFab& erf_mf_zvel = forecast_state[lev][Vars::zvel];
152  MultiFab& erf_mf_latlon = forecast_state[lev][4];
153 
154  erf_mf_cons.setVal(0.0);
155  erf_mf_xvel.setVal(0.0);
156  erf_mf_yvel.setVal(0.0);
157  erf_mf_zvel.setVal(0.0);
158  erf_mf_latlon.setVal(0.0);
159 
160  // Interpolate the data on to the ERF mesh
161 
162  for (MFIter mfi(erf_mf_cons); mfi.isValid(); ++mfi) {
163  const auto z_arr = (a_z_phys_nd) ? a_z_phys_nd->const_array(mfi) :
164  Array4<const Real> {};
165  const Array4<Real> &fine_cons_arr = erf_mf_cons.array(mfi);
166  const Array4<Real> &fine_xvel_arr = erf_mf_xvel.array(mfi);
167  const Array4<Real> &fine_yvel_arr = erf_mf_yvel.array(mfi);
168  const Array4<Real> &fine_zvel_arr = erf_mf_zvel.array(mfi);
169  const Array4<Real> &fine_latlon_arr = erf_mf_latlon.array(mfi);
170 
171 
172  const Box& gbx = mfi.growntilebox(); // tilebox + ghost cells
173 
174  const Box &gtbx = mfi.tilebox(IntVect(1,0,0));
175  const Box &gtby = mfi.tilebox(IntVect(0,1,0));
176  const Box &gtbz = mfi.tilebox(IntVect(0,0,1));
177  const auto prob_lo = geom[lev].ProbLoArray();
178  const auto dx = geom[lev].CellSizeArray();
179  //const Box &gtbz = mfi.tilebox(IntVect(0,0,1));
180 
181  ParallelFor(gbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
182  // Geometry (note we must include these here to get the data on device)
183  const Real x = prob_lo[0] + (i + myhalf) * dx[0];
184  const Real y = prob_lo[1] + (j + myhalf) * dx[1];
185  //const Real z = prob_lo[2] + (k + myhalf) * dx[2];
186  const Real z = (z_arr(i,j,k) + z_arr(i,j,k+1))/two;
187 
188  // First interpolate where the weather data is available from
189  Real tmp_rho, tmp_theta, tmp_qv, tmp_qc, tmp_qr, tmp_lat, tmp_lon;
190  bilinear_interpolation(xvec_d_ptr, yvec_d_ptr, zvec_d_ptr,
191  dxvec, dyvec,
192  nx, ny, nz,
193  x, y, z,
194  rho_d_ptr, tmp_rho);
195 
196  bilinear_interpolation(xvec_d_ptr, yvec_d_ptr, zvec_d_ptr,
197  dxvec, dyvec,
198  nx, ny, nz,
199  x, y, z,
200  theta_d_ptr, tmp_theta);
201 
202  bilinear_interpolation(xvec_d_ptr, yvec_d_ptr, zvec_d_ptr,
203  dxvec, dyvec,
204  nx, ny, nz,
205  x, y, z,
206  qv_d_ptr, tmp_qv);
207 
208  bilinear_interpolation(xvec_d_ptr, yvec_d_ptr, zvec_d_ptr,
209  dxvec, dyvec,
210  nx, ny, nz,
211  x, y, z,
212  qc_d_ptr, tmp_qc);
213 
214  bilinear_interpolation(xvec_d_ptr, yvec_d_ptr, zvec_d_ptr,
215  dxvec, dyvec,
216  nx, ny, nz,
217  x, y, z,
218  qr_d_ptr, tmp_qr);
219 
220  bilinear_interpolation(xvec_d_ptr, yvec_d_ptr, zvec_d_ptr,
221  dxvec, dyvec,
222  nx, ny, 1,
223  x, y, zero,
224  latvec_d_ptr, tmp_lat);
225 
226  bilinear_interpolation(xvec_d_ptr, yvec_d_ptr, zvec_d_ptr,
227  dxvec, dyvec,
228  nx, ny, 1,
229  x, y, zero,
230  lonvec_d_ptr, tmp_lon);
231 
232  fine_cons_arr(i,j,k,Rho_comp) = tmp_rho;
233  fine_latlon_arr(i,j,k,0) = tmp_lat;
234  fine_latlon_arr(i,j,k,1) = tmp_lon;
235  });
236 
237  ParallelFor(gtbx, gtby, gtbz,
238  [=] AMREX_GPU_DEVICE(int i, int j, int k) {
239  // Physical location of the fine node
240  Real x = prob_lo_erf[0] + i * dx_erf[0];
241  Real y = prob_lo_erf[1] + (j+myhalf) * dx_erf[1];
242  //Real z = prob_lo_erf[2] + (k+myhalf) * dx_erf[2];
243  const Real z = (z_arr(i,j,k) + z_arr(i,j,k+1))/two;
244 
245  Real tmp_uvel;
246  bilinear_interpolation(xvec_d_ptr, yvec_d_ptr, zvec_d_ptr,
247  dxvec, dyvec,
248  nx, ny, nz,
249  x, y, z,
250  uvel_d_ptr, tmp_uvel);
251 
252  fine_xvel_arr(i, j, k, 0) = tmp_uvel;
253  },
254  [=] AMREX_GPU_DEVICE(int i, int j, int k) {
255  // Physical location of the fine node
256  Real x = prob_lo_erf[0] + (i+myhalf) * dx_erf[0];
257  Real y = prob_lo_erf[1] + j * dx_erf[1];
258  //Real z = prob_lo_erf[2] + (k+myhalf) * dx_erf[2];
259  const Real z = (z_arr(i,j,k) + z_arr(i,j,k+1))/two;
260 
261  Real tmp_vvel;
262  bilinear_interpolation(xvec_d_ptr, yvec_d_ptr, zvec_d_ptr,
263  dxvec, dyvec,
264  nx, ny, nz,
265  x, y, z,
266  vvel_d_ptr, tmp_vvel);
267 
268  fine_yvel_arr(i, j, k, 0) = tmp_vvel;
269  },
270  [=] AMREX_GPU_DEVICE(int i, int j, int k) {
271  // Physical location of the fine node
272  Real x = prob_lo_erf[0] + (i+myhalf) * dx_erf[0];
273  Real y = prob_lo_erf[1] + (j+myhalf) * dx_erf[1];
274  Real z = prob_lo_erf[2] + k * dx_erf[2];
275  //const Real z = (z_arr(i,j,k) + z_arr(i,j,k+1))/two;
276 
277  Real tmp_wvel;
278  bilinear_interpolation(xvec_d_ptr, yvec_d_ptr, zvec_d_ptr,
279  dxvec, dyvec,
280  nx, ny, nz,
281  x, y, z,
282  wvel_d_ptr, tmp_wvel);
283 
284  fine_zvel_arr(i, j, k, 0) = tmp_wvel;
285  });
286  }
287 
288  /*Vector<std::string> varnames = {
289  "rho", "uvel", "vvel", "wvel", "theta", "qv", "qc", "qr"
290  }; // Customize variable names
291 
292  Vector<std::string> varnames_cons = {
293  "rho", "rhotheta", "ke", "sc", "rhoqv", "rhoqc", "rhoqr"
294  }; // Customize variable names
295 
296  Vector<std::string> varnames_plot_mf = {
297  "rho", "rhotheta", "rhoqv", "rhoqc", "rhoqr", "xvel", "yvel", "zvel", "latitude", "longitude"
298  }; // Customize variable names
299 
300  const Real time = zero;
301 
302  std::string pltname = "plt_interp";
303 
304  MultiFab plot_mf(erf_mf_cons.boxArray(), erf_mf_cons.DistributionMap(),
305  10, 0);
306 
307  plot_mf.setVal(0.0);
308 
309  for (MFIter mfi(plot_mf); mfi.isValid(); ++mfi) {
310  const Array4<Real> &plot_mf_arr = plot_mf.array(mfi);
311  const Array4<Real> &erf_mf_cons_arr = erf_mf_cons.array(mfi);
312  const Array4<Real> &erf_mf_xvel_arr = erf_mf_xvel.array(mfi);
313  const Array4<Real> &erf_mf_yvel_arr = erf_mf_yvel.array(mfi);
314  const Array4<Real> &erf_mf_zvel_arr = erf_mf_zvel.array(mfi);
315  const Array4<Real> &erf_mf_latlon_arr = erf_mf_latlon.array(mfi);
316 
317  const Box& bx = mfi.validbox();
318 
319  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
320  plot_mf_arr(i,j,k,0) = erf_mf_cons_arr(i,j,k,Rho_comp);
321  plot_mf_arr(i,j,k,1) = erf_mf_cons_arr(i,j,k,RhoTheta_comp);
322  plot_mf_arr(i,j,k,2) = erf_mf_cons_arr(i,j,k,RhoQ1_comp);
323  plot_mf_arr(i,j,k,3) = erf_mf_cons_arr(i,j,k,RhoQ2_comp);
324  plot_mf_arr(i,j,k,4) = erf_mf_cons_arr(i,j,k,RhoQ3_comp);
325 
326  plot_mf_arr(i,j,k,5) = (erf_mf_xvel_arr(i,j,k,0) + erf_mf_xvel_arr(i+1,j,k,0))/two;
327  plot_mf_arr(i,j,k,6) = (erf_mf_yvel_arr(i,j,k,0) + erf_mf_yvel_arr(i,j+1,k,0))/two;
328  plot_mf_arr(i,j,k,7) = (erf_mf_zvel_arr(i,j,k,0) + erf_mf_zvel_arr(i,j,k+1,0))/two;
329 
330  plot_mf_arr(i,j,k,8) = erf_mf_latlon_arr(i,j,k,0);
331  plot_mf_arr(i,j,k,9) = erf_mf_latlon_arr(i,j,k,1);
332  });
333  }
334 
335 
336  WriteSingleLevelPlotfile(
337  pltname,
338  plot_mf,
339  varnames_plot_mf,
340  geom[0],
341  time,
342  0 // level
343  );*/
344 }
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE void bilinear_interpolation(const amrex::Real *xvec, const amrex::Real *yvec, const amrex::Real *zvec, const amrex::Real dxvec, const amrex::Real dyvec, const int nx, const int ny, const int nz, const amrex::Real x, const amrex::Real y, const amrex::Real z, const amrex::Real *varvec, amrex::Real &tmp_var)
Definition: ERF_Interpolation_Bilinear.H:42
void ReadCustomBinaryIC(const std::string filename, amrex::Vector< amrex::Real > &latvec_h, amrex::Vector< amrex::Real > &lonvec_h, amrex::Vector< amrex::Real > &xvec_h, amrex::Vector< amrex::Real > &yvec_h, amrex::Vector< amrex::Real > &zvec_h, amrex::Vector< amrex::Real > &rho_h, amrex::Vector< amrex::Real > &uvel_h, amrex::Vector< amrex::Real > &vvel_h, amrex::Vector< amrex::Real > &wvel_h, amrex::Vector< amrex::Real > &theta_h, amrex::Vector< amrex::Real > &qv_h, amrex::Vector< amrex::Real > &qc_h, amrex::Vector< amrex::Real > &qr_h)
Definition: ERF_ReadCustomBinaryIC.H:15
Vector< Real > rho_h(khi+1, zero)
Gpu::DeviceVector< Real > rho_d(khi+1, zero)
Here is the call graph for this function:

◆ FillIntermediatePatch()

void ERF::FillIntermediatePatch ( int  lev,
amrex::Real  time,
const amrex::Vector< amrex::MultiFab * > &  mfs_vel,
const amrex::Vector< amrex::MultiFab * > &  mfs_mom,
int  ng_cons,
int  ng_vel,
bool  cons_only,
int  icomp_cons,
int  ncomp_cons 
)
private
33 {
34  BL_PROFILE_VAR("FillIntermediatePatch()",FillIntermediatePatch);
35  Interpolater* mapper;
36 
37  PhysBCFunctNoOp null_bc;
38 
39  //
40  // ***************************************************************************
41  // The first thing we do is interpolate the momenta on the "valid" faces of
42  // the fine grids (where the interface is coarse/fine not fine/fine) -- this
43  // will not be over-written by interpolation below because the FillPatch
44  // operators see these as valid faces. But we must have these interpolated
45  // values in the fine data before we call FillPatchTwoLevels.
46  //
47  // Also -- note that we might be filling values by interpolation at physical boundaries
48  // here but that's ok because we will overwrite those values when we impose
49  // the physical bc's below
50  // ***************************************************************************
51  if (lev>0) {
52  if (cf_set_width > 0) {
53  // We note that mfs_vel[Vars::cons] and mfs_mom[Vars::cons] are in fact the same pointer
54  FPr_c[lev-1].FillSet(*mfs_vel[Vars::cons], time, null_bc, domain_bcs_type);
55  }
56  if ( !cons_only && (cf_set_width >= 0) ) {
57  FPr_u[lev-1].FillSet(*mfs_mom[IntVars::xmom], time, null_bc, domain_bcs_type);
58  FPr_v[lev-1].FillSet(*mfs_mom[IntVars::ymom], time, null_bc, domain_bcs_type);
59  FPr_w[lev-1].FillSet(*mfs_mom[IntVars::zmom], time, null_bc, domain_bcs_type);
60  }
61  }
62 
63  // amrex::Print() << "LEVEL " << lev << " CONS ONLY " << cons_only <<
64  // " ICOMP NCOMP " << icomp_cons << " " << ncomp_cons << " NGHOST " << ng_cons << std::endl;
65 
66  if (!cons_only) {
67  AMREX_ALWAYS_ASSERT(mfs_mom.size() == IntVars::NumTypes);
68  AMREX_ALWAYS_ASSERT(mfs_vel.size() == Vars::NumTypes);
69  }
70 
71  // Enforce no penetration for thin immersed body
72  if (!cons_only) {
73  // Enforce no penetration for thin immersed body
74  if (xflux_imask[lev]) {
75  ApplyMask(*mfs_mom[IntVars::xmom], *xflux_imask[lev]);
76  }
77  if (yflux_imask[lev]) {
78  ApplyMask(*mfs_mom[IntVars::ymom], *yflux_imask[lev]);
79  }
80  if (zflux_imask[lev]) {
81  ApplyMask(*mfs_mom[IntVars::zmom], *zflux_imask[lev]);
82  }
83  }
84 
85  //
86  // We now start working on conserved quantities + VELOCITY
87  //
88  if (lev == 0)
89  {
90  // We don't do anything here because we will call the physbcs routines below,
91  // which calls FillBoundary and fills other domain boundary conditions
92  // Physical boundaries will be filled below
93 
94  if (!cons_only)
95  {
96  // ***************************************************************************
97  // We always come in to this call with updated momenta but we need to create updated velocity
98  // in order to impose the rest of the bc's
99  // ***************************************************************************
100  const MultiFab* c_vfrac = nullptr;
101  if (solverChoice.terrain_type == TerrainType::EB) {
102  c_vfrac = &((get_eb(lev).get_const_factory())->getVolFrac());
103  }
104 
105  // This only fills VALID region of velocity
106  MomentumToVelocity(*mfs_vel[Vars::xvel], *mfs_vel[Vars::yvel], *mfs_vel[Vars::zvel],
107  *mfs_vel[Vars::cons],
108  *mfs_mom[IntVars::xmom], *mfs_mom[IntVars::ymom], *mfs_mom[IntVars::zmom],
109  Geom(lev).Domain(), domain_bcs_type, c_vfrac);
110  }
111  }
112  else
113  {
114  //
115  // We must fill a temporary then copy it back so we don't double add/subtract
116  //
117  MultiFab mf(mfs_vel[Vars::cons]->boxArray(),mfs_vel[Vars::cons]->DistributionMap(),
118  mfs_vel[Vars::cons]->nComp() ,mfs_vel[Vars::cons]->nGrowVect());
119  //
120  // Set all components to 1.789e19, then copy just the density from *mfs_vel[Vars::cons]
121  //
122  mf.setVal(Real(1.789e19));
123  MultiFab::Copy(mf,*mfs_vel[Vars::cons],Rho_comp,Rho_comp,1,mf.nGrowVect());
124 
125  Vector<MultiFab*> fmf = {mfs_vel[Vars::cons],mfs_vel[Vars::cons]};
126  Vector<MultiFab*> cmf = {&vars_old[lev-1][Vars::cons], &vars_new[lev-1][Vars::cons]};
127  Vector<Real> ctime = {t_old[lev-1], t_new[lev-1]};
128  Vector<Real> ftime = {time,time};
129 
130  if (interpolation_type == StateInterpType::Perturbational)
131  {
132  if (icomp_cons+ncomp_cons > 1)
133  {
134  // Divide (rho theta) by rho to get theta
135  MultiFab::Divide(*mfs_vel[Vars::cons],*mfs_vel[Vars::cons],Rho_comp,RhoTheta_comp,1,IntVect{0});
136 
137  // Subtract theta_0 from theta
138  MultiFab::Subtract(*mfs_vel[Vars::cons],base_state[lev],BaseState::th0_comp,RhoTheta_comp,1,IntVect{0});
139 
140  if (!amrex::almostEqual(time,ctime[1])) {
141  MultiFab::Divide(vars_old[lev-1][Vars::cons], vars_old[lev-1][Vars::cons],
142  Rho_comp,RhoTheta_comp,1,vars_old[lev-1][Vars::cons].nGrowVect());
143  MultiFab::Subtract(vars_old[lev-1][Vars::cons], base_state[lev-1],
144  BaseState::th0_comp,RhoTheta_comp,1,vars_old[lev-1][Vars::cons].nGrowVect());
145  }
146  if (!amrex::almostEqual(time,ctime[0])) {
147  MultiFab::Divide(vars_new[lev-1][Vars::cons], vars_new[lev-1][Vars::cons],
148  Rho_comp,RhoTheta_comp,1,vars_new[lev-1][Vars::cons].nGrowVect());
149  MultiFab::Subtract(vars_new[lev-1][Vars::cons], base_state[lev-1],
150  BaseState::th0_comp,RhoTheta_comp,1,vars_new[lev-1][Vars::cons].nGrowVect());
151  }
152  }
153 
154  // Subtract rho_0 from rho before we interpolate -- note we only subtract
155  // on valid region of mf since the ghost cells will be filled below
156  if (icomp_cons == 0)
157  {
158  MultiFab::Subtract(*mfs_vel[Vars::cons],base_state[lev],BaseState::r0_comp,Rho_comp,1,IntVect{0});
159 
160  if (!amrex::almostEqual(time,ctime[1])) {
161  MultiFab::Subtract(vars_old[lev-1][Vars::cons], base_state[lev-1],
162  BaseState::r0_comp,Rho_comp,1,vars_old[lev-1][Vars::cons].nGrowVect());
163  }
164  if (!amrex::almostEqual(time,ctime[0])) {
165  MultiFab::Subtract(vars_new[lev-1][Vars::cons], base_state[lev-1],
166  BaseState::r0_comp,Rho_comp,1,vars_new[lev-1][Vars::cons].nGrowVect());
167  }
168  }
169  } // interpolation_type == StateInterpType::Perturbational
170 
171  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
172  mapper = &cell_cons_interp;
173  FillPatchTwoLevels(mf, IntVect{ng_cons}, IntVect(0,0,0),
174  time, cmf, ctime, fmf, ftime,
175  icomp_cons, icomp_cons, ncomp_cons, geom[lev-1], geom[lev],
176  refRatio(lev-1), mapper, domain_bcs_type,
177  icomp_cons);
178 
179  if (interpolation_type == StateInterpType::Perturbational)
180  {
181  if (icomp_cons == 0)
182  {
183  // Restore the coarse values to what they were
184  if (!amrex::almostEqual(time,ctime[1])) {
185  MultiFab::Add(vars_old[lev-1][Vars::cons], base_state[lev-1],
186  BaseState::r0_comp,Rho_comp,1,vars_old[lev-1][Vars::cons].nGrowVect());
187  }
188  if (!amrex::almostEqual(time,ctime[0])) {
189  MultiFab::Add(vars_new[lev-1][Vars::cons], base_state[lev-1],
190  BaseState::r0_comp,Rho_comp,1,vars_new[lev-1][Vars::cons].nGrowVect());
191  }
192 
193  // Set values in the cells outside the domain boundary so that we can do the Add
194  // without worrying about uninitialized values outside the domain -- these
195  // will be filled in the physbcs call
196  mf.setDomainBndry(Real(1.234e20),Rho_comp,1,geom[lev]);
197 
198  // Add rho_0 back to rho after we interpolate -- on all the valid + ghost region
199  MultiFab::Add(mf, base_state[lev],BaseState::r0_comp,Rho_comp,1,IntVect{ng_cons});
200  }
201 
202  if (icomp_cons+ncomp_cons > 1)
203  {
204  // Add theta_0 to theta
205  if (!amrex::almostEqual(time,ctime[1])) {
206  MultiFab::Add(vars_old[lev-1][Vars::cons], base_state[lev-1],
207  BaseState::th0_comp,RhoTheta_comp,1,vars_old[lev-1][Vars::cons].nGrowVect());
208  MultiFab::Multiply(vars_old[lev-1][Vars::cons], vars_old[lev-1][Vars::cons],
209  Rho_comp,RhoTheta_comp,1,vars_old[lev-1][Vars::cons].nGrowVect());
210  }
211  if (!amrex::almostEqual(time,ctime[0])) {
212  MultiFab::Add(vars_new[lev-1][Vars::cons], base_state[lev-1],
213  BaseState::th0_comp,RhoTheta_comp,1,vars_new[lev-1][Vars::cons].nGrowVect());
214  MultiFab::Multiply(vars_new[lev-1][Vars::cons], vars_new[lev-1][Vars::cons],
215  Rho_comp,RhoTheta_comp,1,vars_new[lev-1][Vars::cons].nGrowVect());
216  }
217 
218  // Multiply theta by rho to get (rho theta)
219  MultiFab::Multiply(*mfs_vel[Vars::cons],*mfs_vel[Vars::cons],Rho_comp,RhoTheta_comp,1,IntVect{0});
220 
221  // Add theta_0 to theta
222  MultiFab::Add(*mfs_vel[Vars::cons],base_state[lev],BaseState::th0_comp,RhoTheta_comp,1,IntVect{0});
223 
224  // Add theta_0 back to theta
225  MultiFab::Add(mf,base_state[lev],BaseState::th0_comp,RhoTheta_comp,1,IntVect{ng_cons});
226 
227  // Multiply (theta) by rho to get (rho theta)
228  MultiFab::Multiply(mf,mf,Rho_comp,RhoTheta_comp,1,IntVect{ng_cons});
229  }
230  } // interpolation_type == StateInterpType::Perturbational
231 
232  // Impose physical bc's on fine data (note time and 0 are not used)
233  // Note that we do this after the FillPatch because imposing physical bc's on fine ghost
234  // cells that need to be filled from coarse requires that we have done the interpolation first
235  bool do_fb = true; bool do_terrain_adjustment = false;
236  (*physbcs_cons[lev])(mf,*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
237  icomp_cons,ncomp_cons,IntVect{ng_cons},time,BCVars::cons_bc,
238  do_fb, do_terrain_adjustment);
239 
240  // Make sure to only copy back the components we worked on
241  MultiFab::Copy(*mfs_vel[Vars::cons],mf,icomp_cons,icomp_cons,ncomp_cons,IntVect{ng_cons});
242 
243  // *****************************************************************************************
244 
245  if (!cons_only)
246  {
247  // ***************************************************************************
248  // We always come in to this call with updated momenta but we need to create updated velocity
249  // in order to impose the rest of the bc's
250  // ***************************************************************************
251  const MultiFab* c_vfrac = nullptr;
252  if (solverChoice.terrain_type == TerrainType::EB) {
253  c_vfrac = &((get_eb(lev).get_const_factory())->getVolFrac());
254  }
255 
256  // This only fills VALID region of velocity
257  MomentumToVelocity(*mfs_vel[Vars::xvel], *mfs_vel[Vars::yvel], *mfs_vel[Vars::zvel],
258  *mfs_vel[Vars::cons],
259  *mfs_mom[IntVars::xmom], *mfs_mom[IntVars::ymom], *mfs_mom[IntVars::zmom],
260  Geom(lev).Domain(), domain_bcs_type, c_vfrac);
261 
262  mapper = &face_cons_linear_interp;
263 
264  //
265  // NOTE: All interpolation here happens on velocities not momenta;
266  // note we only do the interpolation and FillBoundary here,
267  // physical bc's are imposed later
268  //
269  // NOTE: This will only fill velocity from coarse grid *outside* the fine grids
270  // unlike the FillSet calls above which filled momenta on the coarse/fine bdy
271  //
272 
273  MultiFab& mfu = *mfs_vel[Vars::xvel];
274 
275  fmf = {&mfu,&mfu};
276  cmf = {&vars_old[lev-1][Vars::xvel], &vars_new[lev-1][Vars::xvel]};
277 
278  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
279  FillPatchTwoLevels(mfu, IntVect{ng_vel}, IntVect(0,0,0),
280  time, cmf, ctime, fmf, ftime,
281  0, 0, 1, geom[lev-1], geom[lev],
282  refRatio(lev-1), mapper, domain_bcs_type,
284 
285  // *****************************************************************************************
286 
287  MultiFab& mfv = *mfs_vel[Vars::yvel];
288 
289  fmf = {&mfv,&mfv};
290  cmf = {&vars_old[lev-1][Vars::yvel], &vars_new[lev-1][Vars::yvel]};
291 
292  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
293  FillPatchTwoLevels(mfv, IntVect{ng_vel}, IntVect(0,0,0),
294  time, cmf, ctime, fmf, ftime,
295  0, 0, 1, geom[lev-1], geom[lev],
296  refRatio(lev-1), mapper, domain_bcs_type,
298 
299  // *****************************************************************************************
300 
301  MultiFab& mfw = *mfs_vel[Vars::zvel];
302 
303  fmf = {&mfw,&mfw};
304  cmf = {&vars_old[lev-1][Vars::zvel], &vars_new[lev-1][Vars::zvel]};
305 
306  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
307  FillPatchTwoLevels(mfw, IntVect{ng_vel}, IntVect(0,0,0),
308  time, cmf, ctime, fmf, ftime,
309  0, 0, 1, geom[lev-1], geom[lev],
310  refRatio(lev-1), mapper, domain_bcs_type,
312  } // !cons_only
313  } // lev > 0
314 
315  // ***************************************************************************
316  // Physical bc's at domain boundary
317  // ***************************************************************************
318  IntVect ngvect_cons = IntVect(ng_cons,ng_cons,ng_cons);
319  IntVect ngvect_vels = IntVect(ng_vel ,ng_vel ,ng_vel);
320 
321  bool do_fb = true;
322 
323 #ifdef ERF_USE_NETCDF
324  if (solverChoice.use_real_bcs && (lev==0)) {
325  fill_from_realbdy(mfs_vel,time,cons_only,icomp_cons,ncomp_cons,ngvect_cons,ngvect_vels);
326  do_fb = false;
327  }
328 #endif
329 
330  if (m_r2d && !solverChoice.use_real_bcs) { fill_from_bndryregs(mfs_vel,time); }
331 
332  // We call this even if use_real_bcs is true because these will fill the vertical bcs
333  (*physbcs_cons[lev])(*mfs_vel[Vars::cons],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
334  icomp_cons,ncomp_cons,ngvect_cons,time,BCVars::cons_bc, do_fb);
335  if (!cons_only) {
336  (*physbcs_u[lev])(*mfs_vel[Vars::xvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
337  ngvect_vels,time,BCVars::xvel_bc, do_fb);
338  (*physbcs_v[lev])(*mfs_vel[Vars::yvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
339  ngvect_vels,time,BCVars::yvel_bc, do_fb);
340  (*physbcs_w[lev])(*mfs_vel[Vars::zvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
341  ngvect_vels,time,BCVars::zvel_bc, do_fb);
342  }
343  // ***************************************************************************
344 
345  // We always come in to this call with momenta so we need to leave with momenta!
346  // We need to make sure we convert back on all ghost cells/faces because this is
347  // how velocity from fine-fine copies (as well as physical and interpolated bcs) will be filled
348  if (!cons_only)
349  {
350  IntVect ngu = (!solverChoice.use_num_diff) ? IntVect(1,1,1) : mfs_vel[Vars::xvel]->nGrowVect();
351  IntVect ngv = (!solverChoice.use_num_diff) ? IntVect(1,1,1) : mfs_vel[Vars::yvel]->nGrowVect();
352  IntVect ngw = (!solverChoice.use_num_diff) ? IntVect(1,1,0) : mfs_vel[Vars::zvel]->nGrowVect();
353 
354  const MultiFab* c_vfrac = nullptr;
355  if (solverChoice.terrain_type == TerrainType::EB) {
356  c_vfrac = &((get_eb(lev).get_const_factory())->getVolFrac());
357  }
358 
359  VelocityToMomentum(*mfs_vel[Vars::xvel], ngu,
360  *mfs_vel[Vars::yvel], ngv,
361  *mfs_vel[Vars::zvel], ngw,
362  *mfs_vel[Vars::cons],
363  *mfs_mom[IntVars::xmom], *mfs_mom[IntVars::ymom], *mfs_mom[IntVars::zmom],
364  Geom(lev).Domain(),
365  domain_bcs_type, c_vfrac);
366  }
367 
368  // NOTE: There are not FillBoundary calls here for the following reasons:
369  // Removal of the FillBoundary (FB) calls has bee completed for the following reasons:
370  //
371  // one physbc_cons is called before VelocityToMomentum and a FB is completed in that functor.
372  // Therefore, the conserved CC vars have their inter-rank ghost cells filled and then their
373  // domain ghost cells filled from the BC operations. We should not call FB on this MF again.
374  //
375  // two physbc_u/v/w is also called before VelocityToMomentum and a FB is completed those functors.
376  // Furthermore, VelocityToMomentum operates on a growntilebox so we exit that routine with momentum
377  // filled everywhere---i.e., physbc_u/v/w fills velocity ghost cells (inter-rank and domain)
378  // and then V2M does the conversion to momenta everywhere; so there is again no need to do a FB on momenta.
379 }
AMREX_GPU_HOST AMREX_FORCE_INLINE void ApplyMask(amrex::MultiFab &dst, const amrex::iMultiFab &imask, const int nghost=0)
Definition: ERF_Utils.H:315
void fill_from_bndryregs(const amrex::Vector< amrex::MultiFab * > &mfs, amrex::Real time)
Definition: ERF_BoundaryConditionsBndryReg.cpp:13
void FillIntermediatePatch(int lev, amrex::Real time, const amrex::Vector< amrex::MultiFab * > &mfs_vel, const amrex::Vector< amrex::MultiFab * > &mfs_mom, int ng_cons, int ng_vel, bool cons_only, int icomp_cons, int ncomp_cons)
Definition: ERF_FillIntermediatePatch.cpp:28
@ NumTypes
Definition: ERF_IndexDefines.H:196
Here is the call graph for this function:

◆ FillPatchCrseLevel()

void ERF::FillPatchCrseLevel ( int  lev,
double  time,
const amrex::Vector< amrex::MultiFab * > &  mfs_vel,
bool  cons_only = false 
)
private
293 {
294  BL_PROFILE_VAR("ERF::FillPatchCrseLevel()",ERF_FillPatchCrseLevel);
295 
296  AMREX_ALWAYS_ASSERT(lev == 0);
297 
298  Real time = static_cast<Real>(time_d);
299 
300  IntVect ngvect_cons = mfs_vel[Vars::cons]->nGrowVect();
301  IntVect ngvect_vels = mfs_vel[Vars::xvel]->nGrowVect();
302 
303  Vector<Real> ftime = {t_old[lev], t_new[lev]};
304 
305  //
306  // Below we call FillPatchSingleLevel which does NOT fill ghost cells outside the domain
307  //
308 
309  Vector<MultiFab*> fmf;
310  Vector<MultiFab*> fmf_u;
311  Vector<MultiFab*> fmf_v;
312  Vector<MultiFab*> fmf_w;
313 
314  if (amrex::almostEqual(time,ftime[0])) {
315  fmf = {&vars_old[lev][Vars::cons], &vars_old[lev][Vars::cons]};
316  } else if (amrex::almostEqual(time,ftime[1])) {
317  fmf = {&vars_new[lev][Vars::cons], &vars_new[lev][Vars::cons]};
318  } else {
319  fmf = {&vars_old[lev][Vars::cons], &vars_new[lev][Vars::cons]};
320  }
321 
322  const int ncomp = mfs_vel[Vars::cons]->nComp();
323 
324  FillPatchSingleLevel(*mfs_vel[Vars::cons], ngvect_cons, time, fmf, IntVect(0,0,0), ftime,
325  0, 0, ncomp, geom[lev]);
326 
327  if (!cons_only) {
328  if (amrex::almostEqual(time,ftime[0])) {
329  fmf_u = {&vars_old[lev][Vars::xvel], &vars_old[lev][Vars::xvel]};
330  fmf_v = {&vars_old[lev][Vars::yvel], &vars_old[lev][Vars::yvel]};
331  fmf_w = {&vars_old[lev][Vars::zvel], &vars_old[lev][Vars::zvel]};
332  } else if (amrex::almostEqual(time,ftime[1])) {
333  fmf_u = {&vars_new[lev][Vars::xvel], &vars_new[lev][Vars::xvel]};
334  fmf_v = {&vars_new[lev][Vars::yvel], &vars_new[lev][Vars::yvel]};
335  fmf_w = {&vars_new[lev][Vars::zvel], &vars_new[lev][Vars::zvel]};
336  } else {
337  fmf_u = {&vars_old[lev][Vars::xvel], &vars_new[lev][Vars::xvel]};
338  fmf_v = {&vars_old[lev][Vars::yvel], &vars_new[lev][Vars::yvel]};
339  fmf_w = {&vars_old[lev][Vars::zvel], &vars_new[lev][Vars::zvel]};
340  }
341  FillPatchSingleLevel(*mfs_vel[Vars::xvel], ngvect_vels, time, fmf_u,
342  IntVect(0,0,0), ftime, 0, 0, 1, geom[lev]);
343 
344  FillPatchSingleLevel(*mfs_vel[Vars::yvel], ngvect_vels, time, fmf_v,
345  IntVect(0,0,0), ftime, 0, 0, 1, geom[lev]);
346 
347  FillPatchSingleLevel(*mfs_vel[Vars::zvel], ngvect_vels, time, fmf_w,
348  IntVect(0,0,0), ftime, 0, 0, 1, geom[lev]);
349  } // !cons_only
350 
351  // ***************************************************************************
352  // Physical bc's at domain boundary
353  // ***************************************************************************
354  int icomp_cons = 0;
355  int ncomp_cons = mfs_vel[Vars::cons]->nComp();
356 
357  bool do_fb = true;
358 
359 #ifdef ERF_USE_NETCDF
360  if(solverChoice.use_real_bcs && (lev==0)) {
361  fill_from_realbdy(mfs_vel,time,cons_only,icomp_cons,ncomp_cons,ngvect_cons,ngvect_vels);
362  do_fb = false;
363  }
364 #endif
365 
366  if (m_r2d && !solverChoice.use_real_bcs) { fill_from_bndryregs(mfs_vel,time); }
367 
368  // We call this even if use_real_bcs is true because these will fill the vertical bcs
369  // Note that we call FillBoundary inside the physbcs call
370  (*physbcs_cons[lev])(*mfs_vel[Vars::cons],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
371  icomp_cons,ncomp_cons,ngvect_cons,time,BCVars::cons_bc, do_fb);
372  if (!cons_only) {
373  (*physbcs_u[lev])(*mfs_vel[Vars::xvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
374  ngvect_vels,time,BCVars::xvel_bc, do_fb);
375  (*physbcs_v[lev])(*mfs_vel[Vars::yvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
376  ngvect_vels,time,BCVars::yvel_bc, do_fb);
377  (*physbcs_w[lev])(*mfs_vel[Vars::zvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
378  ngvect_vels,time,BCVars::zvel_bc, do_fb);
379  }
380 }
Here is the call graph for this function:

◆ FillPatchFineLevel()

void ERF::FillPatchFineLevel ( int  lev,
double  time,
const amrex::Vector< amrex::MultiFab * > &  mfs_vel,
const amrex::Vector< amrex::MultiFab * > &  mfs_mom,
const amrex::MultiFab &  old_base_state,
const amrex::MultiFab &  new_base_state,
bool  fillset = true,
bool  cons_only = false 
)
private
26 {
27  BL_PROFILE_VAR("ERF::FillPatchFineLevel()",ERF_FillPatchFineLevel);
28 
29  AMREX_ALWAYS_ASSERT(lev > 0);
30 
31  Real time = static_cast<Real>(time_d);
32 
33  Interpolater* mapper = nullptr;
34 
35  PhysBCFunctNoOp null_bc;
36 
37  //
38  // ***************************************************************************
39  // The first thing we do is interpolate the momenta on the "valid" faces of
40  // the fine grids (where the interface is coarse/fine not fine/fine) -- this
41  // will not be over-written below because the FillPatch operators see these as
42  // valid faces.
43  //
44  // Note that we interpolate momentum not velocity, but all the other boundary
45  // conditions are imposed on velocity, so we convert to momentum here then
46  // convert back.
47  // ***************************************************************************
48  if (fillset) {
49  if (cf_set_width > 0) {
50  FPr_c[lev-1].FillSet(*mfs_vel[Vars::cons], time, null_bc, domain_bcs_type);
51  }
52  if (cf_set_width >= 0 && !cons_only) {
53 
54  const MultiFab* c_vfrac = nullptr;
55  if (solverChoice.terrain_type == TerrainType::EB) {
56  c_vfrac = &((get_eb(lev).get_const_factory())->getVolFrac());
57  }
58 
59  VelocityToMomentum(*mfs_vel[Vars::xvel], IntVect{0},
60  *mfs_vel[Vars::yvel], IntVect{0},
61  *mfs_vel[Vars::zvel], IntVect{0},
62  *mfs_vel[Vars::cons],
63  *mfs_mom[IntVars::xmom],
64  *mfs_mom[IntVars::ymom],
65  *mfs_mom[IntVars::zmom],
66  Geom(lev).Domain(),
67  domain_bcs_type, c_vfrac);
68 
69  FPr_u[lev-1].FillSet(*mfs_mom[IntVars::xmom], time, null_bc, domain_bcs_type);
70  FPr_v[lev-1].FillSet(*mfs_mom[IntVars::ymom], time, null_bc, domain_bcs_type);
71  FPr_w[lev-1].FillSet(*mfs_mom[IntVars::zmom], time, null_bc, domain_bcs_type);
72 
73  MomentumToVelocity(*mfs_vel[Vars::xvel], *mfs_vel[Vars::yvel], *mfs_vel[Vars::zvel],
74  *mfs_vel[Vars::cons],
75  *mfs_mom[IntVars::xmom],
76  *mfs_mom[IntVars::ymom],
77  *mfs_mom[IntVars::zmom],
78  Geom(lev).Domain(),
79  domain_bcs_type, c_vfrac);
80  }
81  }
82 
83  IntVect ngvect_cons = mfs_vel[Vars::cons]->nGrowVect();
84  IntVect ngvect_vels = mfs_vel[Vars::xvel]->nGrowVect();
85 
86  Vector<Real> ftime = {t_old[lev ], t_new[lev ]};
87  Vector<Real> ctime = {t_old[lev-1], t_new[lev-1]};
88 
89  amrex::Real small_dt = Real(1.e-8) * (ftime[1] - ftime[0]);
90 
91  Vector<MultiFab*> fmf;
92  if ( amrex::almostEqual(time,ftime[0]) || (time-ftime[0]) < small_dt ) {
93  fmf = {&vars_old[lev][Vars::cons], &vars_old[lev][Vars::cons]};
94  } else if (amrex::almostEqual(time,ftime[1])) {
95  fmf = {&vars_new[lev][Vars::cons], &vars_new[lev][Vars::cons]};
96  } else {
97  fmf = {&vars_old[lev][Vars::cons], &vars_new[lev][Vars::cons]};
98  }
99  Vector<MultiFab*> cmf = {&vars_old[lev-1][Vars::cons], &vars_new[lev-1][Vars::cons]};
100 
101  // We must fill a temporary then copy it back so we don't double add/subtract
102  MultiFab mf_c(mfs_vel[Vars::cons]->boxArray(),mfs_vel[Vars::cons]->DistributionMap(),
103  mfs_vel[Vars::cons]->nComp() ,mfs_vel[Vars::cons]->nGrowVect());
104 
105  mapper = &cell_cons_interp;
106 
107  if (interpolation_type == StateInterpType::Perturbational)
108  {
109  // Divide (rho theta) by rho to get theta (before we subtract rho0 from rho!)
110  if (!amrex::almostEqual(time,ctime[1])) {
111  MultiFab::Divide(vars_old[lev-1][Vars::cons],vars_old[lev-1][Vars::cons],
112  Rho_comp,RhoTheta_comp,1,ngvect_cons);
113  MultiFab::Subtract(vars_old[lev-1][Vars::cons],base_state[lev-1],
114  BaseState::r0_comp,Rho_comp,1,ngvect_cons);
115  MultiFab::Subtract(vars_old[lev-1][Vars::cons],base_state[lev-1],
116  BaseState::th0_comp,RhoTheta_comp,1,ngvect_cons);
117  }
118  if (!amrex::almostEqual(time,ctime[0])) {
119  MultiFab::Divide(vars_new[lev-1][Vars::cons],vars_new[lev-1][Vars::cons],
120  Rho_comp,RhoTheta_comp,1,ngvect_cons);
121  MultiFab::Subtract(vars_new[lev-1][Vars::cons],base_state[lev-1],
122  BaseState::r0_comp,Rho_comp,1,ngvect_cons);
123  MultiFab::Subtract(vars_new[lev-1][Vars::cons],base_state[lev-1],
124  BaseState::th0_comp,RhoTheta_comp,1,ngvect_cons);
125  }
126 
127  if (!amrex::almostEqual(time,ftime[1])) {
128  MultiFab::Divide(vars_old[lev ][Vars::cons],vars_old[lev ][Vars::cons],
129  Rho_comp,RhoTheta_comp,1,IntVect{0});
130  MultiFab::Subtract(vars_old[lev ][Vars::cons],old_base_state,
131  BaseState::r0_comp,Rho_comp,1,IntVect{0});
132  MultiFab::Subtract(vars_old[lev ][Vars::cons],old_base_state,
133  BaseState::th0_comp,RhoTheta_comp,1,IntVect{0});
134  }
135  if (!amrex::almostEqual(time,ftime[0])) {
136  MultiFab::Divide(vars_new[lev ][Vars::cons],vars_new[lev ][Vars::cons],
137  Rho_comp,RhoTheta_comp,1,IntVect{0});
138  MultiFab::Subtract(vars_new[lev ][Vars::cons],old_base_state,
139  BaseState::r0_comp,Rho_comp,1,IntVect{0});
140  MultiFab::Subtract(vars_new[lev ][Vars::cons],old_base_state,
141  BaseState::th0_comp,RhoTheta_comp,1,IntVect{0});
142  }
143  }
144 
145  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
146  FillPatchTwoLevels(mf_c, ngvect_cons, IntVect(0,0,0),
147  time, cmf, ctime, fmf, ftime,
148  0, 0, mf_c.nComp(), geom[lev-1], geom[lev],
149  refRatio(lev-1), mapper, domain_bcs_type,
151 
152  if (interpolation_type == StateInterpType::Perturbational)
153  {
154  // Restore the coarse values to what they were
155  if (!amrex::almostEqual(time,ctime[1])) {
156  MultiFab::Add(vars_old[lev-1][Vars::cons], base_state[lev-1],
157  BaseState::r0_comp,Rho_comp,1,ngvect_cons);
158  MultiFab::Add(vars_old[lev-1][Vars::cons], base_state[lev-1],
159  BaseState::th0_comp,RhoTheta_comp,1,ngvect_cons);
160  MultiFab::Multiply(vars_old[lev-1][Vars::cons], vars_old[lev-1][Vars::cons],
161  Rho_comp,RhoTheta_comp,1,ngvect_cons);
162  }
163  if (!amrex::almostEqual(time,ctime[0])) {
164  MultiFab::Add(vars_new[lev-1][Vars::cons], base_state[lev-1],
165  BaseState::r0_comp,Rho_comp,1,vars_new[lev-1][Vars::cons].nGrowVect());
166  MultiFab::Add(vars_new[lev-1][Vars::cons], base_state[lev-1],
167  BaseState::th0_comp,RhoTheta_comp,1,vars_new[lev-1][Vars::cons].nGrowVect());
168  MultiFab::Multiply(vars_new[lev-1][Vars::cons], vars_new[lev-1][Vars::cons],
169  Rho_comp,RhoTheta_comp,1,ngvect_cons);
170  }
171 
172  if (!amrex::almostEqual(time,ftime[1])) {
173  MultiFab::Add(vars_old[lev][Vars::cons],base_state[lev ],BaseState::r0_comp,Rho_comp,1,ngvect_cons);
174  MultiFab::Add(vars_old[lev][Vars::cons],base_state[lev ],BaseState::th0_comp,RhoTheta_comp,1,ngvect_cons);
175  MultiFab::Multiply(vars_old[lev][Vars::cons], vars_old[lev][Vars::cons],
176  Rho_comp,RhoTheta_comp,1,ngvect_cons);
177  }
178  if (!amrex::almostEqual(time,ftime[0])) {
179  MultiFab::Add(vars_new[lev][Vars::cons], base_state[lev],BaseState::r0_comp,Rho_comp,1,ngvect_cons);
180  MultiFab::Add(vars_new[lev][Vars::cons], base_state[lev],BaseState::th0_comp,RhoTheta_comp,1,ngvect_cons);
181  MultiFab::Multiply(vars_new[lev][Vars::cons], vars_new[lev][Vars::cons],
182  Rho_comp,RhoTheta_comp,1,ngvect_cons);
183  }
184 
185  // Set values in the cells outside the domain boundary so that we can do the Add
186  // without worrying about uninitialized values outside the domain -- these
187  // will be filled in the physbcs call
188  mf_c.setDomainBndry(Real(1.234e20),0,2,geom[lev]); // Do both rho and (rho theta) together
189 
190  // Add rho_0 back to rho and theta_0 back to theta
191  MultiFab::Add(mf_c, new_base_state,BaseState::r0_comp,Rho_comp,1,ngvect_cons);
192  MultiFab::Add(mf_c, new_base_state,BaseState::th0_comp,RhoTheta_comp,1,ngvect_cons);
193 
194  // Multiply (theta) by rho to get (rho theta)
195  MultiFab::Multiply(mf_c,mf_c,Rho_comp,RhoTheta_comp,1,ngvect_cons);
196  }
197 
198  MultiFab::Copy(*mfs_vel[Vars::cons],mf_c,0,0,mf_c.nComp(),mf_c.nGrowVect());
199 
200  // ***************************************************************************************
201 
202  if (!cons_only)
203  {
204  mapper = &face_cons_linear_interp;
205 
206  MultiFab& mf_u = *mfs_vel[Vars::xvel];
207  MultiFab& mf_v = *mfs_vel[Vars::yvel];
208  MultiFab& mf_w = *mfs_vel[Vars::zvel];
209 
210  Vector<MultiFab*> fmf_u; Vector<MultiFab*> fmf_v; Vector<MultiFab*> fmf_w;
211  Vector<MultiFab*> cmf_u; Vector<MultiFab*> cmf_v; Vector<MultiFab*> cmf_w;
212 
213  // **********************************************************************
214 
215  if ( amrex::almostEqual(time,ftime[0]) || (time-ftime[0]) < small_dt ) {
216  fmf_u = {&vars_old[lev][Vars::xvel], &vars_old[lev][Vars::xvel]};
217  fmf_v = {&vars_old[lev][Vars::yvel], &vars_old[lev][Vars::yvel]};
218  fmf_w = {&vars_old[lev][Vars::zvel], &vars_old[lev][Vars::zvel]};
219  } else if ( amrex::almostEqual(time,ftime[1]) ) {
220  fmf_u = {&vars_new[lev][Vars::xvel], &vars_new[lev][Vars::xvel]};
221  fmf_v = {&vars_new[lev][Vars::yvel], &vars_new[lev][Vars::yvel]};
222  fmf_w = {&vars_new[lev][Vars::zvel], &vars_new[lev][Vars::zvel]};
223  } else {
224  fmf_u = {&vars_old[lev][Vars::xvel], &vars_new[lev][Vars::xvel]};
225  fmf_v = {&vars_old[lev][Vars::yvel], &vars_new[lev][Vars::yvel]};
226  fmf_w = {&vars_old[lev][Vars::zvel], &vars_new[lev][Vars::zvel]};
227  }
228  cmf_u = {&vars_old[lev-1][Vars::xvel], &vars_new[lev-1][Vars::xvel]};
229  cmf_v = {&vars_old[lev-1][Vars::yvel], &vars_new[lev-1][Vars::yvel]};
230  cmf_w = {&vars_old[lev-1][Vars::zvel], &vars_new[lev-1][Vars::zvel]};
231 
232  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
233  FillPatchTwoLevels(mf_u, ngvect_vels, IntVect(0,0,0),
234  time, cmf_u, ctime, fmf_u, ftime,
235  0, 0, 1, geom[lev-1], geom[lev],
236  refRatio(lev-1), mapper, domain_bcs_type,
238 
239  FillPatchTwoLevels(mf_v, ngvect_vels, IntVect(0,0,0),
240  time, cmf_v, ctime, fmf_v, ftime,
241  0, 0, 1, geom[lev-1], geom[lev],
242  refRatio(lev-1), mapper, domain_bcs_type,
244 
245  // We put these here because these may be used in constructing omega outside the
246  // domain when fillpatching w
247  bool do_fb = true;
248  (*physbcs_u[lev])(*mfs_vel[Vars::xvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
249  ngvect_vels,time,BCVars::xvel_bc, do_fb);
250  (*physbcs_v[lev])(*mfs_vel[Vars::yvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
251  ngvect_vels,time,BCVars::yvel_bc, do_fb);
252 
253  // **********************************************************************
254 
255  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
256  FillPatchTwoLevels(mf_w, ngvect_vels, IntVect(0,0,0),
257  time, cmf_w, ctime, fmf_w, ftime,
258  0, 0, 1, geom[lev-1], geom[lev],
259  refRatio(lev-1), mapper, domain_bcs_type,
261  } // !cons_only
262 
263  // ***************************************************************************
264  // Physical bc's at domain boundary
265  // ***************************************************************************
266  int icomp_cons = 0;
267  int ncomp_cons = mfs_vel[Vars::cons]->nComp();
268 
269  bool do_fb = true;
270 
271  if (m_r2d && !solverChoice.use_real_bcs) fill_from_bndryregs(mfs_vel,time);
272 
273  // We call this even if use_real_bcs is true because these will fill the vertical bcs
274  // Note that we call FillBoundary inside the physbcs call
275  (*physbcs_cons[lev])(*mfs_vel[Vars::cons],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
276  icomp_cons,ncomp_cons,ngvect_cons,time,BCVars::cons_bc, do_fb);
277  if (!cons_only) {
278  // Note that we need to fill u and v in the case of terrain because we will use
279  // these in the call of WFromOmega in lateral ghost cells of the fine grid
280  // (*physbcs_u[lev])(*mfs_vel[Vars::xvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
281  // ngvect_vels,time,BCVars::xvel_bc, do_fb);
282  // (*physbcs_v[lev])(*mfs_vel[Vars::yvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
283  // ngvect_vels,time,BCVars::yvel_bc, do_fb);
284  (*physbcs_w[lev])(*mfs_vel[Vars::zvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
285  ngvect_vels,time,BCVars::zvel_bc, do_fb);
286  }
287 }
Here is the call graph for this function:

◆ FillSurfaceStateMultiFabs()

void ERF::FillSurfaceStateMultiFabs ( const int  lev,
const std::string &  filename,
amrex::Vector< amrex::MultiFab > &  surface_state 
)
22 {
23  // Open the binary file in input mode
24  std::ifstream infile(filename, std::ios::binary);
25  if (!infile) {
26  std::cerr << "Error: Could not open file " << filename << std::endl;
27  }
28  Vector<Real> xvec_h, yvec_h, zvec_h;
29  Vector<Real> sst_h, q_star_h, t_star_h, u_star_h, ls_mask_h;
30 
31  int nx, ny, nz, ndata;
32  float value;
33 
34  // Read the four integers
35  infile.read(reinterpret_cast<char*>(&nx), sizeof(int));
36  infile.read(reinterpret_cast<char*>(&ny), sizeof(int));
37  infile.read(reinterpret_cast<char*>(&nz), sizeof(int));
38  infile.read(reinterpret_cast<char*>(&ndata), sizeof(int));
39 
40  amrex::Gpu::DeviceVector<Real> xvec_d(nx*ny*nz), yvec_d(nx*ny*nz), zvec_d(nz);
41  for(int i=0; i<nx; i++) {
42  infile.read(reinterpret_cast<char*>(&value), sizeof(float));
43  xvec_h.emplace_back(value);
44  }
45  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, xvec_h.begin(), xvec_h.end(), xvec_d.begin());
46 
47  for(int j=0; j<ny; j++) {
48  infile.read(reinterpret_cast<char*>(&value), sizeof(float));
49  yvec_h.emplace_back(value);
50  }
51  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, yvec_h.begin(), yvec_h.end(), yvec_d.begin());
52 
53  for(int k=0; k<nz; k++) {
54  infile.read(reinterpret_cast<char*>(&value), sizeof(float));
55  zvec_h.emplace_back(value);
56  }
57  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, zvec_h.begin(), zvec_h.end(), zvec_d.begin());
58 
59  // Vector to store the data
60 
61  Vector<Real>* data_h = nullptr; // Declare pointer outside the loop
62 
63  Real* xvec_d_ptr = xvec_d.data();
64  Real* yvec_d_ptr = yvec_d.data();
65 
66  Real dxvec = (xvec_h[nx-1]-xvec_h[0])/(nx-1);
67  Real dyvec = (yvec_h[ny-1]-yvec_h[0])/(ny-1);
68 
69  // Read the file
70  for(int idx=0; idx<ndata; idx++){
71  if(idx == 0){
72  data_h = &sst_h;
73  } else if (idx==1) {
74  data_h = &q_star_h;
75  } else if (idx==2) {
76  data_h = &t_star_h;
77  } else if (idx==3) {
78  data_h = &u_star_h;
79  } else if(idx==4) {
80  data_h = &ls_mask_h;
81  }
82  for(int k=0; k<nz; k++) {
83  for(int j=0; j<ny; j++) {
84  for(int i=0; i<nx; i++) {
85  infile.read(reinterpret_cast<char*>(&value), sizeof(float));
86  //if(idx == 3) {
87  //printf("theta is %0.15g, %0.15g, %0.15g %0.15g\n", xvec_h[i], yvec_h[j], zvec_h[k], value);
88  //}
89  data_h->emplace_back(value);
90  }
91  }
92  }
93  }
94 
95  infile.close();
96 
97  amrex::Gpu::DeviceVector<Real> ls_mask_d(nx*ny*nz), sst_d(nx*ny*nz);
98 
99  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, ls_mask_h.begin(), ls_mask_h.end(), ls_mask_d.begin());
100  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, sst_h.begin(), sst_h.end(), sst_d.begin());
101 
102  Real* ls_mask_d_ptr = ls_mask_d.data();
103  Real* sst_d_ptr = sst_d.data();
104 
105  const auto prob_lo = geom[lev].ProbLo();
106  const auto dx = geom[lev].CellSize();
107 
108  for (amrex::MFIter mfi(surface_state[lev]); mfi.isValid(); ++mfi) {
109  const Box gbx = mfi.growntilebox();
110  const Array4<Real>& surf_arr = surface_state[lev].array(mfi);
111 
112  ParallelFor(gbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
113 
114  if(k == 0) {
115  const Real x = prob_lo[0] + (i + myhalf) * dx[0];
116  const Real y = prob_lo[1] + (j + myhalf) * dx[1];
117 
118  // First interpolate where the weather data is available from
119  Real tmp_ls_mask, tmp_sst;
120 
121  bilinear_interpolation_2d(xvec_d_ptr, yvec_d_ptr,
122  dxvec, dyvec,
123  nx, ny,
124  x, y,
125  ls_mask_d_ptr, tmp_ls_mask);
126 
127  bilinear_interpolation_2d(xvec_d_ptr, yvec_d_ptr,
128  dxvec, dyvec,
129  nx, ny,
130  x, y,
131  sst_d_ptr, tmp_sst);
132 
133  surf_arr(i, j, 0) = std::min(tmp_ls_mask, amrex::Real(1.0));
134  surf_arr(i, j, 1) = tmp_sst;
135  }
136  });
137  }
138 
139 }
amrex::Real value
Definition: ERF_HurricaneDiagnostics.H:20
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE int idx(int i, int j, int k, int nx, int ny)
Definition: ERF_InitForEnsemble.cpp:287
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE void bilinear_interpolation_2d(const amrex::Real *xvec, const amrex::Real *yvec, const amrex::Real dxvec, const amrex::Real dyvec, const int nx, const int ny, amrex::Real x, amrex::Real y, const amrex::Real *varvec, amrex::Real &tmp_var)
Definition: ERF_Interpolation_Bilinear.H:156
Here is the call graph for this function:

◆ FindInitialEye()

bool ERF::FindInitialEye ( int  lev,
const amrex::MultiFab &  cc_vel,
const amrex::Real  velmag_threshold,
amrex::Real eye_x,
amrex::Real eye_y 
)
884 {
885  const auto dx = geom[levc].CellSizeArray();
886  const auto prob_lo = geom[levc].ProbLoArray();
887 
888  Gpu::DeviceVector<Real> d_coords(2, zero);
889  Gpu::DeviceVector<int> d_found(1,0);
890 
891  Real* d_coords_ptr = d_coords.data();
892  int* d_found_ptr = d_found.data();
893 
894  for (MFIter mfi(mf_cc_vel); mfi.isValid(); ++mfi)
895  {
896  const Box& box = mfi.validbox();
897  const Array4<const Real>& vel_arr = mf_cc_vel.const_array(mfi);
898 
899  ParallelFor(box, [=] AMREX_GPU_DEVICE(int i, int j, int k)
900  {
901  Real magnitude = std::sqrt(vel_arr(i,j,k,0) * vel_arr(i,j,k,0) +
902  vel_arr(i,j,k,1) * vel_arr(i,j,k,1) +
903  vel_arr(i,j,k,2) * vel_arr(i,j,k,2));
904 
905  magnitude *= Real(3.6);
906 
907  Real z = prob_lo[2] + (k + myhalf) * dx[2];
908 
909  // Check if magnitude exceeds threshold
910  if (z < Real(2000.) && magnitude > velmag_threshold) {
911  // Use atomic operations to set found flag and store coordinates
912  Gpu::Atomic::Add(&d_found_ptr[0], 1); // Mark as found
913 
914  Real x = prob_lo[0] + (i + myhalf) * dx[0];
915  Real y = prob_lo[1] + (j + myhalf) * dx[1];
916 
917  // Store coordinates
918  Gpu::Atomic::Add(&d_coords_ptr[0],x); // Store x index
919  Gpu::Atomic::Add(&d_coords_ptr[1],y); // Store x index
920  }
921  });
922  }
923 
924  // Synchronize to ensure all threads complete their execution
925  amrex::Gpu::streamSynchronize(); // Wait for all GPU threads to finish
926 
927  Vector<int> h_found(1,0);
928  Gpu::copy(Gpu::deviceToHost, d_found.begin(), d_found.end(), h_found.begin());
929  ParallelAllReduce::Sum(h_found.data(), h_found.size(), ParallelContext::CommunicatorAll());
930 
931  // Broadcast coordinates if found
932  if (h_found[0] > 0) {
933  Vector<Real> h_coords(2,-1e10);
934  Gpu::copy(Gpu::deviceToHost, d_coords.begin(), d_coords.end(), h_coords.begin());
935 
936  ParallelAllReduce::Sum(h_coords.data(), h_coords.size(), ParallelContext::CommunicatorAll());
937 
938  eye_x = h_coords[0]/h_found[0];
939  eye_y = h_coords[1]/h_found[0];
940 
941  } else {
942  // Random large negative numbers so we don't trigger refinement in this case
943  eye_x = -Real(1.e20);
944  eye_y = -Real(1.e20);
945  }
946 
947  return (h_found[0] > 0);
948 }
Here is the call graph for this function:

◆ get_eb()

eb_ const& ERF::get_eb ( int  lev) const
inlineprivatenoexcept
1670  {
1671  AMREX_ASSERT(lev >= 0 && lev < eb.size() && eb[lev] != nullptr);
1672  return *eb[lev];
1673  }

◆ getAdvFluxReg()

AMREX_FORCE_INLINE amrex::YAFluxRegister* ERF::getAdvFluxReg ( int  lev)
inlineprivate
1456  {
1457  return advflux_reg[lev];
1458  }

◆ getCPUTime()

static amrex::Real ERF::getCPUTime ( )
inlinestaticprivate
1548  {
1549  int numCores = amrex::ParallelDescriptor::NProcs();
1550 #ifdef _OPENMP
1551  numCores = numCores * omp_get_max_threads();
1552 #endif
1553 
1554  amrex::Real T =
1555  numCores * amrex::Real(amrex::ParallelDescriptor::second() - startCPUTime) +
1557 
1558  return T;
1559  }
Real T
Definition: ERF_InitCustomPert_Bubble.H:105
static amrex::Real previousCPUTimeUsed
Definition: ERF.H:1544
static amrex::Real startCPUTime
Definition: ERF.H:1543

◆ GotoNextLine()

void ERF::GotoNextLine ( std::istream &  is)
staticprivate

Utility to skip to next line in Header file input stream.

17 {
18  constexpr std::streamsize bl_ignore_max { 100000 };
19  is.ignore(bl_ignore_max, '\n');
20 }

◆ HurricaneTracker()

void ERF::HurricaneTracker ( int  lev,
amrex::Real  time,
const amrex::MultiFab &  cc_vel,
const amrex::Real  velmag_threshold,
amrex::TagBoxArray *  tags = nullptr 
)
985 {
986  bool is_found;
987 
988  Real eye_x, eye_y;
989 
990  if (time==zero) {
991  is_found = FindInitialEye(levc, mf_cc_vel, velmag_threshold, eye_x, eye_y);
992  } else {
993  is_found = true;
994  const auto& last = hurricane_eye_track_xy.back();
995  eye_x = last[0];
996  eye_y = last[1];
997  }
998 
999  if (is_found) {
1000  const int exponent = max_level-1-levc;
1001  Real rad_tag = std::ldexp(Real(4.e5), exponent);
1002  tag_on_distance_from_eye(geom[levc], tags, eye_x, eye_y, rad_tag);
1003  }
1004 }
amrex::Vector< std::array< amrex::Real, 2 > > hurricane_eye_track_xy
Definition: ERF.H:161
bool FindInitialEye(int lev, const amrex::MultiFab &cc_vel, const amrex::Real velmag_threshold, amrex::Real &eye_x, amrex::Real &eye_y)
Definition: ERF_Tagging.cpp:880
Here is the call graph for this function:

◆ ImposeBCsOnPhi()

void ERF::ImposeBCsOnPhi ( int  lev,
amrex::MultiFab &  phi,
const amrex::Box &  subdomain 
)

Impose bc's on the pressure that comes out of the solve

13 {
14  BL_PROFILE("ERF::ImposeBCsOnPhi()");
15 
16  auto const sub_lo = lbound(subdomain);
17  auto const sub_hi = ubound(subdomain);
18 
19  auto const dom_lo = lbound(geom[lev].Domain());
20  auto const dom_hi = ubound(geom[lev].Domain());
21 
22  phi.setBndry(Real(1.e25));
23  phi.FillBoundary(geom[lev].periodicity());
24 
25  // ****************************************************************************
26  // Impose bc's on pprime
27  // ****************************************************************************
28 #ifdef _OPENMP
29 #pragma omp parallel if (Gpu::notInLaunchRegion())
30 #endif
31  for (MFIter mfi(phi,TilingIfNotGPU()); mfi.isValid(); ++mfi)
32  {
33  Array4<Real> const& pp_arr = phi.array(mfi);
34  Box const& bx = mfi.tilebox();
35  auto const bx_lo = lbound(bx);
36  auto const bx_hi = ubound(bx);
37 
38  auto bc_type_xlo = domain_bc_type[Orientation(0,Orientation::low)];
39  auto bc_type_xhi = domain_bc_type[Orientation(0,Orientation::high)];
40  auto bc_type_ylo = domain_bc_type[Orientation(1,Orientation::low)];
41  auto bc_type_yhi = domain_bc_type[Orientation(1,Orientation::high)];
42  auto bc_type_zhi = domain_bc_type[Orientation(2,Orientation::high)];
43 
44  if ( (bx_lo.x == dom_lo.x) && (bc_type_xlo == "Outflow" || bc_type_xlo == "Open") && !solverChoice.use_real_bcs) {
45  ParallelFor(makeSlab(bx,0,dom_lo.x), [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
46  {
47  pp_arr(i-1,j,k) = -pp_arr(i,j,k);
48  });
49  } else if (bx_lo.x == sub_lo.x) {
50  ParallelFor(makeSlab(bx,0,sub_lo.x), [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
51  {
52  pp_arr(i-1,j,k) = pp_arr(i,j,k);
53  });
54  }
55 
56  if ( (bx_hi.x == dom_hi.x) && (bc_type_xhi == "Outflow" || bc_type_xhi == "Open") && !solverChoice.use_real_bcs) {
57  ParallelFor(makeSlab(bx,0,dom_hi.x), [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
58  {
59  pp_arr(i+1,j,k) = -pp_arr(i,j,k);
60  });
61  } else if (bx_hi.x == sub_hi.x) {
62  ParallelFor(makeSlab(bx,0,sub_hi.x), [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
63  {
64  pp_arr(i+1,j,k) = pp_arr(i,j,k);
65  });
66  }
67 
68  if ( (bx_lo.y == dom_lo.y) && (bc_type_ylo == "Outflow" || bc_type_ylo == "Open") && !solverChoice.use_real_bcs) {
69  ParallelFor(makeSlab(bx,1,dom_lo.y), [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
70  {
71  pp_arr(i,j-1,k) = -pp_arr(i,j,k);
72  });
73  } else if (bx_lo.y == sub_lo.y) {
74  ParallelFor(makeSlab(bx,1,sub_lo.y), [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
75  {
76  pp_arr(i,j-1,k) = pp_arr(i,j,k);
77  });
78  }
79 
80  if ( (bx_hi.y == dom_hi.y) && (bc_type_yhi == "Outflow" || bc_type_yhi == "Open") && !solverChoice.use_real_bcs) {
81  ParallelFor(makeSlab(bx,1,dom_hi.y), [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
82  {
83  pp_arr(i,j+1,k) = -pp_arr(i,j,k);
84  });
85  } else if (bx_hi.y == sub_hi.y) {
86  ParallelFor(makeSlab(bx,1,sub_hi.y), [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
87  {
88  pp_arr(i,j+1,k) = pp_arr(i,j,k);
89  });
90  }
91 
92  // At low z we are always Neumann whether the box touches the bottom boundary or not
93  Box zbx(bx); zbx.grow(0,1); zbx.grow(1,1); // Grow in x-dir and y-dir because we have filled that above
94  if (bx_lo.z == sub_lo.z) {
95  ParallelFor(makeSlab(zbx,2,dom_lo.z), [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
96  {
97  pp_arr(i,j,k-1) = pp_arr(i,j,k);
98  });
99  }
100 
101  if ( (bx_hi.z == dom_hi.z) && (bc_type_zhi == "Outflow" || bc_type_zhi == "Open") ) {
102  ParallelFor(makeSlab(bx,2,dom_hi.z), [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
103  {
104  pp_arr(i,j,k+1) = -pp_arr(i,j,k);
105  });
106  } else if (bx_hi.z == sub_hi.z) {
107  ParallelFor(makeSlab(bx,2,sub_hi.z), [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
108  {
109  pp_arr(i,j,k+1) = pp_arr(i,j,k);
110  });
111  }
112  } // mfi
113 
114  // Now overwrite with periodic fill outside domain and fine-fine fill inside
115  phi.FillBoundary(geom[lev].periodicity());
116 }
amrex::Array< std::string, 2 *AMREX_SPACEDIM > domain_bc_type
Definition: ERF.H:1023
Here is the call graph for this function:

◆ init1DArrays()

void ERF::init1DArrays ( )
private

◆ init_bcs()

void ERF::init_bcs ( )
private
296 {
297  bool rho_read = false;
298  bool read_prim_theta = true;
299 
300  init_phys_bcs(rho_read, read_prim_theta);
301 
302  Vector<Real> cons_dir_init(NBCVAR_max,zero);
303  cons_dir_init[BCVars::Rho_bc_comp] = one;
304  cons_dir_init[BCVars::RhoTheta_bc_comp] = -one;
305 
306  bool keqn_dir = (solverChoice.turbChoice[max_level].rans_type == RANSType::kEqn &&
307  solverChoice.turbChoice[max_level].dirichlet_k == true);
308  if (keqn_dir) {
309  // Need to change wall BC type, assume for now that all levels are RANS
310  for (int lev = 0; lev < max_level; ++lev) {
311  if (solverChoice.turbChoice[lev].rans_type != RANSType::kEqn) {
312  Error("If using one-eqn RANS, all levels must be RANS for now");
313  }
314  }
315  Print() << "Using dirichlet BC for k equation" << std::endl;
316  }
317 
318  // *****************************************************************************
319  //
320  // Here we translate the physical boundary conditions -- one type per face --
321  // into logical boundary conditions for each velocity component
322  //
323  // *****************************************************************************
324  {
325  domain_bcs_type.resize(AMREX_SPACEDIM+NBCVAR_max);
326  domain_bcs_type_d.resize(AMREX_SPACEDIM+NBCVAR_max);
327 
328  for (OrientationIter oit; oit; ++oit) {
329  Orientation ori = oit();
330  int dir = ori.coordDir();
331  Orientation::Side side = ori.faceDir();
332  auto const bct = phys_bc_type[ori];
333  if ( bct == ERF_BC::symmetry )
334  {
335  if (side == Orientation::low) {
336  for (int i = 0; i < AMREX_SPACEDIM; i++) {
338  }
340  } else {
341  for (int i = 0; i < AMREX_SPACEDIM; i++) {
343  }
345  }
346  }
347  else if (bct == ERF_BC::outflow or bct == ERF_BC::ho_outflow )
348  {
349  if (side == Orientation::low) {
350  for (int i = 0; i < AMREX_SPACEDIM; i++) {
352  }
353  if (!solverChoice.anelastic[0]) {
355  }
356  } else {
357  for (int i = 0; i < AMREX_SPACEDIM; i++) {
359  }
360  if (!solverChoice.anelastic[0]) {
362  }
363  }
364  }
365  else if (bct == ERF_BC::open)
366  {
367  if (side == Orientation::low) {
368  for (int i = 0; i < AMREX_SPACEDIM; i++)
370  } else {
371  for (int i = 0; i < AMREX_SPACEDIM; i++)
373  }
374  }
375  else if (bct == ERF_BC::inflow)
376  {
377  if (side == Orientation::low) {
378  for (int i = 0; i < AMREX_SPACEDIM; i++) {
380  if (input_bndry_planes && dir < 2 && m_r2d->ingested_velocity()) {
382  }
383  }
384  } else {
385  for (int i = 0; i < AMREX_SPACEDIM; i++) {
387  if (input_bndry_planes && dir < 2 && m_r2d->ingested_velocity()) {
389  }
390  }
391  }
392  }
393  else if (bct == ERF_BC::inflow_outflow)
394  {
395  if (side == Orientation::low) {
396  for (int i = 0; i < AMREX_SPACEDIM; i++) {
398  }
399  } else {
400  for (int i = 0; i < AMREX_SPACEDIM; i++) {
402  }
403  }
404  }
405  else if (bct == ERF_BC::no_slip_wall)
406  {
407  if (side == Orientation::low) {
408  for (int i = 0; i < AMREX_SPACEDIM; i++) {
410  }
411  } else {
412  for (int i = 0; i < AMREX_SPACEDIM; i++) {
414  }
415  }
416  }
417  else if (bct == ERF_BC::slip_wall)
418  {
419  if (side == Orientation::low) {
420  for (int i = 0; i < AMREX_SPACEDIM; i++) {
422  }
423  // Only normal direction has ext_dir
425 
426  } else {
427  for (int i = 0; i < AMREX_SPACEDIM; i++) {
429  }
430  // Only normal direction has ext_dir
432  }
433  }
434  else if (bct == ERF_BC::periodic)
435  {
436  if (side == Orientation::low) {
437  for (int i = 0; i < AMREX_SPACEDIM; i++) {
439  }
440  } else {
441  for (int i = 0; i < AMREX_SPACEDIM; i++) {
443  }
444  }
445  }
446  else if ( bct == ERF_BC::surface_layer )
447  {
448  AMREX_ALWAYS_ASSERT(dir == 2 && side == Orientation::low);
452  }
453  }
454  }
455 
456  // *****************************************************************************
457  //
458  // Here we translate the physical boundary conditions -- one type per face --
459  // into logical boundary conditions for each cell-centered variable
460  // (including the base state variables)
461  // NOTE: all "scalars" share the same type of boundary condition
462  //
463  // *****************************************************************************
464  {
465  for (OrientationIter oit; oit; ++oit) {
466  Orientation ori = oit();
467  int dir = ori.coordDir();
468  Orientation::Side side = ori.faceDir();
469  auto const bct = phys_bc_type[ori];
470  if ( bct == ERF_BC::symmetry )
471  {
472  if (side == Orientation::low) {
473  for (int i = 0; i < NBCVAR_max; i++) {
475  }
476  } else {
477  for (int i = 0; i < NBCVAR_max; i++) {
479  }
480  }
481  }
482  else if ( bct == ERF_BC::outflow )
483  {
484  if (side == Orientation::low) {
485  for (int i = 0; i < NBCVAR_max; i++) {
487  }
488  } else {
489  for (int i = 0; i < NBCVAR_max; i++) {
491  }
492  }
493  }
494  else if ( bct == ERF_BC::ho_outflow )
495  {
496  if (side == Orientation::low) {
497  for (int i = 0; i < NBCVAR_max; i++) {
499  }
500  } else {
501  for (int i = 0; i < NBCVAR_max; i++) {
503  }
504  }
505  }
506  else if ( bct == ERF_BC::open )
507  {
508  if (side == Orientation::low) {
509  for (int i = 0; i < NBCVAR_max; i++)
511  } else {
512  for (int i = 0; i < NBCVAR_max; i++)
514  }
515  }
516  else if ( bct == ERF_BC::no_slip_wall )
517  {
518  if (side == Orientation::low) {
519  for (int i = 0; i < NBCVAR_max; i++) {
521  if (m_bc_extdir_vals[BCVars::cons_bc+i][ori] != cons_dir_init[BCVars::cons_bc+i]) {
522  if (rho_read) {
524  } else {
526  }
527  }
528  }
529  if (std::abs(m_bc_neumann_vals[BCVars::RhoTheta_bc_comp][ori]) > zero) {
531  }
532  } else {
533  for (int i = 0; i < NBCVAR_max; i++) {
535  if (m_bc_extdir_vals[BCVars::cons_bc+i][ori] != cons_dir_init[BCVars::cons_bc+i]) {
536  if (rho_read) {
538  } else {
540  }
541  }
542  }
543  if (std::abs(m_bc_neumann_vals[BCVars::RhoTheta_bc_comp][ori]) > zero) {
545  }
546  }
547  }
548  else if (bct == ERF_BC::slip_wall)
549  {
550  if (side == Orientation::low) {
551  for (int i = 0; i < NBCVAR_max; i++) {
553  if (m_bc_extdir_vals[BCVars::cons_bc+i][ori] != cons_dir_init[BCVars::cons_bc+i]) {
554  if (rho_read) {
556  } else {
558  }
559  }
560  }
561  if (std::abs(m_bc_neumann_vals[BCVars::RhoTheta_bc_comp][ori]) > zero) {
563  }
564  if (std::abs(m_bc_neumann_vals[BCVars::Rho_bc_comp][ori]) > zero) {
566  }
567  } else {
568  for (int i = 0; i < NBCVAR_max; i++) {
570  if (m_bc_extdir_vals[BCVars::cons_bc+i][ori] != cons_dir_init[BCVars::cons_bc+i]) {
571  if (rho_read) {
573  } else {
575  }
576  }
577  }
578  if (std::abs(m_bc_neumann_vals[BCVars::RhoTheta_bc_comp][ori]) > zero) {
580  }
581  if (std::abs(m_bc_neumann_vals[BCVars::Rho_bc_comp][ori]) > zero) {
583  }
584  }
585  }
586  else if (bct == ERF_BC::inflow)
587  {
588  if (side == Orientation::low) {
589  for (int i = 0; i < NBCVAR_max; i++) {
591  if ((BCVars::cons_bc+i == RhoTheta_comp) &&
592  (th_bc_data[0].data() != nullptr))
593  {
594  if (read_prim_theta) domain_bcs_type[BCVars::cons_bc+i].setLo(dir, ERFBCType::ext_dir_prim);
595  }
596  else if (input_bndry_planes && dir < 2 && (
597  ( (BCVars::cons_bc+i == BCVars::Rho_bc_comp) && m_r2d->ingested_density()) ||
598  ( (BCVars::cons_bc+i == BCVars::RhoTheta_bc_comp) && m_r2d->ingested_theta() ) ||
599  ( (BCVars::cons_bc+i == BCVars::RhoKE_bc_comp) && m_r2d->ingested_KE() ) ||
600  ( (BCVars::cons_bc+i == BCVars::RhoScalar_bc_comp) && m_r2d->ingested_scalar() ) ||
601  ( (BCVars::cons_bc+i == BCVars::RhoQ1_bc_comp) && m_r2d->ingested_q1() ) ||
602  ( (BCVars::cons_bc+i == BCVars::RhoQ2_bc_comp) && m_r2d->ingested_q2() )) )
603  {
605  }
606  else if (m_bc_extdir_vals[BCVars::Rho_bc_comp][ori] == 0) {
608  }
609  }
610  // Non-reflecting: extrapolate RhoTheta from interior so
611  // pressure is not prescribed, allowing acoustic waves out
612  if (m_bc_nonreflecting[ori]) {
614  }
615  } else {
616  for (int i = 0; i < NBCVAR_max; i++) {
618  if ((BCVars::cons_bc+i == RhoTheta_comp) &&
619  (th_bc_data[0].data() != nullptr))
620  {
621  if (read_prim_theta) domain_bcs_type[BCVars::cons_bc+i].setHi(dir, ERFBCType::ext_dir_prim);
622  }
623  else if (input_bndry_planes && dir < 2 && (
624  ( (BCVars::cons_bc+i == BCVars::Rho_bc_comp) && m_r2d->ingested_density()) ||
625  ( (BCVars::cons_bc+i == BCVars::RhoTheta_bc_comp) && m_r2d->ingested_theta() ) ||
626  ( (BCVars::cons_bc+i == BCVars::RhoKE_bc_comp) && m_r2d->ingested_KE() ) ||
627  ( (BCVars::cons_bc+i == BCVars::RhoScalar_bc_comp) && m_r2d->ingested_scalar() ) ||
628  ( (BCVars::cons_bc+i == BCVars::RhoQ1_bc_comp) && m_r2d->ingested_q1() ) ||
629  ( (BCVars::cons_bc+i == BCVars::RhoQ2_bc_comp) && m_r2d->ingested_q2() )
630  ) )
631  {
633  }
634  else if (m_bc_extdir_vals[BCVars::Rho_bc_comp][ori] == 0) {
636  }
637  }
638  // Non-reflecting: extrapolate RhoTheta from interior
639  if (m_bc_nonreflecting[ori]) {
641  }
642  }
643  }
644  else if (bct == ERF_BC::inflow_outflow )
645  {
646  if (side == Orientation::low) {
647  for (int i = 0; i < NBCVAR_max; i++) {
649  if (m_bc_extdir_vals[BCVars::Rho_bc_comp][ori] == 0) {
651  }
652  }
653  } else {
654  for (int i = 0; i < NBCVAR_max; i++) {
656  if (m_bc_extdir_vals[BCVars::Rho_bc_comp][ori] == 0) {
658  }
659  }
660  }
661  }
662  else if (bct == ERF_BC::periodic)
663  {
664  if (side == Orientation::low) {
665  for (int i = 0; i < NBCVAR_max; i++) {
667  }
668  } else {
669  for (int i = 0; i < NBCVAR_max; i++) {
671  }
672  }
673  }
674  else if ( bct == ERF_BC::surface_layer )
675  {
676  AMREX_ALWAYS_ASSERT(dir == 2 && side == Orientation::low);
677  for (int i = 0; i < NBCVAR_max; i++) {
679  }
680  if (keqn_dir) {
681  Print() << "Setting surface layer logical BC to dirichlet for RANS with k model" << std::endl;
683  }
684  }
685  }
686  }
687 
688  // NOTE: Gpu:copy is a wrapper to htod_memcpy (GPU) or memcpy (CPU) and is a blocking comm
689  Gpu::copy(Gpu::hostToDevice, domain_bcs_type.begin(), domain_bcs_type.end(), domain_bcs_type_d.begin());
690 }
#define NBCVAR_max
Definition: ERF_IndexDefines.H:29
@ ho_outflow
@ inflow_outflow
amrex::Array< bool, AMREX_SPACEDIM *2 > m_bc_nonreflecting
Definition: ERF.H:1032
void init_phys_bcs(bool &rho_read, bool &read_prim_theta)
Definition: ERF_InitBCs.cpp:20
amrex::Array< amrex::Array< amrex::Real, AMREX_SPACEDIM *2 >, AMREX_SPACEDIM+NBCVAR_max > m_bc_neumann_vals
Definition: ERF.H:1029
@ RhoQ1_bc_comp
Definition: ERF_IndexDefines.H:91
@ RhoKE_bc_comp
Definition: ERF_IndexDefines.H:89
@ RhoTheta_bc_comp
Definition: ERF_IndexDefines.H:88
@ RhoQ2_bc_comp
Definition: ERF_IndexDefines.H:92
@ Rho_bc_comp
Definition: ERF_IndexDefines.H:87
@ neumann
Definition: ERF_IndexDefines.H:248
@ open
Definition: ERF_IndexDefines.H:250
@ reflect_odd
Definition: ERF_IndexDefines.H:239
@ hoextrap
Definition: ERF_IndexDefines.H:244
@ foextrap
Definition: ERF_IndexDefines.H:242
@ ext_dir
Definition: ERF_IndexDefines.H:243
@ ext_dir_prim
Definition: ERF_IndexDefines.H:246
@ ext_dir_upwind
Definition: ERF_IndexDefines.H:251
@ int_dir
Definition: ERF_IndexDefines.H:240
@ neumann_int
Definition: ERF_IndexDefines.H:249
@ reflect_even
Definition: ERF_IndexDefines.H:241
Here is the call graph for this function:

◆ init_custom()

void ERF::init_custom ( int  lev)

Wrapper for custom problem-specific initialization routines that can be defined by the user as they set up a new problem in ERF. This wrapper handles all the overhead of defining the perturbation as well as initializing the random seed if needed.

This wrapper calls a user function to customize initialization on a per-Fab level inside an MFIter loop, so all the MultiFab operations are hidden from the user.

Parameters
levInteger specifying the current level
27 {
28  auto& lev_new = vars_new[lev];
29 
30  MultiFab r_hse(base_state[lev], make_alias, BaseState::r0_comp, 1);
31  MultiFab p_hse(base_state[lev], make_alias, BaseState::p0_comp, 1);
32 
33  MultiFab cons_pert(lev_new[Vars::cons].boxArray(), lev_new[Vars::cons].DistributionMap(),
34  lev_new[Vars::cons].nComp() , lev_new[Vars::cons].nGrow());
35  MultiFab xvel_pert(lev_new[Vars::xvel].boxArray(), lev_new[Vars::xvel].DistributionMap(), 1, lev_new[Vars::xvel].nGrowVect());
36  MultiFab yvel_pert(lev_new[Vars::yvel].boxArray(), lev_new[Vars::yvel].DistributionMap(), 1, lev_new[Vars::yvel].nGrowVect());
37  MultiFab zvel_pert(lev_new[Vars::zvel].boxArray(), lev_new[Vars::zvel].DistributionMap(), 1, lev_new[Vars::zvel].nGrowVect());
38 
39  // Default all perturbations to zero
40  cons_pert.setVal(0.);
41  xvel_pert.setVal(0.);
42  yvel_pert.setVal(0.);
43  zvel_pert.setVal(0.);
44 
45 
46 #ifdef _OPENMP
47 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
48 #endif
49  for (MFIter mfi(lev_new[Vars::cons], TileNoZ()); mfi.isValid(); ++mfi)
50  {
51  const Box &bx = mfi.tilebox();
52  const Box &xbx = mfi.tilebox(IntVect(1,0,0));
53  const Box &ybx = mfi.tilebox(IntVect(0,1,0));
54  const Box &zbx = mfi.tilebox(IntVect(0,0,1));
55 
56  const auto &cons_pert_arr = cons_pert.array(mfi);
57  const auto &xvel_pert_arr = xvel_pert.array(mfi);
58  const auto &yvel_pert_arr = yvel_pert.array(mfi);
59  const auto &zvel_pert_arr = zvel_pert.array(mfi);
60 
61  Array4<Real const> cons_arr = lev_new[Vars::cons].const_array(mfi);
62  Array4<Real const> z_nd_arr = (z_phys_nd[lev]) ? z_phys_nd[lev]->const_array(mfi) : Array4<Real const>{};
63  Array4<Real const> z_cc_arr = (z_phys_cc[lev]) ? z_phys_cc[lev]->const_array(mfi) : Array4<Real const>{};
64 
65  // Here we arbitrarily choose the x-oriented map factor -- this should be generalized
66  Array4<Real const> mf_m = mapfac[lev][MapFacType::m_x]->const_array(mfi);
67  Array4<Real const> mf_u = mapfac[lev][MapFacType::u_x]->const_array(mfi);
68  Array4<Real const> mf_v = mapfac[lev][MapFacType::v_y]->const_array(mfi);
69 
70  Array4<Real> r_hse_arr = r_hse.array(mfi);
71  Array4<Real> p_hse_arr = p_hse.array(mfi);
72 
73  prob->init_custom_pert(bx, cons_arr, cons_pert_arr,
74  r_hse_arr, p_hse_arr, z_nd_arr, z_cc_arr,
75  geom[lev].data(), mf_m, solverChoice, lev);
76  prob->init_custom_pert_vels(xbx, ybx, zbx,
77  xvel_pert_arr, yvel_pert_arr, zvel_pert_arr,
78  z_nd_arr, geom[lev].data(), mf_u, mf_v,
79  solverChoice, lev);
80 
81  // Zero out perturbations in covered cells in EB
82  if (solverChoice.terrain_type == TerrainType::EB) {
83 
84  Array4<const EBCellFlag> c_cellflg = (get_eb(lev).get_const_factory())->getMultiEBCellFlagFab()[mfi].const_array();
85  Array4<const EBCellFlag> u_cellflg = (get_eb(lev).get_u_const_factory())->getMultiEBCellFlagFab()[mfi].const_array();
86  Array4<const EBCellFlag> v_cellflg = (get_eb(lev).get_v_const_factory())->getMultiEBCellFlagFab()[mfi].const_array();
87  Array4<const EBCellFlag> w_cellflg = (get_eb(lev).get_w_const_factory())->getMultiEBCellFlagFab()[mfi].const_array();
88 
89  ParallelFor(bx,
90  [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
91  if (c_cellflg(i,j,k).isCovered()) {
92  cons_pert_arr(i,j,k,RhoTheta_comp) = 0.0;
93  }
94  });
95 
97  [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
98  if (u_cellflg(i,j,k).isCovered()) {
99  xvel_pert_arr(i,j,k) = 0.0;
100  }
101  },
102  [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
103  if (v_cellflg(i,j,k).isCovered()) {
104  yvel_pert_arr(i,j,k) = 0.0;
105  }
106  },
107  [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
108  if (w_cellflg(i,j,k).isCovered()) {
109  zvel_pert_arr(i,j,k) = 0.0;
110  }
111  });
112  }
113 
114  } //mfi
115 
116 
117  // Add problem-specific perturbation to background flow if not doing anelastic with fixed-in-time density
118  if (!solverChoice.fixed_density[lev]) {
119  MultiFab::Add(lev_new[Vars::cons], cons_pert, Rho_comp, Rho_comp, 1, cons_pert.nGrow());
120  }
121  MultiFab::Add(lev_new[Vars::cons], cons_pert, RhoTheta_comp, RhoTheta_comp, 1, cons_pert.nGrow());
122  MultiFab::Add(lev_new[Vars::cons], cons_pert, RhoScalar_comp,RhoScalar_comp,NSCALARS, cons_pert.nGrow());
123 
124  // RhoKE is relevant if using Deardorff with LES, k-equation for RANS, MYJ, SHOC, MYNN2.5 or MYNN-EDMF
125  // Here we initialize TKE to the tke_min value and then add problem-specific perturbations
126  if (solverChoice.turbChoice[lev].use_tke) {
127  lev_new[Vars::cons].setVal(solverChoice.turbChoice[lev].tke_min, RhoKE_comp, 1);
128  MultiFab::Multiply(lev_new[Vars::cons],lev_new[Vars::cons],Rho_comp,RhoKE_comp,1,lev_new[Vars::cons].nGrowVect());
129  MultiFab::Add(lev_new[Vars::cons], cons_pert, RhoKE_comp, RhoKE_comp, 1, cons_pert.nGrow());
130  }
131 
132  if (solverChoice.moisture_type != MoistureType::None) {
133  int qstate_size = micro->Get_Qstate_Size();
134  for (int q_offset(0); q_offset<qstate_size; ++q_offset) {
135  int q_idx = RhoQ1_comp+q_offset;
136  MultiFab::Add(lev_new[Vars::cons], cons_pert, q_idx, q_idx, 1, cons_pert.nGrow());
137  }
138  }
139 
140  // Should we initialize the velocities from a checkpoint file?
141  static std::string init_vels_from_checkpoint;
142  ParmParse pp("erf");
143  if (pp.query("init_vels_from_checkpoint",init_vels_from_checkpoint)) {
144  ReadVelsOnlyFromCheckpointFile(lev,init_vels_from_checkpoint);
145  } else {
146  MultiFab::Add(lev_new[Vars::xvel], xvel_pert, 0, 0, 1, xvel_pert.nGrowVect());
147  MultiFab::Add(lev_new[Vars::yvel], yvel_pert, 0, 0, 1, yvel_pert.nGrowVect());
148  MultiFab::Add(lev_new[Vars::zvel], zvel_pert, 0, 0, 1, zvel_pert.nGrowVect());
149  }
150 
151  // If initializing for ensemble simluations, then
152  // 1. Create cell-centered random perturbations
153  // 2. Create cell-centered spatially correlated perturbations
154  // 3. Read in the coarse background state from the coarse data file,
155  // interpolate the state data onto the current mesh, and
156  // add the perturbations to the background state and then populate the "pert variables
157 
159  MultiFab mf_cc_pert;
160  create_random_perturbations(lev, mf_cc_pert);
162  create_background_state_for_ensemble(lev, mf_cc_pert, lev_new[Vars::cons], lev_new[Vars::xvel], lev_new[Vars::yvel], lev_new[Vars::zvel]);
163  }
164 }
const Box xbx
Definition: ERF_SetupDiff.H:7
const Box ybx
Definition: ERF_SetupDiff.H:8
void create_background_state_for_ensemble(int lev, amrex::MultiFab &mf_cc_pert, amrex::MultiFab &cons_pert, amrex::MultiFab &xvel_pert, amrex::MultiFab &yvel_pert, amrex::MultiFab &zvel_pert)
Definition: ERF_InitForEnsemble.cpp:515
void apply_gaussian_smoothing_to_perturbations(const int lev, amrex::MultiFab &mf_cc_pert)
Definition: ERF_InitForEnsemble.cpp:86
void ReadVelsOnlyFromCheckpointFile(int lev_to_fill, std::string &chkfile)
Definition: ERF_Checkpoint.cpp:1088
void create_random_perturbations(const int lev, amrex::MultiFab &mf_cc_pert)
Definition: ERF_InitForEnsemble.cpp:14
eb_aux_ const * get_w_const_factory() const noexcept
Definition: ERF_EB.H:52
eb_aux_ const * get_v_const_factory() const noexcept
Definition: ERF_EB.H:51
eb_aux_ const * get_u_const_factory() const noexcept
Definition: ERF_EB.H:50
amrex::Vector< int > fixed_density
Definition: ERF_DataStruct.H:1142
bool is_init_for_ensemble
Definition: ERF_DataStruct.H:1341
Here is the call graph for this function:

◆ init_Dirichlet_bc_data()

void ERF::init_Dirichlet_bc_data ( const std::string  input_file)
private
693 {
694  // Read the dirichlet_input file
695  Print() << "dirichlet_input file location : " << input_file << std::endl;
696  std::ifstream input_reader(input_file);
697  if (!input_reader.is_open()) {
698  amrex::Abort("Error opening the dirichlet_input file.\n");
699  }
700 
701  Print() << "Successfully opened the dirichlet_input file. Now reading... " << std::endl;
702  std::string line;
703 
704  // Size of Ninp (number of z points in input file)
705  Vector<Real> z_inp_tmp, u_inp_tmp, v_inp_tmp, w_inp_tmp, th_inp_tmp;
706 
707  // Top and bot for domain
708  const int klo = geom[0].Domain().smallEnd()[2];
709  const int khi = geom[0].Domain().bigEnd()[2];
710  const Real zbot = zlevels_stag[0][klo];
711  const Real ztop = zlevels_stag[0][khi+1];
712 
713  // Flag if theta input
714  Real th_init = -Real(300.0);
715  bool th_read{false};
716 
717  // Add surface
718  z_inp_tmp.push_back(zbot); // height above sea level [m]
719  u_inp_tmp.push_back(zero);
720  v_inp_tmp.push_back(zero);
721  w_inp_tmp.push_back(zero);
722  th_inp_tmp.push_back(th_init);
723 
724  // Read the vertical profile at each given height
725  Real z, u, v, w, th;
726  while(std::getline(input_reader, line)) {
727  std::istringstream iss_z(line);
728 
729  Vector<Real> rval_v;
730  Real rval;
731  while (iss_z >> rval) {
732  rval_v.push_back(rval);
733  }
734  if ((rval_v.size() != 4) && (rval_v.size() != 5)) {
735  Abort("Unknown inflow file format!");
736  }
737  z = rval_v[0];
738  u = rval_v[1];
739  v = rval_v[2];
740  w = rval_v[3];
741 
742  // Format without theta
743  if (rval_v.size() == 4) {
744  if (z == zbot) {
745  u_inp_tmp[0] = u;
746  v_inp_tmp[0] = v;
747  w_inp_tmp[0] = w;
748  } else {
749  AMREX_ALWAYS_ASSERT(z > z_inp_tmp[z_inp_tmp.size()-1]); // sounding is increasing in height
750  z_inp_tmp.push_back(z);
751  u_inp_tmp.push_back(u);
752  v_inp_tmp.push_back(v);
753  w_inp_tmp.push_back(w);
754  if (z >= ztop) break;
755  }
756  } else if (rval_v.size() == 5) {
757  th_read = true;
758  th = rval_v[4];
759  if (z == zbot) {
760  u_inp_tmp[0] = u;
761  v_inp_tmp[0] = v;
762  w_inp_tmp[0] = w;
763  th_inp_tmp[0] = th;
764  } else {
765  AMREX_ALWAYS_ASSERT(z > z_inp_tmp[z_inp_tmp.size()-1]); // sounding is increasing in height
766  z_inp_tmp.push_back(z);
767  u_inp_tmp.push_back(u);
768  v_inp_tmp.push_back(v);
769  w_inp_tmp.push_back(w);
770  th_inp_tmp.push_back(th);
771  if (z >= ztop) break;
772  }
773  } else {
774  Abort("Unknown inflow file format!");
775  }
776  }
777 
778  // Ensure we set a reasonable theta surface
779  if (th_read) {
780  if (th_inp_tmp[0] == th_init) {
781  AMREX_ALWAYS_ASSERT_WITH_MESSAGE((th_inp_tmp.size() > 2) && (z_inp_tmp.size() > 2),
782  "Need at least 3 theta profile points to extrapolate surface theta");
783  Real slope = (th_inp_tmp[2] - th_inp_tmp[1]) / (z_inp_tmp[2] - z_inp_tmp[1]);
784  Real dz = z_inp_tmp[0] - z_inp_tmp[1];
785  th_inp_tmp[0] = slope * dz + th_inp_tmp[1];
786  }
787  }
788 
789  amrex::Print() << "Successfully read and interpolated the dirichlet_input file..." << std::endl;
790  input_reader.close();
791 
792  for (int lev = 0; lev <= max_level; lev++) {
793 
794  const int Nz = geom[lev].Domain().size()[2];
795 
796  // Size of Nz (domain grid)
797  Vector<Real> zcc_inp(Nz );
798  Vector<Real> znd_inp(Nz+1);
799  Vector<Real> u_inp(Nz ); xvel_bc_data[lev].resize(Nz ,zero);
800  Vector<Real> v_inp(Nz ); yvel_bc_data[lev].resize(Nz ,zero);
801  Vector<Real> w_inp(Nz+1); zvel_bc_data[lev].resize(Nz+1,zero);
802  Vector<Real> th_inp;
803  if (th_read) {
804  th_inp.resize(Nz);
805  th_bc_data[lev].resize(Nz, zero);
806  }
807 
808  // At this point, we have an input from zbot up to
809  // z_inp_tmp[N-1] >= ztop. Now, interpolate to grid level 0 heights
810  const int Ninp = z_inp_tmp.size();
811  for (int k(0); k<Nz; ++k) {
812  zcc_inp[k] = myhalf * (zlevels_stag[lev][k] + zlevels_stag[lev][k+1]);
813  znd_inp[k] = zlevels_stag[lev][k+1];
814  u_inp[k] = interpolate_1d(z_inp_tmp.dataPtr(), u_inp_tmp.dataPtr(), zcc_inp[k], Ninp);
815  v_inp[k] = interpolate_1d(z_inp_tmp.dataPtr(), v_inp_tmp.dataPtr(), zcc_inp[k], Ninp);
816  w_inp[k] = interpolate_1d(z_inp_tmp.dataPtr(), w_inp_tmp.dataPtr(), znd_inp[k], Ninp);
817  if (th_read) {
818  th_inp[k] = interpolate_1d(z_inp_tmp.dataPtr(), th_inp_tmp.dataPtr(), zcc_inp[k], Ninp);
819  }
820  }
821  znd_inp[Nz] = ztop;
822  w_inp[Nz] = interpolate_1d(z_inp_tmp.dataPtr(), w_inp_tmp.dataPtr(), ztop, Ninp);
823 
824  // Copy host data to the device
825  Gpu::copy(Gpu::hostToDevice, u_inp.begin(), u_inp.end(), xvel_bc_data[lev].begin());
826  Gpu::copy(Gpu::hostToDevice, v_inp.begin(), v_inp.end(), yvel_bc_data[lev].begin());
827  Gpu::copy(Gpu::hostToDevice, w_inp.begin(), w_inp.end(), zvel_bc_data[lev].begin());
828  if (th_read) {
829  Gpu::copy(Gpu::hostToDevice, th_inp.begin(), th_inp.end(), th_bc_data[lev].begin());
830  }
831 
832  // NOTE: These device vectors are passed to the PhysBC constructors when that
833  // class is instantiated in ERF_MakeNewArrays.cpp.
834  } // lev
835 }
const Real ztop
Definition: ERF_InitCustomPertVels_ParticleTests.H:4
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real interpolate_1d(const amrex::Real *alpha, const amrex::Real *beta, const amrex::Real alpha_interp, const int alpha_size)
Definition: ERF_Interpolation_1D.H:12
Here is the call graph for this function:

◆ init_from_hse()

void ERF::init_from_hse ( int  lev)

Initialize the background flow to have the calculated HSE density and rho*theta calculated from the HSE pressure. In general, the hydrostatically balanced density and pressure (r_hse and p_hse from base_state) used here may be calculated through a solver path such as:

ERF::initHSE(lev)

  • call prob->erf_init_dens_hse_dry(...)
    • call Problem::init_isentropic_hse(...), to simultaneously calculate r_hse and p_hse with Newton iteration – assuming constant theta
    • save r_hse
  • call ERF::enforce_hse(...), calculates p_hse from saved r_hse (redundant, but needed because p_hse is not necessarily calculated by the Problem implementation) and pi_hse and th_hse – note: this pressure does not exactly match the p_hse from before because what is calculated by init_isentropic_hse comes from the EOS whereas what is calculated here comes from the hydro- static equation
Parameters
levInteger specifying the current level
33 {
34  auto& lev_new = vars_new[lev];
35 
36  MultiFab r_hse(base_state[lev], make_alias, BaseState::r0_comp, 1);
37  MultiFab p_hse(base_state[lev], make_alias, BaseState::p0_comp, 1);
38 
39 #ifdef _OPENMP
40 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
41 #endif
42  for (MFIter mfi(lev_new[Vars::cons], TileNoZ()); mfi.isValid(); ++mfi)
43  {
44  const Box &gbx = mfi.growntilebox(1);
45  const Array4<Real >& cons_arr = lev_new[Vars::cons].array(mfi);
46  const Array4<Real const>& r_hse_arr = r_hse.const_array(mfi);
47  const Array4<Real const>& p_hse_arr = p_hse.const_array(mfi);
48 
49  ParallelFor(gbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
50  {
51  cons_arr(i,j,k,Rho_comp) = r_hse_arr(i,j,k);
52  cons_arr(i,j,k,RhoTheta_comp) = getRhoThetagivenP(p_hse_arr(i,j,k));
53  });
54  } //mfi
55 }
Here is the call graph for this function:

◆ init_from_input_sounding()

void ERF::init_from_input_sounding ( int  lev)

High level wrapper for initializing scalar and velocity level data from input sounding data.

Parameters
levInteger specifying the current level
54 {
55  // We only want to read the file once -- here we fill one FArrayBox (per variable) that spans the domain
56  if (lev == 0) {
58  Error("input_sounding file name must be provided via input");
59  }
60 
62 
63  // this will interpolate the input profiles to the nominal height levels
64  // (ranging from 0 to the domain top)
65  for (int n = 0; n < input_sounding_data.n_sounding_files; n++) {
67  }
68 
69  // this will calculate the hydrostatically balanced density and pressure
70  // profiles following WRF ideal.exe
71  if (solverChoice.sounding_type == SoundingType::Ideal) {
73  } else if (solverChoice.sounding_type == SoundingType::Isentropic ||
74  solverChoice.sounding_type == SoundingType::DryIsentropic) {
75  input_sounding_data.assume_dry = (solverChoice.sounding_type == SoundingType::DryIsentropic);
77  }
78 
79  } else {
80  //
81  // We need to do this interp from coarse level in order to set the values of
82  // the base state inside the domain but outside of the fine region
83  //
84  base_state[lev-1].FillBoundary(geom[lev-1].periodicity());
85  //
86  // NOTE: this interpolater assumes that ALL ghost cells of the coarse MultiFab
87  // have been pre-filled - this includes ghost cells both inside and outside
88  // the domain
89  //
90  InterpFromCoarseLevel(base_state[lev], base_state[lev].nGrowVect(),
91  IntVect(0,0,0), // do not fill ghost cells outside the domain
92  base_state[lev-1], 0, 0, base_state[lev].nComp(),
93  geom[lev-1], geom[lev],
94  refRatio(lev-1), &cell_cons_interp,
96 
97  // We need to do this here because the interpolation above may leave corners unfilled
98  // when the corners need to be filled by, for example, reflection of the fine ghost
99  // cell outside the fine region but inide the domain.
100  (*physbcs_base[lev])(base_state[lev],0,base_state[lev].nComp(),base_state[lev].nGrowVect());
101  }
102 
103  auto& lev_new = vars_new[lev];
104 
105  // updated if sounding is ideal (following WRF) or isentropic
106  const bool l_isentropic = (solverChoice.sounding_type == SoundingType::Isentropic ||
107  solverChoice.sounding_type == SoundingType::DryIsentropic);
108  const bool sounding_ideal_or_isentropic = (solverChoice.sounding_type == SoundingType::Ideal ||
109  l_isentropic);
110  MultiFab r_hse (base_state[lev], make_alias, BaseState::r0_comp, 1);
111  MultiFab p_hse (base_state[lev], make_alias, BaseState::p0_comp, 1);
112  MultiFab pi_hse(base_state[lev], make_alias, BaseState::pi0_comp, 1);
113  MultiFab th_hse(base_state[lev], make_alias, BaseState::th0_comp, 1);
114  MultiFab qv_hse(base_state[lev], make_alias, BaseState::qv0_comp, 1);
115 
116  const Real l_gravity = solverChoice.gravity;
117  const Real l_rdOcp = solverChoice.rdOcp;
118  const bool l_moist = (solverChoice.moisture_type != MoistureType::None);
119 
120  int ngz = r_hse.nGrow(2);
121 
122 #ifdef _OPENMP
123 #pragma omp parallel if (Gpu::notInLaunchRegion())
124 #endif
125  for (MFIter mfi(lev_new[Vars::cons], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
126  const Box &bx = mfi.tilebox();
127  const auto &cons_arr = lev_new[Vars::cons].array(mfi);
128  const auto &xvel_arr = lev_new[Vars::xvel].array(mfi);
129  const auto &yvel_arr = lev_new[Vars::yvel].array(mfi);
130  const auto &zvel_arr = lev_new[Vars::zvel].array(mfi);
131  Array4<Real> r_hse_arr = r_hse.array(mfi);
132  Array4<Real> p_hse_arr = p_hse.array(mfi);
133  Array4<Real> pi_hse_arr = pi_hse.array(mfi);
134  Array4<Real> th_hse_arr = th_hse.array(mfi);
135  Array4<Real> qv_hse_arr = qv_hse.array(mfi);
136 
137  Array4<Real const> z_cc_arr = (z_phys_cc[lev]) ? z_phys_cc[lev]->const_array(mfi) : Array4<Real const>{};
138  Array4<Real const> z_nd_arr = (z_phys_nd[lev]) ? z_phys_nd[lev]->const_array(mfi) : Array4<Real const>{};
139 
140  if (sounding_ideal_or_isentropic)
141  {
142  // HSE will be initialized here, interpolated from values previously
143  // calculated by calc_rho_p or calc_rho_p_isentropic
145  bx, cons_arr,
146  r_hse_arr, p_hse_arr, pi_hse_arr, th_hse_arr, qv_hse_arr,
147  geom[lev].data(), z_cc_arr,
148  l_gravity, l_rdOcp, l_moist, input_sounding_data,
149  l_isentropic, ngz);
150  }
151  else
152  {
153  // This assumes rho_0 = one
154  // HSE will be calculated later with call to initHSE
156  bx, cons_arr,
157  geom[lev].data(), z_cc_arr,
158  l_moist, input_sounding_data);
159  }
160 
162  bx, xvel_arr, yvel_arr, zvel_arr,
163  geom[lev].data(), z_nd_arr,
165 
166  } //mfi
167 }
void init_bx_scalars_from_input_sounding(const Box &bx, Array4< Real > const &state, GeometryData const &geomdata, Array4< const Real > const &z_cc_arr, const bool &l_moist, InputSoundingData const &inputSoundingData)
Definition: ERF_InitFromInputSounding.cpp:179
void init_bx_velocities_from_input_sounding(const Box &bx, Array4< Real > const &x_vel, Array4< Real > const &y_vel, Array4< Real > const &z_vel, GeometryData const &geomdata, Array4< const Real > const &z_nd_arr, InputSoundingData const &inputSoundingData)
Definition: ERF_InitFromInputSounding.cpp:375
void init_bx_scalars_from_input_sounding_hse(const Box &bx, Array4< Real > const &state, Array4< Real > const &r_hse_arr, Array4< Real > const &p_hse_arr, Array4< Real > const &pi_hse_arr, Array4< Real > const &th_hse_arr, Array4< Real > const &qv_hse_arr, GeometryData const &geomdata, Array4< const Real > const &z_cc_arr, const Real &l_gravity, const Real &l_rdOcp, const bool &l_moist, InputSoundingData const &inputSoundingData, const bool &l_isentropic, const int &ngz)
Definition: ERF_InitFromInputSounding.cpp:241
InputSoundingData input_sounding_data
Definition: ERF.H:797
@ rho0_bc_comp
Definition: ERF_IndexDefines.H:113
@ qv0_comp
Definition: ERF_IndexDefines.H:77
void resize_arrays()
Definition: ERF_InputSoundingData.H:60
int n_sounding_files
Definition: ERF_InputSoundingData.H:395
void read_from_file(const amrex::Geometry &geom, const amrex::Vector< amrex::Real > &zlevels_stag, int itime)
Definition: ERF_InputSoundingData.H:77
amrex::Vector< std::string > input_sounding_file
Definition: ERF_InputSoundingData.H:393
void calc_rho_p(int itime)
Definition: ERF_InputSoundingData.H:173
void calc_rho_p_isentropic(int itime)
Definition: ERF_InputSoundingData.H:259
bool assume_dry
Definition: ERF_InputSoundingData.H:398
static SoundingType sounding_type
Definition: ERF_DataStruct.H:1111
Here is the call graph for this function:

◆ init_geo_wind_profile()

void ERF::init_geo_wind_profile ( const std::string  input_file,
amrex::Vector< amrex::Real > &  u_geos,
amrex::Gpu::DeviceVector< amrex::Real > &  u_geos_d,
amrex::Vector< amrex::Real > &  v_geos,
amrex::Gpu::DeviceVector< amrex::Real > &  v_geos_d,
const amrex::Geometry &  lgeom,
const amrex::Vector< amrex::Real > &  zlev_stag 
)
private
17 {
18  const int klo = 0;
19  const int khi = lgeom.Domain().bigEnd()[AMREX_SPACEDIM-1];
20  const amrex::Real dz = lgeom.CellSize()[AMREX_SPACEDIM-1];
21 
22  const bool grid_stretch = (zlev_stag.size() > 0);
23  const Real zbot = (grid_stretch) ? zlev_stag[klo] : lgeom.ProbLo(AMREX_SPACEDIM-1);
24  const Real ztop = (grid_stretch) ? zlev_stag[khi+1] : lgeom.ProbHi(AMREX_SPACEDIM-1);
25 
26  amrex::Print() << "Reading geostrophic wind profile from " << input_file << std::endl;
27  std::ifstream profile_reader(input_file);
28  if(!profile_reader.is_open()) {
29  amrex::Error("Error opening the abl_geo_wind_table\n");
30  }
31 
32  // First, read the input data into temp vectors
33  std::string line;
34  Vector<Real> z_inp, Ug_inp, Vg_inp;
35  Real z, Ug, Vg;
36  amrex::Print() << "z Ug Vg" << std::endl;
37  while(std::getline(profile_reader, line)) {
38  std::istringstream iss(line);
39  iss >> z >> Ug >> Vg;
40  amrex::Print() << z << " " << Ug << " " << Vg << std::endl;
41  z_inp.push_back(z);
42  Ug_inp.push_back(Ug);
43  Vg_inp.push_back(Vg);
44  if (z >= ztop) break;
45  }
46 
47  const int Ninp = z_inp.size();
48  AMREX_ALWAYS_ASSERT(z_inp[0] <= zbot);
49  AMREX_ALWAYS_ASSERT(z_inp[Ninp-1] >= ztop);
50 
51  // Now, interpolate vectors to the cell centers
52  for (int k = 0; k <= khi; k++) {
53  z = (grid_stretch) ? myhalf * (zlev_stag[k] + zlev_stag[k+1])
54  : zbot + (k + myhalf) * dz;
55  u_geos[k] = interpolate_1d(z_inp.dataPtr(), Ug_inp.dataPtr(), z, Ninp);
56  v_geos[k] = interpolate_1d(z_inp.dataPtr(), Vg_inp.dataPtr(), z, Ninp);
57  }
58 
59  // Copy from host version to device version
60  Gpu::copy(Gpu::hostToDevice, u_geos.begin(), u_geos.end(), u_geos_d.begin());
61  Gpu::copy(Gpu::hostToDevice, v_geos.begin(), v_geos.end(), v_geos_d.begin());
62 
63  profile_reader.close();
64 }
Here is the call graph for this function:

◆ init_immersed_forcing()

void ERF::init_immersed_forcing ( int  lev)

Set velocities in cells that are immersed to be 0 (or a very small number)

Parameters
levInteger specifying the current level
16 {
17  auto& lev_new = vars_new[lev];
18  MultiFab* terrain_blank = terrain_blanking[lev].get();
19 
20 #ifdef _OPENMP
21 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
22 #endif
23  for (MFIter mfi(lev_new[Vars::cons], TileNoZ()); mfi.isValid(); ++mfi)
24  {
25  const Box &xbx = mfi.tilebox(IntVect(1,0,0));
26  const Box &ybx = mfi.tilebox(IntVect(0,1,0));
27  const Box &zbx = mfi.tilebox(IntVect(0,0,1));
28  const Real epsilon = Real(1e-2);
29 
30  const Array4<const Real>& t_blank_arr = terrain_blank->const_array(mfi);
31 
32  const auto &xvel_arr = lev_new[Vars::xvel].array(mfi);
33  const auto &yvel_arr = lev_new[Vars::yvel].array(mfi);
34  const auto &zvel_arr = lev_new[Vars::zvel].array(mfi);
35 
36  // Set the x,y,z-velocities
38  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept {
39  const Real t_blank = myhalf * (t_blank_arr(i, j, k) + t_blank_arr(i-1, j, k));
40  if (t_blank == one) { xvel_arr(i, j, k) = epsilon; }
41  },
42  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept {
43  const Real t_blank = myhalf * (t_blank_arr(i, j, k) + t_blank_arr(i, j-1, k));
44  if (t_blank == one) { yvel_arr(i, j, k) = epsilon; }
45  },
46  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept {
47  const Real t_blank = myhalf * (t_blank_arr(i, j, k) + t_blank_arr(i, j, k-1));
48  if (t_blank == one) { zvel_arr(i, j, k) = epsilon; }
49  });
50  } //mfi
51 }
real(c_double), parameter epsilon
Definition: ERF_module_model_constants.F90:12
Here is the call graph for this function:

◆ init_only()

void ERF::init_only ( int  lev,
amrex::Real  time 
)
2273 {
2274  t_new[lev] = elapsed_time;
2275  t_old[lev] = elapsed_time - Real(1.e200);
2276 
2277  auto& lev_new = vars_new[lev];
2278  auto& lev_old = vars_old[lev];
2279 
2280  // Loop over grids at this level to initialize our grid data
2281  lev_new[Vars::cons].setVal(0.0); lev_old[Vars::cons].setVal(0.0);
2282  lev_new[Vars::xvel].setVal(0.0); lev_old[Vars::xvel].setVal(0.0);
2283  lev_new[Vars::yvel].setVal(0.0); lev_old[Vars::yvel].setVal(0.0);
2284  lev_new[Vars::zvel].setVal(0.0); lev_old[Vars::zvel].setVal(0.0);
2285 
2286  // Initialize background flow (optional)
2287  if (solverChoice.init_type == InitType::Input_Sounding) {
2288  // The physbc's need the terrain but are needed for initHSE
2289  // We have already made the terrain in the call to init_zphys
2290  // in MakeNewLevelFromScratch
2291  make_physbcs(lev);
2292 
2293  // Now init the base state and the data itself
2295 
2296  // The base state has been initialized by integrating vertically
2297  // through the sounding for ideal (like WRF) or isentropic approaches
2298  if (solverChoice.sounding_type == SoundingType::Ideal ||
2299  solverChoice.sounding_type == SoundingType::Isentropic ||
2300  solverChoice.sounding_type == SoundingType::DryIsentropic) {
2301  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(solverChoice.use_gravity,
2302  "Gravity should be on to be consistent with sounding initialization.");
2303  } else { // SoundingType::ConstantDensity
2304  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(!solverChoice.use_gravity || (solverChoice.anelastic[lev] == 1),
2305  "Constant density probably doesn't make sense for compressible flow with gravity");
2306  initHSE();
2307  }
2308 
2309 #ifdef ERF_USE_NETCDF
2310  }
2311  else if (solverChoice.init_type == InitType::WRFInput && !nc_init_file[lev].empty())
2312  {
2313  // The base state is initialized from WRF wrfinput data, output by
2314  // ideal.exe or real.exe
2315 
2316  init_from_wrfinput(lev, *mf_PSFC[lev]);
2317 
2318  // The physbc's need the terrain but are needed for initHSE
2319  make_physbcs(lev);
2320  (*physbcs_base[lev])(base_state[lev],0,base_state[lev].nComp(),base_state[lev].nGrowVect());
2321  }
2322  else if (solverChoice.init_type == InitType::WRFInput && nc_init_file[lev].empty())
2323  {
2324  amrex::Abort("This pathway is not quite implemented yet");
2325  }
2326  else if (solverChoice.init_type == InitType::NCFile)
2327  {
2328  // The state is initialized by reading from a Netcdf file
2329  init_from_ncfile(lev);
2330 
2331  // The physbc's need the terrain but are needed for initHSE
2332  make_physbcs(lev);
2333  }
2334  else if (solverChoice.init_type == InitType::Metgrid)
2335  {
2336  // The base state is initialized from data output by WPS metgrid;
2337  // we will rebalance after interpolation
2338  init_from_metgrid(lev);
2339 #endif
2340  } else if ( (solverChoice.init_type == InitType::Uniform ) ||
2341  (solverChoice.init_type == InitType::ConstantDensity) ||
2342  (solverChoice.init_type == InitType::Isentropic ) ||
2343  (solverChoice.init_type == InitType::ConstantDensityLinearTheta ) ||
2344  (solverChoice.init_type == InitType::HindCast ) ||
2345  (solverChoice.init_type == InitType::MoistBaseState ) ) {
2346  // Initialize a uniform density/entropy background field and base state
2347  // based on the problem-specified reference density and temperature
2348 
2349  // The physbc's need the terrain but are needed for initHSE
2350  make_physbcs(lev);
2351 
2352  // We will initialize the state from the background state so must set that first
2353  // The choice between constant rho and constant theta will be made inside initHSE
2354  initHSE(lev);
2355 
2356  // Copy rho and rhotheta from rho_hse and p_hse
2357  init_from_hse(lev);
2358 
2359  } else {
2360  Abort("Unknown init_type!");
2361  }
2362 
2363  // Add problem-specific flow features
2364  //
2365  // Notes:
2366  // - This calls init_custom_pert that is defined for each problem
2367  // - This may modify the base state
2368  // - The fields set by init_custom_pert are **perturbations** to the
2369  // background flow set based on init_type
2370  if (solverChoice.init_type != InitType::NCFile) {
2371  init_custom(lev);
2372  }
2373 
2374  // Ensure that the face-based data are the same on both sides of a periodic domain.
2375  // The data associated with the lower grid ID is considered the correct value.
2376  lev_new[Vars::xvel].OverrideSync(geom[lev].periodicity());
2377  lev_new[Vars::yvel].OverrideSync(geom[lev].periodicity());
2378  lev_new[Vars::zvel].OverrideSync(geom[lev].periodicity());
2379 
2380  if (solverChoice.spongeChoice.sponge_type == SpongeType::Input_Sponge)
2381  {
2382  input_sponge(lev);
2383  }
2384 
2385  // Initialize turbulent perturbation
2386  if (solverChoice.use_perturbation(lev)) {
2387  turbPert_update(lev, zero);
2388  turbPert_amplitude(lev);
2389  }
2390 
2391  // Set initial velocity field for immersed cells to be close to 0
2392  if (solverChoice.terrain_type == TerrainType::ImmersedForcing ||
2393  solverChoice.buildings_type == BuildingsType::ImmersedForcing) {
2394  init_immersed_forcing(lev);
2395  }
2396 }
void init_from_input_sounding(int lev)
Definition: ERF_InitFromInputSounding.cpp:53
void init_custom(int lev)
Definition: ERF_InitCustomPertState.cpp:26
void init_from_hse(int lev)
Definition: ERF_InitFromHSE.cpp:32
void initHSE()
Initialize HSE.
Definition: ERF_Init1D.cpp:192
void turbPert_update(const int lev, const amrex::Real dt)
Definition: ERF_InitTurbPert.cpp:12
void input_sponge(int lev)
Definition: ERF_InitSponge.cpp:17
void make_physbcs(int lev)
Definition: ERF_MakeNewArrays.cpp:897
void init_immersed_forcing(int lev)
Definition: ERF_InitImmersedForcing.cpp:15
void turbPert_amplitude(const int lev)
Definition: ERF_InitTurbPert.cpp:33
bool use_gravity
Definition: ERF_DataStruct.H:1180
SpongeChoice spongeChoice
Definition: ERF_DataStruct.H:1134

◆ init_phys_bcs()

void ERF::init_phys_bcs ( bool &  rho_read,
bool &  read_prim_theta 
)
private

Initializes data structures in the ERF class that specify which boundary conditions we are implementing on each face of the domain.

This function also maps the selected boundary condition types (e.g. Outflow, Inflow, InflowOutflow, Periodic, Dirichlet, ...) to the specific implementation needed for each variable.

Stores this information in both host and device vectors so it is available for GPU kernels.

21 {
22  auto f = [this,&rho_read,&read_prim_theta] (std::string const& bcid, Orientation ori)
23  {
24  // These are simply defaults for Dirichlet faces -- they should be over-written below
26  m_bc_extdir_vals[BCVars::RhoTheta_bc_comp][ori] = -one; // It is important to set this negative
27  // because the sign is tested on below
28  for (int n = BCVars::RhoKE_bc_comp; n < BCVars::xvel_bc; n++) {
29  m_bc_extdir_vals[n][ori] = zero;
30  }
31 
32  m_bc_extdir_vals[BCVars::xvel_bc][ori] = zero; // default
35 
36  // These are simply defaults for Neumann gradients -- they should be over-written below
39 
48 
52 
53  std::string pp_text = pp_prefix + "." + bcid;
54  ParmParse pp(pp_text);
55 
56  std::string bc_type_in;
57  if (pp.query("type", bc_type_in) <= 0)
58  {
59  pp_text = bcid;
60  pp = ParmParse(pp_text);
61  pp.query("type", bc_type_in);
62  }
63 
64  std::string bc_type = amrex::toLower(bc_type_in);
65 
66  if (bc_type == "symmetry")
67  {
68  // Print() << bcid << " set to symmetry.\n";
70  domain_bc_type[ori] = "Symmetry";
71  }
72  else if (bc_type == "outflow")
73  {
74  // Print() << bcid << " set to outflow.\n";
76  domain_bc_type[ori] = "Outflow";
77  }
78  else if (bc_type == "open")
79  {
80  // Print() << bcid << " set to open.\n";
81  AMREX_ASSERT_WITH_MESSAGE((ori.coordDir() != 2), "Open boundary not valid on zlo or zhi!");
83  domain_bc_type[ori] = "Open";
84  }
85  else if (bc_type == "ho_outflow")
86  {
88  domain_bc_type[ori] = "HO_Outflow";
89  }
90 
91  else if (bc_type == "inflow" || bc_type == "inflow_outflow")
92  {
93  if (bc_type == "inflow") {
94  // Print() << bcid << " set to inflow.\n";
96  domain_bc_type[ori] = "Inflow";
97  } else {
98  // Print() << bcid << " set to inflow_outflow.\n";
100  domain_bc_type[ori] = "InflowOutflow";
101  }
102 
103  std::vector<Real> v;
104  if (input_bndry_planes && m_r2d->ingested_velocity()) {
108  } else {
109  // Test for input data file if at xlo face
110  std::string dirichlet_file;
111  auto file_exists = pp.query("dirichlet_file", dirichlet_file);
112  if (file_exists) {
113  pp.query("read_prim_theta", read_prim_theta);
114  init_Dirichlet_bc_data(dirichlet_file);
115  } else {
116  pp.getarr("velocity", v, 0, AMREX_SPACEDIM);
117  m_bc_extdir_vals[BCVars::xvel_bc][ori] = v[0];
118  m_bc_extdir_vals[BCVars::yvel_bc][ori] = v[1];
119  m_bc_extdir_vals[BCVars::zvel_bc][ori] = v[2];
120  }
121  }
122 
123  Real rho_in = zero;
124  if (input_bndry_planes && m_r2d->ingested_density()) {
126  } else {
127  if (!pp.query("density", rho_in)) {
128  amrex::Print() << "Using interior values to set conserved vars" << std::endl;
129  }
130  m_bc_extdir_vals[BCVars::Rho_bc_comp][ori] = rho_in;
131  }
132 
133  bool th_read = (th_bc_data[0].data()!=nullptr);
134  Real theta_in = zero;
135  if (input_bndry_planes && m_r2d->ingested_theta()) {
137  } else if (!th_read) {
138  if (rho_in > 0) {
139  pp.get("theta", theta_in);
140  }
141  m_bc_extdir_vals[BCVars::RhoTheta_bc_comp][ori] = rho_in*theta_in;
142  }
143 
144  // Non-reflecting inflow: prescribe velocity and density but
145  // extrapolate RhoTheta (and hence pressure) from the interior.
146  // This lets upstream-propagating acoustic waves exit the domain
147  // instead of reflecting off the rigid Dirichlet boundary.
148  bool nonreflecting = false;
149  pp.query("nonreflecting", nonreflecting);
150  m_bc_nonreflecting[ori] = nonreflecting;
151 
152  Real scalar_in = zero;
153  if (input_bndry_planes && m_r2d->ingested_scalar()) {
155  } else {
156  if (pp.query("scalar", scalar_in))
157  m_bc_extdir_vals[BCVars::RhoScalar_bc_comp][ori] = rho_in*scalar_in;
158  }
159 
160  if (solverChoice.moisture_type != MoistureType::None) {
161  Real qv_in = zero;
162  if (input_bndry_planes && m_r2d->ingested_q1()) {
164  } else {
165  if (pp.query("qv", qv_in))
166  m_bc_extdir_vals[BCVars::RhoQ1_bc_comp][ori] = rho_in*qv_in;
167  }
168  Real qc_in = zero;
169  if (input_bndry_planes && m_r2d->ingested_q2()) {
171  } else {
172  if (pp.query("qc", qc_in))
173  m_bc_extdir_vals[BCVars::RhoQ2_bc_comp][ori] = rho_in*qc_in;
174  }
175  }
176 
177  Real KE_in = zero;
178  if (input_bndry_planes && m_r2d->ingested_KE()) {
180  } else {
181  if (pp.query("KE", KE_in))
182  m_bc_extdir_vals[BCVars::RhoKE_bc_comp][ori] = rho_in*KE_in;
183  }
184  }
185  else if (bc_type == "noslipwall")
186  {
187  // Print() << bcid <<" set to no-slip wall.\n";
189  domain_bc_type[ori] = "NoSlipWall";
190 
191  std::vector<Real> v;
192 
193  // The values of m_bc_extdir_vals default to zero
194  // But if we find "velocity" in the inputs file, use those values instead.
195  if (pp.queryarr("velocity", v, 0, AMREX_SPACEDIM))
196  {
197  v[ori.coordDir()] = zero;
198  m_bc_extdir_vals[BCVars::xvel_bc][ori] = v[0];
199  m_bc_extdir_vals[BCVars::yvel_bc][ori] = v[1];
200  m_bc_extdir_vals[BCVars::zvel_bc][ori] = v[2];
201  }
202 
203  Real rho_in;
204  rho_read = pp.query("density", rho_in);
205  if (rho_read)
206  {
207  m_bc_extdir_vals[BCVars::Rho_bc_comp][ori] = rho_in;
208  }
209 
210  Real theta_in;
211  if (pp.query("theta", theta_in))
212  {
214  }
215 
216  Real theta_grad_in;
217  if (pp.query("theta_grad", theta_grad_in))
218  {
219  m_bc_neumann_vals[BCVars::RhoTheta_bc_comp][ori] = theta_grad_in;
220  }
221 
222  Real qv_in;
223  if (pp.query("qv", qv_in))
224  {
226  }
227  }
228  else if (bc_type == "slipwall")
229  {
230  // Print() << bcid <<" set to slip wall.\n";
231 
233  domain_bc_type[ori] = "SlipWall";
234 
235  Real rho_in;
236  rho_read = pp.query("density", rho_in);
237  if (rho_read)
238  {
239  m_bc_extdir_vals[BCVars::Rho_bc_comp][ori] = rho_in;
240  }
241 
242  Real theta_in;
243  if (pp.query("theta", theta_in))
244  {
246  }
247 
248  Real rho_grad_in;
249  if (pp.query("density_grad", rho_grad_in))
250  {
251  m_bc_neumann_vals[BCVars::Rho_bc_comp][ori] = rho_grad_in;
252  }
253 
254  Real theta_grad_in;
255  if (pp.query("theta_grad", theta_grad_in))
256  {
257  m_bc_neumann_vals[BCVars::RhoTheta_bc_comp][ori] = theta_grad_in;
258  }
259  }
260  else if (bc_type == "surface_layer")
261  {
263  domain_bc_type[ori] = "surface_layer";
264  }
265  else
266  {
268  }
269 
270  if (geom[0].isPeriodic(ori.coordDir())) {
271  domain_bc_type[ori] = "Periodic";
272  if (phys_bc_type[ori] == ERF_BC::undefined)
273  {
275  } else {
276  Abort("Wrong BC type for periodic boundary");
277  }
278  }
279 
280  if (phys_bc_type[ori] == ERF_BC::undefined)
281  {
282  Print() << "BC Type specified for face " << bcid << " is " << bc_type_in << std::endl;
283  Abort("This BC type is unknown");
284  }
285  };
286 
287  f("xlo", Orientation(Direction::x,Orientation::low));
288  f("xhi", Orientation(Direction::x,Orientation::high));
289  f("ylo", Orientation(Direction::y,Orientation::low));
290  f("yhi", Orientation(Direction::y,Orientation::high));
291  f("zlo", Orientation(Direction::z,Orientation::low));
292  f("zhi", Orientation(Direction::z,Orientation::high));
293 }
AMREX_ASSERT_WITH_MESSAGE(wbar_cutoff_min > wbar_cutoff_max, "ERROR: wbar_cutoff_min < wbar_cutoff_max")
void init_Dirichlet_bc_data(const std::string input_file)
Definition: ERF_InitBCs.cpp:692
@ RhoQ6_bc_comp
Definition: ERF_IndexDefines.H:96
@ RhoQ4_bc_comp
Definition: ERF_IndexDefines.H:94
@ RhoQ3_bc_comp
Definition: ERF_IndexDefines.H:93
@ RhoQ5_bc_comp
Definition: ERF_IndexDefines.H:95
Here is the call graph for this function:

◆ init_stuff()

void ERF::init_stuff ( int  lev,
const amrex::BoxArray &  ba,
const amrex::DistributionMapping &  dm,
amrex::Vector< amrex::MultiFab > &  lev_new,
amrex::Vector< amrex::MultiFab > &  lev_old,
amrex::MultiFab &  tmp_base_state,
std::unique_ptr< amrex::MultiFab > &  tmp_zphys_nd 
)
private
28 {
29  // ********************************************************************************************
30  // Base state holds r_0, pres_0, pi_0, th_0 (in that order)
31  //
32  // Here is where we set the number of ghost cells for the base state!
33  // ********************************************************************************************
34  int ngb = (solverChoice.terrain_type == TerrainType::EB) ? ComputeGhostCells(solverChoice)+1 : 3;
35  tmp_base_state.define(ba,dm,BaseState::num_comps,ngb);
36  tmp_base_state.setVal(zero);
37 
38  if (solverChoice.terrain_type == TerrainType::MovingFittedMesh) {
39  base_state_new[lev].define(ba,dm,BaseState::num_comps,base_state[lev].nGrowVect());
40  base_state_new[lev].setVal(zero);
41  }
42 
43  // ********************************************************************************************
44  // Allocate terrain arrays
45  // ********************************************************************************************
46 
47  BoxArray ba_nd(ba);
48  ba_nd.surroundingNodes();
49 
50  // NOTE: this is where we actually allocate z_phys_nd -- but here it's called "tmp_zphys_nd"
51  // We need this to be one greater than the ghost cells to handle levels > 0
52 
53  int ngrow = ComputeGhostCells(solverChoice) + 2;
54  tmp_zphys_nd = std::make_unique<MultiFab>(ba_nd,dm,1,IntVect(ngrow,ngrow,ngrow));
55 
56  // Offset z-coordinate for interpolate_1d when plane EB is used.
57  Real z_offset = zero;
58  if (solverChoice.terrain_type == TerrainType::EB) {
59  ParmParse pp_eb2("eb2");
60  std::string geometry;
61  pp_eb2.query("geometry", geometry);
62  if (geometry == "plane") {
63  RealArray plane_point{zero, zero, zero};
64  pp_eb2.query("plane_point", plane_point);
65  z_offset = plane_point[2];
66  }
67  }
68 
69  z_phys_cc[lev] = std::make_unique<MultiFab>(ba,dm,1,2);
70  init_default_zphys(lev, geom[lev], *tmp_zphys_nd, *z_phys_cc[lev], z_offset);
71 
72  if (solverChoice.terrain_type == TerrainType::MovingFittedMesh)
73  {
74  detJ_cc_new[lev] = std::make_unique<MultiFab>(ba,dm,1,1);
75  detJ_cc_src[lev] = std::make_unique<MultiFab>(ba,dm,1,1);
76 
77  ax_src[lev] = std::make_unique<MultiFab>(convert(ba,IntVect(1,0,0)),dm,1,1);
78  ay_src[lev] = std::make_unique<MultiFab>(convert(ba,IntVect(0,1,0)),dm,1,1);
79  az_src[lev] = std::make_unique<MultiFab>(convert(ba,IntVect(0,0,1)),dm,1,1);
80 
81  z_t_rk[lev] = std::make_unique<MultiFab>( convert(ba, IntVect(0,0,1)), dm, 1, 1 );
82 
83  z_phys_nd_new[lev] = std::make_unique<MultiFab>(ba_nd,dm,1,IntVect(ngrow,ngrow,ngrow));
84  z_phys_nd_src[lev] = std::make_unique<MultiFab>(ba_nd,dm,1,IntVect(ngrow,ngrow,ngrow));
85  z_phys_cc_src[lev] = std::make_unique<MultiFab>(ba,dm,1,1);
86  }
87  else
88  {
89  z_phys_nd_new[lev] = nullptr;
90  detJ_cc_new[lev] = nullptr;
91 
92  z_phys_nd_src[lev] = nullptr;
93  z_phys_cc_src[lev] = nullptr;
94  detJ_cc_src[lev] = nullptr;
95 
96  z_t_rk[lev] = nullptr;
97  }
98 
99  if (solverChoice.terrain_type == TerrainType::ImmersedForcing ||
100  solverChoice.buildings_type == BuildingsType::ImmersedForcing)
101  {
102  terrain_blanking[lev] = std::make_unique<MultiFab>(ba,dm,1,ngrow);
103  terrain_blanking[lev]->setVal(one);
104  }
105 
106  // We use these area arrays regardless of terrain, EB or none of the above
107  detJ_cc[lev] = std::make_unique<MultiFab>(ba,dm,1,1);
108  ax[lev] = std::make_unique<MultiFab>(convert(ba,IntVect(1,0,0)),dm,1,1);
109  ay[lev] = std::make_unique<MultiFab>(convert(ba,IntVect(0,1,0)),dm,1,1);
110  az[lev] = std::make_unique<MultiFab>(convert(ba,IntVect(0,0,1)),dm,1,1);
111 
112  detJ_cc[lev]->setVal(one);
113  ax[lev]->setVal(one);
114  ay[lev]->setVal(one);
115  az[lev]->setVal(one);
116 
117  // ********************************************************************************************
118  // Create wall distance array for RANS modeling
119  // ********************************************************************************************
120  if (solverChoice.turbChoice[lev].rans_type != RANSType::None) {
121  walldist[lev] = std::make_unique<MultiFab>(ba,dm,1,1);
122  walldist[lev]->setVal(Real(1.234e10));
123  } else {
124  walldist[lev] = nullptr;
125  }
126 
127  // ********************************************************************************************
128  // These are the persistent containers for the old and new data
129  // ********************************************************************************************
130  int ncomp;
131  if (lev > 0) {
132  ncomp = vars_new[lev-1][Vars::cons].nComp();
133  } else {
134  int n_qstate = micro->Get_Qstate_Size();
135  ncomp = NDRY + NSCALARS + n_qstate;
136  }
137 
138  // ********************************************************************************************
139  // The number of ghost cells for density must be 1 greater than that for velocity
140  // so that we can go back in forth between velocity and momentum on all faces
141  // ********************************************************************************************
142  int ngrow_state = ComputeGhostCells(solverChoice) + 1;
143  int ngrow_vels = ComputeGhostCells(solverChoice);
144 
145  // ********************************************************************************************
146  // New solution data containers
147  // ********************************************************************************************
148  if (solverChoice.terrain_type != TerrainType::EB) {
149  lev_new[Vars::cons].define(ba, dm, ncomp, ngrow_state);
150  lev_old[Vars::cons].define(ba, dm, ncomp, ngrow_state);
151  } else {
152  // EB: Define the MultiFabs with the EBFactory
153  lev_new[Vars::cons].define(ba, dm, ncomp, ngrow_state, MFInfo(), EBFactory(lev));
154  lev_old[Vars::cons].define(ba, dm, ncomp, ngrow_state, MFInfo(), EBFactory(lev));
155  }
156 
157  // Initialize all components to zero so we don't need to explicitly set
158  // scalars / moisture variables to zero in the initialization
159  lev_new[Vars::cons].setVal(zero);
160  lev_old[Vars::cons].setVal(zero);
161 
162  lev_new[Vars::xvel].define(convert(ba, IntVect(1,0,0)), dm, 1, ngrow_vels);
163  lev_old[Vars::xvel].define(convert(ba, IntVect(1,0,0)), dm, 1, ngrow_vels);
164 
165  lev_new[Vars::yvel].define(convert(ba, IntVect(0,1,0)), dm, 1, ngrow_vels);
166  lev_old[Vars::yvel].define(convert(ba, IntVect(0,1,0)), dm, 1, ngrow_vels);
167 
168  // Set these to avoid operations on uninitialized data
169  lev_new[Vars::xvel].setVal(Real(1.234e10));
170  lev_old[Vars::xvel].setVal(Real(1.234e10));
171  lev_new[Vars::yvel].setVal(Real(1.234e10));
172  lev_old[Vars::yvel].setVal(Real(1.234e10));
173 
174  // Note that we need the ghost cells in the z-direction if we are doing any
175  // kind of domain decomposition in the vertical (at level 0 or above)
176  lev_new[Vars::zvel].define(convert(ba, IntVect(0,0,1)), dm, 1, ngrow_vels);
177  lev_old[Vars::zvel].define(convert(ba, IntVect(0,0,1)), dm, 1, ngrow_vels);
178 
179  gradp[lev][GpVars::gpx].define(convert(ba, IntVect(1,0,0)), dm, 1, 1); gradp[lev][GpVars::gpx].setVal(zero);
180  gradp[lev][GpVars::gpy].define(convert(ba, IntVect(0,1,0)), dm, 1, 1); gradp[lev][GpVars::gpy].setVal(zero);
181  gradp[lev][GpVars::gpz].define(convert(ba, IntVect(0,0,1)), dm, 1, 1); gradp[lev][GpVars::gpz].setVal(zero);
182 
183  if ( (solverChoice.anelastic[lev] == 1) || (solverChoice.project_initial_velocity[lev] == 1) ) {
184  pp_inc[lev].define(ba, dm, 1, 1);
185  pp_inc[lev].setVal(zero);
186  }
187 
188  // We use this in the fast substepping only
189  if (solverChoice.anelastic[lev] == 0) {
190  lagged_delta_rt[lev].define(ba, dm, 1, 1);
191  lagged_delta_rt[lev].setVal(zero);
192  }
193 
194  // We use these for advecting the slow variables, whether anelastic or compressible
195  avg_xmom[lev].define(convert(ba, IntVect(1,0,0)), dm, 1, 1);
196  avg_ymom[lev].define(convert(ba, IntVect(0,1,0)), dm, 1, 1);
197  avg_zmom[lev].define(convert(ba, IntVect(0,0,1)), dm, 1, 1);
198  avg_xmom[lev].setVal(0); avg_ymom[lev].setVal(0); avg_zmom[lev].setVal(zero);
199 
200  // ********************************************************************************************
201  // These are just used for scratch in the time integrator but we might as well define them here
202  // ********************************************************************************************
203  if (solverChoice.terrain_type != TerrainType::EB) {
204  rU_old[lev].define(convert(ba, IntVect(1,0,0)), dm, 1, ngrow_vels);
205  rU_new[lev].define(convert(ba, IntVect(1,0,0)), dm, 1, ngrow_vels);
206 
207  rV_old[lev].define(convert(ba, IntVect(0,1,0)), dm, 1, ngrow_vels);
208  rV_new[lev].define(convert(ba, IntVect(0,1,0)), dm, 1, ngrow_vels);
209 
210  rW_old[lev].define(convert(ba, IntVect(0,0,1)), dm, 1, ngrow_vels);
211  rW_new[lev].define(convert(ba, IntVect(0,0,1)), dm, 1, ngrow_vels);
212  } else {
213  // EB: Define the MultiFabs with the EBFactory
214  rU_old[lev].define(convert(ba, IntVect(1,0,0)), dm, 1, ngrow_vels, MFInfo(), EBFactory(lev));
215  rU_new[lev].define(convert(ba, IntVect(1,0,0)), dm, 1, ngrow_vels, MFInfo(), EBFactory(lev));
216 
217  rV_old[lev].define(convert(ba, IntVect(0,1,0)), dm, 1, ngrow_vels, MFInfo(), EBFactory(lev));
218  rV_new[lev].define(convert(ba, IntVect(0,1,0)), dm, 1, ngrow_vels, MFInfo(), EBFactory(lev));
219 
220  rW_old[lev].define(convert(ba, IntVect(0,0,1)), dm, 1, ngrow_vels, MFInfo(), EBFactory(lev));
221  rW_new[lev].define(convert(ba, IntVect(0,0,1)), dm, 1, ngrow_vels, MFInfo(), EBFactory(lev));
222  }
223 
224  if (lev > 0) {
225  //xmom_crse_rhs[lev].define(convert(ba, IntVect(1,0,0)), dm, 1, IntVect{0});
226  //ymom_crse_rhs[lev].define(convert(ba, IntVect(0,1,0)), dm, 1, IntVect{0});
227  zmom_crse_rhs[lev].define(convert(ba, IntVect(0,0,1)), dm, 1, IntVect{0});
228  }
229 
230  // We do this here just so they won't be undefined in the initial FillPatch
231  rU_old[lev].setVal(Real(1.234e10));
232  rV_old[lev].setVal(Real(1.234e10));
233  rW_old[lev].setVal(Real(1.234e10));
234  rU_new[lev].setVal(Real(1.234e10));
235  rV_new[lev].setVal(Real(1.234e10));
236  rW_new[lev].setVal(Real(1.234e10));
237 
238  // ********************************************************************************************
239  // These are just time averaged fields for diagnostics
240  // ********************************************************************************************
241 
242  // NOTE: We are not completing a fillpatch call on the time averaged data;
243  // which would copy on intersection and interpolate from coarse.
244  // Therefore, we are restarting the averaging when the ba changes,
245  // this may give poor statistics for dynamic mesh refinement.
246  vel_t_avg[lev] = nullptr;
248  vel_t_avg[lev] = std::make_unique<MultiFab>(ba, dm, 4, 0); // Each vel comp and the mag
249  vel_t_avg[lev]->setVal(zero);
250  t_avg_cnt[lev] = zero;
251  }
252 
253  // ********************************************************************************************
254  // Initialize flux registers whenever we create/re-create a level
255  // ********************************************************************************************
256  if (solverChoice.coupling_type == CouplingType::TwoWay) {
257  if (lev == 0) {
258  advflux_reg[0] = nullptr;
259  } else {
260  int ncomp_reflux = vars_new[0][Vars::cons].nComp();
261  advflux_reg[lev] = new YAFluxRegister(ba , grids[lev-1],
262  dm , dmap[lev-1],
263  geom[lev], geom[lev-1],
264  ref_ratio[lev-1], lev, ncomp_reflux);
265  }
266  }
267 
268  // ********************************************************************************************
269  // Define Theta_prim storage if using surface_layer BC
270  // ********************************************************************************************
271  if (phys_bc_type[Orientation(Direction::z,Orientation::low)] == ERF_BC::surface_layer) {
272  Theta_prim[lev] = std::make_unique<MultiFab>(ba,dm,1,IntVect(ngrow_state,ngrow_state,1));
273  if (solverChoice.moisture_type != MoistureType::None) {
274  Qv_prim[lev] = std::make_unique<MultiFab>(ba,dm,1,IntVect(ngrow_state,ngrow_state,1));
275  Qr_prim[lev] = std::make_unique<MultiFab>(ba,dm,1,IntVect(ngrow_state,ngrow_state,1));
276  } else {
277  Qv_prim[lev] = nullptr;
278  Qr_prim[lev] = nullptr;
279  }
280  } else {
281  Theta_prim[lev] = nullptr;
282  Qv_prim[lev] = nullptr;
283  Qr_prim[lev] = nullptr;
284  }
285 
286  // ********************************************************************************************
287  // Build 1D BA and 2D BA
288  // ********************************************************************************************
289 
290  // NOTE: By design, the compressed BAs have their compressed indices set to 0
291  // MFIters that need more detailed box information should be done over 3D MFs
292 
293  // Build 2D BA
294  BoxList bl2d = ba.boxList();
295  for (auto& b : bl2d) {
296  b.setRange(2,0);
297  }
298  ba2d[lev] = BoxArray(std::move(bl2d));
299 
300  // Build 1D BA
301  BoxList bl1d = ba.boxList();
302  for (auto& b : bl1d) {
303  b.setRange(0,0);
304  b.setRange(1,0);
305  }
306  ba1d[lev] = BoxArray(std::move(bl1d));
307 
308  // ********************************************************************************************
309  // Map factors
310  // ********************************************************************************************
311  mapfac[lev].resize(MapFacType::num);
312  mapfac[lev][MapFacType::m_x] = std::make_unique<MultiFab>( ba2d[lev],dm,1,IntVect(3,3,0));
313  mapfac[lev][MapFacType::u_x] = std::make_unique<MultiFab>(convert(ba2d[lev],IntVect(1,0,0)),dm,1,IntVect(3,3,0));
314  mapfac[lev][MapFacType::v_x] = std::make_unique<MultiFab>(convert(ba2d[lev],IntVect(0,1,0)),dm,1,IntVect(3,3,0));
315 
316 #if 0
317  // For now we comment this out to avoid CI failures but we will need to re-enable
318  // this if using non-conformal mappings
320  mapfac[lev][MapFacType::m_y] = std::make_unique<MultiFab>(ba2d[lev],dm,1,IntVect(3,3,0));
321  }
323  mapfac[lev][MapFacType::u_y] = std::make_unique<MultiFab>(convert(ba2d[lev],IntVect(1,0,0)),dm,1,IntVect(3,3,0));
324  }
326  mapfac[lev][MapFacType::v_y] = std::make_unique<MultiFab>(convert(ba2d[lev],IntVect(0,1,0)),dm,1,IntVect(3,3,0));
327  }
328 #endif
329 
331  for (int i = 0; i < 3; i++) {
332  mapfac[lev][i]->setVal(myhalf);
333  }
334  for (int i = 3; i < mapfac[lev].size(); i++) {
335  mapfac[lev][i]->setVal(fourth);
336  }
337  } else {
338  for (int i = 0; i < mapfac[lev].size(); i++) {
339  mapfac[lev][i]->setVal(one);
340  }
341  }
342 
343  // ********************************************************************************************
344  // Build WRF data structures
345  // ********************************************************************************************
346  IntVect ng = vars_new[lev][Vars::cons].nGrowVect();
347 
348  if (lev == 0) {
349  wrf_C1H = std::make_unique<MultiFab>(ba1d[lev],dm,1,IntVect(ng[0],ng[1],ng[2]));
350  wrf_C2H = std::make_unique<MultiFab>(ba1d[lev],dm,1,IntVect(ng[0],ng[1],ng[2]));
351  wrf_MUB = std::make_unique<MultiFab>(ba2d[lev],dm,1,IntVect(ng[0],ng[1],ng[2]));
352  }
353 
354  mf_PSFC[lev] = std::make_unique<MultiFab>(ba2d[lev],dm,1,ng);
355 
356  //*********************************************************
357  // Variables for Fitch model for windfarm parametrization
358  //*********************************************************
359 #if defined(ERF_USE_WINDFARM)
360  if (solverChoice.windfarm_type == WindFarmType::Fitch){
361  vars_windfarm[lev].define(ba, dm, 5, ngrow_state); // V, dVabsdt, dudt, dvdt, dTKEdt
362  }
363  if (solverChoice.windfarm_type == WindFarmType::EWP){
364  vars_windfarm[lev].define(ba, dm, 3, ngrow_state); // dudt, dvdt, dTKEdt
365  }
366  if (solverChoice.windfarm_type == WindFarmType::SimpleAD) {
367  vars_windfarm[lev].define(ba, dm, 2, ngrow_state);// dudt, dvdt
368  }
369  if (solverChoice.windfarm_type == WindFarmType::GeneralAD) {
370  vars_windfarm[lev].define(ba, dm, 3, ngrow_state);// dudt, dvdt, dwdt
371  }
372  Nturb[lev].define(ba, dm, 1, ngrow_state); // Number of turbines in a cell
373  SMark[lev].define(ba, dm, 2, 1); // Free stream velocity/source term
374  // sampling marker in a cell - 2 components
375 #endif
376 
377  if(solverChoice.init_type == InitType::HindCast and
379 
380  int ncomp_extra = 2;
381  int nvars = vars_new[lev].size();
382 
383  // Resize all containers
384  forecast_state_1[lev].resize(nvars + 1);
385  forecast_state_2[lev].resize(nvars + 1);
386  forecast_state_interp[lev].resize(nvars + 1);
387 
388  // Define the "normal" components
389  for (int comp = 0; comp < nvars; ++comp) {
390  const MultiFab& src = vars_new[lev][comp];
391  ncomp = src.nComp();
392  ngrow = src.nGrow();
393 
394  forecast_state_1[lev][comp].define(ba, dm, ncomp, ng);
395  forecast_state_2[lev][comp].define(ba, dm, ncomp, ng);
396  forecast_state_interp[lev][comp].define(ba, dm, ncomp, ng);
397  }
398 
399  // Define the "extra" component (last slot)
400  {
401  const MultiFab& src0 = vars_new[lev][0];
402  ngrow = src0.nGrow();
403  int idx = nvars;
404 
405  forecast_state_1[lev][idx].define(ba, dm, ncomp_extra, ngrow);
406  forecast_state_2[lev][idx].define(ba, dm, ncomp_extra, ngrow);
407  forecast_state_interp[lev][idx].define(ba, dm, ncomp_extra, ngrow);
408  }
409  bool regrid_forces_file_read = true;
410  WeatherDataInterpolation(lev, t_new[0],z_phys_nd, regrid_forces_file_read);
411  }
412 
413 
414  if(solverChoice.init_type == InitType::HindCast and
416 
417  {
418  const MultiFab& src = vars_new[lev][0];
419  const amrex::DistributionMapping& dm_hc = src.DistributionMap();
420 
421  surface_state_1[lev].define(ba2d[lev], dm_hc, 2, src.nGrow());
422  surface_state_2[lev].define(ba2d[lev], dm_hc, 2, src.nGrow());
423  surface_state_interp[lev].define(ba2d[lev], dm_hc, 2, src.nGrow());
424 
425  bool regrid_forces_file_read = true;
426  SurfaceDataInterpolation(lev, t_new[0], z_phys_nd, regrid_forces_file_read);
427  }
428 
429 #ifdef ERF_USE_WW3_COUPLING
430  // create a new BoxArray and DistributionMapping for a MultiFab with 1 box
431  BoxArray ba_onegrid(geom[lev].Domain());
432  BoxList bl2d_onegrid = ba_onegrid.boxList();
433  for (auto& b : bl2d_onegrid) { b.setRange(2,b.smallEnd(2)); }
434  BoxArray ba2d_onegrid(std::move(bl2d_onegrid));
435  Vector<int> pmap;
436  pmap.resize(1);
437  pmap[0]=0;
438  DistributionMapping dm_onegrid(ba2d_onegrid);
439  dm_onegrid.define(pmap);
440 
441  Hwave_onegrid[lev] = std::make_unique<MultiFab>(ba2d_onegrid,dm_onegrid,1,IntVect(1,1,0));
442  Lwave_onegrid[lev] = std::make_unique<MultiFab>(ba2d_onegrid,dm_onegrid,1,IntVect(1,1,0));
443 
444  BoxList bl2d_wave = ba.boxList();
445  for (auto& b : bl2d_wave) { b.setRange(2,b.smallEnd(2)); }
446  BoxArray ba2d_wave(std::move(bl2d_wave));
447 
448  Hwave[lev] = std::make_unique<MultiFab>(ba2d_wave,dm,1,IntVect(3,3,0));
449  Lwave[lev] = std::make_unique<MultiFab>(ba2d_wave,dm,1,IntVect(3,3,0));
450 
451  std::cout<<ba_onegrid<<std::endl;
452  std::cout<<ba2d_onegrid<<std::endl;
453  std::cout<<dm_onegrid<<std::endl;
454 #endif
455 
456 
457  //*********************************************************
458  // Radiation heating source terms
459  //*********************************************************
460  if (solverChoice.rad_type != RadiationType::None)
461  {
462  qheating_rates[lev] = std::make_unique<MultiFab>(ba, dm, 2, 0);
463  rad_fluxes[lev] = std::make_unique<MultiFab>(ba, dm, 4, 0);
464  qheating_rates[lev]->setVal(zero);
465  rad_fluxes[lev]->setVal(zero);
466  }
467 
468  //*********************************************************
469  // Turbulent perturbation region initialization
470  //*********************************************************
472  {
473  turbPert.init_tpi_type(lev, solverChoice.pert_type[lev], max_level);
474  turbPert.init_tpi(lev, subdomains[lev], geom[lev].CellSizeArray(),
475  ba, dm, ngrow_state, pp_prefix, refRatio(), max_level);
476  }
477 
478  //
479  // Define the land mask here and set it to all land by default
480  // NOTE: the logic below will BREAK if we have any grids not touching the bottom boundary
481  //
482  {
483  lmask_lev[lev].resize(1);
484  auto ngv = lev_new[Vars::cons].nGrowVect(); ngv[2] = 0;
485  lmask_lev[lev][0] = std::make_unique<iMultiFab>(ba2d[lev],dm,1,ngv);
486  lmask_lev[lev][0]->setVal(1);
487  lmask_lev[lev][0]->FillBoundary(geom[lev].periodicity());
488 
489  land_type_lev[lev].resize(1);
490  land_type_lev[lev][0] = std::make_unique<iMultiFab>(ba2d[lev],dm,1,ngv);
491  land_type_lev[lev][0]->setVal(0);
492  land_type_lev[lev][0]->FillBoundary(geom[lev].periodicity());
493 
494  soil_type_lev[lev].resize(1);
495  soil_type_lev[lev][0] = std::make_unique<iMultiFab>(ba2d[lev],dm,1,ngv);
496  soil_type_lev[lev][0]->setVal(0);
497  soil_type_lev[lev][0]->FillBoundary(geom[lev].periodicity());
498 
499  urb_frac_lev[lev].resize(1);
500  urb_frac_lev[lev][0] = std::make_unique<MultiFab>(ba2d[lev],dm,1,ngv);
501  urb_frac_lev[lev][0]->setVal(one);
502  urb_frac_lev[lev][0]->FillBoundary(geom[lev].periodicity());
503  }
504 
505  // Read in tables needed for windfarm simulations
506  // fill in Nturb multifab - number of turbines in each mesh cell
507  // write out the vtk files for wind turbine location and/or
508  // actuator disks
509  #ifdef ERF_USE_WINDFARM
510  //init_windfarm(lev);
511  #endif
512 
513  if (lev > 0) {
514  fine_mask[lev] = std::make_unique<MultiFab>(grids[lev-1], dmap[lev-1], 1, 0);
515  build_fine_mask(lev, *fine_mask[lev].get());
516  }
517 
518 #ifdef ERF_USE_FFT
519  if ( ( (solverChoice.anelastic[lev] == 1) || (solverChoice.project_initial_velocity[lev] == 1) ) &&
520  ( (solverChoice.mesh_type == MeshType::ConstantDz) || (solverChoice.mesh_type == MeshType::StretchedDz) ) ) {
521  build_fft_solvers(lev);
522  }
523 #endif
524 }
@ num
Definition: ERF_DataStruct.H:24
#define NDRY
Definition: ERF_IndexDefines.H:13
void init_default_zphys(int, const Geometry &geom, MultiFab &z_phys_nd, MultiFab &z_phys_cc, Real z_offset)
Definition: ERF_TerrainMetrics.cpp:15
std::unique_ptr< amrex::MultiFab > wrf_MUB
Definition: ERF.H:1302
std::unique_ptr< amrex::MultiFab > wrf_C1H
Definition: ERF.H:1300
void build_fine_mask(int lev, amrex::MultiFab &fine_mask)
Definition: ERF_VolWgtSum.cpp:125
static AMREX_FORCE_INLINE int ComputeGhostCells(const SolverChoice &sc)
Definition: ERF.H:1397
amrex::EBFArrayBoxFactory const & EBFactory(int lev) const noexcept
Definition: ERF.H:1676
std::unique_ptr< amrex::MultiFab > wrf_C2H
Definition: ERF.H:1301
@ num_comps
Definition: ERF_IndexDefines.H:78
@ gpz
Definition: ERF_IndexDefines.H:186
@ gpy
Definition: ERF_IndexDefines.H:185
@ gpx
Definition: ERF_IndexDefines.H:184
amrex::Vector< PerturbationType > pert_type
Definition: ERF_DataStruct.H:1280
bool test_mapfactor
Definition: ERF_DataStruct.H:1173
void init_tpi_type(const int lev, const PerturbationType &pert_type, const int max_level)
Definition: ERF_TurbPertStruct.H:28
void init_tpi(const int lev, const amrex::Vector< amrex::BoxArray > &subdomains_lev, const amrex::GpuArray< amrex::Real, 3 > dx, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm, const int ngrow_state, std::string pp_prefix, const amrex::Vector< amrex::IntVect > refRatio, const int max_level)
Definition: ERF_TurbPertStruct.H:52
Here is the call graph for this function:

◆ init_thin_body()

void ERF::init_thin_body ( int  lev,
const amrex::BoxArray &  ba,
const amrex::DistributionMapping &  dm 
)
896 {
897  //********************************************************************************************
898  // Thin immersed body
899  // *******************************************************************************************
900 #if 0
901  if ((solverChoice.advChoice.zero_xflux.size() > 0) ||
902  (solverChoice.advChoice.zero_yflux.size() > 0) ||
903  (solverChoice.advChoice.zero_zflux.size() > 0))
904  {
905  overset_imask[lev] = std::make_unique<iMultiFab>(ba,dm,1,0);
906  overset_imask[lev]->setVal(1); // == value is unknown (to be solved)
907  }
908 #endif
909 
910  if (solverChoice.advChoice.zero_xflux.size() > 0) {
911  amrex::Print() << "Setting up thin immersed body for "
912  << solverChoice.advChoice.zero_xflux.size() << " xfaces" << std::endl;
913  BoxArray ba_xf(ba);
914  ba_xf.surroundingNodes(0);
915  thin_xforce[lev] = std::make_unique<MultiFab>(ba_xf,dm,1,0);
916  thin_xforce[lev]->setVal(0.0);
917  xflux_imask[lev] = std::make_unique<iMultiFab>(ba_xf,dm,1,0);
918  xflux_imask[lev]->setVal(1);
919  for ( MFIter mfi(*xflux_imask[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi )
920  {
921  Array4<int> const& imask_arr = xflux_imask[lev]->array(mfi);
922  //Array4<int> const& imask_cell_arr = overset_imask[lev]->array(mfi);
923  Box xbx = mfi.nodaltilebox(0);
924  for (int iv=0; iv < solverChoice.advChoice.zero_xflux.size(); ++iv) {
925  const auto& faceidx = solverChoice.advChoice.zero_xflux[iv];
926  if ((faceidx[0] >= xbx.smallEnd(0)) && (faceidx[0] <= xbx.bigEnd(0)) &&
927  (faceidx[1] >= xbx.smallEnd(1)) && (faceidx[1] <= xbx.bigEnd(1)) &&
928  (faceidx[2] >= xbx.smallEnd(2)) && (faceidx[2] <= xbx.bigEnd(2)))
929  {
930  imask_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
931  //imask_cell_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
932  //imask_cell_arr(faceidx[0]-1,faceidx[1],faceidx[2]) = 0;
933  amrex::AllPrint() << " mask xface at " << faceidx << std::endl;
934  }
935  }
936  }
937  } else {
938  thin_xforce[lev] = nullptr;
939  xflux_imask[lev] = nullptr;
940  }
941 
942  if (solverChoice.advChoice.zero_yflux.size() > 0) {
943  amrex::Print() << "Setting up thin immersed body for "
944  << solverChoice.advChoice.zero_yflux.size() << " yfaces" << std::endl;
945  BoxArray ba_yf(ba);
946  ba_yf.surroundingNodes(1);
947  thin_yforce[lev] = std::make_unique<MultiFab>(ba_yf,dm,1,0);
948  thin_yforce[lev]->setVal(0.0);
949  yflux_imask[lev] = std::make_unique<iMultiFab>(ba_yf,dm,1,0);
950  yflux_imask[lev]->setVal(1);
951  for ( MFIter mfi(*yflux_imask[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi )
952  {
953  Array4<int> const& imask_arr = yflux_imask[lev]->array(mfi);
954  //Array4<int> const& imask_cell_arr = overset_imask[lev]->array(mfi);
955  Box ybx = mfi.nodaltilebox(1);
956  for (int iv=0; iv < solverChoice.advChoice.zero_yflux.size(); ++iv) {
957  const auto& faceidx = solverChoice.advChoice.zero_yflux[iv];
958  if ((faceidx[0] >= ybx.smallEnd(0)) && (faceidx[0] <= ybx.bigEnd(0)) &&
959  (faceidx[1] >= ybx.smallEnd(1)) && (faceidx[1] <= ybx.bigEnd(1)) &&
960  (faceidx[2] >= ybx.smallEnd(2)) && (faceidx[2] <= ybx.bigEnd(2)))
961  {
962  imask_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
963  //imask_cell_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
964  //imask_cell_arr(faceidx[0],faceidx[1]-1,faceidx[2]) = 0;
965  amrex::AllPrint() << " mask yface at " << faceidx << std::endl;
966  }
967  }
968  }
969  } else {
970  thin_yforce[lev] = nullptr;
971  yflux_imask[lev] = nullptr;
972  }
973 
974  if (solverChoice.advChoice.zero_zflux.size() > 0) {
975  amrex::Print() << "Setting up thin immersed body for "
976  << solverChoice.advChoice.zero_zflux.size() << " zfaces" << std::endl;
977  BoxArray ba_zf(ba);
978  ba_zf.surroundingNodes(2);
979  thin_zforce[lev] = std::make_unique<MultiFab>(ba_zf,dm,1,0);
980  thin_zforce[lev]->setVal(0.0);
981  zflux_imask[lev] = std::make_unique<iMultiFab>(ba_zf,dm,1,0);
982  zflux_imask[lev]->setVal(1);
983  for ( MFIter mfi(*zflux_imask[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi )
984  {
985  Array4<int> const& imask_arr = zflux_imask[lev]->array(mfi);
986  //Array4<int> const& imask_cell_arr = overset_imask[lev]->array(mfi);
987  Box zbx = mfi.nodaltilebox(2);
988  for (int iv=0; iv < solverChoice.advChoice.zero_zflux.size(); ++iv) {
989  const auto& faceidx = solverChoice.advChoice.zero_zflux[iv];
990  if ((faceidx[0] >= zbx.smallEnd(0)) && (faceidx[0] <= zbx.bigEnd(0)) &&
991  (faceidx[1] >= zbx.smallEnd(1)) && (faceidx[1] <= zbx.bigEnd(1)) &&
992  (faceidx[2] >= zbx.smallEnd(2)) && (faceidx[2] <= zbx.bigEnd(2)))
993  {
994  imask_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
995  //imask_cell_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
996  //imask_cell_arr(faceidx[0],faceidx[1],faceidx[2]-1) = 0;
997  amrex::AllPrint() << " mask zface at " << faceidx << std::endl;
998  }
999  }
1000  }
1001  } else {
1002  thin_zforce[lev] = nullptr;
1003  zflux_imask[lev] = nullptr;
1004  }
1005 }
amrex::Vector< amrex::IntVect > zero_yflux
Definition: ERF_AdvStruct.H:438
amrex::Vector< amrex::IntVect > zero_xflux
Definition: ERF_AdvStruct.H:437
amrex::Vector< amrex::IntVect > zero_zflux
Definition: ERF_AdvStruct.H:439

◆ init_zphys()

void ERF::init_zphys ( int  lev,
amrex::Real  elapsed_time 
)
694 {
695  // For EB, z_phys_nd was already initialized with the correct z_offset by init_default_zphys.
696  // The terrain-fitting (BTF) done below is irrelevant for a flat EB mesh and would clobber
697  // the offset, so return early here.
698  if (solverChoice.terrain_type == TerrainType::EB) {
699  Real dzmin = get_dzmin_terrain(*z_phys_nd[lev]);
700  micro->Set_dzmin(lev, dzmin);
701  return;
702  }
703 
704  if (solverChoice.init_type != InitType::WRFInput && solverChoice.init_type != InitType::Metgrid)
705  {
706  if (lev > 0) {
707  //
708  // First interpolate from coarser level if there is one
709  // NOTE: this interpolater assumes that ALL ghost cells of the coarse MultiFab
710  // have been pre-filled - this includes ghost cells both inside and outside
711  // the domain
712  //
713  InterpFromCoarseLevel(*z_phys_nd[lev], z_phys_nd[lev]->nGrowVect(),
714  IntVect(0,0,0), // do NOT fill ghost cells outside the domain
715  *z_phys_nd[lev-1], 0, 0, 1,
716  geom[lev-1], geom[lev],
717  refRatio(lev-1), &node_bilinear_interp,
719  }
720 
721  int ngrow = ComputeGhostCells(solverChoice) + 2;
722  Box bx(surroundingNodes(Geom(lev).Domain())); bx.grow(ngrow);
723  FArrayBox terrain_fab(makeSlab(bx,2,0),1);
724 
725  //
726  // If we are using fitted mesh then we use the surface as defined above
727  // If we are not using fitted mesh but are using z_levels, we still need z_phys (for now)
728  // but we need to use a flat terrain for the mesh itself (the EB data has already been made
729  // from the correct terrain)
730  //
731  if (solverChoice.terrain_type != TerrainType::StaticFittedMesh &&
732  solverChoice.terrain_type != TerrainType::MovingFittedMesh) {
733  terrain_fab.template setVal<RunOn::Device>(zero);
734  } else {
735  //
736  // Fill the values of the terrain height at k=0 only
737  //
738  prob->init_terrain_surface(geom[lev],terrain_fab,elapsed_time);
739  }
740 
741  for (MFIter mfi(*z_phys_nd[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
742  {
743  Box isect = terrain_fab.box() & (*z_phys_nd[lev])[mfi].box();
744  if (!isect.isEmpty()) {
745  (*z_phys_nd[lev])[mfi].template copy<RunOn::Device>(terrain_fab,isect,0,isect,0,1);
746  }
747  }
748 
750 
751  z_phys_nd[lev]->FillBoundary(geom[lev].periodicity());
752 
753  if (lev == 0) {
754  Real zmax = z_phys_nd[0]->max(0,0,false);
755  Real rel_diff = (zmax - zlevels_stag[0][zlevels_stag[0].size()-1]) / zmax;
756  if (rel_diff < Real(1.e-8)) {
757  amrex::Print() << "max of zphys_nd " << zmax << std::endl;
758  amrex::Print() << "max of zlevels " << zlevels_stag[0][zlevels_stag[0].size()-1] << std::endl;
759  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(rel_diff < Real(1.e-8), "Terrain is taller than domain top!");
760  }
761  } // lev == 0
762 
763  } else {
764  // NOTE: If a WRFInput file is NOT provided for a finer level,
765  // we simply interpolate from the coarse. This is necessary
766  // since we average_down the terrain (ERF_MakeNewLevel.cpp L351).
767  // If a WRFInput file IS present, it overwrites the terrain data.
768  if (lev > 0) {
769  //
770  // First interpolate from coarser level if there is one
771  // NOTE: this interpolater assumes that ALL ghost cells of the coarse MultiFab
772  // have been pre-filled - this includes ghost cells both inside and outside
773  // the domain
774  //
775  InterpFromCoarseLevel(*z_phys_nd[lev], z_phys_nd[lev]->nGrowVect(),
776  z_phys_nd[lev]->nGrowVect(), // DO fill ghost cells outside the domain
777  *z_phys_nd[lev-1], 0, 0, 1,
778  geom[lev-1], geom[lev],
779  refRatio(lev-1), &node_bilinear_interp,
781  }
782  } // init_type
783 
784  if (solverChoice.terrain_type == TerrainType::ImmersedForcing ||
785  solverChoice.buildings_type == BuildingsType::ImmersedForcing) {
786  terrain_blanking[lev]->setVal(one);
787  MultiFab::Subtract(*terrain_blanking[lev], EBFactory(lev).getVolFrac(), 0, 0, 1, ComputeGhostCells(solverChoice) + 2);
788  terrain_blanking[lev]->FillBoundary(geom[lev].periodicity());
789  init_immersed_forcing(lev); // needed for real cases
790  }
791 
792  // Compute the min dz and pass to the micro model
793  Real dzmin = get_dzmin_terrain(*z_phys_nd[lev]);
794  micro->Set_dzmin(lev, dzmin);
795 }
Real get_dzmin_terrain(MultiFab &z_phys_nd)
Definition: ERF_TerrainMetrics.cpp:653
void make_terrain_fitted_coords(int lev, const Geometry &geom, MultiFab &z_phys_nd, Vector< Real > const &z_levels_h, GpuArray< ERF_BC, AMREX_SPACEDIM *2 > &phys_bc_type)
Definition: ERF_TerrainMetrics.cpp:47
Here is the call graph for this function:

◆ InitData()

void ERF::InitData ( )
986 {
987  BL_PROFILE_VAR("ERF::InitData()", InitData);
988  InitData_pre();
989  InitData_post();
990  BL_PROFILE_VAR_STOP(InitData);
991 }
void InitData_pre()
Definition: ERF.cpp:994
void InitData_post()
Definition: ERF.cpp:1018
void InitData()
Definition: ERF.cpp:985

Referenced by main().

Here is the caller graph for this function:

◆ InitData_post()

void ERF::InitData_post ( )
1019 {
1021  {
1022  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(finest_level == 0,
1023  "Thin immersed body with refinement not currently supported.");
1024  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
1025  amrex::Print() << "NOTE: Thin immersed body with non-constant dz has not been tested." << std::endl;
1026  }
1027  }
1028 
1029  if (!restart_chkfile.empty()) {
1030  restart();
1031  }
1032 
1033  //
1034  // Make sure that detJ and z_phys_cc are the average of the data on a finer level if there is one and if two way coupling
1035  //
1036  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
1037  if (solverChoice.coupling_type == CouplingType::TwoWay) {
1038  for (int crse_lev = finest_level-1; crse_lev >= 0; crse_lev--) {
1039  average_down( *detJ_cc[crse_lev+1], *detJ_cc[crse_lev], 0, 1, refRatio(crse_lev));
1040  average_down(*z_phys_cc[crse_lev+1], *z_phys_cc[crse_lev], 0, 1, refRatio(crse_lev));
1041  }
1042  }
1043  for (int crse_lev = finest_level-1; crse_lev >= 0; crse_lev--) {
1044  detJ_cc[crse_lev]->FillBoundary(geom[crse_lev].periodicity());
1045  z_phys_cc[crse_lev]->FillBoundary(geom[crse_lev].periodicity());
1046  }
1047  }
1048 
1049 #ifdef ERF_IMPLICIT_W
1050  if (SolverChoice::mesh_type == MeshType::VariableDz &&
1051  (solverChoice.vert_implicit_fac[0] > 0 ||
1053  solverChoice.vert_implicit_fac[2] > 0 ) &&
1055  {
1056  Warning("Doing implicit solve for u, v, and w with terrain -- this has not been tested");
1057  }
1058 #endif
1059 
1060  //
1061  // Copy vars_new into vars_old, then use vars_old to fill covered cells in vars_new during AverageDown
1062  //
1063  if (SolverChoice::terrain_type == TerrainType::EB) {
1064  for (int lev = 0; lev <= finest_level; lev++) {
1065  int ncomp_cons = vars_new[lev][Vars::cons].nComp();
1066  MultiFab::Copy(vars_old[lev][Vars::cons],vars_new[lev][Vars::cons],0,0,ncomp_cons,vars_new[lev][Vars::cons].nGrowVect());
1067  }
1068  }
1069 
1070  if (restart_chkfile.empty()) {
1071  if (solverChoice.coupling_type == CouplingType::TwoWay) {
1072  AverageDown();
1073  }
1074  }
1075 
1076 #ifdef ERF_USE_PARTICLES
1077  if (Microphysics::modelType(solverChoice.moisture_type) == MoistureModelType::Lagrangian) {
1078  // Promote the Lagrangian PC to the multi-level ParGDB before init so
1079  // per-level addParticles() can use ParticleBoxArray(lev)/DistributionMap(lev).
1080  auto* pc_ptr = dynamic_cast<LagrangianMicrophysics&>(*micro).getParticleContainer();
1081  AMREX_ALWAYS_ASSERT(pc_ptr != nullptr);
1082  pc_ptr->Define(static_cast<amrex::ParGDBBase*>(GetParGDB()));
1083 
1084  if (restart_chkfile.empty()) {
1086  Warning("Tight coupling has not been tested with Lagrangian microphysics");
1087  }
1088 
1089  for (int lev = 0; lev <= finest_level; lev++) {
1090  dynamic_cast<LagrangianMicrophysics&>(*micro).initParticles(lev, z_phys_nd[lev]);
1091  }
1092  }
1093  }
1094 #endif
1095 
1096  if (!restart_chkfile.empty()) { // Restart from a checkpoint
1097 
1098  // Create the physbc objects for {cons, u, v, w, base state}
1099  // We fill the additional base state ghost cells just in case we have read the old format
1100  for (int lev(0); lev <= finest_level; ++lev) {
1101  make_physbcs(lev);
1102  (*physbcs_base[lev])(base_state[lev],0,base_state[lev].nComp(),base_state[lev].nGrowVect());
1103  }
1104 
1106  for (int lev(0); lev <= finest_level; ++lev) {
1107  m_forest_drag[lev]->define_drag_field(grids[lev], dmap[lev], geom[lev],
1108  z_phys_cc[lev].get(), z_phys_nd[lev].get());
1109  }
1110  }
1111 
1112 #ifdef ERF_USE_NETCDF
1113  //
1114  // Create the needed bdy_data_xlo etc ... since we don't read it in from checkpoint any more
1115  // This follows init_from_wrfinput()
1116  //
1117  bool use_moist = (solverChoice.moisture_type != MoistureType::None);
1118  if (solverChoice.use_real_bcs && solverChoice.init_type == InitType::WRFInput) {
1119 
1120  if ( geom[0].isPeriodic(0) || geom[0].isPeriodic(1) ) {
1121  amrex::Error("Cannot set periodic lateral boundary conditions when reading in real boundary values");
1122  }
1123 
1124  bdy_time_interval = read_times_from_wrfbdy(nc_bdy_file,
1125  bdy_data_xlo,bdy_data_xhi,bdy_data_ylo,bdy_data_yhi,
1126  start_bdy_time, final_bdy_time);
1127 
1128  Real time_since_start_bdy = t_new[0] + start_time - start_bdy_time;
1129  int n_time_old = static_cast<int>(time_since_start_bdy / bdy_time_interval);
1130  MultiFab r_hse(base_state[0], make_alias, BaseState::r0_comp, 1);
1131  Array<MultiFab*, AMREX_SPACEDIM> area_vec = {ax[0].get(), ay[0].get(), az[0].get()};
1132 
1133  // Need itime=0 for vertical interpolation
1134  if (n_time_old > 0) {
1135  int itime = 0;
1136  bool is_anelastic = (solverChoice.anelastic[0] == 1);
1137  read_and_convert_from_wrfbdy(itime,nc_bdy_file,
1138  bdy_data_xlo,bdy_data_xhi,bdy_data_ylo,bdy_data_yhi,
1141  r_hse, area_vec, geom[0], use_moist, domain_bcs_type,
1142  real_width, bdy_time_interval, is_anelastic);
1143  }
1144 
1145  int ntimes = std::min(n_time_old+3, static_cast<int>(bdy_data_xlo.size()));
1146 
1147  for (int itime = n_time_old; itime < ntimes; itime++)
1148  {
1149  bool is_anelastic = (solverChoice.anelastic[0] == 1);
1150  read_and_convert_from_wrfbdy(itime,nc_bdy_file,
1151  bdy_data_xlo,bdy_data_xhi,bdy_data_ylo,bdy_data_yhi,
1154  r_hse, area_vec, geom[0], use_moist, domain_bcs_type,
1155  real_width, bdy_time_interval, is_anelastic);
1156  } // itime
1157  } // use_real_bcs
1158 
1159  if (!nc_low_file.empty())
1160  {
1161  low_time_interval = read_times_from_wrflow(nc_low_file, low_data_zlo, start_low_time, final_low_time);
1162 
1163  int lev = 0;
1164  sst_lev[lev].resize(low_data_zlo.size());
1165  tsk_lev[lev].resize(low_data_zlo.size());
1166 
1167  Real time_since_start_low = t_new[0] + start_time - start_low_time;
1168  int n_time_old = static_cast<int>(time_since_start_low / low_time_interval);
1169 
1170  int ntimes = std::min(n_time_old+3, static_cast<int>(low_data_zlo.size()));
1171 
1172  for (int itime = n_time_old; itime < ntimes; itime++)
1173  {
1174  read_from_wrflow(itime, nc_low_file, geom[lev].Domain(), low_data_zlo);
1175 
1176  // Need to read PSFC
1177  FArrayBox NC_fab_var_file;
1178  for (int idx = 0; idx < num_boxes_at_level[lev]; idx++) {
1179  int success, use_theta_m;
1180  read_from_wrfinput(lev, boxes_at_level[lev][idx], nc_init_file[lev][0],
1181  NC_fab_var_file, "PSFC", geom[lev],
1182  use_theta_m, success);
1183  auto& var_fab = NC_fab_var_file;
1184 #ifdef _OPENMP
1185 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
1186 #endif
1187  for ( MFIter mfi(*mf_PSFC[lev], false); mfi.isValid(); ++mfi )
1188  {
1189  FArrayBox &cur_fab = (*mf_PSFC[lev])[mfi];
1190  cur_fab.template copy<RunOn::Device>(var_fab, 0, 0, 1);
1191  }
1192  var_fab.clear();
1193  }
1194 
1195  update_sst_tsk(itime, geom[lev], ba2d[lev],
1196  sst_lev[lev], tsk_lev[lev],
1197  m_SurfaceLayer, low_data_zlo,
1198  vars_new[lev][Vars::cons], *mf_PSFC[lev],
1199  solverChoice.rdOcp, lmask_lev[lev][0], use_moist);
1200  } // itime
1201  }
1202 #endif
1203  } // end restart
1204 
1205 #ifdef ERF_USE_PARTICLES
1206  /* If using a Lagrangian microphysics model, its particle container has now been
1207  constructed and initialized (calls to micro->Init). So, add its pointer to
1208  ERF::particleData and remove its name from list of unallocated particle containers. */
1209  if (Microphysics::modelType(solverChoice.moisture_type) == MoistureModelType::Lagrangian) {
1210  const auto& pc_name( dynamic_cast<LagrangianMicrophysics&>(*micro).getName() );
1211  const auto& pc_ptr( dynamic_cast<LagrangianMicrophysics&>(*micro).getParticleContainer() );
1212  AMREX_ALWAYS_ASSERT(pc_ptr != nullptr);
1213  particleData.pushBack(pc_name, pc_ptr);
1214  particleData.getNamesUnalloc().remove(pc_name);
1215  }
1216 #endif
1217 
1218  if (input_bndry_planes) {
1219  // Read the "time.dat" file to know what data is available
1220  m_r2d->read_time_file();
1221 
1222  // We haven't populated dt yet, set to 0 to ensure assert doesn't crash
1223  Real dt_dummy = zero;
1224  m_r2d->read_input_files(t_new[0]+start_time,dt_dummy,m_bc_extdir_vals);
1225  }
1226 
1228  {
1229  rhotheta_src.resize(max_level+1);
1230  for (int lev = 0; lev <= finest_level; lev++) {
1231  BoxList bl_src = vars_new[lev][Vars::cons].boxArray().boxList();
1232  for (auto& b : bl_src) {
1234  {
1235  // source is only defined in Z
1236  b.setRange(0, 0, 1);
1237  b.setRange(1, 0, 1);
1238  }
1239  }
1240  BoxArray ba_src(std::move(bl_src));
1241  rhotheta_src[lev] = std::make_unique<MultiFab>(ba_src, vars_new[lev][Vars::cons].DistributionMap(), 1, 0);
1242  rhotheta_src[lev]->setVal(0.);
1243  prob->update_rhotheta_sources(t_new[0],
1244  rhotheta_src[lev].get(),
1245  geom[lev], z_phys_cc[lev]);
1246  }
1247  }
1248 
1250  {
1251  h_u_geos.resize(max_level+1, Vector<Real>(0));
1252  d_u_geos.resize(max_level+1, Gpu::DeviceVector<Real>(0));
1253  h_v_geos.resize(max_level+1, Vector<Real>(0));
1254  d_v_geos.resize(max_level+1, Gpu::DeviceVector<Real>(0));
1255  for (int lev = 0; lev <= finest_level; lev++) {
1256  const int domlen = geom[lev].Domain().length(2);
1257  h_u_geos[lev].resize(domlen, 0.0_rt);
1258  d_u_geos[lev].resize(domlen, 0.0_rt);
1259  h_v_geos[lev].resize(domlen, 0.0_rt);
1260  d_v_geos[lev].resize(domlen, 0.0_rt);
1262  prob->update_geostrophic_profile(t_new[0],
1263  h_u_geos[lev], d_u_geos[lev],
1264  h_v_geos[lev], d_v_geos[lev],
1265  geom[lev], z_phys_cc[lev]);
1266  } else {
1267  if (SolverChoice::mesh_type == MeshType::VariableDz) {
1268  amrex::Print() << "Note: 1-D geostrophic wind profile input is not defined for real terrain" << std::endl;
1269  }
1271  h_u_geos[lev], d_u_geos[lev],
1272  h_v_geos[lev], d_v_geos[lev],
1273  geom[lev],
1274  zlevels_stag[0]);
1275  }
1276  }
1277  }
1278 
1280  {
1281  rhoqt_src.resize(max_level+1);
1282  for (int lev = 0; lev <= finest_level; lev++) {
1283  BoxList bl_src = vars_new[lev][Vars::cons].boxArray().boxList();
1284  for (auto& b : bl_src) {
1286  {
1287  // source is only defined in Z
1288  b.setRange(0, 0, 1);
1289  b.setRange(1, 0, 1);
1290  }
1291  }
1292  BoxArray ba_src(std::move(bl_src));
1293  rhoqt_src[lev] = std::make_unique<MultiFab>(ba_src, vars_new[lev][Vars::cons].DistributionMap(), 1, 0);
1294  rhoqt_src[lev]->setVal(0.);
1295  prob->update_rhoqt_sources(t_new[0],
1296  rhoqt_src[lev].get(),
1297  geom[lev], z_phys_cc[lev]);
1298  }
1299  }
1300 
1302  {
1303  h_w_subsid.resize(max_level+1, Vector<Real>(0));
1304  d_w_subsid.resize(max_level+1, Gpu::DeviceVector<Real>(0));
1305  for (int lev = 0; lev <= finest_level; lev++) {
1306  const int domlen = geom[lev].Domain().length(2) + 1; // lives on z-faces
1307  h_w_subsid[lev].resize(domlen, 0.0_rt);
1308  d_w_subsid[lev].resize(domlen, 0.0_rt);
1309  prob->update_w_subsidence(t_new[0],
1310  h_w_subsid[lev], d_w_subsid[lev], base_state[lev],
1311  geom[lev], z_phys_nd[lev]);
1312  }
1313  }
1314 
1317  {
1318  for (int lev = 0; lev <= finest_level; lev++) {
1319  initRayleigh_at_level(lev);
1320  }
1321  if (solverChoice.init_type == InitType::Input_Sounding)
1322  {
1323  // Overwrite ubar, vbar, and thetabar with input profiles;
1324  // wbar is assumed to be zero Note: the tau coefficient set by
1325  // prob->erf_init_rayleigh() is still used
1326  bool restarting = (!restart_chkfile.empty());
1327  setRayleighRefFromSounding(restarting);
1328  }
1329  }
1330 
1331  // Read in sponge data from input file
1332  if(solverChoice.spongeChoice.sponge_type == SpongeType::Input_Sponge)
1333  {
1334  initSponge();
1335  bool restarting = (!restart_chkfile.empty());
1336  setSpongeRefFromSounding(restarting);
1337  }
1338 
1340  if (is_it_time_for_action(istep[0], t_new[0], dt[0], pert_interval, -one)) {
1341  turbPert.debug(t_new[0]);
1342  }
1343  }
1344 
1345  // We only write the file at level 0 for now
1346  if (output_bndry_planes)
1347  {
1348  // Create the WriteBndryPlanes object so we can handle writing of boundary plane data
1349  m_w2d = std::make_unique<WriteBndryPlanes>(grids,geom);
1350 
1351  Real tot_time = t_new[0]+start_time;
1352  if (tot_time >= bndry_output_planes_start_time) {
1353  bool is_moist = (micro->Get_Qstate_Moist_Size() > 0);
1354  m_w2d->write_planes(0, tot_time, vars_new, is_moist);
1355  }
1356  }
1357 
1358  // Fill boundary conditions in vars_new
1359  for (int lev = 0; lev <= finest_level; ++lev)
1360  {
1361  auto& lev_new = vars_new[lev];
1362 
1363  // ***************************************************************************
1364  // Physical bc's at domain boundary
1365  // ***************************************************************************
1366  IntVect ngvect_cons = vars_new[lev][Vars::cons].nGrowVect();
1367  IntVect ngvect_vels = vars_new[lev][Vars::xvel].nGrowVect();
1368 
1369  int ncomp_cons = lev_new[Vars::cons].nComp();
1370  bool do_fb = true;
1371 
1372 #ifdef ERF_USE_NETCDF
1373  if (solverChoice.use_real_bcs && (lev==0)) {
1374  int icomp_cons = 0;
1375  bool cons_only = false;
1376  Vector<MultiFab*> mfs_vec = {&lev_new[Vars::cons],&lev_new[Vars::xvel],
1377  &lev_new[Vars::yvel],&lev_new[Vars::zvel]};
1378  fill_from_realbdy(mfs_vec,t_new[lev],cons_only,icomp_cons,
1379  ncomp_cons,ngvect_cons,ngvect_vels);
1380  do_fb = false;
1381  }
1382 #endif
1383 
1384  (*physbcs_cons[lev])(lev_new[Vars::cons],lev_new[Vars::xvel],lev_new[Vars::yvel],0,ncomp_cons,
1385  ngvect_cons,t_new[lev],BCVars::cons_bc,do_fb);
1386  ( *physbcs_u[lev])(lev_new[Vars::xvel],lev_new[Vars::xvel],lev_new[Vars::yvel],
1387  ngvect_vels,t_new[lev],BCVars::xvel_bc,do_fb);
1388  ( *physbcs_v[lev])(lev_new[Vars::yvel],lev_new[Vars::xvel],lev_new[Vars::yvel],
1389  ngvect_vels,t_new[lev],BCVars::yvel_bc,do_fb);
1390  ( *physbcs_w[lev])(lev_new[Vars::zvel],lev_new[Vars::xvel],lev_new[Vars::yvel],
1391  ngvect_vels,t_new[lev],BCVars::zvel_bc,do_fb);
1392  }
1393 
1394  //
1395  // If we are starting from scratch, we have the option to project the initial velocity field
1396  // regardless of how we initialized. Note that project_initial_velocity operates on vars_new.
1397  // pp_inc is used as scratch space here; we zero it out after the projection
1398  //
1399  if (restart_chkfile == "")
1400  {
1401  for (int lev = 0; lev <= finest_level; ++lev)
1402  {
1403  if (solverChoice.project_initial_velocity[lev] == 1) {
1404  Real dummy_dt = one;
1405  if (verbose > 0) {
1406  amrex::Print() << "Projecting initial velocity field at level " << lev << std::endl;
1407  }
1408 
1409  project_initial_velocity(lev, t_new[lev], dummy_dt);
1410 
1411  pp_inc[lev].setVal(0.);
1412  gradp[lev][GpVars::gpx].setVal(0.);
1413  gradp[lev][GpVars::gpy].setVal(0.);
1414  gradp[lev][GpVars::gpz].setVal(0.);
1415  } // project
1416  } // lev
1417  }
1418 
1419  // Copy from new into old just in case (after filling boundary conditions and possibly projecting)
1420  for (int lev = 0; lev <= finest_level; ++lev)
1421  {
1422  int nc = vars_new[lev][Vars::cons].nComp();
1423 
1424  MultiFab::Copy(vars_old[lev][Vars::cons],vars_new[lev][Vars::cons],0,0,nc,vars_new[lev][Vars::cons].nGrowVect());
1425  MultiFab::Copy(vars_old[lev][Vars::xvel],vars_new[lev][Vars::xvel],0,0, 1,vars_new[lev][Vars::xvel].nGrowVect());
1426  MultiFab::Copy(vars_old[lev][Vars::yvel],vars_new[lev][Vars::yvel],0,0, 1,vars_new[lev][Vars::yvel].nGrowVect());
1427  MultiFab::Copy(vars_old[lev][Vars::zvel],vars_new[lev][Vars::zvel],0,0, 1,vars_new[lev][Vars::zvel].nGrowVect());
1428  }
1429 
1430  // Compute the minimum dz in the domain at each level (to be used for setting the timestep)
1431  dz_min.resize(max_level+1);
1432  for (int lev = 0; lev <= finest_level; ++lev)
1433  {
1434  dz_min[lev] = geom[lev].CellSize(2);
1435  if ( SolverChoice::mesh_type != MeshType::ConstantDz ) {
1436  dz_min[lev] *= (*detJ_cc[lev]).min(0);
1437  }
1438  }
1439 
1440 
1441  // We don't need to recompute dt[lev] on restart because we read it in from the checkpoint file.
1442  if (restart_chkfile.empty()) {
1443  ComputeDt();
1444  }
1445 
1446  // Check the viscous limit
1450  Real delta = std::min({geom[finest_level].CellSize(0),
1451  geom[finest_level].CellSize(1),
1452  dz_min[finest_level]});
1453  if (dc.dynamic_viscosity == 0) {
1454  Print() << "Note: Molecular diffusion specified but dynamic_viscosity has not been specified" << std::endl;
1455  } else {
1456  Real nu = dc.dynamic_viscosity / dc.rho0_trans;
1457  Real viscous_limit = two * delta*delta / nu;
1458  Print() << "smallest grid spacing at level " << finest_level << " = " << delta << std::endl;
1459  Print() << "dt at level " << finest_level << " = " << dt[finest_level] << std::endl;
1460  Print() << "Viscous CFL is " << dt[finest_level] / viscous_limit << std::endl;
1461  if (fixed_dt[finest_level] >= viscous_limit) {
1462  Warning("Specified fixed_dt is above the viscous limit");
1463  } else if (dt[finest_level] >= viscous_limit) {
1464  Warning("Adaptive dt based on convective CFL only is above the viscous limit");
1465  }
1466  }
1467  }
1468 
1469  // Fill ghost cells/faces
1470  for (int lev = 0; lev <= finest_level; ++lev)
1471  {
1472  if (lev > 0 && cf_width >= 0) {
1474  }
1475 
1476  auto& lev_new = vars_new[lev];
1477 
1478  //
1479  // Fill boundary conditions -- not sure why we need this here
1480  //
1481  bool fillset = false;
1482  if (lev == 0) {
1483  FillPatchCrseLevel(lev, t_new[lev],
1484  {&lev_new[Vars::cons],&lev_new[Vars::xvel],&lev_new[Vars::yvel],&lev_new[Vars::zvel]});
1485  } else {
1486  FillPatchFineLevel(lev, t_new[lev],
1487  {&lev_new[Vars::cons],&lev_new[Vars::xvel],&lev_new[Vars::yvel],&lev_new[Vars::zvel]},
1488  {&lev_new[Vars::cons],&rU_new[lev],&rV_new[lev],&rW_new[lev]},
1489  base_state[lev], base_state[lev],
1490  fillset);
1491  }
1492 
1493  //
1494  // We do this here to make sure level (lev-1) boundary conditions are filled
1495  // before we interpolate to level (lev) ghost cells
1496  //
1497  if (lev < finest_level) {
1498  auto& lev_old = vars_old[lev];
1499  MultiFab::Copy(lev_old[Vars::cons],lev_new[Vars::cons],0,0,lev_old[Vars::cons].nComp(),lev_old[Vars::cons].nGrowVect());
1500  MultiFab::Copy(lev_old[Vars::xvel],lev_new[Vars::xvel],0,0,lev_old[Vars::xvel].nComp(),lev_old[Vars::xvel].nGrowVect());
1501  MultiFab::Copy(lev_old[Vars::yvel],lev_new[Vars::yvel],0,0,lev_old[Vars::yvel].nComp(),lev_old[Vars::yvel].nGrowVect());
1502  MultiFab::Copy(lev_old[Vars::zvel],lev_new[Vars::zvel],0,0,lev_old[Vars::zvel].nComp(),lev_old[Vars::zvel].nGrowVect());
1503  }
1504 
1505  //
1506  // We fill the ghost cell values of the base state in case it wasn't done in the initialization
1507  //
1508  base_state[lev].FillBoundary(geom[lev].periodicity());
1509 
1510  // For moving terrain only
1511  if (solverChoice.terrain_type == TerrainType::MovingFittedMesh) {
1512  MultiFab::Copy(base_state_new[lev],base_state[lev],0,0,BaseState::num_comps,base_state[lev].nGrowVect());
1513  base_state_new[lev].FillBoundary(geom[lev].periodicity());
1514  }
1515 
1516  }
1517 
1518  // Allow idealized cases over water, used to set lmask
1519  ParmParse pp("erf");
1520  int is_land;
1521  for (int lev = 0; lev <= finest_level; ++lev)
1522  {
1523  if (pp.query("is_land", is_land, lev)) {
1524  if (is_land == 1) {
1525  amrex::Print() << "Level " << lev << " is land" << std::endl;
1526  } else if (is_land == 0) {
1527  amrex::Print() << "Level " << lev << " is water" << std::endl;
1528  } else {
1529  Error("is_land should be 0 or 1");
1530  }
1531  lmask_lev[lev][0]->setVal(is_land);
1532  lmask_lev[lev][0]->FillBoundary(geom[lev].periodicity());
1533  }
1534  }
1535 
1536  // If lev > 0, we need to fill bc's by interpolation from coarser grid
1537  for (int lev = 1; lev <= finest_level; ++lev)
1538  {
1539  Interp2DArrays(lev,ba2d[lev],dmap[lev]);
1540  } // lev
1541 
1542 #ifdef ERF_USE_WW3_COUPLING
1543  int my_lev = 0;
1544  amrex::Print() << " About to call send_to_ww3 from ERF.cpp" << std::endl;
1545  send_to_ww3(my_lev);
1546  amrex::Print() << " About to call read_waves from ERF.cpp" << std::endl;
1547  read_waves(my_lev);
1548  // send_to_ww3(my_lev);
1549 #endif
1550 
1551  // Create wall distance field for RANS model
1552  for (int lev = 0; lev <= finest_level; lev++) {
1553  if (solverChoice.turbChoice[lev].rans_type != RANSType::None) {
1554  // Handle bottom boundary
1555  poisson_wall_dist(lev);
1556 
1557  // Correct the wall distance for immersed bodies
1563  geom[lev],
1564  z_phys_cc[lev]);
1565  }
1566  }
1567  }
1568 
1569  // Configure SurfaceLayer params if used
1570  // NOTE: we must set up the MOST routine after calling FillPatch
1571  // in order to have lateral ghost cells filled (MOST + terrain interp).
1572  if (phys_bc_type[Orientation(Direction::z,Orientation::low)] == ERF_BC::surface_layer)
1573  {
1575  (solverChoice.turbChoice[0].les_type != LESType::None) ||
1576  (solverChoice.turbChoice[0].rans_type != RANSType::None) ||
1577  (solverChoice.turbChoice[0].pbl_type != PBLType::None) );
1578  AMREX_ALWAYS_ASSERT(has_diff);
1579 
1580  bool rotate = solverChoice.use_rotate_surface_flux;
1581  if (rotate) {
1582  Print() << "Using surface layer model with stress rotations" << std::endl;
1583  }
1584 
1585  //
1586  // This constructor will make the SurfaceLayer object but not allocate the arrays at each level.
1587  //
1588  // Build vector of eb pointers for all levels
1589  amrex::Vector<const eb_*> eb_ptrs;
1590  eb_ptrs.resize(finest_level + 1, nullptr);
1591  if (solverChoice.terrain_type == TerrainType::EB) {
1592  for (int lev = 0; lev <= finest_level; lev++) {
1593  eb_ptrs[lev] = eb[lev] ? eb[lev].get() : nullptr;
1594  }
1595  }
1596 
1597  m_SurfaceLayer = std::make_unique<SurfaceLayer>(geom, rotate, pp_prefix, Qv_prim,
1598  z_phys_nd,
1601  solverChoice.turbChoice[finest_level],
1602 #ifdef ERF_USE_NETCDF
1603  start_low_time, final_low_time, low_time_interval,
1604 #else
1605  zero, zero, zero,
1606 #endif
1607  eb_ptrs);
1608  // This call will allocate the arrays at each level. If we regrid later, either changing
1609  // the number of levels or just the grids at each existing level, we will call an update routine
1610  // to redefine the internal arrays in m_SurfaceLayer.
1611  for (int lev = 0; lev <= finest_level; lev++)
1612  {
1613  Vector<MultiFab*> mfv_old = {&vars_old[lev][Vars::cons], &vars_old[lev][Vars::xvel],
1614  &vars_old[lev][Vars::yvel], &vars_old[lev][Vars::zvel]};
1615  m_SurfaceLayer->make_SurfaceLayer_at_level(lev,finest_level+1,
1616  mfv_old, Theta_prim[lev], Qv_prim[lev],
1617  Qr_prim[lev], z_phys_nd[lev],
1618  Hwave[lev].get(),Lwave[lev].get(),eddyDiffs_lev[lev].get(),
1620  sst_lev[lev], tsk_lev[lev], lmask_lev[lev]);
1621  }
1622 
1623  // If initializing from an input_sounding, make sure the surface layer
1624  // is using the same surface conditions
1625  if (solverChoice.init_type == InitType::Input_Sounding) {
1628  for (int lev = 0; lev <= finest_level; lev++) {
1629  m_SurfaceLayer->set_t_surf(lev, theta0);
1630  m_SurfaceLayer->set_q_surf(lev, qv0);
1631  }
1632  }
1633 
1634  if (restart_chkfile != "") {
1635  // Update surface fields if needed (and available)
1637  }
1638 
1639  // We now configure ABLMost params here so that we can print the averages at t=0
1640  // Note we don't fill ghost cells here because this is just for diagnostics
1641  for (int lev = 0; lev <= finest_level; ++lev)
1642  {
1643  IntVect ng = Theta_prim[lev]->nGrowVect();
1644 
1645  MultiFab::Copy( *Theta_prim[lev], vars_new[lev][Vars::cons], RhoTheta_comp, 0, 1, ng);
1646  MultiFab::Divide(*Theta_prim[lev], vars_new[lev][Vars::cons], Rho_comp, 0, 1, ng);
1647 
1648  if (solverChoice.moisture_type != MoistureType::None) {
1649  ng = Qv_prim[lev]->nGrowVect();
1650 
1651  MultiFab::Copy( *Qv_prim[lev], vars_new[lev][Vars::cons], RhoQ1_comp, 0, 1, ng);
1652  MultiFab::Divide(*Qv_prim[lev], vars_new[lev][Vars::cons], Rho_comp, 0, 1, ng);
1653 
1654  int rhoqr_comp = solverChoice.moisture_indices.qr;
1655  if (rhoqr_comp > -1) {
1656  MultiFab::Copy( *Qr_prim[lev], vars_new[lev][Vars::cons], rhoqr_comp, 0, 1, ng);
1657  MultiFab::Divide(*Qr_prim[lev], vars_new[lev][Vars::cons], Rho_comp, 0, 1, ng);
1658  } else {
1659  Qr_prim[lev]->setVal(0.0);
1660  }
1661  }
1662  m_SurfaceLayer->update_mac_ptrs(lev, vars_new, Theta_prim, Qv_prim, Qr_prim);
1663 
1664  if (restart_chkfile == "") {
1665  // Only do this if starting from scratch; if restarting, then
1666  // we don't want to call update_fluxes multiple times because
1667  // it will change u* and theta* from their previous values
1668  m_SurfaceLayer->update_pblh(lev, vars_new, z_phys_cc[lev].get(),
1670 #ifdef ERF_USE_NETCDF
1671  Real elapsed_time_since_start_low = t_new[lev] + (start_time - start_low_time);
1672 #else
1673  Real elapsed_time_since_start_low = t_new[lev] + start_time;
1674 #endif
1675  m_SurfaceLayer->update_fluxes(lev, t_new[lev], elapsed_time_since_start_low,
1676  vars_new[lev][Vars::cons],
1677  z_phys_nd[lev],
1678  walldist[lev]);
1679 
1680  // Initialize tke(x,y,z) as a function of u*(x,y)
1681  if (solverChoice.turbChoice[lev].init_tke_from_ustar) {
1682  Real qkefac = one;
1683  if (solverChoice.turbChoice[lev].pbl_type == PBLType::MYNN25 ||
1684  solverChoice.turbChoice[lev].pbl_type == PBLType::MYNNEDMF)
1685  {
1686  // https://github.com/NCAR/MYNN-EDMF/blob/90f36c25259ec1960b24325f5b29ac7c5adeac73/module_bl_mynnedmf.F90#L1325-L1333
1687  const Real B1 = solverChoice.turbChoice[lev].pbl_mynn.B1;
1688  qkefac = Real(1.5) * std::pow(B1, two/three);
1689  }
1690  m_SurfaceLayer->init_tke_from_ustar(lev, vars_new[lev][Vars::cons], z_phys_nd[lev], qkefac);
1691  }
1692  }
1693  }
1694  } // end if (phys_bc_type[Orientation(Direction::z,Orientation::low)] == ERF_BC::surface_layer)
1695 
1696  // Update micro vars and finish moisture model initializations before first plot file
1697  if (solverChoice.moisture_type != MoistureType::None) {
1698  for (int lev = 0; lev <= finest_level; ++lev) {
1699  micro->Update_Micro_Vars_Lev(lev, vars_new[lev][Vars::cons]);
1700  micro->FinishInit(lev, vars_new[lev][Vars::cons], z_phys_nd);
1701  }
1702  }
1703 
1704  // Fill time averaged velocities before first plot file
1705  if (solverChoice.time_avg_vel) {
1706  for (int lev = 0; lev <= finest_level; ++lev) {
1707  Time_Avg_Vel_atCC(dt[lev], t_avg_cnt[lev], vel_t_avg[lev].get(),
1708  vars_new[lev][Vars::xvel],
1709  vars_new[lev][Vars::yvel],
1710  vars_new[lev][Vars::zvel]);
1711  }
1712  }
1713 
1714 #ifdef ERF_USE_PARTICLES
1715  // Redistribute particles so the container has valid data at all AMR levels
1716  // before the initial plotfile write
1717  if (finest_level > 0) {
1718  particleData.Redistribute(z_phys_nd);
1719  }
1720 #endif
1721 
1722  // Print max values of lateral gradients of base state pressure at level 0
1723  if (verbose > 0) {
1724  for (int lev = 0; lev <= finest_level; ++lev) {
1726  }
1727  }
1728 
1729  // check for additional plotting variables that are available after particle containers
1730  // are setup.
1731  const std::string& pv3d_1 = "plot_vars_1" ; appendPlotVariables(pv3d_1,plot3d_var_names_1);
1732  const std::string& pv3d_2 = "plot_vars_2" ; appendPlotVariables(pv3d_2,plot3d_var_names_2);
1733  const std::string& pv2d_1 = "plot2d_vars_1"; appendPlotVariables(pv2d_1,plot2d_var_names_1);
1734  const std::string& pv2d_2 = "plot2d_vars_2"; appendPlotVariables(pv2d_2,plot2d_var_names_2);
1735 
1736  if ( restart_chkfile.empty() && (m_check_int > 0 || m_check_per > zero) )
1737  {
1741  }
1742 
1743  if ( (restart_chkfile.empty()) ||
1744  (!restart_chkfile.empty() && plot_file_on_restart) )
1745  {
1746  if (m_plot3d_int_1 > 0 || m_plot3d_per_1 > zero)
1747  {
1751  }
1752  if (m_plot3d_int_2 > 0 || m_plot3d_per_2 > zero)
1753  {
1757  }
1758  if (m_plot2d_int_1 > 0 || m_plot2d_per_1 > zero)
1759  {
1763  }
1764  if (m_plot2d_int_2 > 0 || m_plot2d_per_2 > zero)
1765  {
1769  }
1770  for (int i = 0; i < m_subvol_int.size(); i++) {
1771  if (m_subvol_int[i] > 0 || m_subvol_per[i] > zero) {
1773  last_subvol_step[i] = istep[0];
1774  if (m_subvol_per[i] > zero) {last_subvol_time[i] += m_subvol_per[i];}
1775  }
1776  }
1777  }
1778 
1779  // Set these up here because we need to know which MPI rank "cell" is on...
1780  if (pp.contains("data_log"))
1781  {
1782  int num_datalogs = pp.countval("data_log");
1783  datalog.resize(num_datalogs);
1784  datalogname.resize(num_datalogs);
1785  pp.queryarr("data_log",datalogname,0,num_datalogs);
1786  for (int i = 0; i < num_datalogs; i++) {
1788  }
1789  }
1790 
1791  if (pp.contains("der_data_log"))
1792  {
1793  int num_der_datalogs = pp.countval("der_data_log");
1794  der_datalog.resize(num_der_datalogs);
1795  der_datalogname.resize(num_der_datalogs);
1796  pp.queryarr("der_data_log",der_datalogname,0,num_der_datalogs);
1797  for (int i = 0; i < num_der_datalogs; i++) {
1799  }
1800  }
1801 
1802  if (pp.contains("energy_data_log"))
1803  {
1804  int num_energy_datalogs = pp.countval("energy_data_log");
1805  tot_e_datalog.resize(num_energy_datalogs);
1806  tot_e_datalogname.resize(num_energy_datalogs);
1807  pp.queryarr("energy_data_log",tot_e_datalogname,0,num_energy_datalogs);
1808  for (int i = 0; i < num_energy_datalogs; i++) {
1810  }
1811  }
1812 
1813  if (solverChoice.rad_type != RadiationType::None)
1814  {
1815  // Create data log for radiation model if requested
1816  rad[0]->setupDataLog();
1817  }
1818 
1819 
1820  if (restart_chkfile.empty() && profile_int > 0) {
1821  if (destag_profiles) {
1822  // all variables cell-centered
1824  } else {
1825  // some variables staggered
1827  }
1828  }
1829 
1830  if (pp.contains("sample_point_log") && pp.contains("sample_point"))
1831  {
1832  int lev = 0;
1833 
1834  int num_samplepts = pp.countval("sample_point") / AMREX_SPACEDIM;
1835  if (num_samplepts > 0) {
1836  Vector<int> index; index.resize(num_samplepts*AMREX_SPACEDIM);
1837  samplepoint.resize(num_samplepts);
1838 
1839  pp.queryarr("sample_point",index,0,num_samplepts*AMREX_SPACEDIM);
1840  for (int i = 0; i < num_samplepts; i++) {
1841  IntVect iv(index[AMREX_SPACEDIM*i+0],index[AMREX_SPACEDIM*i+1],index[AMREX_SPACEDIM*i+2]);
1842  samplepoint[i] = iv;
1843  }
1844  }
1845 
1846  int num_sampleptlogs = pp.countval("sample_point_log");
1847  AMREX_ALWAYS_ASSERT(num_sampleptlogs == num_samplepts);
1848  if (num_sampleptlogs > 0) {
1849  sampleptlog.resize(num_sampleptlogs);
1850  sampleptlogname.resize(num_sampleptlogs);
1851  pp.queryarr("sample_point_log",sampleptlogname,0,num_sampleptlogs);
1852 
1853  for (int i = 0; i < num_sampleptlogs; i++) {
1855  }
1856  }
1857 
1858  }
1859 
1860  bool has_sample_line = pp.contains("sample_line");
1861  bool has_sample_line_real = pp.contains("sample_line_real");
1862  if (has_sample_line && has_sample_line_real) {
1863  Abort("Specify only one of erf.sample_line or erf.sample_line_real");
1864  }
1865 
1866  if (pp.contains("sample_line_log") && (has_sample_line || has_sample_line_real))
1867  {
1868  int lev = 0;
1869 
1870  int num_samplelines = 0;
1871  if (has_sample_line) {
1872  num_samplelines = pp.countval("sample_line") / AMREX_SPACEDIM;
1873  if (num_samplelines > 0) {
1874  Vector<int> index; index.resize(num_samplelines*AMREX_SPACEDIM);
1875  sampleline.resize(num_samplelines);
1876 
1877  pp.queryarr("sample_line",index,0,num_samplelines*AMREX_SPACEDIM);
1878  for (int i = 0; i < num_samplelines; i++) {
1879  IntVect iv(index[AMREX_SPACEDIM*i+0],index[AMREX_SPACEDIM*i+1],index[AMREX_SPACEDIM*i+2]);
1880  sampleline[i] = iv;
1881  }
1882  }
1883  } else {
1884  int num_real_vals = pp.countval("sample_line_real");
1885  if (num_real_vals % AMREX_SPACEDIM != 0) {
1886  Abort("erf.sample_line_real must be specified as (x,y,z) triples");
1887  }
1888 
1889  num_samplelines = num_real_vals / AMREX_SPACEDIM;
1890  if (num_samplelines > 0) {
1891  Vector<Real> location; location.resize(num_real_vals);
1892  sampleline.resize(num_samplelines);
1893 
1894  pp.queryarr("sample_line_real",location,0,num_real_vals);
1895 
1896  const Box& domain = geom[lev].Domain();
1897  const auto* prob_lo = geom[lev].ProbLo();
1898  const auto* prob_hi = geom[lev].ProbHi();
1899  const auto* dx = geom[lev].CellSize();
1900 
1901  for (int i = 0; i < num_samplelines; i++) {
1902  Real xloc = location[AMREX_SPACEDIM*i+0];
1903  Real yloc = location[AMREX_SPACEDIM*i+1];
1904  Real zloc = location[AMREX_SPACEDIM*i+2];
1905 
1906  if (xloc < prob_lo[0] || xloc > prob_hi[0] ||
1907  yloc < prob_lo[1] || yloc > prob_hi[1] ||
1908  zloc < prob_lo[2] || zloc > prob_hi[2]) {
1909  Abort("erf.sample_line_real must lie within the level-0 domain");
1910  }
1911 
1912  int i_cell = domain.smallEnd(0) + static_cast<int>(std::floor((xloc - prob_lo[0]) / dx[0]));
1913  int j_cell = domain.smallEnd(1) + static_cast<int>(std::floor((yloc - prob_lo[1]) / dx[1]));
1914  int k_cell = domain.smallEnd(2) + static_cast<int>(std::floor((zloc - prob_lo[2]) / dx[2]));
1915 
1916  i_cell = std::min(i_cell, domain.bigEnd(0));
1917  j_cell = std::min(j_cell, domain.bigEnd(1));
1918  k_cell = std::min(k_cell, domain.bigEnd(2));
1919 
1920  sampleline[i] = IntVect(i_cell, j_cell, k_cell);
1921  }
1922  }
1923  }
1924 
1925  int num_samplelinelogs = pp.countval("sample_line_log");
1926  AMREX_ALWAYS_ASSERT(num_samplelinelogs == num_samplelines);
1927  if (num_samplelinelogs > 0) {
1928  samplelinelog.resize(num_samplelinelogs);
1929  samplelinelogname.resize(num_samplelinelogs);
1930  pp.queryarr("sample_line_log",samplelinelogname,0,num_samplelinelogs);
1931 
1932  for (int i = 0; i < num_samplelinelogs; i++) {
1934  }
1935  }
1936 
1937  }
1938 
1943  }
1944 
1945  // Create object to do line and plane sampling if needed
1946  bool do_line = false; bool do_plane = false;
1947  pp.query("do_line_sampling",do_line); pp.query("do_plane_sampling",do_plane);
1948  if (do_line) {
1949  if (line_sampling_interval < 0 && line_sampling_per < 0) {
1950  Abort("Need to specify line_sampling_interval or line_sampling_per");
1951  }
1952  line_sampler = std::make_unique<LineSampler>();
1953  line_sampler->write_coords(z_phys_cc, geom);
1954  }
1955  if (do_plane) {
1957  Abort("Need to specify plane_sampling_interval or plane_sampling_per");
1958  }
1959  plane_sampler = std::make_unique<PlaneSampler>();
1960  }
1961 
1962  if ( solverChoice.terrain_type == TerrainType::EB ||
1963  solverChoice.terrain_type == TerrainType::ImmersedForcing ||
1964  solverChoice.buildings_type == BuildingsType::ImmersedForcing )
1965  {
1966  bool write_eb_surface = false;
1967  pp.query("write_eb_surface", write_eb_surface);
1968  if (write_eb_surface) {
1969  if (verbose > 0) {
1970  amrex::Print() << "Writing the geometry to a vtp file.\n" << std::endl;
1971  }
1972  WriteEBSurface(grids[finest_level],dmap[finest_level],Geom(finest_level),&EBFactory(finest_level));
1973  }
1974  }
1975 }
constexpr amrex::Real three
Definition: ERF_Constants.H:9
const amrex::Real * prob_hi
Definition: ERF_InitCustomPert_DataAssimilation_ISV.H:17
void thinbody_wall_dist(std::unique_ptr< MultiFab > &wdist, Vector< IntVect > &xfaces, Vector< IntVect > &yfaces, Vector< IntVect > &zfaces, const Geometry &geomdata, std::unique_ptr< MultiFab > &z_phys_cc)
Definition: ERF_ThinBodyWallDist.cpp:12
amrex::Vector< std::string > samplelinelogname
Definition: ERF.H:1654
void setRayleighRefFromSounding(bool restarting)
Set Rayleigh mean profiles from input sounding.
Definition: ERF_InitRayleigh.cpp:83
amrex::Vector< amrex::IntVect > sampleline
Definition: ERF.H:1655
void project_initial_velocity(int lev, amrex::Real time, amrex::Real dt)
Definition: ERF_PoissonSolve.cpp:31
amrex::Real plane_sampling_per
Definition: ERF.H:1638
static amrex::Real sum_per
Definition: ERF.H:1257
void setRecordDataInfo(int i, const std::string &filename)
Definition: ERF.H:1561
static bool plot_file_on_restart
Definition: ERF.H:1063
amrex::Vector< std::string > lsm_flux_name
Definition: ERF.H:911
void sum_derived_quantities(double time)
Definition: ERF_WriteScalarProfiles.cpp:177
std::unique_ptr< amrex::MultiFab > wrf_PHB
Definition: ERF.H:1305
amrex::Vector< std::unique_ptr< std::fstream > > samplelinelog
Definition: ERF.H:1653
static int sum_interval
Definition: ERF.H:1255
static int pert_interval
Definition: ERF.H:1256
amrex::Real line_sampling_per
Definition: ERF.H:1637
void restart()
Definition: ERF.cpp:2210
int profile_int
Definition: ERF.H:1132
bool destag_profiles
Definition: ERF.H:1133
void compute_max_pressure_gradient_diagnostic(int lev)
Definition: ERF_Diagnostics.cpp:12
void write_1D_profiles(double time)
Definition: ERF_Write1DProfiles.cpp:17
void initRayleigh_at_level(const int &lev)
Initialize Rayleigh damping profiles at a level.
Definition: ERF_InitRayleigh.cpp:14
void appendPlotVariables(const std::string &pp_plot_var_names, amrex::Vector< std::string > &plot_var_names)
Definition: ERF_Plotfile.cpp:232
amrex::Vector< std::string > tot_e_datalogname
Definition: ERF.H:1647
static int output_bndry_planes
Definition: ERF.H:1318
static std::string nc_bdy_file
Definition: ERF.H:1275
void AverageDown()
Definition: ERF_AverageDown.cpp:16
void write_1D_profiles_stag(double time)
Definition: ERF_Write1DProfiles_stag.cpp:25
static amrex::Real bndry_output_planes_start_time
Definition: ERF.H:1321
std::string restart_chkfile
Definition: ERF.H:1085
amrex::Vector< std::string > sampleptlogname
Definition: ERF.H:1650
void setRecordDerDataInfo(int i, const std::string &filename)
Definition: ERF.H:1574
amrex::Vector< std::unique_ptr< std::fstream > > sampleptlog
Definition: ERF.H:1649
void poisson_wall_dist(int lev)
Definition: ERF_PoissonWallDist.cpp:22
void sum_integrated_quantities(double time)
Definition: ERF_WriteScalarProfiles.cpp:15
std::unique_ptr< WriteBndryPlanes > m_w2d
Definition: ERF.H:1381
void init_geo_wind_profile(const std::string input_file, amrex::Vector< amrex::Real > &u_geos, amrex::Gpu::DeviceVector< amrex::Real > &u_geos_d, amrex::Vector< amrex::Real > &v_geos, amrex::Gpu::DeviceVector< amrex::Real > &v_geos_d, const amrex::Geometry &lgeom, const amrex::Vector< amrex::Real > &zlev_stag)
Definition: ERF_InitGeowind.cpp:10
void sum_energy_quantities(double time)
Definition: ERF_WriteScalarProfiles.cpp:313
amrex::Vector< std::string > lsm_data_name
Definition: ERF.H:909
void initSponge()
Initialize sponge profiles.
Definition: ERF_InitSponge.cpp:35
std::unique_ptr< PlaneSampler > plane_sampler
Definition: ERF.H:1640
amrex::Vector< std::unique_ptr< std::fstream > > tot_e_datalog
Definition: ERF.H:1644
int real_width
Definition: ERF.H:1276
void setRecordEnergyDataInfo(int i, const std::string &filename)
Definition: ERF.H:1587
void Interp2DArrays(int lev, const amrex::BoxArray &my_ba2d, const amrex::DistributionMapping &my_dm)
Definition: ERF.cpp:1978
int plane_sampling_interval
Definition: ERF.H:1636
static std::string nc_low_file
Definition: ERF.H:1280
void Construct_ERFFillPatchers(int lev)
Definition: ERF.cpp:3140
void setRecordSampleLineInfo(int i, int lev, amrex::IntVect &cell, const std::string &filename)
Definition: ERF.H:1617
void setSpongeRefFromSounding(bool restarting)
Set sponge mean profiles from input sounding.
Definition: ERF_InitSponge.cpp:65
int line_sampling_interval
Definition: ERF.H:1635
amrex::Vector< amrex::IntVect > samplepoint
Definition: ERF.H:1651
std::unique_ptr< LineSampler > line_sampler
Definition: ERF.H:1639
static bool is_it_time_for_action(int nstep, double time, amrex::Real dt, int action_interval, amrex::Real action_per)
Definition: ERF_WriteScalarProfiles.cpp:654
void setRecordSamplePointInfo(int i, int lev, amrex::IntVect &cell, const std::string &filename)
Definition: ERF.H:1600
void ReadCheckpointFileSurfaceLayer()
Definition: ERF_Checkpoint.cpp:1128
@ nc
Definition: ERF_Morrison.H:44
bool have_zero_flux_faces
Definition: ERF_AdvStruct.H:440
amrex::Real rho0_trans
Definition: ERF_DiffStruct.H:91
amrex::Real dynamic_viscosity
Definition: ERF_DiffStruct.H:96
amrex::Real theta_ref_inp_sound
Definition: ERF_InputSoundingData.H:401
amrex::Real qv_ref_inp_sound
Definition: ERF_InputSoundingData.H:401
bool spatial_moisture_forcing
Definition: ERF_DataStruct.H:1231
bool any_perturbation() const
Definition: ERF_DataStruct.H:1267
bool have_geo_wind_profile
Definition: ERF_DataStruct.H:1297
amrex::Vector< amrex::Real > vert_implicit_fac
Definition: ERF_DataStruct.H:1157
std::string abl_geo_wind_table
Definition: ERF_DataStruct.H:1296
bool implicit_momentum_diffusion
Definition: ERF_DataStruct.H:1161
bool use_rotate_surface_flux
Definition: ERF_DataStruct.H:1238
bool do_forest_drag
Definition: ERF_DataStruct.H:1319
bool spatial_rhotheta_forcing
Definition: ERF_DataStruct.H:1230
void debug(amrex::Real)
Definition: ERF_TurbPertStruct.H:640
Here is the call graph for this function:

◆ InitData_pre()

void ERF::InitData_pre ( )
995 {
996  // Initialize the start time for our CPU-time tracker
997  startCPUTime = Real(ParallelDescriptor::second());
998 
999  // Create the ReadBndryPlanes object so we can read boundary plane data
1000  // m_r2d is used by init_bcs so we must instantiate this class before
1001  if (input_bndry_planes) {
1002  Print() << "Defining r2d for the first time " << std::endl;
1003  m_r2d = std::make_unique<ReadBndryPlanes>(geom[0], solverChoice.rdOcp);
1004  }
1005 
1006  if (restart_chkfile.empty()) {
1007  // Start simulation from the beginning
1008  InitFromScratch(zero);
1009  } else {
1010  // For initialization this is done in init_only; it is done here for restart
1011  init_bcs();
1012  }
1013 
1014  solverChoice.check_params(max_level,geom,phys_bc_type);
1015 }
void init_bcs()
Definition: ERF_InitBCs.cpp:295
void check_params(int max_level, const amrex::Vector< amrex::Geometry > &geom_vect, amrex::GpuArray< ERF_BC, AMREX_SPACEDIM *2 > phys_bc_type)
Definition: ERF_DataStruct.H:822

◆ initHSE() [1/2]

void ERF::initHSE ( )
private

Initialize HSE.

193 {
194  for (int lev = 0; lev <= finest_level; lev++)
195  {
196  initHSE(lev);
197  }
198 }

◆ initHSE() [2/2]

void ERF::initHSE ( int  lev)
private

Initialize density and pressure base state in hydrostatic equilibrium.

20 {
21  // This integrates up through column to update p_hse, pi_hse, th_hse;
22  // r_hse is not const b/c FillBoundary is called at the end for r_hse and p_hse
23 
24  MultiFab r_hse (base_state[lev], make_alias, BaseState::r0_comp, 1);
25  MultiFab p_hse (base_state[lev], make_alias, BaseState::p0_comp, 1);
26  MultiFab pi_hse(base_state[lev], make_alias, BaseState::pi0_comp, 1);
27  MultiFab th_hse(base_state[lev], make_alias, BaseState::th0_comp, 1);
28  MultiFab qv_hse(base_state[lev], make_alias, BaseState::qv0_comp, 1);
29 
30  bool all_boxes_touch_bottom = true;
31  Box domain(geom[lev].Domain());
32 
33  int icomp = 0; int ncomp = BaseState::num_comps;
34 
35  if (lev == 0) {
36  BoxArray ba(base_state[lev].boxArray());
37  for (int i = 0; i < ba.size(); i++) {
38  if (ba[i].smallEnd(2) != domain.smallEnd(2)) {
39  all_boxes_touch_bottom = false;
40  }
41  }
42  }
43  else
44  {
45  //
46  // We need to do this interp from coarse level in order to set the values of
47  // the base state inside the domain but outside of the fine region
48  //
49  base_state[lev-1].FillBoundary(geom[lev-1].periodicity());
50  //
51  // NOTE: this interpolater assumes that ALL ghost cells of the coarse MultiFab
52  // have been pre-filled - this includes ghost cells both inside and outside
53  // the domain
54  //
55  InterpFromCoarseLevel(base_state[lev], base_state[lev].nGrowVect(),
56  IntVect(0,0,0), // do not fill ghost cells outside the domain
57  base_state[lev-1], icomp, icomp, ncomp,
58  geom[lev-1], geom[lev],
59  refRatio(lev-1), &cell_cons_interp,
61 
62  // We need to do this here because the interpolation above may leave corners unfilled
63  // when the corners need to be filled by, for example, reflection of the fine ghost
64  // cell outside the fine region but inide the domain.
65  (*physbcs_base[lev])(base_state[lev],icomp,ncomp,base_state[lev].nGrowVect());
66  }
67 
68  bool is_constant_dz = (solverChoice.mesh_type == MeshType::ConstantDz);
69  bool is_stretched_dz = (solverChoice.mesh_type == MeshType::StretchedDz);
70 
71  if (all_boxes_touch_bottom || lev > 0) {
72 
73  // Initial r_hse may or may not be in HSE -- defined in ERF_Prob.cpp
74  if ( (solverChoice.init_type == InitType::MoistBaseState) ||
75  (solverChoice.init_type == InitType::HindCast) )
76  {
77  AMREX_ALWAYS_ASSERT(solverChoice.mesh_type == MeshType::ConstantDz);
78  prob->erf_init_dens_hse_moist(r_hse, z_phys_nd[lev], geom[lev]);
79 
80  }
81  else if (solverChoice.init_type == InitType::ConstantDensity)
82  {
83  // In this case we set rho from user-specified values, then integrate
84  // to define p from HSE (even if gravity = 0), then compute theta from (p,rho)
85  prob->erf_init_const_dens_hse(r_hse);
86  }
87  else if (solverChoice.init_type == InitType::Uniform)
88  {
89  // In this case we set both rho and theta from user-specified values
91  prob->erf_init_const_dens_and_th_hse(r_hse,p_hse,pi_hse,th_hse,qv_hse,solverChoice.rdOcp);
92  }
93  else if (solverChoice.init_type == InitType::ConstantDensityLinearTheta)
94  {
95  // In this case we set both rho and theta from user-specified values
97  prob->erf_init_const_dens_and_linear_th_hse(r_hse,p_hse,pi_hse,th_hse,qv_hse,
99  }
100  else
101  {
102  // In this case we set rho from user-specified values, then integrate
103  // to define p from HSE (even if gravity = 0), then compute theta from (p,rho)
104  prob->erf_init_dens_hse_dry(r_hse, z_phys_nd[lev], z_phys_cc[lev], geom[lev], stretched_dz_h[lev],
105  is_constant_dz, is_stretched_dz);
106  }
107 
108  if (solverChoice.init_type != InitType::Uniform && solverChoice.init_type !=InitType::ConstantDensityLinearTheta) {
109  erf_enforce_hse(lev, r_hse, p_hse, pi_hse, th_hse, qv_hse, z_phys_cc[lev]);
110  }
111 
112  //
113  // Impose physical bc's on the base state
114  //
115  (*physbcs_base[lev])(base_state[lev],0,base_state[lev].nComp(),base_state[lev].nGrowVect());
116 
117  } else {
118 
119  BoxArray ba_new(domain);
120 
121  ChopGrids2D(ba_new, domain, ParallelDescriptor::NProcs());
122 
123  DistributionMapping dm_new(ba_new);
124 
125  MultiFab new_base_state(ba_new, dm_new, BaseState::num_comps, base_state[lev].nGrowVect());
126  new_base_state.ParallelCopy(base_state[lev],0,0,base_state[lev].nComp(),
127  base_state[lev].nGrowVect(),base_state[lev].nGrowVect());
128 
129  MultiFab new_r_hse (new_base_state, make_alias, BaseState::r0_comp, 1);
130  MultiFab new_p_hse (new_base_state, make_alias, BaseState::p0_comp, 1);
131  MultiFab new_pi_hse(new_base_state, make_alias, BaseState::pi0_comp, 1);
132  MultiFab new_th_hse(new_base_state, make_alias, BaseState::th0_comp, 1);
133  MultiFab new_qv_hse(new_base_state, make_alias, BaseState::qv0_comp, 1);
134 
135  std::unique_ptr<MultiFab> new_z_phys_cc;
136  std::unique_ptr<MultiFab> new_z_phys_nd;
137  if (solverChoice.mesh_type != MeshType::ConstantDz) {
138  new_z_phys_cc = std::make_unique<MultiFab>(ba_new,dm_new,1,1);
139  new_z_phys_cc->ParallelCopy(*z_phys_cc[lev],0,0,1,1,1);
140 
141  BoxArray ba_new_nd(ba_new);
142  ba_new_nd.surroundingNodes();
143  new_z_phys_nd = std::make_unique<MultiFab>(ba_new_nd,dm_new,1,1);
144  new_z_phys_nd->ParallelCopy(*z_phys_nd[lev],0,0,1,1,1);
145  }
146 
147  // Initial r_hse may or may not be in HSE -- defined in ERF_Prob.cpp
148  if (solverChoice.init_type == InitType::MoistBaseState) {
149  AMREX_ALWAYS_ASSERT(solverChoice.mesh_type == MeshType::ConstantDz);
150  prob->erf_init_dens_hse_moist(new_r_hse, new_z_phys_nd, geom[lev]);
151  } else if (solverChoice.init_type == InitType::ConstantDensity) {
152 
153  // In this case we set rho from user-specified values, then integrate
154  // to define p from HSE (even if gravity = 0), then compute theta from (p,rho)
155  prob->erf_init_const_dens_hse(new_r_hse);
156 
157  } else if (solverChoice.init_type == InitType::Uniform) {
158 
159  // In this case we set both rho and theta from user-specified values
161  prob->erf_init_const_dens_and_th_hse(new_r_hse,new_p_hse,new_pi_hse,new_th_hse,new_qv_hse,solverChoice.rdOcp);
162 
163  } else {
164  prob->erf_init_dens_hse_dry(new_r_hse, new_z_phys_nd, new_z_phys_cc, geom[lev], stretched_dz_h[lev],
165  is_constant_dz, is_stretched_dz);
166  }
167 
168  erf_enforce_hse(lev, new_r_hse, new_p_hse, new_pi_hse, new_th_hse, new_qv_hse, new_z_phys_cc);
169 
170  //
171  // Impose physical bc's on the base state (we must make new, temporary bcs object because the z_phys_nd is different)
172  //
173  ERFPhysBCFunct_base* temp_physbcs_base =
174  new ERFPhysBCFunct_base(lev, geom[lev], domain_bcs_type, domain_bcs_type_d, new_z_phys_nd,
175  (solverChoice.terrain_type == TerrainType::MovingFittedMesh));
176  (*temp_physbcs_base)(new_base_state,0,new_base_state.nComp(),new_base_state.nGrowVect());
177  delete temp_physbcs_base;
178 
179  // Now copy back into the original arrays
180  base_state[lev].ParallelCopy(new_base_state,0,0,base_state[lev].nComp(),
181  base_state[lev].nGrowVect(),base_state[lev].nGrowVect());
182  }
183 
184  //
185  // Impose physical bc's on the base state -- the values outside the fine region
186  // but inside the domain have already been filled in the call above to InterpFromCoarseLevel
187  //
188  (*physbcs_base[lev])(base_state[lev],0,base_state[lev].nComp(),base_state[lev].nGrowVect());
189 }
void ChopGrids2D(BoxArray &ba, const Box &domain, int target_size)
Definition: ERF_ChopGrids.cpp:21
Definition: ERF_PhysBCFunct.H:286
void erf_enforce_hse(int lev, amrex::MultiFab &dens, amrex::MultiFab &pres, amrex::MultiFab &pi, amrex::MultiFab &th, amrex::MultiFab &qv, std::unique_ptr< amrex::MultiFab > &z_cc)
Definition: ERF_Init1D.cpp:210
Here is the call graph for this function:

◆ initialize_integrator()

void ERF::initialize_integrator ( int  lev,
amrex::MultiFab &  cons_mf,
amrex::MultiFab &  vel_mf 
)
private
876 {
877  const BoxArray& ba(cons_mf.boxArray());
878  const DistributionMapping& dm(cons_mf.DistributionMap());
879 
880  int ncomp_cons = cons_mf.nComp();
881 
882  // Initialize the integrator memory
883  Vector<MultiFab> int_state; // integration state data structure example
884  int_state.push_back(MultiFab(cons_mf, make_alias, 0, ncomp_cons)); // cons
885  int_state.push_back(MultiFab(convert(ba,IntVect(1,0,0)), dm, 1, vel_mf.nGrow())); // xmom
886  int_state.push_back(MultiFab(convert(ba,IntVect(0,1,0)), dm, 1, vel_mf.nGrow())); // ymom
887  int_state.push_back(MultiFab(convert(ba,IntVect(0,0,1)), dm, 1, vel_mf.nGrow())); // zmom
888 
889  mri_integrator_mem[lev] = std::make_unique<MRISplitIntegrator<Vector<MultiFab> > >(int_state);
890  mri_integrator_mem[lev]->setNoSubstepping((solverChoice.substepping_type[lev] == SubsteppingType::None));
891  mri_integrator_mem[lev]->setAnelastic(solverChoice.anelastic[lev]);
892  mri_integrator_mem[lev]->setNcompCons(ncomp_cons);
893  mri_integrator_mem[lev]->setForceFirstStageSingleSubstep(solverChoice.force_stage1_single_substep);
894 }

◆ InitializeFromFile()

void ERF::InitializeFromFile ( )
private

◆ InitializeLevelFromData()

void ERF::InitializeLevelFromData ( int  lev,
const amrex::MultiFab &  initial_data 
)
private

◆ initializeMicrophysics()

void ERF::initializeMicrophysics ( const int &  a_nlevsmax)
private
Parameters
a_nlevsmaxnumber of AMR levels
2177 {
2178  if (Microphysics::modelType(solverChoice.moisture_type) == MoistureModelType::Eulerian) {
2179 
2180  micro = std::make_unique<EulerianMicrophysics>(a_nlevsmax, solverChoice.moisture_type);
2181 
2182  } else if (Microphysics::modelType(solverChoice.moisture_type) == MoistureModelType::Lagrangian) {
2183 #ifdef ERF_USE_PARTICLES
2184  micro = std::make_unique<LagrangianMicrophysics>(a_nlevsmax, solverChoice.moisture_type);
2185  /* Lagrangian microphysics models will have a particle container; it needs to be added
2186  to ERF::particleData */
2187  const auto& pc_name( dynamic_cast<LagrangianMicrophysics&>(*micro).getName() );
2188  /* The particle container has not yet been constructed and initialized, so just add
2189  its name here for now (so that functions to set plotting variables can see it). */
2190  particleData.addName( pc_name );
2191 
2192 #else
2193  Abort("Lagrangian microphysics can be used when compiled with ERF_USE_PARTICLES");
2194 #endif
2195  }
2196 
2197  qmoist.resize(a_nlevsmax);
2198  return;
2199 }
amrex::Vector< amrex::Vector< amrex::MultiFab * > > qmoist
Definition: ERF.H:893
Here is the call graph for this function:

◆ initRayleigh_at_level()

void ERF::initRayleigh_at_level ( const int &  lev)
private

Initialize Rayleigh damping profiles at a level.

Initialization function for host and device vectors used to store averaged quantities when calculating the effects of Rayleigh Damping.

15 {
16  const int khi = geom[0].Domain().bigEnd(2);
17  solverChoice.dampingChoice.rayleigh_ztop = (solverChoice.terrain_type == TerrainType::None) ? geom[0].ProbHi(2) : zlevels_stag[0][khi+1];
18 
19  // These have 4 components: ubar, vbar, wbar, thetabar
20  h_rayleigh_ptrs[lev].resize(Rayleigh::nvars);
21  d_rayleigh_ptrs[lev].resize(Rayleigh::nvars);
22 
23  const int zlen_rayleigh = geom[lev].Domain().length(2);
24 
25  // Allocate space for these 1D vectors
26  for (int n = 0; n < Rayleigh::nvars; n++) {
27  h_rayleigh_ptrs[lev][n].resize(zlen_rayleigh, 0.0_rt);
28  d_rayleigh_ptrs[lev][n].resize(zlen_rayleigh, 0.0_rt);
29  }
30 
31  h_sinesq_ptrs[lev].resize(zlen_rayleigh);
32  d_sinesq_ptrs[lev].resize(zlen_rayleigh);
33 
34  h_sinesq_stag_ptrs[lev].resize(zlen_rayleigh+1);
35  d_sinesq_stag_ptrs[lev].resize(zlen_rayleigh+1);
36 
39 
40  for (int k = 0; k < zlen_rayleigh; k++) {
41  Real z = myhalf * (zlevels_stag[lev][k] + zlevels_stag[lev][k+1]);
42  if (z > (ztop - zdamp)) {
43  Real zfrac = one - (ztop - z) / zdamp;
44  Real s = std::sin(PIoTwo*zfrac);
45  h_sinesq_ptrs[lev][k] = s*s;
46  } else {
47  h_sinesq_ptrs[lev][k] = zero;
48  }
49  }
50 
51  for (int k = 0; k < zlen_rayleigh+1; k++) {
52  Real z = zlevels_stag[lev][k];
53  if (z > (ztop - zdamp)) {
54  Real zfrac = one - (ztop - z) / zdamp;
55  Real s = std::sin(PIoTwo*zfrac);
56  h_sinesq_stag_ptrs[lev][k] = s*s;
57  } else {
58  h_sinesq_stag_ptrs[lev][k] = zero;
59  }
60  }
61 
62  // Init the host vectors for the reference states
63  prob->erf_init_rayleigh(h_rayleigh_ptrs[lev], geom[lev], z_phys_nd[lev],
65 
66  // Copy from host vectors to device vectors
67  for (int n = 0; n < Rayleigh::nvars; n++) {
68  Gpu::copy(Gpu::hostToDevice, h_rayleigh_ptrs[lev][n].begin(), h_rayleigh_ptrs[lev][n].end(),
69  d_rayleigh_ptrs[lev][n].begin());
70  }
71  Gpu::copy(Gpu::hostToDevice, h_sinesq_ptrs[lev].begin(), h_sinesq_ptrs[lev].end(), d_sinesq_ptrs[lev].begin());
72  Gpu::copy(Gpu::hostToDevice, h_sinesq_stag_ptrs[lev].begin(), h_sinesq_stag_ptrs[lev].end(), d_sinesq_stag_ptrs[lev].begin());
73 }
constexpr amrex::Real PIoTwo
Definition: ERF_Constants.H:25
amrex::Real rayleigh_ztop
Definition: ERF_DampingStruct.H:90
amrex::Real rayleigh_zdamp
Definition: ERF_DampingStruct.H:89

◆ initSponge()

void ERF::initSponge ( )
private

Initialize sponge profiles.

Initialization function for host and device vectors used to store the effects of sponge Damping.

36 {
37  h_sponge_ptrs.resize(max_level+1);
38  d_sponge_ptrs.resize(max_level+1);
39 
40  for (int lev = 0; lev <= finest_level; lev++)
41  {
42  // These have 2 components: ubar, vbar
45 
46  const int zlen_sponge = geom[lev].Domain().length(2);
47 
48  // Allocate space for these 1D vectors
49  for (int n = 0; n < Sponge::nvars_sponge; n++) {
50  h_sponge_ptrs[lev][n].resize(zlen_sponge, 0.0_rt);
51  d_sponge_ptrs[lev][n].resize(zlen_sponge, 0.0_rt);
52  }
53 
54  }
55 }
amrex::Vector< amrex::Vector< amrex::Vector< amrex::Real > > > h_sponge_ptrs
Definition: ERF.H:1353

◆ input_sponge()

void ERF::input_sponge ( int  lev)

High level wrapper for sponge x and y velocities level data from input sponge data.

Parameters
levInteger specifying the current level
18 {
19  // We only want to read the file once
20  if (lev == 0) {
22  Error("input_sounding file name must be provided via input");
23 
24  // this will interpolate the input profiles to the nominal height levels
25  // (ranging from 0 to the domain top)
27  }
28 }
InputSpongeData input_sponge_data
Definition: ERF.H:800
void read_from_file(const amrex::Geometry &geom, const amrex::Vector< amrex::Real > &zlevels_stag)
Definition: ERF_InputSpongeData.H:28
std::string input_sponge_file
Definition: ERF_InputSpongeData.H:108

◆ Interp2DArrays()

void ERF::Interp2DArrays ( int  lev,
const amrex::BoxArray &  my_ba2d,
const amrex::DistributionMapping &  my_dm 
)
1979 {
1980  if (lev == 0) { return; }
1981 
1982  if (lon_m[lev-1] && !lon_m[lev]) {
1983  auto ngv = lon_m[lev-1]->nGrowVect(); ngv[2] = 0;
1984  lon_m[lev] = std::make_unique<MultiFab>(my_ba2d,my_dm,1,ngv);
1985  InterpFromCoarseLevel(*lon_m[lev], ngv, IntVect(0,0,0), // do not fill ghost cells outside the domain
1986  *lon_m[lev-1], 0, 0, 1,
1987  geom[lev-1], geom[lev],
1988  refRatio(lev-1), &cell_cons_interp,
1990  }
1991  if (lat_m[lev-1] && !lat_m[lev]) {
1992  auto ngv = lat_m[lev-1]->nGrowVect(); ngv[2] = 0;
1993  lat_m[lev] = std::make_unique<MultiFab>(my_ba2d,my_dm,1,ngv);
1994  InterpFromCoarseLevel(*lat_m[lev], ngv, IntVect(0,0,0), // do not fill ghost cells outside the domain
1995  *lat_m[lev-1], 0, 0, 1,
1996  geom[lev-1], geom[lev],
1997  refRatio(lev-1), &cell_cons_interp,
1999  }
2000  if (sinPhi_m[lev-1] && !sinPhi_m[lev]) {
2001  auto ngv = sinPhi_m[lev-1]->nGrowVect(); ngv[2] = 0;
2002  sinPhi_m[lev] = std::make_unique<MultiFab>(my_ba2d,my_dm,1,ngv);
2003  InterpFromCoarseLevel(*sinPhi_m[lev], ngv, IntVect(0,0,0), // do not fill ghost cells outside the domain
2004  *sinPhi_m[lev-1], 0, 0, 1,
2005  geom[lev-1], geom[lev],
2006  refRatio(lev-1), &cell_cons_interp,
2008  }
2009  if (cosPhi_m[lev-1] && !cosPhi_m[lev]) {
2010  auto ngv = cosPhi_m[lev-1]->nGrowVect(); ngv[2] = 0;
2011  cosPhi_m[lev] = std::make_unique<MultiFab>(my_ba2d,my_dm,1,ngv);
2012  InterpFromCoarseLevel(*cosPhi_m[lev], ngv, IntVect(0,0,0), // do not fill ghost cells outside the domain
2013  *cosPhi_m[lev-1], 0, 0, 1,
2014  geom[lev-1], geom[lev],
2015  refRatio(lev-1), &cell_cons_interp,
2017  }
2018  if (sst_lev[lev-1][0]) {
2019  if (sst_lev[lev].size() < sst_lev[lev-1].size()) {
2020  sst_lev[lev].resize(sst_lev[lev-1].size());
2021  }
2022 #ifdef ERF_USE_NETCDF
2023  Real time_since_start_low = t_new[0] + start_time - start_low_time;
2024  int n_time_old = static_cast<int>(time_since_start_low / low_time_interval);
2025  int ntimes_to_interp = std::min(n_time_old+3, static_cast<int>(sst_lev[lev-1].size()));
2026 #else
2027  // TODO: Fix if SST is provided without NETCDF
2028  int n_time_old = 0;
2029  int ntimes_to_interp = 1;
2030 #endif
2031  auto ngv = sst_lev[lev-1][0]->nGrowVect(); ngv[2] = 0;
2032 
2033  for (int n = n_time_old; n < ntimes_to_interp; n++) {
2034  if (!sst_lev[lev-1][n]) { continue; }
2035  if (!sst_lev[lev][n]) {
2036  sst_lev[lev][n] = std::make_unique<MultiFab>(my_ba2d,my_dm,1,ngv);
2037  InterpFromCoarseLevel(*sst_lev[lev][n], ngv, IntVect(0,0,0), // do not fill ghost cells outside the domain
2038  *sst_lev[lev-1][n], 0, 0, 1,
2039  geom[lev-1], geom[lev],
2040  refRatio(lev-1), &cell_cons_interp,
2042  }
2043  }
2044  }
2045  if (tsk_lev[lev-1][0]) {
2046  if (tsk_lev[lev].size() < tsk_lev[lev-1].size()) {
2047  tsk_lev[lev].resize(tsk_lev[lev-1].size());
2048  }
2049 #ifdef ERF_USE_NETCDF
2050  Real time_since_start_low = t_new[0] + start_time - start_low_time;
2051  int n_time_old = static_cast<int>(time_since_start_low / low_time_interval);
2052  int ntimes_to_interp = std::min(n_time_old+3, static_cast<int>(tsk_lev[lev-1].size()));
2053 #else
2054  // TODO: Fix if TSK is provided without NETCDF
2055  int n_time_old = 0;
2056  int ntimes_to_interp = 1;
2057 #endif
2058  auto ngv = tsk_lev[lev-1][0]->nGrowVect(); ngv[2] = 0;
2059 
2060  for (int n = n_time_old; n < ntimes_to_interp; n++) {
2061  if (!tsk_lev[lev-1][n]) { continue; }
2062  if (!tsk_lev[lev][n]) {
2063  tsk_lev[lev][n] = std::make_unique<MultiFab>(my_ba2d,my_dm,1,ngv);
2064  InterpFromCoarseLevel(*tsk_lev[lev][n], ngv, IntVect(0,0,0), // do not fill ghost cells outside the domain
2065  *tsk_lev[lev-1][n], 0, 0, 1,
2066  geom[lev-1], geom[lev],
2067  refRatio(lev-1), &cell_cons_interp,
2069  }
2070  }
2071  }
2072 
2073  Real time_for_fp = zero; // This is not actually used
2074  Vector<Real> ftime = {time_for_fp, time_for_fp};
2075  Vector<Real> ctime = {time_for_fp, time_for_fp};
2076  if (lat_m[lev]) {
2077  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
2078  Vector<MultiFab*> fmf = {lat_m[lev ].get(), lat_m[lev ].get()};
2079  Vector<MultiFab*> cmf = {lat_m[lev-1].get(), lat_m[lev-1].get()};
2080  IntVect ngv = lat_m[lev]->nGrowVect(); ngv[2] = 0;
2081  Interpolater* mapper = &cell_cons_interp;
2082  FillPatchTwoLevels(*lat_m[lev].get(), ngv, IntVect(0,0,0),
2083  time_for_fp, cmf, ctime, fmf, ftime,
2084  0, 0, 1, geom[lev-1], geom[lev],
2085  refRatio(lev-1), mapper, domain_bcs_type,
2086  BCVars::cons_bc);
2087  }
2088  if (lon_m[lev]) {
2089  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
2090  Vector<MultiFab*> fmf = {lon_m[lev ].get(), lon_m[lev ].get()};
2091  Vector<MultiFab*> cmf = {lon_m[lev-1].get(), lon_m[lev-1].get()};
2092  IntVect ngv = lon_m[lev]->nGrowVect(); ngv[2] = 0;
2093  Interpolater* mapper = &cell_cons_interp;
2094  FillPatchTwoLevels(*lon_m[lev].get(), ngv, IntVect(0,0,0),
2095  time_for_fp, cmf, ctime, fmf, ftime,
2096  0, 0, 1, geom[lev-1], geom[lev],
2097  refRatio(lev-1), mapper, domain_bcs_type,
2098  BCVars::cons_bc);
2099  } // lon_m
2100  if (sinPhi_m[lev]) {
2101  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
2102  Vector<MultiFab*> fmf = {sinPhi_m[lev ].get(), sinPhi_m[lev ].get()};
2103  Vector<MultiFab*> cmf = {sinPhi_m[lev-1].get(), sinPhi_m[lev-1].get()};
2104  IntVect ngv = sinPhi_m[lev]->nGrowVect(); ngv[2] = 0;
2105  Interpolater* mapper = &cell_cons_interp;
2106  FillPatchTwoLevels(*sinPhi_m[lev].get(), ngv, IntVect(0,0,0),
2107  time_for_fp, cmf, ctime, fmf, ftime,
2108  0, 0, 1, geom[lev-1], geom[lev],
2109  refRatio(lev-1), mapper, domain_bcs_type,
2110  BCVars::cons_bc);
2111  } // sinPhi
2112  if (cosPhi_m[lev]) {
2113  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
2114  Vector<MultiFab*> fmf = {cosPhi_m[lev ].get(), cosPhi_m[lev ].get()};
2115  Vector<MultiFab*> cmf = {cosPhi_m[lev-1].get(), cosPhi_m[lev-1].get()};
2116  IntVect ngv = cosPhi_m[lev]->nGrowVect(); ngv[2] = 0;
2117  Interpolater* mapper = &cell_cons_interp;
2118  FillPatchTwoLevels(*cosPhi_m[lev].get(), ngv, IntVect(0,0,0),
2119  time_for_fp, cmf, ctime, fmf, ftime,
2120  0, 0, 1, geom[lev-1], geom[lev],
2121  refRatio(lev-1), mapper, domain_bcs_type,
2122  BCVars::cons_bc);
2123  } // cosPhi
2124  if (sst_lev[lev][0]) {
2125  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
2126 #ifdef ERF_USE_NETCDF
2127  Real time_since_start_low = t_new[0] + start_time - start_low_time;
2128  int n_time_old = static_cast<int>(time_since_start_low / low_time_interval);
2129  int ntimes_to_interp = std::min(n_time_old+3, static_cast<int>(sst_lev[lev-1].size()));
2130 #else
2131  // TODO: Fix if SST is provided without NETCDF
2132  int n_time_old = 0;
2133  int ntimes_to_interp = 1;
2134 #endif
2135  for (int n = n_time_old; n < ntimes_to_interp; n++) {
2136  if (!sst_lev[lev][n] || !sst_lev[lev-1][n]) { continue; }
2137  Vector<MultiFab*> fmf = {sst_lev[lev ][n].get(), sst_lev[lev ][n].get()};
2138  Vector<MultiFab*> cmf = {sst_lev[lev-1][n].get(), sst_lev[lev-1][n].get()};
2139  IntVect ngv = sst_lev[lev][n]->nGrowVect(); ngv[2] = 0;
2140  Interpolater* mapper = &cell_cons_interp;
2141  FillPatchTwoLevels(*sst_lev[lev][n].get(), ngv, IntVect(0,0,0),
2142  time_for_fp, cmf, ctime, fmf, ftime,
2143  0, 0, 1, geom[lev-1], geom[lev],
2144  refRatio(lev-1), mapper, domain_bcs_type,
2145  BCVars::cons_bc);
2146  } // ntimes
2147  } // sst_lev
2148  if (tsk_lev[lev][0]) {
2149  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
2150 #ifdef ERF_USE_NETCDF
2151  Real time_since_start_low = t_new[0] + start_time - start_low_time;
2152  int n_time_old = static_cast<int>(time_since_start_low / low_time_interval);
2153  int ntimes_to_interp = std::min(n_time_old+3, static_cast<int>(tsk_lev[lev-1].size()));
2154 #else
2155  // TODO: Fix if TSK is provided without NETCDF
2156  int n_time_old = 0;
2157  int ntimes_to_interp = 1;
2158 #endif
2159  for (int n = n_time_old; n < ntimes_to_interp; n++) {
2160  if (!tsk_lev[lev][n] || !tsk_lev[lev-1][n]) { continue; }
2161  Vector<MultiFab*> fmf = {tsk_lev[lev ][n].get(), tsk_lev[lev ][n].get()};
2162  Vector<MultiFab*> cmf = {tsk_lev[lev-1][n].get(), tsk_lev[lev-1][n].get()};
2163  IntVect ngv = tsk_lev[lev][n]->nGrowVect(); ngv[2] = 0;
2164  Interpolater* mapper = &cell_cons_interp;
2165  FillPatchTwoLevels(*tsk_lev[lev][n].get(), ngv, IntVect(0,0,0),
2166  time_for_fp, cmf, ctime, fmf, ftime,
2167  0, 0, 1, geom[lev-1], geom[lev],
2168  refRatio(lev-1), mapper, domain_bcs_type,
2169  BCVars::cons_bc);
2170  } // ntimes
2171  } // tsk_lev
2172 }
Here is the call graph for this function:

◆ is_it_time_for_action()

bool ERF::is_it_time_for_action ( int  nstep,
double  time,
amrex::Real  dt,
int  action_interval,
amrex::Real  action_per 
)
static

Helper function which uses the current step number, time, and timestep to determine whether it is time to take an action specified at every interval of timesteps.

Parameters
nstepTimestep number
timeCurrent time
dtlevTimestep for the current level
action_intervalInterval in number of timesteps for taking action
action_perInterval in simulation time for taking action
655 {
656  bool int_test = (action_interval > 0 && nstep % action_interval == 0);
657 
658  bool per_test = false;
659  if (action_per > zero) {
660  const int num_per_old = static_cast<int>(amrex::Math::floor((time - dtlev) / action_per));
661  const int num_per_new = static_cast<int>(amrex::Math::floor((time) / action_per));
662 
663  if (num_per_old != num_per_new) {
664  per_test = true;
665  }
666  }
667 
668  return int_test || per_test;
669 }

◆ make_eb_box()

void ERF::make_eb_box ( )

◆ make_eb_regular()

void ERF::make_eb_regular ( )

◆ make_physbcs()

void ERF::make_physbcs ( int  lev)
private
898 {
899  if (SolverChoice::mesh_type == MeshType::VariableDz) {
900  AMREX_ALWAYS_ASSERT(z_phys_nd[lev] != nullptr);
901  }
902 
903  physbcs_cons[lev] = std::make_unique<ERFPhysBCFunct_cons> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
905  z_phys_nd[lev], solverChoice.use_real_bcs, th_bc_data[lev].data());
906  physbcs_u[lev] = std::make_unique<ERFPhysBCFunct_u> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
908  z_phys_nd[lev], solverChoice.use_real_bcs, xvel_bc_data[lev].data());
909  physbcs_v[lev] = std::make_unique<ERFPhysBCFunct_v> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
911  z_phys_nd[lev], solverChoice.use_real_bcs, yvel_bc_data[lev].data());
912  physbcs_w[lev] = std::make_unique<ERFPhysBCFunct_w> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
915  solverChoice.use_real_bcs, zvel_bc_data[lev].data());
916  physbcs_base[lev] = std::make_unique<ERFPhysBCFunct_base> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d, z_phys_nd[lev],
917  (solverChoice.terrain_type == TerrainType::MovingFittedMesh));
918 }
Here is the call graph for this function:

◆ make_subdomains()

void ERF::make_subdomains ( const amrex::BoxList &  ba,
amrex::Vector< amrex::BoxArray > &  bins 
)
7 {
8  Vector<BoxList> bins_bl;
9 
10  // Clear out any old bins
11  bins.clear();
12 
13  // Iterate over boxes
14  for (auto bx : bl)
15  {
16  bool added = false;
17 
18  // Try to add box to existing bin
19  for (int j = 0; j < bins_bl.size(); ++j) {
20  BoxList& bin = bins_bl[j];
21  bool touches = false;
22 
23  for (auto& b : bin)
24  {
25  Box gbx(bx); gbx.grow(1);
26  if (gbx.intersects(b)) {
27  touches = true;
28  break;
29  }
30  }
31 
32  if (touches) {
33  bin.push_back(bx);
34  added = true;
35  break;
36  }
37  }
38 
39  // If box couldn't be added to existing bin, create new bin
40  if (!added) {
41  BoxList new_bin;
42  new_bin.push_back(bx);
43  bins_bl.push_back(new_bin);
44  }
45  }
46 
47  // Convert the BoxLists to BoxArrays
48  for (int i = 0; i < bins_bl.size(); ++i) {
49  bins.push_back(BoxArray(bins_bl[i]));
50  }
51 }

◆ MakeDiagnosticAverage()

void ERF::MakeDiagnosticAverage ( amrex::Vector< amrex::Real > &  h_havg,
amrex::MultiFab &  S,
int  n 
)
3095 {
3096  // Get the number of cells in z at level 0
3097  int dir_z = AMREX_SPACEDIM-1;
3098  auto domain = geom[0].Domain();
3099  int size_z = domain.length(dir_z);
3100  int start_z = domain.smallEnd()[dir_z];
3101  Real area_z = static_cast<Real>(domain.length(0)*domain.length(1));
3102 
3103  // resize the level 0 horizontal average vectors
3104  h_havg.resize(size_z, 0.0_rt);
3105 
3106  // Get the cell centered data and construct sums
3107 #ifdef _OPENMP
3108 #pragma omp parallel if (Gpu::notInLaunchRegion())
3109 #endif
3110  for (MFIter mfi(S); mfi.isValid(); ++mfi) {
3111  const Box& box = mfi.validbox();
3112  const IntVect& se = box.smallEnd();
3113  const IntVect& be = box.bigEnd();
3114 
3115  auto fab_arr = S[mfi].array();
3116 
3117  FArrayBox fab_reduce(box, 1, The_Async_Arena());
3118  auto arr_reduce = fab_reduce.array();
3119 
3120  ParallelFor(box, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
3121  arr_reduce(i, j, k, 0) = fab_arr(i,j,k,n);
3122  });
3123 
3124  for (int k=se[dir_z]; k <= be[dir_z]; ++k) {
3125  Box kbox(box); kbox.setSmall(dir_z,k); kbox.setBig(dir_z,k);
3126  h_havg[k-start_z] += fab_reduce.sum<RunOn::Device>(kbox,0);
3127  }
3128  }
3129 
3130  // combine sums from different MPI ranks
3131  ParallelDescriptor::ReduceRealSum(h_havg.dataPtr(), static_cast<int>(h_havg.size()));
3132 
3133  // divide by the total number of cells we are averaging over
3134  for (int k = 0; k < size_z; ++k) {
3135  h_havg[k] /= area_z;
3136  }
3137 }
Here is the call graph for this function:

◆ MakeEBGeometry()

void ERF::MakeEBGeometry ( )

◆ MakeFilename_EyeTracker_latlon()

std::string ERF::MakeFilename_EyeTracker_latlon ( int  nstep)
52  {
53  // Ensure output directory exists
54  const std::string dir = "Output_StormTracker/latlon";
55  if (!fs::exists(dir)) {
56  fs::create_directories(dir);
57  }
58 
59  // Construct filename with zero-padded step
60  std::ostringstream oss;
61  oss << dir << "/storm_track_latlon" << std::setw(7) << std::setfill('0') << nstep << ".txt";
62  return oss.str();
63 }

◆ MakeFilename_EyeTracker_maxvel()

std::string ERF::MakeFilename_EyeTracker_maxvel ( int  nstep)
66  {
67  // Ensure output directory exists
68  const std::string dir = "Output_StormTracker/maxvel";
69  if (!fs::exists(dir)) {
70  fs::create_directories(dir);
71  }
72 
73  // Construct filename with zero-padded step
74  std::ostringstream oss;
75  oss << dir << "/storm_maxvel_" << std::setw(7) << std::setfill('0') << nstep << ".txt";
76  return oss.str();
77 }

◆ MakeFilename_EyeTracker_minpressure()

std::string ERF::MakeFilename_EyeTracker_minpressure ( int  nstep)
80  {
81  // Ensure output directory exists
82  const std::string dir = "Output_StormTracker/minpressure";
83  if (!fs::exists(dir)) {
84  fs::create_directories(dir);
85  }
86 
87  // Construct filename with zero-padded step
88  std::ostringstream oss;
89  oss << dir << "/storm_minpressure_" << std::setw(7) << std::setfill('0') << nstep << ".txt";
90  return oss.str();
91 }

◆ MakeHorizontalAverages()

void ERF::MakeHorizontalAverages ( )
2989 {
2990  int lev = 0;
2991 
2992  // First, average down all levels (if doing two-way coupling)
2993  if (solverChoice.coupling_type == CouplingType::TwoWay) {
2994  AverageDown();
2995  }
2996 
2997  MultiFab mf(grids[lev], dmap[lev], 5, 0);
2998 
2999  int zdir = 2;
3000  auto domain = geom[0].Domain();
3001 
3002  bool use_moisture = (solverChoice.moisture_type != MoistureType::None);
3003  bool is_anelastic = (solverChoice.anelastic[lev] == 1);
3004 
3005  for (MFIter mfi(mf); mfi.isValid(); ++mfi) {
3006  const Box& bx = mfi.validbox();
3007  auto fab_arr = mf.array(mfi);
3008  auto const hse_arr = base_state[lev].const_array(mfi);
3009  auto const cons_arr = vars_new[lev][Vars::cons].const_array(mfi);
3010  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
3011  Real dens = cons_arr(i, j, k, Rho_comp);
3012  fab_arr(i, j, k, 0) = dens;
3013  fab_arr(i, j, k, 1) = cons_arr(i, j, k, RhoTheta_comp) / dens;
3014  if (!use_moisture) {
3015  if (is_anelastic) {
3016  fab_arr(i,j,k,2) = hse_arr(i,j,k,BaseState::p0_comp);
3017  } else {
3018  fab_arr(i,j,k,2) = getPgivenRTh(cons_arr(i,j,k,RhoTheta_comp));
3019  }
3020  }
3021  });
3022  }
3023 
3024  if (use_moisture)
3025  {
3026  for (MFIter mfi(mf); mfi.isValid(); ++mfi) {
3027  const Box& bx = mfi.validbox();
3028  auto fab_arr = mf.array(mfi);
3029  auto const hse_arr = base_state[lev].const_array(mfi);
3030  auto const cons_arr = vars_new[lev][Vars::cons].const_array(mfi);
3031  int ncomp = vars_new[lev][Vars::cons].nComp();
3032 
3033  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
3034  Real dens = cons_arr(i, j, k, Rho_comp);
3035  if (is_anelastic) {
3036  fab_arr(i,j,k,2) = hse_arr(i,j,k,BaseState::p0_comp);
3037  } else {
3038  Real qv = cons_arr(i, j, k, RhoQ1_comp) / dens;
3039  fab_arr(i, j, k, 2) = getPgivenRTh(cons_arr(i, j, k, RhoTheta_comp), qv);
3040  }
3041  fab_arr(i, j, k, 3) = (ncomp > RhoQ1_comp ? cons_arr(i, j, k, RhoQ1_comp) / dens : zero);
3042  fab_arr(i, j, k, 4) = (ncomp > RhoQ2_comp ? cons_arr(i, j, k, RhoQ2_comp) / dens : zero);
3043  });
3044  }
3045 
3046  Gpu::HostVector<Real> h_avg_qv = sumToLine(mf,3,1,domain,zdir);
3047  Gpu::HostVector<Real> h_avg_qc = sumToLine(mf,4,1,domain,zdir);
3048  }
3049 
3050  // Sum in the horizontal plane
3051  Gpu::HostVector<Real> h_avg_density = sumToLine(mf,0,1,domain,zdir);
3052  Gpu::HostVector<Real> h_avg_temperature = sumToLine(mf,1,1,domain,zdir);
3053  Gpu::HostVector<Real> h_avg_pressure = sumToLine(mf,2,1,domain,zdir);
3054 
3055  // Divide by the total number of cells we are averaging over
3056  int size_z = domain.length(zdir);
3057  Real area_z = static_cast<Real>(domain.length(0)*domain.length(1));
3058  int klen = static_cast<int>(h_avg_density.size());
3059 
3060  for (int k = 0; k < klen; ++k) {
3061  h_havg_density[k] /= area_z;
3062  h_havg_temperature[k] /= area_z;
3063  h_havg_pressure[k] /= area_z;
3064  if (solverChoice.moisture_type != MoistureType::None)
3065  {
3066  h_havg_qc[k] /= area_z;
3067  h_havg_qv[k] /= area_z;
3068  }
3069  } // k
3070 
3071  // resize device vectors
3072  d_havg_density.resize(size_z, 0.0_rt);
3073  d_havg_temperature.resize(size_z, 0.0_rt);
3074  d_havg_pressure.resize(size_z, 0.0_rt);
3075 
3076  // copy host vectors to device vectors
3077  Gpu::copy(Gpu::hostToDevice, h_havg_density.begin(), h_havg_density.end(), d_havg_density.begin());
3078  Gpu::copy(Gpu::hostToDevice, h_havg_temperature.begin(), h_havg_temperature.end(), d_havg_temperature.begin());
3079  Gpu::copy(Gpu::hostToDevice, h_havg_pressure.begin(), h_havg_pressure.end(), d_havg_pressure.begin());
3080 
3081  if (solverChoice.moisture_type != MoistureType::None)
3082  {
3083  d_havg_qv.resize(size_z, 0.0_rt);
3084  d_havg_qc.resize(size_z, 0.0_rt);
3085  Gpu::copy(Gpu::hostToDevice, h_havg_qv.begin(), h_havg_qv.end(), d_havg_qv.begin());
3086  Gpu::copy(Gpu::hostToDevice, h_havg_qc.begin(), h_havg_qc.end(), d_havg_qc.begin());
3087  }
3088 }
amrex::Gpu::DeviceVector< amrex::Real > d_havg_temperature
Definition: ERF.H:1374
amrex::Gpu::DeviceVector< amrex::Real > d_havg_qv
Definition: ERF.H:1376
amrex::Vector< amrex::Real > h_havg_pressure
Definition: ERF.H:1369
amrex::Vector< amrex::Real > h_havg_qc
Definition: ERF.H:1371
amrex::Vector< amrex::Real > h_havg_density
Definition: ERF.H:1367
amrex::Gpu::DeviceVector< amrex::Real > d_havg_qc
Definition: ERF.H:1377
amrex::Gpu::DeviceVector< amrex::Real > d_havg_density
Definition: ERF.H:1373
amrex::Vector< amrex::Real > h_havg_temperature
Definition: ERF.H:1368
amrex::Gpu::DeviceVector< amrex::Real > d_havg_pressure
Definition: ERF.H:1375
amrex::Vector< amrex::Real > h_havg_qv
Definition: ERF.H:1370
Here is the call graph for this function:

◆ MakeNewLevelFromCoarse()

void ERF::MakeNewLevelFromCoarse ( int  lev,
amrex::Real  time,
const amrex::BoxArray &  ba,
const amrex::DistributionMapping &  dm 
)
override
276 {
277  //
278  // Note that "time" here is elapsed time
279  //
280  AMREX_ALWAYS_ASSERT(lev > 0);
281 
282  if (verbose) {
283  amrex::Print() <<" NEW BA FROM COARSE AT LEVEL " << lev << " " << ba << std::endl;
284  }
285 
286  //
287  // Grow the subdomains vector and build the subdomains vector at this level
288  //
289  subdomains.resize(lev+1);
290  //
291  // Create subdomains at each level within the domain such that
292  // 1) all boxes in a given subdomain are "connected"
293  // 2) no boxes in a subdomain touch any boxes in any other subdomain
294  //
295  make_subdomains(ba.simplified_list(), subdomains[lev]);
296 
297  if (lev == 0) init_bcs();
298 
299  //********************************************************************************************
300  // This allocates all kinds of things, including but not limited to: solution arrays,
301  // terrain arrays, ba2d, metric terms and base state.
302  // *******************************************************************************************
303  init_stuff(lev, ba, dm, vars_new[lev], vars_old[lev], base_state[lev], z_phys_nd[lev]);
304 
305  //
306  // Note that t_new = time here is elapsed time
307  //
308  t_new[lev] = time;
309  t_old[lev] = time - Real(1.e200);
310 
311  // ********************************************************************************************
312  // Build the data structures for metric quantities used with terrain-fitted coordinates
313  // ********************************************************************************************
314  if ( solverChoice.terrain_type == TerrainType::EB ||
315  solverChoice.terrain_type == TerrainType::ImmersedForcing ||
316  solverChoice.buildings_type == BuildingsType::ImmersedForcing)
317  {
318  const amrex::EB2::IndexSpace& ebis = amrex::EB2::IndexSpace::top();
319  const EB2::Level& eb_level = ebis.getLevel(geom[lev]);
320  if (solverChoice.terrain_type == TerrainType::EB) {
321  eb[lev]->make_all_factories(lev, geom[lev], ba, dm, eb_level);
322  } else if (solverChoice.terrain_type == TerrainType::ImmersedForcing ||
323  solverChoice.buildings_type == BuildingsType::ImmersedForcing) {
324  eb[lev]->make_cc_factory(lev, geom[lev], ba, dm, eb_level);
325  }
326  }
327  init_zphys(lev, time);
329 
330  //
331  // Make sure that detJ and z_phys_cc are the average of the data on a finer level if there is one
332  // *and* if there is two-way coupling
333  //
334  if ( (SolverChoice::mesh_type != MeshType::ConstantDz) && (solverChoice.coupling_type == CouplingType::TwoWay) ) {
335  for (int crse_lev = lev-1; crse_lev >= 0; crse_lev--) {
336  average_down( *detJ_cc[crse_lev+1], *detJ_cc[crse_lev], 0, 1, refRatio(crse_lev));
337  average_down(*z_phys_cc[crse_lev+1], *z_phys_cc[crse_lev], 0, 1, refRatio(crse_lev));
338  }
339  }
340 
341  // ********************************************************************************************
342  // Build the data structures for canopy model (depends upon z_phys)
343  // ********************************************************************************************
345  m_forest_drag[lev]->define_drag_field(ba, dm, geom[lev], z_phys_cc[lev].get(), z_phys_nd[lev].get());
346  }
347 
348  //********************************************************************************************
349  // Radiation
350  // *******************************************************************************************
351  if (solverChoice.rad_type != RadiationType::None)
352  {
353  rad[lev]->Init(geom[lev], ba, &vars_new[lev][Vars::cons]);
354  }
355 
356  // *****************************************************************************************************
357  // Initialize the boundary conditions (after initializing the terrain but before calling
358  // initHSE or FillCoarsePatch)
359  // *****************************************************************************************************
360  make_physbcs(lev);
361 
362  // ********************************************************************************************
363  // Update the base state at this level by interpolation from coarser level
364  // ********************************************************************************************
365  InterpFromCoarseLevel(base_state[lev], base_state[lev].nGrowVect(),
366  IntVect(0,0,0), // do not fill ghost cells outside the domain
367  base_state[lev-1], 0, 0, base_state[lev].nComp(),
368  geom[lev-1], geom[lev],
369  refRatio(lev-1), &cell_cons_interp,
371 
372  // Impose bc's outside the domain
373  (*physbcs_base[lev])(base_state[lev],0,base_state[lev].nComp(),base_state[lev].nGrowVect());
374 
375  //********************************************************************************************
376  // Microphysics
377  // *******************************************************************************************
378  int q_size = micro->Get_Qmoist_Size(lev);
379  qmoist[lev].resize(q_size);
380  micro->Define(lev, solverChoice);
381  if (solverChoice.moisture_type != MoistureType::None)
382  {
383  micro->Init(lev, vars_new[lev][Vars::cons],
384  grids[lev], Geom(lev), zero,
385  z_phys_nd[lev], detJ_cc[lev]); // dummy dt value
386  }
387  for (int mvar(0); mvar<qmoist[lev].size(); ++mvar) {
388  qmoist[lev][mvar] = micro->Get_Qmoist_Ptr(lev,mvar);
389  }
390 
391  // ********************************************************************************************
392  // Build the data structures for calculating diffusive/turbulent terms
393  // ********************************************************************************************
394  update_diffusive_arrays(lev, ba, dm);
395 
396  // ********************************************************************************************
397  // Build the data structures for holding sea surface temps and skin temps
398  // ********************************************************************************************
399  sst_lev[lev].resize(1); sst_lev[lev][0] = nullptr;
400  tsk_lev[lev].resize(1); tsk_lev[lev][0] = nullptr;
401 
402  // ********************************************************************************************
403  // Fill data at the new level by interpolation from the coarser level
404  // Note that internal to FillCoarsePatch we will convert velocity to momentum,
405  // then interpolate momentum, then convert momentum back to velocity
406  // Also note that FillCoarsePatch is hard-wired to act only on lev_new at coarse and fine
407  // ********************************************************************************************
408 
409 #ifdef ERF_USE_NETCDF
410  if ( ( (solverChoice.init_type == InitType::WRFInput) || (solverChoice.init_type == InitType::Metgrid) ) &&
411  !nc_init_file[lev].empty() )
412  {
413  // Just making sure that ghost cells aren't uninitialized...
414  vars_new[lev][Vars::cons].setVal(0.0); vars_old[lev][Vars::cons].setVal(0.0);
415  vars_new[lev][Vars::xvel].setVal(0.0); vars_old[lev][Vars::xvel].setVal(0.0);
416  vars_new[lev][Vars::yvel].setVal(0.0); vars_old[lev][Vars::yvel].setVal(0.0);
417  vars_new[lev][Vars::zvel].setVal(0.0); vars_old[lev][Vars::zvel].setVal(0.0);
418 
419  AMREX_ALWAYS_ASSERT(solverChoice.terrain_type == TerrainType::StaticFittedMesh);
420  if (solverChoice.init_type == InitType::Metgrid) {
421  init_from_metgrid(lev);
422  } else if (solverChoice.init_type == InitType::WRFInput) {
423  init_from_wrfinput(lev, *mf_PSFC[lev]);
424  }
425  init_zphys(lev, time);
427  make_physbcs(lev);
428 
429  dz_min[lev] = (*detJ_cc[lev]).min(0) * geom[lev].CellSize(2);
430 
431  } else {
432 #endif
433  //
434  // Interpolate the solution data
435  //
436  FillCoarsePatch(lev, time);
437 
438  //
439  // Interpolate the 2D arrays at the lower boundary
440  // Note that ba2d is constructed already in init_stuff, but we have not yet defined dmap[lev]
441  // so we must explicitly pass dm.
442  Interp2DArrays(lev,ba2d[lev],dm);
443 
444  // Populate dz_min for dynamically-created fine levels (non-terrain path).
445  if (static_cast<int>(dz_min.size()) <= lev) { dz_min.resize(lev+1); }
446  dz_min[lev] = geom[lev].CellSize(2);
447  if ( SolverChoice::mesh_type != MeshType::ConstantDz && detJ_cc[lev] ) {
448  dz_min[lev] *= (*detJ_cc[lev]).min(0);
449  }
450 #ifdef ERF_USE_NETCDF
451  }
452 #endif
453 
454  // ********************************************************************************************
455  // Initialize the integrator class
456  // ********************************************************************************************
457  dt_mri_ratio[lev] = dt_mri_ratio[lev-1];
459 
460  // ********************************************************************************************
461  // If we are making a new level then the FillPatcher for this level hasn't been allocated yet
462  // ********************************************************************************************
463  if (lev > 0 && cf_width >= 0) {
466  }
467 
468  // ********************************************************************************************
469  // For anelastic levels created from coarse (either on restart or during a run), project the
470  // interpolated velocity to enforce the divergence-free constraint. This Initializes gradp[lev]
471  // via the pressure projection, handling both the pure-anelastic case and the hybrid case
472  // (compressible lev-1, anelastic lev) where there is no coarse gradp to interpolate.
473  // FillPatchers must be constructed above before this call. pp_inc is scratch; zero afterward.
474  // ********************************************************************************************
475  if (solverChoice.anelastic[lev]) {
476  Real dummy_dt = one;
477  project_initial_velocity(lev, time, dummy_dt);
478  pp_inc[lev].setVal(0.0);
479  }
480 
481  //********************************************************************************************
482  // Land Surface Model
483  // *******************************************************************************************
484  int lsm_data_size = lsm.Get_Data_Size();
485  int lsm_flux_size = lsm.Get_Flux_Size();
486  lsm_data[lev].resize(lsm_data_size);
487  lsm_data_name.resize(lsm_data_size);
488  lsm_flux[lev].resize(lsm_flux_size);
489  lsm_flux_name.resize(lsm_flux_size);
490  lsm.Define(lev, solverChoice);
491  if (solverChoice.lsm_type != LandSurfaceType::None)
492  {
493  lsm.Init(lev, vars_new[lev][Vars::cons], Geom(lev), zero); // dummy dt value
494  }
495  for (int mvar(0); mvar<lsm_data[lev].size(); ++mvar) {
496  lsm_data[lev][mvar] = lsm.Get_Data_Ptr(lev,mvar);
497  lsm_data_name[mvar] = lsm.Get_DataName(mvar);
498  }
499  for (int mvar(0); mvar<lsm_flux[lev].size(); ++mvar) {
500  lsm_flux[lev][mvar] = lsm.Get_Flux_Ptr(lev,mvar);
501  lsm_flux_name[mvar] = lsm.Get_FluxName(mvar);
502  }
503 
504  // ********************************************************************************************
505  // Create the SurfaceLayer arrays at this (new) level
506  // ********************************************************************************************
507  if (phys_bc_type[Orientation(Direction::z,Orientation::low)] == ERF_BC::surface_layer) {
508  Vector<MultiFab*> mfv_old = {&vars_old[lev][Vars::cons], &vars_old[lev][Vars::xvel],
509  &vars_old[lev][Vars::yvel], &vars_old[lev][Vars::zvel]};
510  m_SurfaceLayer->make_SurfaceLayer_at_level(lev,lev+1,
511  mfv_old, Theta_prim[lev], Qv_prim[lev],
512  Qr_prim[lev], z_phys_nd[lev],
513  Hwave[lev].get(), Lwave[lev].get(), eddyDiffs_lev[lev].get(),
515  sst_lev[lev], tsk_lev[lev], lmask_lev[lev]);
516  }
517 
518  // ********************************************************************************************
519  // Set up the Rayleigh damping vectors at this (new) level
520  // ********************************************************************************************
523  {
525  }
526 
527 }
void update_diffusive_arrays(int lev, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm)
Definition: ERF_MakeNewArrays.cpp:527
void initialize_integrator(int lev, amrex::MultiFab &cons_mf, amrex::MultiFab &vel_mf)
Definition: ERF_MakeNewArrays.cpp:875
void make_subdomains(const amrex::BoxList &ba, amrex::Vector< amrex::BoxArray > &bins)
Definition: ERF_MakeSubdomains.cpp:6
void update_terrain_arrays(int lev)
Definition: ERF_MakeNewArrays.cpp:858
void init_zphys(int lev, amrex::Real elapsed_time)
Definition: ERF_MakeNewArrays.cpp:693
void init_stuff(int lev, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm, amrex::Vector< amrex::MultiFab > &lev_new, amrex::Vector< amrex::MultiFab > &lev_old, amrex::MultiFab &tmp_base_state, std::unique_ptr< amrex::MultiFab > &tmp_zphys_nd)
Definition: ERF_MakeNewArrays.cpp:24
void Define_ERFFillPatchers(int lev)
Definition: ERF.cpp:3166
int Get_Data_Size()
Definition: ERF_LandSurface.H:101
std::string Get_DataName(const int &varIdx)
Definition: ERF_LandSurface.H:107
std::string Get_FluxName(const int &varIdx)
Definition: ERF_LandSurface.H:113
amrex::MultiFab * Get_Flux_Ptr(const int &lev, const int &varIdx)
Definition: ERF_LandSurface.H:95
void Init(const int &lev, const amrex::MultiFab &cons_in, const amrex::Geometry &geom, const amrex::Real &dt_advance)
Definition: ERF_LandSurface.H:44
void Define(const int &lev, SolverChoice &sc)
Definition: ERF_LandSurface.H:37
int Get_Flux_Size()
Definition: ERF_LandSurface.H:104
Here is the call graph for this function:

◆ MakeNewLevelFromScratch()

void ERF::MakeNewLevelFromScratch ( int  lev,
amrex::Real  time,
const amrex::BoxArray &  ba,
const amrex::DistributionMapping &  dm 
)
override
27 {
28  //
29  // Note that "time" here is elapsed time
30  //
31  BoxArray ba;
32  DistributionMapping dm;
33  Box domain(Geom(0).Domain());
34  if (lev == 0 && restart_chkfile.empty() &&
35  (max_grid_size[0][0] >= domain.length(0)) &&
36  (max_grid_size[0][1] >= domain.length(1)) &&
37  ba_in.size() != ParallelDescriptor::NProcs())
38  {
39  // We only decompose in z if max_grid_size_z indicates we should
40  bool decompose_in_z = (max_grid_size[0][2] < domain.length(2));
41 
42  ba = ERFPostProcessBaseGrids(Geom(0).Domain(),decompose_in_z);
43  dm = DistributionMapping(ba);
44  } else {
45  ba = ba_in;
46  dm = dm_in;
47  }
48 
49  // ********************************************************************************************
50  // Define grids[lev] to be ba
51  // ********************************************************************************************
52  SetBoxArray(lev, ba);
53 
54  // ********************************************************************************************
55  // Define dmap[lev] to be dm
56  // ********************************************************************************************
57  SetDistributionMap(lev, dm);
58 
59  if (verbose) {
60  amrex::Print() << "BA FROM SCRATCH AT LEVEL " << lev << " " << ba << std::endl;
61  // amrex::Print() <<" SIMPLIFIED BA FROM SCRATCH AT LEVEL " << lev << " " << ba.simplified_list() << std::endl;
62  }
63 
64  subdomains.resize(lev+1);
65  //
66  // Create subdomains at each level within the domain such that
67  // 1) all boxes in a given subdomain are "connected"
68  // 2) no boxes in a subdomain touch any boxes in any other subdomain
69  //
70  make_subdomains(ba.simplified_list(), subdomains[lev]);
71 
72  if (lev == 0) init_bcs();
73 
74  if ( solverChoice.terrain_type == TerrainType::EB ||
75  solverChoice.terrain_type == TerrainType::ImmersedForcing ||
76  solverChoice.buildings_type == BuildingsType::ImmersedForcing)
77  {
78  const amrex::EB2::IndexSpace& ebis = amrex::EB2::IndexSpace::top();
79  const EB2::Level& eb_level = ebis.getLevel(geom[lev]);
80  if (solverChoice.terrain_type == TerrainType::EB) {
81  eb[lev]->make_all_factories(lev, geom[lev], grids[lev], dmap[lev], eb_level);
82  } else if (solverChoice.terrain_type == TerrainType::ImmersedForcing ||
83  solverChoice.buildings_type == BuildingsType::ImmersedForcing) {
84  eb[lev]->make_cc_factory(lev, geom[lev], grids[lev], dmap[lev], eb_level);
85  }
86  }
87 
88  auto& lev_new = vars_new[lev];
89  auto& lev_old = vars_old[lev];
90 
91  //********************************************************************************************
92  // This allocates all kinds of things, including but not limited to: solution arrays,
93  // terrain arrays, metric terms and base state.
94  // *******************************************************************************************
95  init_stuff(lev, ba, dm, lev_new, lev_old, base_state[lev], z_phys_nd[lev]);
96 
97  //********************************************************************************************
98  // Land Surface Model
99  // *******************************************************************************************
100  int lsm_data_size = lsm.Get_Data_Size();
101  int lsm_flux_size = lsm.Get_Flux_Size();
102  lsm_data[lev].resize(lsm_data_size);
103  lsm_data_name.resize(lsm_data_size);
104  lsm_flux[lev].resize(lsm_flux_size);
105  lsm_flux_name.resize(lsm_flux_size);
106  lsm.Define(lev, solverChoice);
107  if (solverChoice.lsm_type != LandSurfaceType::None)
108  {
109  lsm.Init(lev, vars_new[lev][Vars::cons], Geom(lev), zero); // dummy dt value
110  }
111  for (int mvar(0); mvar<lsm_data[lev].size(); ++mvar) {
112  lsm_data[lev][mvar] = lsm.Get_Data_Ptr(lev,mvar);
113  lsm_data_name[mvar] = lsm.Get_DataName(mvar);
114  }
115  for (int mvar(0); mvar<lsm_flux[lev].size(); ++mvar) {
116  lsm_flux[lev][mvar] = lsm.Get_Flux_Ptr(lev,mvar);
117  lsm_flux_name[mvar] = lsm.Get_FluxName(mvar);
118  }
119 
120 
121 
122  // ********************************************************************************************
123  // Build the data structures for calculating diffusive/turbulent terms
124  // ********************************************************************************************
125  update_diffusive_arrays(lev, ba, dm);
126 
127  // ********************************************************************************************
128  // Build the data structures for holding sea surface temps and skin temps
129  // ********************************************************************************************
130  sst_lev[lev].resize(1); sst_lev[lev][0] = nullptr;
131  tsk_lev[lev].resize(1); tsk_lev[lev][0] = nullptr;
132 
133  // ********************************************************************************************
134  // Thin immersed body
135  // *******************************************************************************************
136  init_thin_body(lev, ba, dm);
137 
138  // ********************************************************************************************
139  // Initialize the integrator class
140  // ********************************************************************************************
141  initialize_integrator(lev, lev_new[Vars::cons],lev_new[Vars::xvel]);
142 
143  // ********************************************************************************************
144  // Initialize the data itself
145  // If (init_type == InitType::WRFInput) then we are initializing terrain and the initial data in
146  // the same call so we must call init_only before update_terrain_arrays
147  // If (init_type != InitType::WRFInput) then we want to initialize the terrain before the initial data
148  // since we may need to use the grid information before constructing
149  // initial idealized data
150  // ********************************************************************************************
151  if (restart_chkfile.empty()) {
152  if ( (solverChoice.init_type == InitType::WRFInput) || (solverChoice.init_type == InitType::Metgrid) )
153  {
154  AMREX_ALWAYS_ASSERT(solverChoice.terrain_type == TerrainType::StaticFittedMesh);
155  //
156  // Note that "time" here is elapsed time, and start_time is the start_time from wrfinput/metgrid files
157  //
158  init_only(lev, time);
159  init_zphys(lev, time);
161  make_physbcs(lev);
162  } else {
163  //
164  // Note that "time" here is elapsed time, and start_time = 0 when not using wrfinput/metgrid
165  //
166  init_zphys(lev, time);
168  // Note that for init_type != InitType::WRFInput and != InitType::Metgrid,
169  // make_physbcs is called inside init_only
170  init_only(lev, time);
171  }
172  } else {
173  // if restarting and nudging from input sounding, load the input sounding files
174  if (lev == 0 && solverChoice.init_type == InitType::Input_Sounding && solverChoice.nudging_from_input_sounding)
175  {
177  Error("input_sounding file name must be provided via input");
178  }
179 
181 
182  // this will interpolate the input profiles to the nominal height levels
183  // (ranging from 0 to the domain top)
184  for (int n = 0; n < input_sounding_data.n_sounding_files; n++) {
185  input_sounding_data.read_from_file(geom[lev], zlevels_stag[lev], n);
186  }
187 
188  // this will calculate the hydrostatically balanced density and pressure
189  // profiles following WRF ideal.exe
190  if (solverChoice.sounding_type == SoundingType::Ideal) {
192  } else if (solverChoice.sounding_type == SoundingType::Isentropic ||
193  solverChoice.sounding_type == SoundingType::DryIsentropic) {
194  input_sounding_data.assume_dry = (solverChoice.sounding_type == SoundingType::DryIsentropic);
196  }
197  }
198 
199  // We re-create terrain_blanking on restart rather than storing it in the checkpoint
200  if (solverChoice.terrain_type == TerrainType::ImmersedForcing ||
201  solverChoice.buildings_type == BuildingsType::ImmersedForcing) {
202  int ngrow = ComputeGhostCells(solverChoice) + 2;
203  terrain_blanking[lev]->setVal(1.0);
204  MultiFab::Subtract(*terrain_blanking[lev], EBFactory(lev).getVolFrac(), 0, 0, 1, ngrow);
205  terrain_blanking[lev]->FillBoundary(geom[lev].periodicity());
206  }
207  }
208 
209  // Read in tables needed for windfarm simulations
210  // fill in Nturb multifab - number of turbines in each mesh cell
211  // write out the vtk files for wind turbine location and/or
212  // actuator disks
213  #ifdef ERF_USE_WINDFARM
214  init_windfarm(lev);
215  #endif
216 
217  // ********************************************************************************************
218  // Build the data structures for canopy model (depends upon z_phys)
219  // ********************************************************************************************
220  if (restart_chkfile.empty()) {
222  m_forest_drag[lev]->define_drag_field(ba, dm, geom[lev], z_phys_cc[lev].get(), z_phys_nd[lev].get());
223  }
224  }
225 
226  //********************************************************************************************
227  // Microphysics
228  // *******************************************************************************************
229  int q_size = micro->Get_Qmoist_Size(lev);
230  qmoist[lev].resize(q_size);
231  micro->Define(lev, solverChoice);
232  if (solverChoice.moisture_type != MoistureType::None)
233  {
234  micro->Init(lev, vars_new[lev][Vars::cons],
235  grids[lev], Geom(lev), zero,
236  z_phys_nd[lev], detJ_cc[lev]); // dummy dt value
237  }
238  for (int mvar(0); mvar<qmoist[lev].size(); ++mvar) {
239  qmoist[lev][mvar] = micro->Get_Qmoist_Ptr(lev,mvar);
240  }
241 
242  //********************************************************************************************
243  // Radiation
244  // *******************************************************************************************
245  if (solverChoice.rad_type != RadiationType::None)
246  {
247  rad[lev]->Init(geom[lev], ba, &vars_new[lev][Vars::cons]);
248  }
249 
250  // ********************************************************************************************
251  // If we are making a new level then the FillPatcher for this level hasn't been allocated yet
252  // ********************************************************************************************
253  if (lev > 0 && cf_width >= 0) {
256  }
257 
258 #ifdef ERF_USE_PARTICLES
259  if (restart_chkfile.empty()) {
260  if (lev == 0) {
261  initializeTracers((ParGDBBase*)GetParGDB(),z_phys_nd,time);
262  }
263  // For lev > 0: particle redistribute is handled in timeStep() AFTER
264  // regrid() completes, not here inside MakeNewLevelFromCoarse.
265  }
266 #endif
267 }
BoxArray ERFPostProcessBaseGrids(const Box &domain, bool decompose_in_z)
Definition: ERF_ChopGrids.cpp:6
void init_only(int lev, amrex::Real time)
Definition: ERF.cpp:2272
void init_thin_body(int lev, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm)
Definition: ERF_MakeNewLevel.cpp:895
bool nudging_from_input_sounding
Definition: ERF_DataStruct.H:1235
Here is the call graph for this function:

◆ MakeVTKFilename()

std::string ERF::MakeVTKFilename ( int  nstep)
11  {
12  // Ensure output directory exists
13  const std::string dir = "Output_StormTracker";
14  if (!fs::exists(dir)) {
15  fs::create_directory(dir);
16  }
17 
18  std::ostringstream oss;
19  oss << dir << "/storm_track_" << std::setw(7) << std::setfill('0') << nstep << ".vtk";
20  return oss.str();
21 }

◆ MakeVTKFilename_EyeTracker_xy()

std::string ERF::MakeVTKFilename_EyeTracker_xy ( int  nstep)
38  {
39  // Ensure output directory exists
40  const std::string dir = "Output_StormTracker/xy";
41  if (!fs::exists(dir)) {
42  fs::create_directories(dir);
43  }
44 
45  // Construct filename with zero-padded step
46  std::ostringstream oss;
47  oss << dir << "/storm_track_xy_" << std::setw(7) << std::setfill('0') << nstep << ".vtk";
48  return oss.str();
49 }

◆ MakeVTKFilename_TrackerCircle()

std::string ERF::MakeVTKFilename_TrackerCircle ( int  nstep)
24  {
25  // Ensure output directory exists
26  const std::string dir = "Output_StormTracker/tracker_circle";
27  if (!fs::exists(dir)) {
28  fs::create_directories(dir);
29  }
30 
31  // Construct filename with zero-padded step
32  std::ostringstream oss;
33  oss << dir << "/storm_tracker_circle_" << std::setw(7) << std::setfill('0') << nstep << ".vtk";
34  return oss.str();
35 }

◆ nghost_eb_basic()

static int ERF::nghost_eb_basic ( )
inlinestaticprivate
1681  { return 5; }

◆ nghost_eb_full()

static int ERF::nghost_eb_full ( )
inlinestaticprivate
1688  { return 4; }

◆ nghost_eb_volume()

static int ERF::nghost_eb_volume ( )
inlinestaticprivate
1685  { return 5; }

◆ NumDataLogs()

AMREX_FORCE_INLINE int ERF::NumDataLogs ( )
inlineprivatenoexcept
1477  {
1478  return static_cast<int>(datalog.size());
1479  }

◆ NumDerDataLogs()

AMREX_FORCE_INLINE int ERF::NumDerDataLogs ( )
inlineprivatenoexcept
1484  {
1485  return static_cast<int>(der_datalog.size());
1486  }

◆ NumSampleLineLogs()

AMREX_FORCE_INLINE int ERF::NumSampleLineLogs ( )
inlineprivatenoexcept
1513  {
1514  return static_cast<int>(samplelinelog.size());
1515  }

◆ NumSampleLines()

AMREX_FORCE_INLINE int ERF::NumSampleLines ( )
inlineprivatenoexcept
1539  {
1540  return static_cast<int>(sampleline.size());
1541  }

◆ NumSamplePointLogs()

AMREX_FORCE_INLINE int ERF::NumSamplePointLogs ( )
inlineprivatenoexcept
1499  {
1500  return static_cast<int>(sampleptlog.size());
1501  }

◆ NumSamplePoints()

AMREX_FORCE_INLINE int ERF::NumSamplePoints ( )
inlineprivatenoexcept
1526  {
1527  return static_cast<int>(samplepoint.size());
1528  }

◆ operator=() [1/2]

ERF& ERF::operator= ( const ERF other)
delete

◆ operator=() [2/2]

ERF& ERF::operator= ( ERF &&  other)
deletenoexcept

◆ PackAtmosphericStates()

void ERF::PackAtmosphericStates ( amrex::Vector< amrex::MultiFab * > &  states,
amrex::Real  time 
)
92 {
93  using namespace amrex;
94 
95  // Contract slot indices (mirrors ERFRemoraCouplingContract.H; repeated here
96  // to avoid a driver→submodule header dependency).
97  constexpr int iUwind = 0, iVwind = 1, iPatm = 2, iRH = 3, iTair = 4;
98  constexpr int iCloud = 5, iRain = 6, iSWrad = 7, iLWrad = 8;
99 
100  const int lev = 0;
101 
102  auto& cons = vars_new[lev][Vars::cons];
103  auto& xvel = vars_new[lev][Vars::xvel]; // XFace
104  auto& yvel = vars_new[lev][Vars::yvel]; // YFace
105 
106  const bool has_moisture = (solverChoice.moisture_type != MoistureType::None);
107  const bool has_radiation = (!rad_fluxes.empty() && rad_fluxes[lev] != nullptr);
108 
109  amrex::ignore_unused(has_moisture, has_radiation);
110 
111  const auto& ba = cons.boxArray();
112  const auto& dm = cons.DistributionMap();
113  const auto& ba2d_lev = ba2d[lev];
114 
115  // --- Uwind + Vwind: use AMReX's average_face_to_cellcenter which correctly
116  // handles tile boundaries via growntilebox(1) internally. ---
117  if ((iUwind < static_cast<int>(states.size()) && states[iUwind] != nullptr) ||
118  (iVwind < static_cast<int>(states.size()) && states[iVwind] != nullptr)) {
119 
120  auto& zvel = vars_new[lev][Vars::zvel];
121  MultiFab cc_vel(ba, dm, AMREX_SPACEDIM, 0);
122  amrex::average_face_to_cellcenter(cc_vel, 0,
123  Array<const MultiFab*, AMREX_SPACEDIM>{&xvel, &yvel, &zvel});
124 
125  // Collapse to 2D slab
126  MultiFab uv_slab(ba2d_lev, dm, 2, 0); // comp0=u, comp1=v
127  uv_slab.ParallelCopy(cc_vel, 0, 0, 2);
128 
129  if (iUwind < static_cast<int>(states.size()) && states[iUwind] != nullptr) {
130  MultiFab u_alias(uv_slab, amrex::make_alias, 0, 1); // alias u component
131  IntVect ratio = ba2d_lev.minimalBox().length()
132  / states[iUwind]->boxArray().minimalBox().length();
133  amrex::average_down(u_alias, *states[iUwind], 0, 1, ratio);
134  }
135 
136  if (iVwind < static_cast<int>(states.size()) && states[iVwind] != nullptr) {
137  MultiFab v_alias(uv_slab, amrex::make_alias, 1, 1); // alias v component
138  IntVect ratio = ba2d_lev.minimalBox().length()
139  / states[iVwind]->boxArray().minimalBox().length();
140  amrex::average_down(v_alias, *states[iVwind], 0, 1, ratio);
141  }
142  }
143 
144  // --- Patm: getPgivenRTh(RhoTheta, qv) at k=0 ---
145  if (iPatm < static_cast<int>(states.size()) && states[iPatm] != nullptr) {
146  MultiFab tmp(ba2d_lev, dm, 1, 0);
147  for (MFIter mfi(tmp, TilingIfNotGPU()); mfi.isValid(); ++mfi) {
148  Box bx = mfi.tilebox();
149  auto const& c = cons.const_array(mfi);
150  auto t = tmp.array(mfi);
151  if (has_moisture) {
152  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
153  const Real qv = c(i,j,k,RhoQ1_comp) / c(i,j,k,Rho_comp);
154  t(i,j,k) = getPgivenRTh(c(i,j,k,RhoTheta_comp), qv);
155  });
156  } else {
157  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
158  t(i,j,k) = getPgivenRTh(c(i,j,k,RhoTheta_comp));
159  });
160  }
161  }
162  IntVect ratio = ba2d_lev.minimalBox().length() / states[iPatm]->boxArray().minimalBox().length();
163  amrex::average_down(tmp, *states[iPatm], 0, 1, ratio);
164  }
165 
166  // --- Tair: getTgivenRandRTh(rho, RhoTheta, qv) at k=0 [K] ---
167  if (iTair < static_cast<int>(states.size()) && states[iTair] != nullptr) {
168  MultiFab tmp(ba2d_lev, dm, 1, 0);
169  for (MFIter mfi(tmp, TilingIfNotGPU()); mfi.isValid(); ++mfi) {
170  Box bx = mfi.tilebox();
171  auto const& c = cons.const_array(mfi);
172  auto t = tmp.array(mfi);
173  if (has_moisture) {
174  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
175  const Real qv = c(i,j,k,RhoQ1_comp) / c(i,j,k,Rho_comp);
176  t(i,j,k) = getTgivenRandRTh(c(i,j,k,Rho_comp), c(i,j,k,RhoTheta_comp), qv);
177  });
178  } else {
179  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
180  t(i,j,k) = getTgivenRandRTh(c(i,j,k,Rho_comp), c(i,j,k,RhoTheta_comp));
181  });
182  }
183  }
184  IntVect ratio = ba2d_lev.minimalBox().length() / states[iTair]->boxArray().minimalBox().length();
185  amrex::average_down(tmp, *states[iTair], 0, 1, ratio);
186  }
187 
188  // --- Moisture fields: from cons when available, else REMORA inputs-file constants ---
189  if (has_moisture) {
190  if (iRH < static_cast<int>(states.size()) && states[iRH] != nullptr) {
191  MultiFab tmp(ba2d_lev, dm, 1, 0);
192  for (MFIter mfi(tmp, TilingIfNotGPU()); mfi.isValid(); ++mfi) {
193  Box bx = mfi.tilebox();
194  auto const& c = cons.const_array(mfi);
195  auto t = tmp.array(mfi);
196  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
197  t(i,j,k) = c(i,j,k,RhoQ1_comp) / c(i,j,k,Rho_comp);
198  });
199  }
200  IntVect ratio = ba2d_lev.minimalBox().length() / states[iRH]->boxArray().minimalBox().length();
201  amrex::average_down(tmp, *states[iRH], 0, 1, ratio);
202  }
203  if (iCloud < static_cast<int>(states.size()) && states[iCloud] != nullptr) {
204  const int qc_idx = solverChoice.moisture_indices.qc;
205  const int qi_idx = solverChoice.moisture_indices.qi;
206  if (qc_idx != -1 || qi_idx != -1) {
207  MultiFab tmp(ba2d_lev, dm, 1, 0);
208  const Real cf = amrex::max(Real(0.0), amrex::min(Real(1.0), cloud_fraction(0.0)));
209  amrex::ignore_unused(cf); // keep diagnostic computation active for consistency with ERF scalar stats
210  for (MFIter mfi(tmp, TilingIfNotGPU()); mfi.isValid(); ++mfi) {
211  Box bx = mfi.tilebox();
212  auto const& c = cons.const_array(mfi);
213  auto t = tmp.array(mfi);
214  const int klo = ba.minimalBox().smallEnd(2);
215  const int khi = ba.minimalBox().bigEnd(2);
216  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
217  int cloudy = 0;
218  for (int kk = klo; kk <= khi; ++kk) {
219  const Real rho = c(i,j,kk,Rho_comp);
220  const Real qc = (qc_idx != -1) ? c(i,j,kk,qc_idx) / rho : Real(0.0);
221  const Real qi = (qi_idx != -1) ? c(i,j,kk,qi_idx) / rho : Real(0.0);
222  if (qc + qi > Real(0.0)) { cloudy = 1; break; }
223  }
224  t(i,j,k) = static_cast<Real>(cloudy);
225  });
226  }
227  IntVect ratio = ba2d_lev.minimalBox().length() / states[iCloud]->boxArray().minimalBox().length();
228  amrex::average_down(tmp, *states[iCloud], 0, 1, ratio);
229  }
230  }
231  if (iRain < static_cast<int>(states.size()) && states[iRain] != nullptr) {
232  int qr_idx = solverChoice.moisture_indices.qr;
233  if (qr_idx != -1) {
234  MultiFab tmp(ba2d_lev, dm, 1, 0);
235  for (MFIter mfi(tmp, TilingIfNotGPU()); mfi.isValid(); ++mfi) {
236  Box bx = mfi.tilebox();
237  auto const& c = cons.const_array(mfi);
238  auto t = tmp.array(mfi);
239  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
240  t(i,j,k) = c(i,j,k,qr_idx) / c(i,j,k,Rho_comp);
241  });
242  }
243  IntVect ratio = ba2d_lev.minimalBox().length() / states[iRain]->boxArray().minimalBox().length();
244  amrex::average_down(tmp, *states[iRain], 0, 1, ratio);
245  }
246  }
247  }
248  // No moisture: leave RH/Cloud/Rain slabs at their driver-pre-filled values.
249 
250  // --- Radiation: sw_flux_dn (comp=1) and lw_flux_dn (comp=3) from rad_fluxes ---
251  // When absent, leave slabs at their driver-pre-filled values.
252  if (has_radiation) {
253  if (iSWrad < static_cast<int>(states.size()) && states[iSWrad] != nullptr) {
254  MultiFab tmp(ba2d_lev, dm, 1, 0);
255  tmp.ParallelCopy(*rad_fluxes[lev], 1, 0, 1);
256  IntVect ratio = ba2d_lev.minimalBox().length() / states[iSWrad]->boxArray().minimalBox().length();
257  amrex::average_down(tmp, *states[iSWrad], 0, 1, ratio);
258  }
259  if (iLWrad < static_cast<int>(states.size()) && states[iLWrad] != nullptr) {
260  MultiFab tmp(ba2d_lev, dm, 1, 0);
261  tmp.ParallelCopy(*rad_fluxes[lev], 3, 0, 1);
262  IntVect ratio = ba2d_lev.minimalBox().length() / states[iLWrad]->boxArray().minimalBox().length();
263  amrex::average_down(tmp, *states[iLWrad], 0, 1, ratio);
264  }
265  }
266 }
amrex::Real cloud_fraction(double time)
Definition: ERF_WriteScalarProfiles.cpp:452
@ qi
Definition: ERF_WSM6.H:26
Definition: ERF_ConsoleIO.cpp:12
int qi
Definition: ERF_DataStruct.H:109
Here is the call graph for this function:

◆ ParameterSanityChecks()

void ERF::ParameterSanityChecks ( )
private
2921 {
2923 
2924  // We don't allow use_real_bcs to be true if init_type is not either InitType::WRFInput or InitType::Metgrid
2926  ((solverChoice.init_type == InitType::WRFInput) || (solverChoice.init_type == InitType::Metgrid)) );
2927 
2929 
2930  if (cf_set_width != 0) {
2931  Abort("You must set cf_set_width == 0");
2932  }
2933  if (cf_width < 0 || cf_set_width < 0 || cf_width < cf_set_width) {
2934  Abort("You must set cf_width >= cf_set_width >= 0");
2935  }
2936  if (max_level > 0 && cf_set_width > 0) {
2937  for (int lev = 1; lev <= max_level; lev++) {
2938  if (cf_set_width%ref_ratio[lev-1][0] != 0 ||
2939  cf_set_width%ref_ratio[lev-1][1] != 0 ||
2940  cf_set_width%ref_ratio[lev-1][2] != 0 ) {
2941  Abort("You must set cf_width to be a multiple of ref_ratio");
2942  }
2943  }
2944  }
2945 
2946  // If fixed_mri_dt_ratio is set, it must be even
2947  if (fixed_mri_dt_ratio > 0 && (fixed_mri_dt_ratio%2 != 0) )
2948  {
2949  Abort("If you specify fixed_mri_dt_ratio, it must be even");
2950  }
2951 
2952  for (int lev = 0; lev <= max_level; lev++)
2953  {
2954  // We ignore fixed_fast_dt if not substepping
2955  if (solverChoice.substepping_type[lev] == SubsteppingType::None) {
2956  fixed_fast_dt[lev] = -one;
2957  }
2958 
2959  // If both fixed_dt and fast_dt are specified, their ratio must be an even integer
2960  if (fixed_dt[lev] > zero && fixed_fast_dt[lev] > zero && fixed_mri_dt_ratio <= 0)
2961  {
2962  Real eps = Real(1.e-12);
2963  int ratio = static_cast<int>( ( (one+eps) * fixed_dt[lev] ) / fixed_fast_dt[lev] );
2964  if (fixed_dt[lev] / fixed_fast_dt[lev] != ratio)
2965  {
2966  Abort("Ratio of fixed_dt to fixed_fast_dt must be an even integer");
2967  }
2968  }
2969 
2970  // If all three are specified, they must be consistent
2971  if (fixed_dt[lev] > zero && fixed_fast_dt[lev] > zero && fixed_mri_dt_ratio > 0)
2972  {
2973  if (fixed_dt[lev] / fixed_fast_dt[lev] != fixed_mri_dt_ratio)
2974  {
2975  Abort("Dt is over-specfied");
2976  }
2977  }
2978  } // lev
2979 
2980  if (solverChoice.coupling_type == CouplingType::TwoWay && cf_width > 0) {
2981  Abort("For two-way coupling you must set cf_width = 0");
2982  }
2983 }
Here is the call graph for this function:

◆ PerformDataAssimilation()

void ERF::PerformDataAssimilation ( int  da_iter)

◆ PlotFileName()

std::string ERF::PlotFileName ( int  lev) const
private

◆ PlotFileVarNames()

Vector< std::string > ERF::PlotFileVarNames ( amrex::Vector< std::string >  plot_var_names)
staticprivate
310 {
311  Vector<std::string> names;
312 
313  names.insert(names.end(), plot_var_names.begin(), plot_var_names.end());
314 
315  return names;
316 
317 }

◆ poisson_wall_dist()

void ERF::poisson_wall_dist ( int  lev)

Calculate wall distances using the Poisson equation

The zlo boundary is assumed to correspond to the land surface. If there are no boundary walls, then the other use case is to calculate wall distances for immersed boundaries (embedded or thin body).

See Tucker, P. G. (2003). Differential equation-based wall distance computation for DES and RANS. Journal of Computational Physics, 190(1), 229–Real(248.) https://doi.org/Real(10.1016)/S0021-9991(03)00272-9

23 {
24  BL_PROFILE("ERF::poisson_wall_dist()");
25 
26  bool havewall{false};
27  Orientation zlo(Direction::z, Orientation::low);
28  if ( ( phys_bc_type[zlo] == ERF_BC::surface_layer ) ||
29  ( phys_bc_type[zlo] == ERF_BC::no_slip_wall ) )/*||
30  ((phys_bc_type[zlo] == ERF_BC::slip_wall) && (dom_hi.z > dom_lo.z)) )*/
31  {
32  havewall = true;
33  }
34 
35  auto const& geomdata = geom[lev];
36  auto const& dxinv = geomdata.InvCellSizeArray();
37 
38  auto const& zphys_arr = z_phys_nd[lev]->const_arrays();
39 
40  if (havewall) {
41 #if 1
42  // Bypass wall dist calc in the trivial cases
43 
44  if (solverChoice.mesh_type == MeshType::ConstantDz) {
45  Print() << "Directly calculating direct wall distance for constant dz" << std::endl;
46  const Real* prob_lo = geomdata.ProbLo();
47  const Real* dx = geomdata.CellSize();
48  for (MFIter mfi(*walldist[lev]); mfi.isValid(); ++mfi) {
49  const Box& bx = mfi.validbox();
50  auto dist_arr = walldist[lev]->array(mfi);
51  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
52  dist_arr(i, j, k) = prob_lo[2] + (k + myhalf) * dx[2];
53  });
54  }
55  return;
56  }
57 
58  if (solverChoice.mesh_type == MeshType::StretchedDz) {
59  Print() << "Directly calculating direct wall distance for stretched dz" << std::endl;
60  for (MFIter mfi(*walldist[lev],TileNoZ()); mfi.isValid(); ++mfi) {
61  const Box& bx = mfi.validbox();
62  auto dist_arr = walldist[lev]->array(mfi);
63  const auto zcc_arr = z_phys_cc[lev]->const_array(mfi);
64  const auto znd_arr = z_phys_nd[lev]->const_array(mfi);
65  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
66  dist_arr(i, j, k) = zcc_arr(i, j, k) - znd_arr(i, j, 0);
67  });
68  }
69  return;
70  }
71 #endif
72  }
73  else
74  {
75  Error("No solid boundaries in the computational domain");
76  }
77 
78  Print() << "Calculating Poisson wall distance for general terrain" << std::endl;
79 
80  // Make sure the solver only sees the levels over which we are solving
81  Vector<Geometry> geom_tmp; geom_tmp.push_back(geom[lev]);
82  Vector<BoxArray> ba_tmp; ba_tmp.push_back(walldist[lev]->boxArray());
83  Vector<DistributionMapping> dm_tmp; dm_tmp.push_back(walldist[lev]->DistributionMap());
84 
85  Vector<MultiFab> rhs;
86  Vector<MultiFab> phi;
87 
88  if (solverChoice.terrain_type == TerrainType::EB) {
89  amrex::Error("Wall dist calc not implemented for EB");
90  } else {
91  rhs.resize(1); rhs[0].define(ba_tmp[0], dm_tmp[0], 1, 0);
92  phi.resize(1); phi[0].define(ba_tmp[0], dm_tmp[0], 1, 1);
93  }
94 
95  rhs[0].setVal(-1.0);
96 
97  auto const dom_lo = lbound(geom[lev].Domain());
98  auto const dom_hi = ubound(geom[lev].Domain());
99 
100  // ****************************************************************************
101  // Initialize phi
102  // (It is essential that we do this in order to fill the corners; this is
103  // used if we include blanking.)
104  // ****************************************************************************
105  phi[0].setVal(0.0);
106 
107  // ****************************************************************************
108  // Interior boundaries are marked with phi=0
109  // ****************************************************************************
110 #if 0
111  // Define an overset mask (0 or 1) to set dirichlet nodes on walls
112  // 1 means the node is an unknown. 0 means it's known.
113  iMultiFab mask(ba_tmp[0], dm_tmp[0], 1, 0);
114  Vector<const iMultiFab*> overset_mask = {&mask};
115 
116  mask.setVal(1);
118  Warning("Poisson distance is inaccurate for bodies in open domains that are small compared to the domain size, skipping");
119  return;
120 
121  Gpu::DeviceVector<IntVect> xfacelist, yfacelist, zfacelist;
122 
123  xfacelist.resize(solverChoice.advChoice.zero_xflux.size());
124  yfacelist.resize(solverChoice.advChoice.zero_yflux.size());
125  zfacelist.resize(solverChoice.advChoice.zero_zflux.size());
126 
127  if (xfacelist.size() > 0) {
128  Gpu::copy(amrex::Gpu::hostToDevice,
131  xfacelist.begin());
132  Print() << " masking interior xfaces" << std::endl;
133  }
134  if (yfacelist.size() > 0) {
135  Gpu::copy(amrex::Gpu::hostToDevice,
138  yfacelist.begin());
139  Print() << " masking interior yfaces" << std::endl;
140  }
141  if (zfacelist.size() > 0) {
142  Gpu::copy(amrex::Gpu::hostToDevice,
145  zfacelist.begin());
146  Print() << " masking interior zfaces" << std::endl;
147  }
148 
149  for (MFIter mfi(phi[0]); mfi.isValid(); ++mfi) {
150  const Box& bx = mfi.validbox();
151 
152  auto phi_arr = phi[0].array(mfi);
153  auto mask_arr = mask.array(mfi);
154 
155  if (xfacelist.size() > 0) {
156  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
157  for (int iface=0; iface < xfacelist.size(); ++iface) {
158  if ((i == xfacelist[iface][0]) &&
159  (j == xfacelist[iface][1]) &&
160  (k == xfacelist[iface][2]))
161  {
162  mask_arr(i, j , k ) = 0;
163  mask_arr(i, j , k+1) = 0;
164  mask_arr(i, j+1, k ) = 0;
165  mask_arr(i, j+1, k+1) = 0;
166  }
167  }
168  });
169  }
170 
171  if (yfacelist.size() > 0) {
172  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
173  for (int iface=0; iface < yfacelist.size(); ++iface) {
174  if ((i == yfacelist[iface][0]) &&
175  (j == yfacelist[iface][1]) &&
176  (k == yfacelist[iface][2]))
177  {
178  mask_arr(i , j, k ) = 0;
179  mask_arr(i , j, k+1) = 0;
180  mask_arr(i+1, j, k ) = 0;
181  mask_arr(i+1, j, k+1) = 0;
182  }
183  }
184  });
185  }
186 
187  if (zfacelist.size() > 0) {
188  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
189  for (int iface=0; iface < zfacelist.size(); ++iface) {
190  if ((i == xfacelist[iface][0]) &&
191  (j == xfacelist[iface][1]) &&
192  (k == xfacelist[iface][2]))
193  {
194  mask_arr(i , j , k) = 0;
195  mask_arr(i , j+1, k) = 0;
196  mask_arr(i+1, j , k) = 0;
197  mask_arr(i+1, j+1, k) = 0;
198  }
199  }
200  });
201  }
202  }
203  }
204 #endif
205 
206  // ****************************************************************************
207  // Setup BCs, with solid domain boundaries being dirichlet
208  // ****************************************************************************
209  amrex::Array<amrex::LinOpBCType,AMREX_SPACEDIM> bc3d_lo, bc3d_hi;
210  for (int dir = 0; dir < AMREX_SPACEDIM; ++dir) {
211  if (geom[0].isPeriodic(dir)) {
212  bc3d_lo[dir] = LinOpBCType::Periodic;
213  bc3d_hi[dir] = LinOpBCType::Periodic;
214  } else {
215  bc3d_lo[dir] = LinOpBCType::Neumann;
216  bc3d_hi[dir] = LinOpBCType::Neumann;
217  }
218  }
219  if (havewall) {
220  Print() << " Poisson zlo BC is dirichlet" << std::endl;
221  bc3d_lo[2] = LinOpBCType::Dirichlet;
222  }
223  Print() << " bc lo : " << bc3d_lo << std::endl;
224  Print() << " bc hi : " << bc3d_hi << std::endl;
225 
226  if (!solverChoice.advChoice.have_zero_flux_faces && !havewall) {
227  Error("No solid boundaries in the computational domain");
228  }
229 
230  LPInfo info; // defaults
231 
232 /* Nodal solver cannot have hidden dimensions */
233 #if 0
234  // Allow a hidden direction if the domain is one cell wide
235  if (dom_lo.x == dom_hi.x) {
236  info.setHiddenDirection(0);
237  Print() << " domain is 2D in yz" << std::endl;
238  } else if (dom_lo.y == dom_hi.y) {
239  info.setHiddenDirection(1);
240  Print() << " domain is 2D in xz" << std::endl;
241  } else if (dom_lo.z == dom_hi.z) {
242  info.setHiddenDirection(2);
243  Print() << " domain is 2D in xy" << std::endl;
244  }
245 #endif
246 
247 #if 0
248  Vector<EBFArrayBoxFactory const*> factory_vec;
249  factory_vec.push_back(static_cast<FabFactory<FArrayBox> const*>(&EBFactory(lev));
250 #endif
251 
252  // ****************************************************************************
253  // Setup Poisson problem
254  // (A \alpha - B \nabla \cdot \beta \nabla ) \phi = f
255  //
256  // In physical space:
257  // \nabla \cdot \nabla \phi = -1
258  //
259  // In computational space:
260  // grad(phi) = T^T \nabla \phi
261  // and
262  // \nabla \cdot (h_zeta T (T^T \nabla \phi)) = -h_zeta
263  // where T = inv(J), T^T is the transpose of inv(J)
264  // ****************************************************************************
265  constexpr Real constA = zero;
266  constexpr Real constB = -one;
267 
268  MLABecLaplacian mlabec(geom_tmp, ba_tmp, dm_tmp, info);
269 
270  mlabec.setScalars(constA, constB);
271  mlabec.setACoeffs(0, zero);
272 #if 1
273  // Set beta coefficients at faces
274  Array<MultiFab, AMREX_SPACEDIM> beta;
275 
276  for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
277  BoxArray ba_face = ba_tmp[0];
278  ba_face.surroundingNodes(idim); // Convert to face-centered in direction idim
279  beta[idim].define(ba_face, dm_tmp[0], 1, 0);
280  }
281 
282  auto beta0_arr = beta[0].arrays();
283  auto beta1_arr = beta[1].arrays();
284  auto beta2_arr = beta[2].arrays();
285 
286  // Note: This ignores the off-diagonal components of (h_zeta T T^T), which
287  // is equivalent to assuming that h_xi and h_eta are small.
288 
289  ParallelFor(beta[0], [=] AMREX_GPU_DEVICE(int b, int i, int j, int k) {
290  beta0_arr[b](i, j, k) = Compute_h_zeta_AtIface(i, j, k, dxinv, zphys_arr[b]);;
291  });
292  ParallelFor(beta[1], [=] AMREX_GPU_DEVICE(int b, int i, int j, int k) {
293  beta1_arr[b](i, j, k) = Compute_h_zeta_AtJface(i, j, k, dxinv, zphys_arr[b]);;
294  });
295  ParallelFor(beta[2], [=] AMREX_GPU_DEVICE(int b, int i, int j, int k) {
296  Real inv_h_zeta = one / Compute_h_zeta_AtKface(i, j, k, dxinv, zphys_arr[b]);
297  Real h_xi = Compute_h_xi_AtKface(i, j, k, dxinv, zphys_arr[b]);
298  Real h_eta = Compute_h_eta_AtKface(i, j, k, dxinv, zphys_arr[b]);
299  beta2_arr[b](i, j, k) = inv_h_zeta * (1 + h_xi*h_xi + h_eta*h_eta);
300  });
301 
302  mlabec.setBCoeffs(0, GetArrOfConstPtrs(beta));
303 
304  // Set RHS := -h_zeta
305  auto rhs_arr = rhs[0].arrays();
306  ParallelFor(rhs[0], [=] AMREX_GPU_DEVICE(int b, int i, int j, int k) {
307  rhs_arr[b](i, j, k) = -Compute_h_zeta_AtCellCenter(i, j, k, dxinv, zphys_arr[b]);
308  });
309 #else
310  mlabec.setBCoeffs(0, one);
311 #endif
312 
313  mlabec.setDomainBC(bc3d_lo, bc3d_hi);
314 
315  if (lev > 0) {
316  mlabec.setCoarseFineBC(nullptr, ref_ratio[lev-1], LinOpBCType::Neumann);
317  }
318 
319  // If we have inhomogeneous BCs -- do this after setCoarseFineBC
320  mlabec.setLevelBC(0, nullptr);
321 
322  // ****************************************************************************
323  // Solve Poisson problem with MLMG
324  // ****************************************************************************
325  const Real reltol = solverChoice.poisson_reltol;
326  const Real abstol = solverChoice.poisson_abstol;
327  const int n_corr = solverChoice.ncorr;
328  constexpr int max_iter = 100;
329 
330  MLMG mlmg(mlabec);
331  mlmg.setMaxIter(max_iter);
332  mlmg.setVerbose(mg_verbose);
333  mlmg.setBottomVerbose(0);
334 
335  for (int icorr=0; icorr <= n_corr; ++icorr) {
336  Print()<< "Solving wall distance poisson, icorr=" << icorr << std::endl;
337 
338  mlmg.solve(GetVecOfPtrs(phi),
339  GetVecOfConstPtrs(rhs),
340  reltol, abstol);
341 
342  // ****************************************************************************
343  // Apply BCs: dirichlet (odd) on zlo, neumann (even) / periodic elsewhere
344  // ****************************************************************************
345 
346  // Overwrite with periodic fill outside domain and fine-fine fill inside
347  phi[0].FillBoundary(geom[lev].periodicity());
348 
349  if (!geom[lev].isPeriodic(0)) {
350  for (MFIter mfi(phi[0],true); mfi.isValid(); ++mfi)
351  {
352  Box bx = mfi.tilebox();
353  const Array4<Real>& phi_arr = phi[0].array(mfi);
354  if (bx.smallEnd(0) <= dom_lo.x) {
355  ParallelFor(makeSlab(bx,0,dom_lo.x),
356  [=] AMREX_GPU_DEVICE (int i, int j, int k)
357  {
358  phi_arr(i-1,j,k) = phi_arr(i,j,k); // even BC
359  });
360  } // lo x
361  if (bx.bigEnd(0) >= dom_hi.x) {
362  ParallelFor(makeSlab(bx,0,dom_hi.x),
363  [=] AMREX_GPU_DEVICE (int i, int j, int k)
364  {
365  phi_arr(i+1,j,k) = phi_arr(i,j,k); // even BC
366  });
367  } // hi x
368  } // mfi
369  } // not periodic in x
370 
371  if (!geom[lev].isPeriodic(1)) {
372  for (MFIter mfi(phi[0],true); mfi.isValid(); ++mfi)
373  {
374  Box bx = mfi.tilebox();
375  Box bx2(bx); bx2.grow(0,1);
376  const Array4<Real>& phi_arr = phi[0].array(mfi);
377  if (bx.smallEnd(1) <= dom_lo.y) {
378  ParallelFor(makeSlab(bx2,1,dom_lo.y),
379  [=] AMREX_GPU_DEVICE (int i, int j, int k)
380  {
381  phi_arr(i,j-1,k) = phi_arr(i,j,k); // even BC
382  });
383  } // lo y
384  if (bx.bigEnd(1) >= dom_hi.y) {
385  ParallelFor(makeSlab(bx2,1,dom_hi.y),
386  [=] AMREX_GPU_DEVICE (int i, int j, int k)
387  {
388  phi_arr(i,j+1,k) = phi_arr(i,j,k); // even BC
389  });
390  } // hi y
391 
392  } // mfi
393  } // not periodic in y
394 
395  for (MFIter mfi(phi[0],true); mfi.isValid(); ++mfi)
396  {
397  Box bx = mfi.tilebox();
398  Box bx3(bx); bx3.grow(0,1); bx3.grow(1,1);
399  const Array4<Real>& phi_arr = phi[0].array(mfi);
400  if (bx.smallEnd(2) <= dom_lo.z) {
401  ParallelFor(makeSlab(bx3,2,dom_lo.z),
402  [=] AMREX_GPU_DEVICE (int i, int j, int k)
403  {
404  phi_arr(i,j,k-1) = -phi_arr(i,j,k); // ODD BC
405  });
406  } // lo z
407  if (bx.bigEnd(2) >= dom_hi.z) {
408  ParallelFor(makeSlab(bx3,2,dom_hi.z),
409  [=] AMREX_GPU_DEVICE (int i, int j, int k)
410  {
411  phi_arr(i,j,k+1) = phi_arr(i,j,k); // even BC
412  });
413  } // hi z
414  } // mfi
415 
416  // ****************************************************************************
417  // Compute grad(phi) to get distances
418  // ****************************************************************************
419  auto const& phi_arr = phi[0].const_arrays();
420  //auto rhs_arr = rhs[0].arrays();
421  auto dist_arr = walldist[lev]->arrays();
422 
423  ParallelFor(*walldist[lev], [=] AMREX_GPU_DEVICE(int b, int i, int j, int k) {
424  Real dpdx{0}, dpdy{0}, dpdz{0};
425 
426  dpdx = terrpoisson_flux_x(i, j, k, phi_arr[b], zphys_arr[b], dxinv[0]);
427  dpdy = terrpoisson_flux_y(i, j, k, phi_arr[b], zphys_arr[b], dxinv[1]);
428  if (k == dom_lo.z) {
429  dpdz = terrpoisson_flux_zlo_dir(i, j, k, phi_arr[b], zphys_arr[b], dxinv[0], dxinv[1]);
430  } else {
431  // This returns 0 at the wall, hence the need for the separate calc above
432  dpdz = terrpoisson_flux_z(i, j, k, phi_arr[b], zphys_arr[b], dxinv[0], dxinv[1]);
433  }
434 
435  Real magsqr_dphi = dpdx*dpdx + dpdy*dpdy + dpdz*dpdz;
436  Real mag_dphi = std::sqrt(magsqr_dphi);
437 #if 1
438  // Tucker 2003 Eqn 2
439  dist_arr[b](i, j, k) = -mag_dphi + std::sqrt(magsqr_dphi + 2*phi_arr[b](i, j, k));
440 #else
441  // DEBUG: output phi instead
442  if (i==0 && j==0) AllPrint() << "walldist"<<IntVect(i,j,k) << " = " << dist_arr[b](i,j,k) << std::endl;
443  dist_arr[b](i, j, k) = phi_arr[b](i, j, k);
444 #endif
445  // Update RHS source term to explicitly include cross-terms
446  if (n_corr > 0) {
447  // d/dxi ( h_xi * dphi/dzeta )
448  Real phi_zeta_xlo = fourth * dxinv[2] * ( phi_arr[b](i , j, k+1) - phi_arr[b](i , j, k-1)
449  + phi_arr[b](i-1, j, k+1) - phi_arr[b](i-1, j, k-1) );
450  Real phi_zeta_xhi = fourth * dxinv[2] * ( phi_arr[b](i , j, k+1) - phi_arr[b](i , j, k-1)
451  + phi_arr[b](i+1, j, k+1) - phi_arr[b](i+1, j, k-1) );
452  Real h_xi_xlo = Compute_h_xi_AtIface(i , j, k, dxinv, zphys_arr[b]);
453  Real h_xi_xhi = Compute_h_xi_AtIface(i+1, j, k, dxinv, zphys_arr[b]);
454 
455  // d/deta ( h_eta * dphi/dzeta )
456  Real phi_zeta_ylo = fourth * dxinv[2] * ( phi_arr[b](i, j , k+1) - phi_arr[b](i, j , k-1)
457  + phi_arr[b](i, j-1, k+1) - phi_arr[b](i, j-1, k-1) );
458  Real phi_zeta_yhi = fourth * dxinv[2] * ( phi_arr[b](i, j , k+1) - phi_arr[b](i, j , k-1)
459  + phi_arr[b](i, j+1, k+1) - phi_arr[b](i, j+1, k-1) );
460  Real h_eta_ylo = Compute_h_eta_AtJface(i, j , k, dxinv, zphys_arr[b]);
461  Real h_eta_yhi = Compute_h_eta_AtJface(i, j+1, k, dxinv, zphys_arr[b]);
462 
463  // d/dzeta ( h_xi * dphi/dxi )
464  Real phi_xi_zlo = fourth * dxinv[0] * ( phi_arr[b](i+1, j, k ) - phi_arr[b](i-1, j, k )
465  + phi_arr[b](i+1, j, k-1) - phi_arr[b](i-1, j, k-1) );
466  Real phi_xi_zhi = fourth * dxinv[0] * ( phi_arr[b](i+1, j, k ) - phi_arr[b](i-1, j, k )
467  + phi_arr[b](i+1, j, k+1) - phi_arr[b](i-1, j, k+1) );
468  Real h_xi_zlo = Compute_h_xi_AtKface(i, j, k , dxinv, zphys_arr[b]);
469  Real h_xi_zhi = Compute_h_xi_AtKface(i, j, k+1, dxinv, zphys_arr[b]);
470 
471  // d/dzeta ( h_eta * dphi/deta )
472  Real phi_eta_zlo = fourth * dxinv[1] * ( phi_arr[b](i, j+1, k ) - phi_arr[b](i, j-1, k )
473  + phi_arr[b](i, j+1, k-1) - phi_arr[b](i, j-1, k-1) );
474  Real phi_eta_zhi = fourth * dxinv[1] * ( phi_arr[b](i, j+1, k ) - phi_arr[b](i, j-1, k )
475  + phi_arr[b](i, j+1, k+1) - phi_arr[b](i, j-1, k+1) );
476  Real h_eta_zlo = Compute_h_eta_AtKface(i, j, k , dxinv, zphys_arr[b]);
477  Real h_eta_zhi = Compute_h_eta_AtKface(i, j, k+1, dxinv, zphys_arr[b]);
478 
479  Real detJ = Compute_h_zeta_AtCellCenter(i, j, k, dxinv, zphys_arr[b]);
480 
481  rhs_arr[b](i, j, k) = -detJ
482  + dxinv[0] * ( h_xi_xhi * phi_zeta_xhi - h_xi_xlo * phi_zeta_xlo)
483  + dxinv[1] * ( h_eta_yhi * phi_zeta_yhi - h_eta_ylo * phi_zeta_ylo)
484  + dxinv[2] * ( h_xi_zhi * phi_xi_zhi - h_xi_zlo * phi_xi_zlo
485  + h_eta_zhi * phi_eta_zhi - h_eta_zlo * phi_eta_zlo);
486  }
487  });
488  } // corrector loop
489 }
amrex::Real beta
Definition: ERF_InitCustomPert_DataAssimilation_ISV.H:10
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_h_xi_AtIface(const int &i, const int &j, const int &k, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &cellSizeInv, const amrex::Array4< const amrex::Real > &z_nd)
Definition: ERF_TerrainMetrics.H:117
AMREX_FORCE_INLINE AMREX_GPU_DEVICE amrex::Real Compute_h_zeta_AtCellCenter(const int &i, const int &j, const int &k, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &cellSizeInv, const amrex::Array4< const amrex::Real > &z_nd)
Definition: ERF_TerrainMetrics.H:55
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_h_zeta_AtKface(const int &i, const int &j, const int &k, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &cellSizeInv, const amrex::Array4< const amrex::Real > &z_nd)
Definition: ERF_TerrainMetrics.H:184
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_h_zeta_AtIface(const int &i, const int &j, const int &k, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &cellSizeInv, const amrex::Array4< const amrex::Real > &z_nd)
Definition: ERF_TerrainMetrics.H:104
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_h_xi_AtKface(const int &i, const int &j, const int &k, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &cellSizeInv, const amrex::Array4< const amrex::Real > &z_nd)
Definition: ERF_TerrainMetrics.H:198
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_h_zeta_AtJface(const int &i, const int &j, const int &k, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &cellSizeInv, const amrex::Array4< const amrex::Real > &z_nd)
Definition: ERF_TerrainMetrics.H:144
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_h_eta_AtJface(const int &i, const int &j, const int &k, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &cellSizeInv, const amrex::Array4< const amrex::Real > &z_nd)
Definition: ERF_TerrainMetrics.H:170
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_h_eta_AtKface(const int &i, const int &j, const int &k, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &cellSizeInv, const amrex::Array4< const amrex::Real > &z_nd)
Definition: ERF_TerrainMetrics.H:211
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE T terrpoisson_flux_x(int i, int j, int k, amrex::Array4< T const > const &sol, amrex::Array4< T const > const &zp, T dxinv) noexcept
Definition: ERF_TerrainPoisson_3D_K.H:9
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE T terrpoisson_flux_zlo_dir(int i, int j, int k, amrex::Array4< T const > const &sol, amrex::Array4< T const > const &zp, T dxinv, T dyinv) noexcept
Definition: ERF_TerrainPoisson_3D_K.H:163
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE T terrpoisson_flux_z(int i, int j, int k, amrex::Array4< T const > const &sol, amrex::Array4< T const > const &zp, T dxinv, T dyinv) noexcept
Definition: ERF_TerrainPoisson_3D_K.H:84
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE T terrpoisson_flux_y(int i, int j, int k, amrex::Array4< T const > const &sol, amrex::Array4< T const > const &zp, T dyinv) noexcept
Definition: ERF_TerrainPoisson_3D_K.H:47
static int mg_verbose
Definition: ERF.H:1249
amrex::Real poisson_reltol
Definition: ERF_DataStruct.H:1170
int ncorr
Definition: ERF_DataStruct.H:1164
amrex::Real poisson_abstol
Definition: ERF_DataStruct.H:1169
Here is the call graph for this function:

◆ post_timestep()

void ERF::post_timestep ( int  nstep,
double  time,
amrex::Real  dt_lev 
)
775 {
776  BL_PROFILE("ERF::post_timestep()");
777 
778 #ifdef ERF_USE_PARTICLES
779  particleData.Redistribute(z_phys_nd);
780 #endif
781 
782  if (solverChoice.coupling_type == CouplingType::TwoWay)
783  {
784  int ncomp = vars_new[0][Vars::cons].nComp();
785  for (int lev = finest_level-1; lev >= 0; lev--)
786  {
787  // The quantity that is conserved is not (rho S), but rather (rho S / m^2) where
788  // m is the map scale factor at cell centers
789  // Here we pre-divide (rho S) by m^2 before refluxing
790  for (MFIter mfi(vars_new[lev][Vars::cons], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
791  const Box& bx = mfi.tilebox();
792  const Array4< Real> cons_arr = vars_new[lev][Vars::cons].array(mfi);
793  const Array4<const Real> mfx_arr = mapfac[lev][MapFacType::m_x]->const_array(mfi);
794  const Array4<const Real> mfy_arr = mapfac[lev][MapFacType::m_y]->const_array(mfi);
795  if (SolverChoice::mesh_type == MeshType::ConstantDz) {
796  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
797  {
798  cons_arr(i,j,k,n) /= (mfx_arr(i,j,0)*mfy_arr(i,j,0));
799  });
800  } else {
801  const Array4<const Real> detJ_arr = detJ_cc[lev]->const_array(mfi);
802  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
803  {
804  cons_arr(i,j,k,n) *= detJ_arr(i,j,k) / (mfx_arr(i,j,0)*mfy_arr(i,j,0));
805  });
806  }
807  } // mfi
808 
809  // This call refluxes all "slow" cell-centered variables
810  // (i.e. not density or (rho theta) or velocities) from the lev/lev+1 interface onto lev
811  getAdvFluxReg(lev+1)->Reflux(vars_new[lev][Vars::cons], 2, 2, ncomp-2);
812 
813  // Here we multiply (rho S) by m^2 after refluxing
814  for (MFIter mfi(vars_new[lev][Vars::cons], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
815  const Box& bx = mfi.tilebox();
816  const Array4< Real> cons_arr = vars_new[lev][Vars::cons].array(mfi);
817  const Array4<const Real> mfx_arr = mapfac[lev][MapFacType::m_x]->const_array(mfi);
818  const Array4<const Real> mfy_arr = mapfac[lev][MapFacType::m_y]->const_array(mfi);
819  if (SolverChoice::mesh_type == MeshType::ConstantDz) {
820  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
821  {
822  cons_arr(i,j,k,n) *= (mfx_arr(i,j,0)*mfy_arr(i,j,0));
823  });
824  } else {
825  const Array4<const Real> detJ_arr = detJ_cc[lev]->const_array(mfi);
826  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
827  {
828  cons_arr(i,j,k,n) *= (mfx_arr(i,j,0)*mfy_arr(i,j,0)) / detJ_arr(i,j,k);
829  });
830  }
831  } // mfi
832 
833  // We need to do this before anything else because refluxing changes the
834  // values of coarse cells underneath fine grids with the assumption they'll
835  // be over-written by averaging down
836  int src_comp;
837  if (solverChoice.anelastic[lev]) {
838  src_comp = 1;
839  } else {
840  src_comp = 0;
841  }
842  int num_comp = ncomp - src_comp;
843  AverageDownTo(lev,src_comp,num_comp);
844  }
845  }
846 
847  if (is_it_time_for_action(nstep, time, dt_lev0, sum_interval, sum_per)) {
850  sum_energy_quantities(time);
851  }
852 
854  if (is_it_time_for_action(nstep, time, dt_lev0, pert_interval, -one)) {
855  turbPert.debug(time);
856  }
857  }
858 
859  if (profile_int > 0 && (nstep+1) % profile_int == 0) {
860  if (destag_profiles) {
861  // all variables cell-centered
862  write_1D_profiles(time);
863  } else {
864  // some variables staggered
866  }
867  }
868 
869  if (solverChoice.rad_type != RadiationType::None)
870  {
871  if ( rad_datalog_int > 0 &&
872  (((nstep+1) % rad_datalog_int == 0) || (nstep==0)) ) {
873  if (rad[0]->hasDatalog()) {
874  rad[0]->WriteDataLog(time+start_time);
875  }
876  }
877  }
878 
879  if (output_1d_column) {
880 #ifdef ERF_USE_NETCDF
881  if (is_it_time_for_action(nstep, time, dt_lev0, column_interval, column_per))
882  {
883  int lev_column = 0;
884  for (int lev = finest_level; lev >= 0; lev--)
885  {
886  Real dx_lev = geom[lev].CellSize(0);
887  Real dy_lev = geom[lev].CellSize(1);
888  int i_lev = static_cast<int>(std::floor(column_loc_x / dx_lev));
889  int j_lev = static_cast<int>(std::floor(column_loc_y / dy_lev));
890  if (grids[lev].contains(IntVect(i_lev,j_lev,0))) lev_column = lev;
891  }
892  writeToNCColumnFile(lev_column, column_file_name, column_loc_x, column_loc_y, time);
893  }
894 #else
895  Abort("To output 1D column files ERF must be compiled with NetCDF");
896 #endif
897  }
898 
900  {
903  {
904  bool is_moist = (micro->Get_Qstate_Moist_Size() > 0);
905  m_w2d->write_planes(istep[0], time+start_time, vars_new, is_moist);
906  }
907  }
908 
909  // Write plane/line sampler data
911  line_sampler->get_sample_data(geom, vars_new);
912  line_sampler->write_sample_data(t_new, istep, ref_ratio, geom);
913  }
915  plane_sampler->get_sample_data(geom, vars_new);
916  plane_sampler->write_sample_data(t_new, istep, ref_ratio, geom);
917  }
918 
919  // Moving terrain
920  if ( solverChoice.terrain_type == TerrainType::MovingFittedMesh )
921  {
922  for (int lev = finest_level; lev >= 0; lev--)
923  {
924  // Copy z_phs_nd and detJ_cc at end of timestep
925  MultiFab::Copy(*z_phys_nd[lev], *z_phys_nd_new[lev], 0, 0, 1, z_phys_nd[lev]->nGrowVect());
926  MultiFab::Copy( *detJ_cc[lev], *detJ_cc_new[lev], 0, 0, 1, detJ_cc[lev]->nGrowVect());
927  MultiFab::Copy(base_state[lev],base_state_new[lev],0,0,BaseState::num_comps,base_state[lev].nGrowVect());
928 
929  make_zcc(geom[lev],*z_phys_nd[lev],*z_phys_cc[lev]);
930  }
931  }
932 
933  if ( solverChoice.io_hurricane_eye_tracker and (nstep == 0 or (nstep+1)%m_plot3d_int_1 == 0) )
934  {
935  int levc=finest_level;
936 
937  HurricaneEyeTracker(geom[levc],
938  vars_new[levc],
946 
947  MultiFab& U_new = vars_new[levc][Vars::xvel];
948  MultiFab& V_new = vars_new[levc][Vars::yvel];
949  MultiFab& W_new = vars_new[levc][Vars::zvel];
950 
951  MultiFab mf_cc_vel(grids[levc], dmap[levc], AMREX_SPACEDIM, IntVect(0,0,0));
952  average_face_to_cellcenter(mf_cc_vel,0,{AMREX_D_DECL(&U_new,&V_new,&W_new)},0);
953 
954  HurricaneMaxVelTracker(geom[levc],
955  mf_cc_vel,
956  t_new[0],
959 
961  geom[levc],
962  vars_new[levc][Vars::cons],
963  t_new[0],
966 
967  std::string filename_tracker = MakeVTKFilename_TrackerCircle(nstep);
968  std::string filename_xy = MakeVTKFilename_EyeTracker_xy(nstep);
969  std::string filename_latlon = MakeFilename_EyeTracker_latlon(nstep);
970  std::string filename_maxvel = MakeFilename_EyeTracker_maxvel(nstep);
971  std::string filename_minpressure = MakeFilename_EyeTracker_minpressure(nstep);
972 
973  if (ParallelDescriptor::IOProcessor()) {
974  WriteVTKPolyline(filename_tracker, hurricane_tracker_circle);
976  WriteLinePlot(filename_latlon, hurricane_eye_track_latlon);
977  WriteLinePlot(filename_maxvel, hurricane_maxvel_vs_time);
978  WriteLinePlot(filename_minpressure, hurricane_minpressure_vs_time);
979  }
980  }
981 } // post_timestep
AMREX_FORCE_INLINE void HurricaneMaxVelTracker(const amrex::Geometry &geom, const amrex::MultiFab &mf_cc_vel, const amrex::Real &time, const amrex::Vector< std::array< amrex::Real, 2 >> &hurricane_eye_track_xy, amrex::Vector< std::array< amrex::Real, 2 >> &hurricane_maxvel_vs_time)
Definition: ERF_HurricaneDiagnostics.H:291
AMREX_FORCE_INLINE void HurricaneEyeTracker(const amrex::Geometry &geom, const amrex::Vector< amrex::MultiFab > &S_data, MoistureType moisture_type, const amrex::Vector< amrex::MultiFab > *forecast_state_at_lev, const amrex::Real &hurricane_eye_latitude, const amrex::Real &hurricane_eye_longitude, amrex::Vector< std::array< amrex::Real, 2 >> &hurricane_eye_track_xy, amrex::Vector< std::array< amrex::Real, 2 >> &hurricane_eye_track_latlon, amrex::Vector< std::array< amrex::Real, 2 >> &hurricane_tracker_circle)
Definition: ERF_HurricaneDiagnostics.H:264
AMREX_FORCE_INLINE void HurricaneMinPressureTracker(MoistureType moisture_type, const amrex::Geometry &geom, const amrex::MultiFab &mf_cons_var, const amrex::Real &time, const amrex::Vector< std::array< amrex::Real, 2 >> &hurricane_eye_track_xy, amrex::Vector< std::array< amrex::Real, 2 >> &hurricane_minpressure_vs_time)
Definition: ERF_HurricaneDiagnostics.H:349
void make_zcc(const Geometry &geom, MultiFab &z_phys_nd, MultiFab &z_phys_cc)
Definition: ERF_TerrainMetrics.cpp:628
std::string MakeFilename_EyeTracker_maxvel(int nstep)
Definition: ERF_TrackerOutput.cpp:66
static amrex::Real column_loc_y
Definition: ERF.H:1314
amrex::Vector< std::array< amrex::Real, 2 > > hurricane_tracker_circle
Definition: ERF.H:165
amrex::Vector< std::array< amrex::Real, 2 > > hurricane_maxvel_vs_time
Definition: ERF.H:163
static std::string column_file_name
Definition: ERF.H:1315
AMREX_FORCE_INLINE amrex::YAFluxRegister * getAdvFluxReg(int lev)
Definition: ERF.H:1455
amrex::Vector< std::array< amrex::Real, 2 > > hurricane_minpressure_vs_time
Definition: ERF.H:164
static amrex::Real bndry_output_planes_per
Definition: ERF.H:1320
static amrex::Real column_per
Definition: ERF.H:1312
static amrex::Real column_loc_x
Definition: ERF.H:1313
amrex::Vector< std::array< amrex::Real, 2 > > hurricane_eye_track_latlon
Definition: ERF.H:162
std::string MakeVTKFilename_TrackerCircle(int nstep)
Definition: ERF_TrackerOutput.cpp:24
std::string MakeVTKFilename_EyeTracker_xy(int nstep)
Definition: ERF_TrackerOutput.cpp:38
static int bndry_output_planes_interval
Definition: ERF.H:1319
std::string MakeFilename_EyeTracker_minpressure(int nstep)
Definition: ERF_TrackerOutput.cpp:80
void WriteLinePlot(const std::string &filename, amrex::Vector< std::array< amrex::Real, 2 >> &points_xy)
Definition: ERF_Write1DProfiles.cpp:574
static int output_1d_column
Definition: ERF.H:1310
void WriteVTKPolyline(const std::string &filename, amrex::Vector< std::array< amrex::Real, 2 >> &points_xy)
Definition: ERF_TrackerOutput.cpp:94
std::string MakeFilename_EyeTracker_latlon(int nstep)
Definition: ERF_TrackerOutput.cpp:52
static int column_interval
Definition: ERF.H:1311
amrex::Real hurricane_eye_latitude
Definition: ERF_DataStruct.H:1339
amrex::Real hurricane_eye_longitude
Definition: ERF_DataStruct.H:1339
bool io_hurricane_eye_tracker
Definition: ERF_DataStruct.H:1338

Referenced by EvolveOneStep().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ post_update()

void ERF::post_update ( amrex::MultiFab &  state_mf,
amrex::Real  time,
const amrex::Geometry &  geom 
)
private

◆ print_banner()

void ERF::print_banner ( MPI_Comm  comm,
std::ostream &  out 
)
static
65  : " << msg << std::endl;
66 }
67 
68 void ERF::print_banner (MPI_Comm comm, std::ostream& out)
69 {
70 #ifdef AMREX_USE_MPI
71  int irank = 0;
72  int num_ranks = 1;
73  MPI_Comm_size(comm, &num_ranks);
74  MPI_Comm_rank(comm, &irank);
75 
76  // Only root process does the printing
77  if (irank != 0) return;
78 #else
79  amrex::ignore_unused(comm);
80 #endif
81 
82  auto etime = std::chrono::system_clock::now();
83  auto etimet = std::chrono::system_clock::to_time_t(etime);
84 #ifndef _WIN32
85  char time_buf[64];
86  ctime_r(&etimet, time_buf);
87  const std::string tstamp(time_buf);
88 #else
89  char* time_buf = new char[64];
90  ctime_s(time_buf, 64, &etimet);
91  const std::string tstamp(time_buf);
92 #endif
93 
94  const char* githash1 = amrex::buildInfoGetGitHash(1);
95  const char* githash2 = amrex::buildInfoGetGitHash(2);
96 
97  // clang-format off
98  out << dbl_line
99  << " ERF (https://github.com/erf-model/ERF)"
100  << std::endl << std::endl
101  << " ERF Git SHA :: " << githash1 << std::endl
102  << " AMReX Git SHA :: " << githash2 << std::endl
103  << " AMReX version :: " << amrex::Version() << std::endl << std::endl
104  << " Exec. time :: " << tstamp
105  << " Build time :: " << amrex::buildInfoGetBuildDate() << std::endl
106  << " C++ compiler :: " << amrex::buildInfoGetComp()
107  << " " << amrex::buildInfoGetCompVersion() << std::endl << std::endl
108  << " MPI :: "
109 #ifdef AMREX_USE_MPI
110  << "ON (Num. ranks = " << num_ranks << ")" << std::endl
111 #else
112  << "OFF " << std::endl
113 #endif
114  << " GPU :: "
115 #ifdef AMREX_USE_GPU
116  << "ON "
117 #if defined(AMREX_USE_CUDA)
118  << "(Backend: CUDA)"
119 #elif defined(AMREX_USE_HIP)
120  << "(Backend: HIP)"
121 #elif defined(AMREX_USE_SYCL)
122  << "(Backend: SYCL)"
123 #endif
124  << std::endl
125 #else
126  << "OFF" << std::endl
127 #endif
128  << " OpenMP :: "
129 #ifdef AMREX_USE_OMP
130  << "ON (Num. threads = " << omp_get_max_threads() << ")" << std::endl
131 #else
132  << "OFF" << std::endl
133 #endif
134  << std::endl;
135 
ERF()
Definition: ERF.cpp:142
const char * buildInfoGetBuildDate()
const char * buildInfoGetComp()
const char * buildInfoGetCompVersion()

Referenced by main().

Here is the caller graph for this function:

◆ print_error()

void ERF::print_error ( MPI_Comm  comm,
const std::string &  msg 
)
static
43  :
44  input_file : Input file with simulation settings
45 
46 Optional:
47  param=value : Overrides for parameters during runtime
48 )doc" << std::endl;
49 }
50 
51 void ERF::print_error (MPI_Comm comm, const std::string& msg)
52 {
53 #ifdef AMREX_USE_MPI
54  int irank = 0;
55  int num_ranks = 1;
56  MPI_Comm_size(comm, &num_ranks);
57  MPI_Comm_rank(comm, &irank);
58 

Referenced by main().

Here is the caller graph for this function:

◆ print_summary()

static void ERF::print_summary ( std::ostream &  )
static

◆ print_tpls()

void ERF::print_tpls ( std::ostream &  out)
static
140  ://github.com/erf-model/ERF/blob/development/LICENSE for details. "
141  << dash_line << std::endl;
142  // clang-format on
143 }
144 
145 void ERF::print_tpls (std::ostream& out)
146 {
147  amrex::Vector<std::string> tpls;
148 
149 #ifdef ERF_USE_NETCDF
150  tpls.push_back(std::string("NetCDF ") + NC_VERSION);
151 #endif
152 #ifdef AMREX_USE_SUNDIALS
153  tpls.push_back(std::string("SUNDIALS ") + SUNDIALS_VERSION);
154 #endif
155 
156  if (!tpls.empty()) {
157  out << " Enabled third-party libraries: ";
158  for (const auto& val : tpls) {
static void print_tpls(std::ostream &)
Definition: ERF_ConsoleIO.cpp:137

◆ print_usage()

void ERF::print_usage ( MPI_Comm  comm,
std::ostream &  out 
)
static
27 {
28 #ifdef AMREX_USE_MPI
29  int irank = 0;
30  int num_ranks = 1;
31  MPI_Comm_size(comm, &num_ranks);
32  MPI_Comm_rank(comm, &irank);
33 
34  // Only root process does the printing
35  if (irank != 0) return;
36 #else
37  amrex::ignore_unused(comm);
38 #endif
39 
40  out << R"doc(Usage:
41  ERF3d.*.ex <input_file> [param=value] [param=value] ...

Referenced by main().

Here is the caller graph for this function:

◆ project_initial_velocity()

void ERF::project_initial_velocity ( int  lev,
amrex::Real  time,
amrex::Real  dt 
)

Project the single-level velocity field to enforce the anelastic constraint Note that the level may or may not be level zero

32 {
33  BL_PROFILE("ERF::project_initial_velocity()");
34  // Impose FillBoundary on density since we use it in the conversion of velocity to momentum
35  vars_new[lev][Vars::cons].FillBoundary(geom[lev].periodicity());
36 
37  const MultiFab* c_vfrac = nullptr;
38  if (solverChoice.terrain_type == TerrainType::EB) {
39  c_vfrac = &((get_eb(lev).get_const_factory())->getVolFrac());
40  }
41 
42  VelocityToMomentum(vars_new[lev][Vars::xvel], IntVect{0},
43  vars_new[lev][Vars::yvel], IntVect{0},
44  vars_new[lev][Vars::zvel], IntVect{0},
45  vars_new[lev][Vars::cons],
46  rU_new[lev], rV_new[lev], rW_new[lev],
47  Geom(lev).Domain(), domain_bcs_type, c_vfrac);
48 
49  Vector<MultiFab> tmp_mom;
50 
51  tmp_mom.push_back(MultiFab(vars_new[lev][Vars::cons],make_alias,0,1));
52  tmp_mom.push_back(MultiFab(rU_new[lev],make_alias,0,1));
53  tmp_mom.push_back(MultiFab(rV_new[lev],make_alias,0,1));
54  tmp_mom.push_back(MultiFab(rW_new[lev],make_alias,0,1));
55 
56  // If at lev > 0 we must first fill the velocities at the c/f interface -- this must
57  // be done *after* the projection at lev-1
58  if (lev > 0) {
59  int levc = lev-1;
60 
61  const MultiFab* c_vfrac_crse = nullptr;
62  if (solverChoice.terrain_type == TerrainType::EB) {
63  c_vfrac_crse = &((get_eb(levc).get_const_factory())->getVolFrac());
64  }
65 
66  MultiFab& S_new_crse = vars_new[levc][Vars::cons];
67  MultiFab& U_new_crse = vars_new[levc][Vars::xvel];
68  MultiFab& V_new_crse = vars_new[levc][Vars::yvel];
69  MultiFab& W_new_crse = vars_new[levc][Vars::zvel];
70 
71  VelocityToMomentum(U_new_crse, IntVect{0}, V_new_crse, IntVect{0}, W_new_crse, IntVect{0}, S_new_crse,
72  rU_new[levc], rV_new[levc], rW_new[levc],
73  Geom(levc).Domain(), domain_bcs_type, c_vfrac_crse);
74 
75  rU_new[levc].FillBoundary(geom[levc].periodicity());
76  FPr_u[levc].RegisterCoarseData({&rU_new[levc], &rU_new[levc]}, {time, time+l_dt});
77 
78  rV_new[levc].FillBoundary(geom[levc].periodicity());
79  FPr_v[levc].RegisterCoarseData({&rV_new[levc], &rV_new[levc]}, {time, time+l_dt});
80 
81  rW_new[levc].FillBoundary(geom[levc].periodicity());
82  FPr_w[levc].RegisterCoarseData({&rW_new[levc], &rW_new[levc]}, {time, time+l_dt});
83  }
84 
85  // Use the same time that was registered in the FillPatcher above so that the
86  // FillSet assertion (time >= crse_times[0] && time <= crse_times[1]) is satisfied
87  // when called at non-zero simulation time (restart or mid-run regrid).
88  project_momenta(lev, time, l_dt, tmp_mom);
89 
91  vars_new[lev][Vars::yvel],
92  vars_new[lev][Vars::zvel],
93  vars_new[lev][Vars::cons],
94  rU_new[lev], rV_new[lev], rW_new[lev],
95  Geom(lev).Domain(), domain_bcs_type, c_vfrac);
96  }
void project_momenta(int lev, amrex::Real l_time, amrex::Real l_dt, amrex::Vector< amrex::MultiFab > &vars)
Definition: ERF_PoissonSolve.cpp:102
Here is the call graph for this function:

◆ project_momenta()

void ERF::project_momenta ( int  lev,
amrex::Real  l_time,
amrex::Real  l_dt,
amrex::Vector< amrex::MultiFab > &  vars 
)

Project the single-level momenta to enforce the anelastic constraint Note that the level may or may not be level zero

103 {
104  BL_PROFILE("ERF::project_momenta()");
105  //
106  // If at lev > 0 we must first fill the momenta at the c/f interface with interpolated coarse values
107  //
108  if (lev > 0) {
109  PhysBCFunctNoOp null_bc;
110  FPr_u[lev-1].FillSet(mom_mf[IntVars::xmom], l_time, null_bc, domain_bcs_type);
111  FPr_v[lev-1].FillSet(mom_mf[IntVars::ymom], l_time, null_bc, domain_bcs_type);
112  FPr_w[lev-1].FillSet(mom_mf[IntVars::zmom], l_time, null_bc, domain_bcs_type);
113  }
114 
115  // Make sure the solver only sees the levels over which we are solving
116  Vector<BoxArray> ba_tmp; ba_tmp.push_back(mom_mf[Vars::cons].boxArray());
117  Vector<DistributionMapping> dm_tmp; dm_tmp.push_back(mom_mf[Vars::cons].DistributionMap());
118  Vector<Geometry> geom_tmp; geom_tmp.push_back(geom[lev]);
119 
120  Box domain = geom[lev].Domain();
121 
122  MultiFab r_hse(base_state[lev], make_alias, BaseState::r0_comp, 1);
123 
124  Vector<MultiFab> rhs;
125  Vector<MultiFab> phi;
126 
127  if (solverChoice.terrain_type == TerrainType::EB)
128  {
129  rhs.resize(1); rhs[0].define(ba_tmp[0], dm_tmp[0], 1, 0, MFInfo(), EBFactory(lev));
130  phi.resize(1); phi[0].define(ba_tmp[0], dm_tmp[0], 1, 1, MFInfo(), EBFactory(lev));
131  } else {
132  rhs.resize(1); rhs[0].define(ba_tmp[0], dm_tmp[0], 1, 0);
133  phi.resize(1); phi[0].define(ba_tmp[0], dm_tmp[0], 1, 1);
134  }
135 
136  MultiFab rhs_lev(rhs[0], make_alias, 0, 1);
137  MultiFab phi_lev(phi[0], make_alias, 0, 1);
138 
139  auto dx = geom[lev].CellSizeArray();
140  auto dxInv = geom[lev].InvCellSizeArray();
141 
142  // Inflow on an x-face -- note only the normal velocity is used in the projection
143  if (domain_bc_type[0] == "Inflow" || domain_bc_type[3] == "Inflow") {
145  IntVect{1,0,0},t_new[lev],BCVars::xvel_bc,false);
146  }
147 
148  // Inflow on a y-face -- note only the normal velocity is used in the projection
149  if (domain_bc_type[1] == "Inflow" || domain_bc_type[4] == "Inflow") {
151  IntVect{0,1,0},t_new[lev],BCVars::yvel_bc,false);
152  }
153 
154  if (domain_bc_type[0] == "Inflow" || domain_bc_type[3] == "Inflow" ||
155  domain_bc_type[1] == "Inflow" || domain_bc_type[4] == "Inflow") {
156 
157  const MultiFab* c_vfrac = nullptr;
158  if (solverChoice.terrain_type == TerrainType::EB) {
159  c_vfrac = &((get_eb(lev).get_const_factory())->getVolFrac());
160  }
161 
162  VelocityToMomentum(vars_new[lev][Vars::xvel], IntVect{0},
163  vars_new[lev][Vars::yvel], IntVect{0},
164  vars_new[lev][Vars::zvel], IntVect{0},
165  vars_new[lev][Vars::cons],
166  mom_mf[IntVars::xmom],
167  mom_mf[IntVars::ymom],
168  mom_mf[IntVars::zmom],
169  Geom(lev).Domain(),
170  domain_bcs_type, c_vfrac);
171  }
172 
173  // If !fixed_density, we must convert (rho u) which came in
174  // to (rho0 u) which is what we will project
175  if (!solverChoice.fixed_density[lev]) {
176  ConvertForProjection(mom_mf[Vars::cons], r_hse,
177  mom_mf[IntVars::xmom],
178  mom_mf[IntVars::ymom],
179  mom_mf[IntVars::zmom],
180  Geom(lev).Domain(),
182  }
183 
184  //
185  // ****************************************************************************
186  // Now convert the rho0w MultiFab to hold Omega rather than rhow
187  // ****************************************************************************
188  //
189  if (solverChoice.mesh_type == MeshType::VariableDz)
190  {
191  for ( MFIter mfi(rhs_lev,TilingIfNotGPU()); mfi.isValid(); ++mfi)
192  {
193  const Array4<Real const>& rho0u_arr = mom_mf[IntVars::xmom].const_array(mfi);
194  const Array4<Real const>& rho0v_arr = mom_mf[IntVars::ymom].const_array(mfi);
195  const Array4<Real >& rho0w_arr = mom_mf[IntVars::zmom].array(mfi);
196 
197  const Array4<Real const>& z_nd = z_phys_nd[lev]->const_array(mfi);
198  const Array4<Real const>& mf_u = mapfac[lev][MapFacType::u_x]->const_array(mfi);
199  const Array4<Real const>& mf_v = mapfac[lev][MapFacType::v_y]->const_array(mfi);
200 
201  //
202  // Define Omega from (rho0 W) but store it in the same array
203  //
204  Box tbz = mfi.nodaltilebox(2);
205  ParallelFor(tbz, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept {
206  if (k == 0) {
207  rho0w_arr(i,j,k) = zero;
208  } else {
209  Real rho0w = rho0w_arr(i,j,k);
210  rho0w_arr(i,j,k) = OmegaFromW(i,j,k,rho0w,
211  rho0u_arr,rho0v_arr,
212  mf_u,mf_v,z_nd,dxInv);
213  }
214  });
215  } // mfi
216  }
217 
218  // ****************************************************************************
219  // Allocate fluxes
220  // ****************************************************************************
221  Vector<Array<MultiFab,AMREX_SPACEDIM> > fluxes;
222  fluxes.resize(1);
223  for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
224  if (solverChoice.terrain_type == TerrainType::EB) {
225  fluxes[0][idim].define(convert(ba_tmp[0], IntVect::TheDimensionVector(idim)), dm_tmp[0], 1, 0, MFInfo(), EBFactory(lev));
226  } else {
227  fluxes[0][idim].define(convert(ba_tmp[0], IntVect::TheDimensionVector(idim)), dm_tmp[0], 1, 0);
228  }
229  }
230 
231  // ****************************************************************************
232  // Initialize phi to 0
233  // (It is essential that we do this in order to fill the corners; these are never
234  // used but the Saxpy requires the values to be initialized.)
235  // ****************************************************************************
236  phi_lev.setVal(0.0);
237 
238  // ****************************************************************************
239  // Break into subdomains
240  // ****************************************************************************
241 
242  std::map<int,int> index_map;
243 
244  BoxArray ba(grids[lev]);
245 
246  Vector<MultiFab> rhs_sub; rhs_sub.resize(1);
247  Vector<MultiFab> phi_sub; phi_sub.resize(1);
248  Vector<Array<MultiFab,AMREX_SPACEDIM>> fluxes_sub; fluxes_sub.resize(1);
249 
250  MultiFab ax_sub, ay_sub, az_sub, dJ_sub, znd_sub;
251  MultiFab mfmx_sub, mfmy_sub;
252 
253  Array<MultiFab,AMREX_SPACEDIM> rho0_u_sub;
254  Array<MultiFab const*, AMREX_SPACEDIM> rho0_u_const;
255 
256  // If we are going to solve with MLMG then we do not need to break this into subdomains
257  bool will_solve_with_mlmg = false;
258  if (solverChoice.mesh_type == MeshType::ConstantDz) {
259  will_solve_with_mlmg = true;
260 #ifdef ERF_USE_FFT
261  if (use_fft) {
262  bool all_boxes_ok = true;
263  for (int isub = 0; isub < subdomains[lev].size(); ++isub) {
264  Box my_region(subdomains[lev][isub].minimalBox());
265  bool boxes_make_rectangle = (my_region.numPts() == subdomains[lev][isub].numPts());
266  if (!boxes_make_rectangle) {
267  all_boxes_ok = false;
268  }
269  } // isub
270  if (all_boxes_ok) {
271  will_solve_with_mlmg = false;
272  }
273  } // use_fft
274 #else
275  if (use_fft) {
276  amrex::Warning("You set use_fft=true but didn't build with USE_FFT = TRUE; defaulting to MLMG");
277  }
278 #endif
279  } // No terrain or grid stretching
280 
281  for (int isub = 0; isub < subdomains[lev].size(); ++isub)
282  {
283  BoxList bl_sub;
284  Vector<int> dm_sub;
285 
286  for (int j = 0; j < ba.size(); j++)
287  {
288  if (subdomains[lev][isub].intersects(ba[j]))
289  {
290  //
291  // Note that bl_sub.size() is effectively a counter which is
292  // incremented above
293  //
294  // if (ParallelDescriptor::MyProc() == j) {
295  // }
296  index_map[bl_sub.size()] = j;
297 
298  bl_sub.push_back(grids[lev][j]);
299  dm_sub.push_back(dmap[lev][j]);
300  } // intersects
301  } // loop over ba (j)
302 
303  BoxArray ba_sub(bl_sub);
304 
305  BoxList bl2d_sub = ba_sub.boxList();
306  for (auto& b : bl2d_sub) {
307  b.setRange(2,0);
308  }
309  BoxArray ba2d_sub(std::move(bl2d_sub));
310 
311  // Define MultiFabs that hold only the data in this particular subdomain
312  if (solverChoice.terrain_type == TerrainType::EB) {
313  if (ba_sub != ba) {
314  amrex::Print() << "EB Solves with multiple regions is not yet supported" << std::endl;
315  }
316  rhs_sub[0].define(ba_sub, DistributionMapping(dm_sub), 1, rhs_lev.nGrowVect(), MFInfo{}.SetAlloc(false), EBFactory(lev));
317  phi_sub[0].define(ba_sub, DistributionMapping(dm_sub), 1, phi_lev.nGrowVect(), MFInfo{}.SetAlloc(false), EBFactory(lev));
318 
319  mfmx_sub.define(ba2d_sub, DistributionMapping(dm_sub), 1, mapfac[lev][MapFacType::m_x]->nGrowVect(), MFInfo{}.SetAlloc(false), EBFactory(lev));
320  mfmy_sub.define(ba2d_sub, DistributionMapping(dm_sub), 1, mapfac[lev][MapFacType::m_y]->nGrowVect(), MFInfo{}.SetAlloc(false), EBFactory(lev));
321  dJ_sub.define(ba_sub, DistributionMapping(dm_sub), 1, detJ_cc[lev]->nGrowVect(), MFInfo{}.SetAlloc(false), EBFactory(lev));
322 
323  for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
324  fluxes_sub[0][idim].define(convert(ba_sub, IntVect::TheDimensionVector(idim)), DistributionMapping(dm_sub), 1,
325  IntVect::TheZeroVector(), MFInfo{}.SetAlloc(false), EBFactory(lev));
326  }
327  rho0_u_sub[0].define(convert(ba_sub, IntVect::TheDimensionVector(0)), DistributionMapping(dm_sub), 1,
328  mom_mf[IntVars::xmom].nGrowVect(), MFInfo{}.SetAlloc(false), EBFactory(lev));
329  rho0_u_sub[1].define(convert(ba_sub, IntVect::TheDimensionVector(1)), DistributionMapping(dm_sub), 1,
330  mom_mf[IntVars::ymom].nGrowVect(), MFInfo{}.SetAlloc(false), EBFactory(lev));
331  rho0_u_sub[2].define(convert(ba_sub, IntVect::TheDimensionVector(2)), DistributionMapping(dm_sub), 1,
332  mom_mf[IntVars::zmom].nGrowVect(), MFInfo{}.SetAlloc(false), EBFactory(lev));
333  } else {
334  rhs_sub[0].define(ba_sub, DistributionMapping(dm_sub), 1, rhs_lev.nGrowVect(), MFInfo{}.SetAlloc(false));
335  phi_sub[0].define(ba_sub, DistributionMapping(dm_sub), 1, phi_lev.nGrowVect(), MFInfo{}.SetAlloc(false));
336 
337  mfmx_sub.define(ba2d_sub, DistributionMapping(dm_sub), 1, mapfac[lev][MapFacType::m_x]->nGrowVect(), MFInfo{}.SetAlloc(false));
338  mfmy_sub.define(ba2d_sub, DistributionMapping(dm_sub), 1, mapfac[lev][MapFacType::m_y]->nGrowVect(), MFInfo{}.SetAlloc(false));
339  dJ_sub.define(ba_sub, DistributionMapping(dm_sub), 1, detJ_cc[lev]->nGrowVect(), MFInfo{}.SetAlloc(false));
340 
341  for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
342  fluxes_sub[0][idim].define(convert(ba_sub, IntVect::TheDimensionVector(idim)), DistributionMapping(dm_sub), 1,
343  IntVect::TheZeroVector(), MFInfo{}.SetAlloc(false));
344  }
345  rho0_u_sub[0].define(convert(ba_sub, IntVect::TheDimensionVector(0)), DistributionMapping(dm_sub), 1,
346  mom_mf[IntVars::xmom].nGrowVect(), MFInfo{}.SetAlloc(false));
347  rho0_u_sub[1].define(convert(ba_sub, IntVect::TheDimensionVector(1)), DistributionMapping(dm_sub), 1,
348  mom_mf[IntVars::ymom].nGrowVect(), MFInfo{}.SetAlloc(false));
349  rho0_u_sub[2].define(convert(ba_sub, IntVect::TheDimensionVector(2)), DistributionMapping(dm_sub), 1,
350  mom_mf[IntVars::zmom].nGrowVect(), MFInfo{}.SetAlloc(false));
351  }
352 
353  // Link the new MultiFabs to the FABs in the original MultiFabs (no copy required)
354  for (MFIter mfi(rhs_sub[0]); mfi.isValid(); ++mfi)
355  {
356  int orig_index = index_map[mfi.index()];
357  rhs_sub[0].setFab(mfi, FArrayBox(rhs_lev[orig_index], amrex::make_alias, 0, 1));
358  phi_sub[0].setFab(mfi, FArrayBox(phi_lev[orig_index], amrex::make_alias, 0, 1));
359 
360  mfmx_sub.setFab(mfi, FArrayBox((*mapfac[lev][MapFacType::m_x])[orig_index], amrex::make_alias, 0, 1));
361  mfmy_sub.setFab(mfi, FArrayBox((*mapfac[lev][MapFacType::m_y])[orig_index], amrex::make_alias, 0, 1));
362 
363  fluxes_sub[0][0].setFab(mfi,FArrayBox(fluxes[0][0][orig_index], amrex::make_alias, 0, 1));
364  fluxes_sub[0][1].setFab(mfi,FArrayBox(fluxes[0][1][orig_index], amrex::make_alias, 0, 1));
365  fluxes_sub[0][2].setFab(mfi,FArrayBox(fluxes[0][2][orig_index], amrex::make_alias, 0, 1));
366 
367  rho0_u_sub[0].setFab(mfi,FArrayBox(mom_mf[IntVars::xmom][orig_index], amrex::make_alias, 0, 1));
368  rho0_u_sub[1].setFab(mfi,FArrayBox(mom_mf[IntVars::ymom][orig_index], amrex::make_alias, 0, 1));
369  rho0_u_sub[2].setFab(mfi,FArrayBox(mom_mf[IntVars::zmom][orig_index], amrex::make_alias, 0, 1));
370  }
371 
372  rho0_u_const[0] = &rho0_u_sub[0];
373  rho0_u_const[1] = &rho0_u_sub[1];
374  rho0_u_const[2] = &rho0_u_sub[2];
375 
376  if (solverChoice.mesh_type != MeshType::ConstantDz) {
377  ax_sub.define(convert(ba_sub,IntVect(1,0,0)), DistributionMapping(dm_sub), 1,
378  ax[lev]->nGrowVect(), MFInfo{}.SetAlloc(false));
379  ay_sub.define(convert(ba_sub,IntVect(0,1,0)), DistributionMapping(dm_sub), 1,
380  ay[lev]->nGrowVect(), MFInfo{}.SetAlloc(false));
381  az_sub.define(convert(ba_sub,IntVect(0,0,1)), DistributionMapping(dm_sub), 1,
382  az[lev]->nGrowVect(), MFInfo{}.SetAlloc(false));
383  znd_sub.define(convert(ba_sub,IntVect(1,1,1)), DistributionMapping(dm_sub), 1,
384  z_phys_nd[lev]->nGrowVect(), MFInfo{}.SetAlloc(false));
385 
386  for (MFIter mfi(rhs_sub[0]); mfi.isValid(); ++mfi) {
387  int orig_index = index_map[mfi.index()];
388  ax_sub.setFab(mfi, FArrayBox((*ax[lev])[orig_index], amrex::make_alias, 0, 1));
389  ay_sub.setFab(mfi, FArrayBox((*ay[lev])[orig_index], amrex::make_alias, 0, 1));
390  az_sub.setFab(mfi, FArrayBox((*az[lev])[orig_index], amrex::make_alias, 0, 1));
391  znd_sub.setFab(mfi, FArrayBox((*z_phys_nd[lev])[orig_index], amrex::make_alias, 0, 1));
392  dJ_sub.setFab(mfi, FArrayBox((*detJ_cc[lev])[orig_index], amrex::make_alias, 0, 1));
393  }
394  }
395 
396  if (solverChoice.terrain_type == TerrainType::EB) {
397  for (MFIter mfi(rhs_sub[0]); mfi.isValid(); ++mfi) {
398  int orig_index = index_map[mfi.index()];
399  dJ_sub.setFab(mfi, FArrayBox((*detJ_cc[lev])[orig_index], amrex::make_alias, 0, 1));
400  }
401  }
402 
403  // ****************************************************************************
404  // Compute divergence which will form RHS
405  // Note that we replace "rho0w" with the contravariant momentum, Omega
406  // ****************************************************************************
407 
408  compute_divergence(lev, rhs_sub[0], rho0_u_const, geom_tmp[0]);
409 
410  Real rhsnorm;
411 
412  // Max norm over the entire MultiFab
413  rhsnorm = rhs_sub[0].norm0();
414 
415  if (mg_verbose > 0) {
416  bool local = false;
417  Real sum = volWgtSumMF(lev,rhs_sub[0],0,dJ_sub,mfmx_sub,mfmy_sub,false,local);
418  Print() << "Max/L2 norm of divergence before solve in subdomain " << isub << " at level " << lev << " : " << rhsnorm << " " <<
419  rhs_sub[0].norm2() << " and volume-weighted sum " << sum << std::endl;
420  }
421 
422  if (lev == 0 && solverChoice.use_real_bcs)
423  {
424  // We always use VariableDz if use_real_bcs is true
425  AMREX_ALWAYS_ASSERT(solverChoice.mesh_type == MeshType::VariableDz);
426 
427  // Note that we always impose the projections one level at a time so this will always be a vector of length 1
428  Array<MultiFab*, AMREX_SPACEDIM> rho0_u_vec =
429  {&mom_mf[IntVars::xmom], &mom_mf[IntVars::ymom], &mom_mf[IntVars::zmom]};
430  Array<MultiFab*, AMREX_SPACEDIM> area_vec = {ax[lev].get(), ay[lev].get(), az[lev].get()};
431  //
432  // Modify ax,ay,ax to include the map factors as used in the divergence calculation
433  // We do this here so that it is seen in the call to enforceInOutSolvability
434  //
435  for (MFIter mfi(rhs_lev); mfi.isValid(); ++mfi)
436  {
437  Box xbx = mfi.nodaltilebox(0);
438  Box ybx = mfi.nodaltilebox(1);
439  Box zbx = mfi.nodaltilebox(2);
440  const Array4<Real >& ax_ar = ax[lev]->array(mfi);
441  const Array4<Real >& ay_ar = ay[lev]->array(mfi);
442  const Array4<Real >& az_ar = az[lev]->array(mfi);
443  const Array4<Real const>& mf_uy = mapfac[lev][MapFacType::u_y]->const_array(mfi);
444  const Array4<Real const>& mf_vx = mapfac[lev][MapFacType::v_x]->const_array(mfi);
445  const Array4<Real const>& mf_mx = mapfac[lev][MapFacType::m_x]->const_array(mfi);
446  const Array4<Real const>& mf_my = mapfac[lev][MapFacType::m_y]->const_array(mfi);
448  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
449  {
450  ax_ar(i,j,k) /= mf_uy(i,j,0);
451  },
452  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
453  {
454  ay_ar(i,j,k) /= mf_vx(i,j,0);
455  },
456  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
457  {
458  az_ar(i,j,k) /= (mf_mx(i,j,0)*mf_my(i,j,0));
459  });
460  } // mfi
461 
462  if (mg_verbose > 0) {
463  Print() << "Calling enforceInOutSolvability" << std::endl;
464  }
465  enforceInOutSolvability(lev, rho0_u_vec, area_vec, geom[lev]);
466 
467  //
468  // Return ax,ay,ax to their original definition
469  //
470  for (MFIter mfi(rhs_lev); mfi.isValid(); ++mfi)
471  {
472  Box xbx = mfi.nodaltilebox(0);
473  Box ybx = mfi.nodaltilebox(1);
474  Box zbx = mfi.nodaltilebox(2);
475  const Array4<Real >& ax_ar = ax[lev]->array(mfi);
476  const Array4<Real >& ay_ar = ay[lev]->array(mfi);
477  const Array4<Real >& az_ar = az[lev]->array(mfi);
478  const Array4<Real const>& mf_uy = mapfac[lev][MapFacType::u_y]->const_array(mfi);
479  const Array4<Real const>& mf_vx = mapfac[lev][MapFacType::v_x]->const_array(mfi);
480  const Array4<Real const>& mf_mx = mapfac[lev][MapFacType::m_x]->const_array(mfi);
481  const Array4<Real const>& mf_my = mapfac[lev][MapFacType::m_y]->const_array(mfi);
483  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
484  {
485  ax_ar(i,j,k) *= mf_uy(i,j,0);
486  },
487  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
488  {
489  ay_ar(i,j,k) *= mf_vx(i,j,0);
490  },
491  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
492  {
493  az_ar(i,j,k) *= (mf_mx(i,j,0)*mf_my(i,j,0));
494  });
495  } // mfi
496 
497  compute_divergence(lev, rhs_lev, rho0_u_const, geom_tmp[0]);
498 
499  // Re-define max norm over the entire MultiFab
500  rhsnorm = rhs_lev.norm0();
501 
502  if (mg_verbose > 0)
503  {
504  bool local = false;
505  Real sum = volWgtSumMF(lev,rhs_sub[0],0,dJ_sub,mfmx_sub,mfmy_sub,false,local);
506  Print() << "Max/L2 norm of divergence before solve at level " << lev << " : " << rhsnorm << " " <<
507  rhs_lev.norm2() << " and volume-weighted sum " << sum << std::endl;
508  }
509  } // lev 0 && use_real_bcs
510 
511  // *******************************************************************************************
512  // Enforce solvability if the problem is singular (i.e all sides Neumann or periodic)
513  // Note that solves at lev > 0 are always singular because we impose Neumann bc's on all sides
514  // *******************************************************************************************
515  bool is_singular = true;
516  if (lev == 0) {
517  if ( (domain_bc_type[0] == "Outflow" || domain_bc_type[0] == "Open") && !solverChoice.use_real_bcs ) is_singular = false;
518  if ( (domain_bc_type[1] == "Outflow" || domain_bc_type[1] == "Open") && !solverChoice.use_real_bcs ) is_singular = false;
519  if ( (domain_bc_type[3] == "Outflow" || domain_bc_type[3] == "Open") && !solverChoice.use_real_bcs ) is_singular = false;
520  if ( (domain_bc_type[4] == "Outflow" || domain_bc_type[4] == "Open") && !solverChoice.use_real_bcs ) is_singular = false;
521  if ( (domain_bc_type[5] == "Outflow" || domain_bc_type[5] == "Open") ) is_singular = false;
522  } else {
523  Box my_region(subdomains[lev][isub].minimalBox());
524  if ( (domain_bc_type[5] == "Outflow" || domain_bc_type[5] == "Open") && (my_region.bigEnd(2) == domain.bigEnd(2)) ) is_singular = false;
525  }
526 
527  if (is_singular)
528  {
529  bool local = false;
530  Real sum = volWgtSumMF(lev,rhs_sub[0],0,dJ_sub,mfmx_sub,mfmy_sub,false,local);
531 
532  Real vol;
533  if (solverChoice.mesh_type == MeshType::ConstantDz) {
534  vol = rhs_sub[0].boxArray().numPts();
535  } else {
536  vol = dJ_sub.sum();
537  }
538 
539  sum /= (vol * dx[0] * dx[1] * dx[2]);
540 
541  for (MFIter mfi(rhs_sub[0]); mfi.isValid(); ++mfi)
542  {
543  rhs_sub[0][mfi.index()].template minus<RunOn::Device>(sum);
544  }
545  if (mg_verbose > 0) {
546  amrex::Print() << " Subtracting " << sum << " from rhs in subdomain " << isub << std::endl;
547 
548  sum = volWgtSumMF(lev,rhs_sub[0],0,dJ_sub,mfmx_sub,mfmy_sub,false,local);
549  Print() << "Sum after subtraction " << sum << " in subdomain " << isub << std::endl;
550  }
551 
552  } // if is_singular
553 
554  rhsnorm = rhs_sub[0].norm0();
555 
556  // ****************************************************************************
557  // No need to build the solver if RHS == 0
558  // ****************************************************************************
559  if (rhsnorm <= solverChoice.poisson_abstol) return;
560 
561  Real start_step = static_cast<Real>(ParallelDescriptor::second());
562 
563  if (mg_verbose > 0) {
564  amrex::Print() << " Solving in subdomain " << isub << " of " << subdomains[lev].size() << " bins at level " << lev << std::endl;
565  }
566 
567  if (solverChoice.mesh_type == MeshType::VariableDz) {
568  //
569  // Modify ax,ay,ax to include the map factors as used in the divergence calculation
570  // We do this here to set the coefficients used in the stencil -- the extra factor
571  // of the mapfac comes from the gradient
572  //
573  for (MFIter mfi(rhs_sub[0]); mfi.isValid(); ++mfi)
574  {
575  Box xbx = mfi.nodaltilebox(0);
576  Box ybx = mfi.nodaltilebox(1);
577  Box zbx = mfi.nodaltilebox(2);
578  const Array4<Real >& ax_ar = ax_sub.array(mfi);
579  const Array4<Real >& ay_ar = ay_sub.array(mfi);
580  const Array4<Real >& az_ar = az_sub.array(mfi);
581  const Array4<Real const>& mf_ux = mapfac[lev][MapFacType::u_x]->const_array(mfi);
582  const Array4<Real const>& mf_uy = mapfac[lev][MapFacType::u_y]->const_array(mfi);
583  const Array4<Real const>& mf_vx = mapfac[lev][MapFacType::v_x]->const_array(mfi);
584  const Array4<Real const>& mf_vy = mapfac[lev][MapFacType::v_y]->const_array(mfi);
585  const Array4<Real const>& mf_mx = mapfac[lev][MapFacType::m_x]->const_array(mfi);
586  const Array4<Real const>& mf_my = mapfac[lev][MapFacType::m_y]->const_array(mfi);
588  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
589  {
590  ax_ar(i,j,k) *= (mf_ux(i,j,0) / mf_uy(i,j,0));
591  },
592  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
593  {
594  ay_ar(i,j,k) *= (mf_vy(i,j,0) / mf_vx(i,j,0));
595  },
596  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
597  {
598  az_ar(i,j,k) /= (mf_mx(i,j,0)*mf_my(i,j,0));
599  });
600  } // mfi
601  }
602 
603  if (solverChoice.terrain_type != TerrainType::EB) {
604 
605 #ifdef ERF_USE_FFT
606  Box my_region(subdomains[lev][isub].minimalBox());
607 #endif
608 
609  // ****************************************************************************
610  // No terrain or grid stretching
611  // ****************************************************************************
612  if (solverChoice.mesh_type == MeshType::ConstantDz) {
613  if (will_solve_with_mlmg) {
614  solve_with_mlmg(lev, rhs_sub, phi_sub, fluxes_sub, geom[lev], ref_ratio, domain_bc_type,
616  } else {
617 #ifdef ERF_USE_FFT
618  solve_with_fft(lev, isub, my_region, rhs_sub[0], phi_sub[0], fluxes_sub[0]);
619 #endif
620  }
621  } // No terrain or grid stretching
622  // ****************************************************************************
623  // Grid stretching (flat terrain)
624  // ****************************************************************************
625  else if (solverChoice.mesh_type == MeshType::StretchedDz) {
626 #ifndef ERF_USE_FFT
627  amrex::Abort("Rebuild with USE_FFT = TRUE so you can use the FFT solver");
628 #else
629  bool boxes_make_rectangle = (my_region.numPts() == subdomains[lev][isub].numPts());
630  if (!boxes_make_rectangle) {
631  amrex::Abort("FFT won't work unless the union of boxes is rectangular");
632  } else {
633  if (!use_fft) {
634  amrex::Warning("Using FFT even though you didn't set use_fft to true; it's the best choice");
635  }
636  solve_with_fft(lev, isub, my_region, rhs_sub[0], phi_sub[0], fluxes_sub[0]);
637  }
638 #endif
639  } // grid stretching
640 
641  // ****************************************************************************
642  // General terrain
643  // ****************************************************************************
644  else if (solverChoice.mesh_type == MeshType::VariableDz) {
645 #ifdef ERF_USE_FFT
646  bool boxes_make_rectangle = (my_region.numPts() == subdomains[lev][isub].numPts());
647  if (!boxes_make_rectangle) {
648  amrex::Abort("FFT preconditioner for GMRES won't work unless the union of boxes is rectangular");
649  } else {
650  solve_with_gmres(lev, my_region, rhs_sub[0], phi_sub[0], fluxes_sub[0], ax_sub, ay_sub, az_sub, dJ_sub, znd_sub);
651  }
652 #else
653  amrex::Abort("Rebuild with USE_FFT = TRUE so you can use the FFT preconditioner for GMRES");
654 #endif
655 
656  //
657  // Restore ax,ay,ax to their original definitions
658  //
659  for (MFIter mfi(rhs_lev); mfi.isValid(); ++mfi)
660  {
661  Box xbx = mfi.nodaltilebox(0);
662  Box ybx = mfi.nodaltilebox(1);
663  Box zbx = mfi.nodaltilebox(2);
664  const Array4<Real >& ax_ar = ax_sub.array(mfi);
665  const Array4<Real >& ay_ar = ay_sub.array(mfi);
666  const Array4<Real >& az_ar = az_sub.array(mfi);
667  const Array4<Real const>& mf_ux = mapfac[lev][MapFacType::u_x]->const_array(mfi);
668  const Array4<Real const>& mf_uy = mapfac[lev][MapFacType::u_y]->const_array(mfi);
669  const Array4<Real const>& mf_vx = mapfac[lev][MapFacType::v_x]->const_array(mfi);
670  const Array4<Real const>& mf_vy = mapfac[lev][MapFacType::v_y]->const_array(mfi);
671  const Array4<Real const>& mf_mx = mapfac[lev][MapFacType::m_x]->const_array(mfi);
672  const Array4<Real const>& mf_my = mapfac[lev][MapFacType::m_y]->const_array(mfi);
674  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
675  {
676  ax_ar(i,j,k) *= (mf_uy(i,j,0) / mf_ux(i,j,0));
677  },
678  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
679  {
680  ay_ar(i,j,k) *= (mf_vx(i,j,0) / mf_vy(i,j,0));
681  },
682  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
683  {
684  az_ar(i,j,k) *= (mf_mx(i,j,0)*mf_my(i,j,0));
685  });
686  } // mfi
687 
688  } // MeshType::VariableDz
689 
690  // ****************************************************************************
691  // Print time in solve
692  // ****************************************************************************
693  Real end_step = static_cast<Real>(ParallelDescriptor::second());
694  if (mg_verbose > 0) {
695  amrex::Print() << "Time in solve " << end_step - start_step << std::endl;
696  }
697 
698  } // not EB
699  } // loop over subdomains (i)
700 
701  // ****************************************************************************
702  // When using multigrid we can solve for all of the level at once, even if there
703  // are disjoint regions
704  // ****************************************************************************
705  if (solverChoice.terrain_type == TerrainType::EB) {
706  Real start_step_eb = static_cast<Real>(ParallelDescriptor::second());
707  solve_with_EB_mlmg(lev, rhs_sub, phi_sub, fluxes_sub,
708  *(get_eb(lev).get_const_factory()),
709  *(get_eb(lev).get_u_const_factory()),
710  *(get_eb(lev).get_v_const_factory()),
711  *(get_eb(lev).get_w_const_factory()),
712  geom[lev], ref_ratio, domain_bc_type,
714  Real end_step_eb = static_cast<Real>(ParallelDescriptor::second());
715  if (mg_verbose > 0) {
716  amrex::Print() << "Time in solve " << end_step_eb - start_step_eb << std::endl;
717  }
718  }
719 
720  // ****************************************************************************
721  // Subtract dt grad(phi) from the momenta (rho0u, rho0v, Omega)
722  // ****************************************************************************
723  MultiFab::Add(mom_mf[IntVars::xmom],fluxes[0][0],0,0,1,0);
724  MultiFab::Add(mom_mf[IntVars::ymom],fluxes[0][1],0,0,1,0);
725  MultiFab::Add(mom_mf[IntVars::zmom],fluxes[0][2],0,0,1,0);
726 
727  // ****************************************************************************
728  // Define gradp from fluxes -- note that fluxes is dt * change in Gp
729  // (weighted by map factor!)
730  // ****************************************************************************
731  MultiFab::Saxpy(gradp[lev][GpVars::gpx],-one/l_dt,fluxes[0][0],0,0,1,0);
732  MultiFab::Saxpy(gradp[lev][GpVars::gpy],-one/l_dt,fluxes[0][1],0,0,1,0);
733  MultiFab::Saxpy(gradp[lev][GpVars::gpz],-one/l_dt,fluxes[0][2],0,0,1,0);
734 
735  gradp[lev][GpVars::gpx].FillBoundary(geom_tmp[0].periodicity());
736  gradp[lev][GpVars::gpy].FillBoundary(geom_tmp[0].periodicity());
737  gradp[lev][GpVars::gpz].FillBoundary(geom_tmp[0].periodicity());
738 
739  //
740  // This call is only to verify the divergence after the solve
741  // It is important we do this before computing the rho0w_arr from Omega back to rho0w
742  //
743  // ****************************************************************************
744  // THIS IS SIMPLY VERIFYING THE DIVERGENCE AFTER THE SOLVE
745  // ****************************************************************************
746  //
747  if (mg_verbose > 0)
748  {
749  rho0_u_const[0] = &mom_mf[IntVars::xmom];
750  rho0_u_const[1] = &mom_mf[IntVars::ymom];
751  rho0_u_const[2] = &mom_mf[IntVars::zmom];
752 
753  compute_divergence(lev, rhs_lev, rho0_u_const, geom_tmp[0]);
754 
755  bool local = false;
756  Real sum = volWgtSumMF(lev,rhs_lev,0,*detJ_cc[lev],*mapfac[lev][MapFacType::m_x],*mapfac[lev][MapFacType::m_y],false,local);
757 
758  if (mg_verbose > 0) {
759  Print() << "Max/L2 norm of divergence after solve at level " << lev << " : " << rhs_lev.norm0() << " " <<
760  rhs_lev.norm2() << " and volume-weighted sum " << sum << std::endl;
761  }
762 
763 #if 0
764  // FOR DEBUGGING ONLY
765  for ( MFIter mfi(rhs_lev,TilingIfNotGPU()); mfi.isValid(); ++mfi)
766  {
767  const Array4<Real const>& rhs_arr = rhs_lev.const_array(mfi);
768  Box bx = mfi.validbox();
769  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept {
770  if (std::abs(rhs_arr(i,j,k)) > Real(1.e-10)) {
771  amrex::AllPrint() << "RHS after solve at " <<
772  IntVect(i,j,k) << " " << rhs_arr(i,j,k) << std::endl;
773  }
774  });
775  } // mfi
776 #endif
777 
778  } // mg_verbose
779 
780  //
781  // ****************************************************************************
782  // Now convert the rho0w MultiFab back to holding (rho0w) rather than Omega
783  // ****************************************************************************
784  //
785  if (solverChoice.mesh_type == MeshType::VariableDz)
786  {
787  for (MFIter mfi(mom_mf[Vars::cons],TilingIfNotGPU()); mfi.isValid(); ++mfi)
788  {
789  Box tbz = mfi.nodaltilebox(2);
790  const Array4<Real >& rho0u_arr = mom_mf[IntVars::xmom].array(mfi);
791  const Array4<Real >& rho0v_arr = mom_mf[IntVars::ymom].array(mfi);
792  const Array4<Real >& rho0w_arr = mom_mf[IntVars::zmom].array(mfi);
793  const Array4<Real const>& z_nd = z_phys_nd[lev]->const_array(mfi);
794  const Array4<Real const>& mf_u = mapfac[lev][MapFacType::u_x]->const_array(mfi);
795  const Array4<Real const>& mf_v = mapfac[lev][MapFacType::v_y]->const_array(mfi);
796  ParallelFor(tbz, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept {
797  Real omega = rho0w_arr(i,j,k);
798  rho0w_arr(i,j,k) = WFromOmega(i,j,k,omega,
799  rho0u_arr,rho0v_arr,
800  mf_u,mf_v,z_nd,dxInv);
801  });
802  } // mfi
803  }
804 
805  // If !fixed_density, we must convert (rho0 u) back
806  // to (rho0 u) which is what we will pass back out
807  if (!solverChoice.fixed_density[lev]) {
808  ConvertForProjection(r_hse, mom_mf[Vars::cons],
809  mom_mf[IntVars::xmom],
810  mom_mf[IntVars::ymom],
811  mom_mf[IntVars::zmom],
812  Geom(lev).Domain(),
814  }
815 
816  // ****************************************************************************
817  // Update pressure variable with phi -- note that phi is dt * change in pressure
818  // ****************************************************************************
819  MultiFab::Saxpy(pp_inc[lev], one/l_dt, phi_lev,0,0,1,1);
820 }
void ConvertForProjection(const MultiFab &den_div, const MultiFab &den_mlt, MultiFab &xmom, MultiFab &ymom, MultiFab &zmom, const Box &domain, const Vector< BCRec > &domain_bcs_type_h)
Definition: ERF_ConvertForProjection.cpp:25
void enforceInOutSolvability(int, Array< MultiFab *, AMREX_SPACEDIM > &vels_vec, Array< MultiFab *, AMREX_SPACEDIM > &area_vec, const Geometry &geom)
Definition: ERF_ConvertForProjection.cpp:326
void solve_with_mlmg(int lev, Vector< amrex::MultiFab > &rhs, Vector< MultiFab > &p, Vector< amrex::Array< MultiFab, AMREX_SPACEDIM >> &fluxes, const Geometry &geom, const amrex::Vector< amrex::IntVect > &ref_ratio, Array< std::string, 2 *AMREX_SPACEDIM > l_domain_bc_type, int mg_verbose, Real reltol, Real abstol)
void solve_with_EB_mlmg(int lev, Vector< amrex::MultiFab > &rhs, Vector< MultiFab > &p, Vector< amrex::Array< MultiFab, AMREX_SPACEDIM >> &fluxes, EBFArrayBoxFactory const &ebfact, eb_aux_ const &ebfact_u, eb_aux_ const &ebfact_v, eb_aux_ const &ebfact_w, const Geometry &geom, const amrex::Vector< amrex::IntVect > &ref_ratio, Array< std::string, 2 *AMREX_SPACEDIM > l_domain_bc_type, int mg_verbose, Real reltol, Real abstol)
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real OmegaFromW(int &i, int &j, int &k, amrex::Real w, const amrex::Array4< const amrex::Real > &u_arr, const amrex::Array4< const amrex::Real > &v_arr, const amrex::Array4< const amrex::Real > &mf_u, const amrex::Array4< const amrex::Real > &mf_v, const amrex::Array4< const amrex::Real > &z_nd, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &dxInv)
Definition: ERF_TerrainMetrics.H:414
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real WFromOmega(int &i, int &j, int &k, amrex::Real omega, const amrex::Array4< const amrex::Real > &u_arr, const amrex::Array4< const amrex::Real > &v_arr, const amrex::Array4< const amrex::Real > &mf_u, const amrex::Array4< const amrex::Real > &mf_v, const amrex::Array4< const amrex::Real > &z_nd, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &dxInv)
Definition: ERF_TerrainMetrics.H:464
static bool use_fft
Definition: ERF.H:1250
void solve_with_gmres(int lev, const amrex::Box &subdomain, amrex::MultiFab &rhs, amrex::MultiFab &p, amrex::Array< amrex::MultiFab, AMREX_SPACEDIM > &fluxes, amrex::MultiFab &ax_sub, amrex::MultiFab &ay_sub, amrex::MultiFab &az_sub, amrex::MultiFab &, amrex::MultiFab &znd_sub)
Definition: ERF_SolveWithGMRES.cpp:12
void compute_divergence(int lev, amrex::MultiFab &rhs, amrex::Array< amrex::MultiFab const *, AMREX_SPACEDIM > rho0_u_const, amrex::Geometry const &geom_at_lev)
Definition: ERF_ComputeDivergence.cpp:10
amrex::Real volWgtSumMF(int lev, const amrex::MultiFab &mf, int comp, const amrex::MultiFab &dJ, const amrex::MultiFab &mfx, const amrex::MultiFab &mfy, bool finemask, bool local=true)
Definition: ERF_VolWgtSum.cpp:20
@ omega
Definition: ERF_Morrison.H:53
Here is the call graph for this function:

◆ project_velocity_tb()

void ERF::project_velocity_tb ( int  lev,
amrex::Real  dt,
amrex::Vector< amrex::MultiFab > &  vars 
)

Project the single-level velocity field to enforce incompressibility with a thin body

23 {
24  BL_PROFILE("ERF::project_velocity_tb()");
25  AMREX_ALWAYS_ASSERT(solverChoice.mesh_type == MeshType::ConstantDz);
26 
27  // Make sure the solver only sees the levels over which we are solving
28  Vector<BoxArray> ba_tmp; ba_tmp.push_back(vmf[Vars::cons].boxArray());
29  Vector<DistributionMapping> dm_tmp; dm_tmp.push_back(vmf[Vars::cons].DistributionMap());
30  Vector<Geometry> geom_tmp; geom_tmp.push_back(geom[lev]);
31 
32  // Use the default settings
33  LPInfo info;
34  std::unique_ptr<MLPoisson> p_mlpoisson;
35 #if 0
36  if (overset_imask[0]) {
37  // Add overset mask around thin body
38  p_mlpoisson = std::make_unique<MLPoisson>(geom, grids, dmap, GetVecOfConstPtrs(overset_imask), info);
39  }
40  else
41 #endif
42  {
43  // Use the default settings
44  p_mlpoisson = std::make_unique<MLPoisson>(geom_tmp, ba_tmp, dm_tmp, info);
45  }
46 
47  auto bclo = get_lo_projection_bc(geom[lev],domain_bc_type);
48  auto bchi = get_hi_projection_bc(geom[lev],domain_bc_type);
49 
50  bool need_adjust_rhs = (projection_has_dirichlet(bclo) || projection_has_dirichlet(bchi)) ? false : true;
51  p_mlpoisson->setDomainBC(bclo, bchi);
52 
53  if (lev > 0) {
54  p_mlpoisson->setCoarseFineBC(nullptr, ref_ratio[lev-1], LinOpBCType::Neumann);
55  }
56 
57  p_mlpoisson->setLevelBC(0, nullptr);
58 
59  Vector<MultiFab> rhs;
60  Vector<MultiFab> phi;
61  Vector<Array<MultiFab,AMREX_SPACEDIM> > fluxes;
62  Vector<Array<MultiFab,AMREX_SPACEDIM> > deltaf; // f^* - f^{n-1}
63  Vector<Array<MultiFab,AMREX_SPACEDIM> > u_plus_dtdf; // u + dt*deltaf
64 
65  // Used to pass array of const MFs to ComputeDivergence
66  Array<MultiFab const*, AMREX_SPACEDIM> u;
67 
68  rhs.resize(1);
69  phi.resize(1);
70  fluxes.resize(1);
71  deltaf.resize(1);
72  u_plus_dtdf.resize(1);
73 
74  rhs[0].define(ba_tmp[0], dm_tmp[0], 1, 0);
75  phi[0].define(ba_tmp[0], dm_tmp[0], 1, 0);
76  rhs[0].setVal(0.0);
77  phi[0].setVal(0.0);
78 
79  for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
80  fluxes[0][idim].define(convert(ba_tmp[0], IntVect::TheDimensionVector(idim)), dm_tmp[0], 1, 0);
81  u_plus_dtdf[0][idim].define(convert(ba_tmp[0], IntVect::TheDimensionVector(idim)), dm_tmp[0], 1, 0);
82 
83  deltaf[0][idim].define(convert(ba_tmp[0], IntVect::TheDimensionVector(idim)), dm_tmp[0], 1, 0);
84  deltaf[0][idim].setVal(0.0); // start with f^* == f^{n-1}
85  }
86 
87 #if 0
88  // DEBUG
89  u[0] = &(vmf[Vars::xvel]);
90  u[1] = &(vmf[Vars::yvel]);
91  u[2] = &(vmf[Vars::zvel]);
92  computeDivergence(rhs[0], u, geom[0]);
93  Print() << "Max norm of divergence before solve at level 0 : " << rhs[0].norm0() << std::endl;
94 #endif
95 
96  for (int itp = 0; itp < solverChoice.ncorr; ++itp)
97  {
98  // Calculate u + dt*deltaf
99  for (int idim = 0; idim < 3; ++idim) {
100  MultiFab::Copy(u_plus_dtdf[0][idim], deltaf[0][idim], 0, 0, 1, 0);
101  u_plus_dtdf[0][0].mult(-l_dt,0,1,0);
102  }
103  MultiFab::Add(u_plus_dtdf[0][0], vmf[Vars::xvel], 0, 0, 1, 0);
104  MultiFab::Add(u_plus_dtdf[0][1], vmf[Vars::yvel], 0, 0, 1, 0);
105  MultiFab::Add(u_plus_dtdf[0][2], vmf[Vars::zvel], 0, 0, 1, 0);
106 
107  u[0] = &(u_plus_dtdf[0][0]);
108  u[1] = &(u_plus_dtdf[0][1]);
109  u[2] = &(u_plus_dtdf[0][2]);
110  computeDivergence(rhs[0], u, geom_tmp[0]);
111 
112 #if 0
113  // DEBUG
114  if (itp==0) {
115  for (MFIter mfi(rhs[0], TilingIfNotGPU()); mfi.isValid(); ++mfi)
116  {
117  const Box& bx = mfi.tilebox();
118  const Array4<Real const>& divU = rhs[0].const_array(mfi);
119  const Array4<Real const>& uarr = vmf[Vars::xvel].const_array(mfi);
120  const Array4<Real const>& varr = vmf[Vars::yvel].const_array(mfi);
121  const Array4<Real const>& warr = vmf[Vars::zvel].const_array(mfi);
122  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
123  {
124  if ((i>=120) && (i<=139) && (j==0) && ((k>=127)&&(k<=128))) {
125  amrex::AllPrint() << "before project div"<<IntVect(i,j,k)<<" = "<< divU(i,j,k)
126  << " u: " << uarr(i,j,k) << " " << uarr(i+1,j,k)
127  << " v: " << varr(i,j,k) << " " << varr(i,j+1,k)
128  << " w: " << warr(i,j,k) << " " << warr(i,j,k+1)
129  << std::endl;
130  }
131  });
132  }
133  }
134 #endif
135 
136  // If all Neumann BCs, adjust RHS to make sure we can converge
137  if (need_adjust_rhs) {
138  bool local = false;
139  Real offset = volWgtSumMF(lev,rhs[0],0,*detJ_cc[lev],*mapfac[lev][MapFacType::m_x],*mapfac[lev][MapFacType::m_y],false,local);
140  // amrex::Print() << "Poisson solvability offset = " << offset << std::endl;
141  rhs[0].plus(-offset, 0, 1);
142  }
143 
144  // Initialize phi to 0
145  phi[0].setVal(0.0);
146 
147  MLMG mlmg(*p_mlpoisson);
148  int max_iter = 100;
149  mlmg.setMaxIter(max_iter);
150 
151  mlmg.setVerbose(mg_verbose);
152  //mlmg.setBottomVerbose(mg_verbose);
153 
154  // solve for dt*p
155  mlmg.solve(GetVecOfPtrs(phi),
156  GetVecOfConstPtrs(rhs),
159 
160  mlmg.getFluxes(GetVecOfArrOfPtrs(fluxes));
161 
162  // Calculate new intermediate body force with updated gradp
163  if (thin_xforce[lev]) {
164  MultiFab::Copy( deltaf[0][0], fluxes[0][0], 0, 0, 1, 0);
165  ApplyInvertedMask(deltaf[0][0], *xflux_imask[0]);
166  }
167  if (thin_yforce[lev]) {
168  MultiFab::Copy( deltaf[0][1], fluxes[0][1], 0, 0, 1, 0);
169  ApplyInvertedMask(deltaf[0][1], *yflux_imask[0]);
170  }
171  if (thin_zforce[lev]) {
172  MultiFab::Copy( deltaf[0][2], fluxes[0][2], 0, 0, 1, 0);
173  ApplyInvertedMask(deltaf[0][2], *zflux_imask[0]);
174  }
175 
176  // DEBUG
177  // for (MFIter mfi(rhs[0], TilingIfNotGPU()); mfi.isValid(); ++mfi)
178  // {
179  // const Box& bx = mfi.tilebox();
180  // const Array4<Real const>& dfz_arr = deltaf[0][2].const_array(mfi);
181  // ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
182  // {
183  // if ((i>=120) && (i<=139) && (j==0) && (k==128)) {
184  // amrex::AllPrint()
185  // << " piter" << itp
186  // << " dfz"<<IntVect(i,j,k)<<" = "<< dfz_arr(i,j,k)
187  // << std::endl;
188  // }
189  // });
190  // }
191 
192  // Update pressure variable with phi -- note that phi is change in pressure, not the full pressure
193  MultiFab::Saxpy(pp_inc[lev], one, phi[0],0,0,1,0);
194 
195  // Subtract grad(phi) from the velocity components
196  Real beta = one;
197  MultiFab::Saxpy(vmf[Vars::xvel], beta, fluxes[0][0], 0, 0, 1, 0);
198  MultiFab::Saxpy(vmf[Vars::yvel], beta, fluxes[0][1], 0, 0, 1, 0);
199  MultiFab::Saxpy(vmf[Vars::zvel], beta, fluxes[0][2], 0, 0, 1, 0);
200  if (thin_xforce[lev]) {
201  ApplyMask(vmf[Vars::xvel], *xflux_imask[0]);
202  }
203  if (thin_yforce[lev]) {
204  ApplyMask(vmf[Vars::yvel], *yflux_imask[0]);
205  }
206  if (thin_zforce[lev]) {
207  ApplyMask(vmf[Vars::zvel], *zflux_imask[0]);
208  }
209  } // itp: pressure-force iterations
210 
211  // ****************************************************************************
212  // Define gradp from fluxes -- note that fluxes is dt * change in Gp
213  // ****************************************************************************
214  MultiFab::Saxpy(gradp[lev][GpVars::gpx],-one/l_dt,fluxes[0][0],0,0,1,0);
215  MultiFab::Saxpy(gradp[lev][GpVars::gpy],-one/l_dt,fluxes[0][1],0,0,1,0);
216  MultiFab::Saxpy(gradp[lev][GpVars::gpz],-one/l_dt,fluxes[0][2],0,0,1,0);
217 
218  gradp[lev][GpVars::gpx].FillBoundary(geom_tmp[0].periodicity());
219  gradp[lev][GpVars::gpy].FillBoundary(geom_tmp[0].periodicity());
220  gradp[lev][GpVars::gpz].FillBoundary(geom_tmp[0].periodicity());
221 
222  // Subtract grad(phi) from the velocity components
223 // Real beta = one;
224 // for (int ilev = lev_min; ilev <= lev_max; ++ilev) {
225 // MultiFab::Saxpy(vmf[Vars::xvel], beta, fluxes[0][0], 0, 0, 1, 0);
226 // MultiFab::Saxpy(vmf[Vars::yvel], beta, fluxes[0][1], 0, 0, 1, 0);
227 // MultiFab::Saxpy(vmf[Vars::zvel], beta, fluxes[0][2], 0, 0, 1, 0);
228 // if (thin_xforce[lev]) {
229 // ApplyMask(vmf[Vars::xvel], *xflux_imask[0]);
230 // }
231 // if (thin_yforce[lev]) {
232 // ApplyMask(vmf[Vars::yvel], *yflux_imask[0]);
233 // }
234 // if (thin_zforce[lev]) {
235 // ApplyMask(vmf[Vars::zvel], *zflux_imask[0]);
236 // }
237 // }
238 
239 #if 0
240  // Confirm that the velocity is now divergence free
241  u[0] = &(vmf[Vars::xvel]);
242  u[1] = &(vmf[Vars::yvel]);
243  u[2] = &(vmf[Vars::zvel]);
244  computeDivergence(rhs[0], u, geom_tmp[0]);
245  Print() << "Max norm of divergence after solve at level " << lev << " : " << rhs[0].norm0() << std::endl;
246 
247 #endif
248 }
bool projection_has_dirichlet(Array< LinOpBCType, AMREX_SPACEDIM > bcs)
Definition: ERF_PoissonSolve_tb.cpp:10
AMREX_FORCE_INLINE IntVect offset(const int face_dir, const int normal)
Definition: ERF_ReadBndryPlanes.cpp:28
Array< LinOpBCType, AMREX_SPACEDIM > get_lo_projection_bc(Geometry const &lev_geom, Array< std::string, 2 *AMREX_SPACEDIM > l_domain_bc_type)
Definition: ERF_SolverUtils.H:13
Array< LinOpBCType, AMREX_SPACEDIM > get_hi_projection_bc(Geometry const &lev_geom, Array< std::string, 2 *AMREX_SPACEDIM > l_domain_bc_type)
Definition: ERF_SolverUtils.H:34
AMREX_GPU_HOST AMREX_FORCE_INLINE void ApplyInvertedMask(amrex::MultiFab &dst, const amrex::iMultiFab &imask, const int nghost=0)
Definition: ERF_Utils.H:337
Here is the call graph for this function:

◆ ReadCheckpointFile()

void ERF::ReadCheckpointFile ( )

ERF function for reading data from a checkpoint file during restart.

472 {
473  Print() << "Restart from native checkpoint " << restart_chkfile << "\n";
474 
475  // Header
476  std::string File(restart_chkfile + "/Header");
477 
478  VisMF::IO_Buffer io_buffer(VisMF::GetIOBufferSize());
479 
480  Vector<char> fileCharPtr;
481  ParallelDescriptor::ReadAndBcastFile(File, fileCharPtr);
482  std::string fileCharPtrString(fileCharPtr.dataPtr());
483  std::istringstream is(fileCharPtrString, std::istringstream::in);
484 
485  std::string line, word;
486 
487  int chk_ncomp_cons, chk_ncomp;
488 
489  // read in title line
490  std::getline(is, line);
491 
492  // read in finest_level
493  is >> finest_level;
494  GotoNextLine(is);
495 
496  // read the number of components
497  // for each variable we store
498 
499  // conservative, cell-centered vars
500  is >> chk_ncomp_cons;
501  GotoNextLine(is);
502 
503  // x-velocity on faces
504  is >> chk_ncomp;
505  GotoNextLine(is);
506  AMREX_ASSERT(chk_ncomp == 1);
507 
508  // y-velocity on faces
509  is >> chk_ncomp;
510  GotoNextLine(is);
511  AMREX_ASSERT(chk_ncomp == 1);
512 
513  // z-velocity on faces
514  is >> chk_ncomp;
515  GotoNextLine(is);
516  AMREX_ASSERT(chk_ncomp == 1);
517 
518  // read in array of istep
519  std::getline(is, line);
520  {
521  std::istringstream lis(line);
522  int i = 0;
523  while (lis >> word) {
524  istep[i++] = std::stoi(word);
525  }
526  }
527 
528  // read in array of dt
529  std::getline(is, line);
530  {
531  std::istringstream lis(line);
532  int i = 0;
533  while (lis >> word) {
534  dt[i++] = static_cast<Real>(std::stod(word));
535  }
536  }
537 
538  // read in array of t_new
539  std::getline(is, line);
540  {
541  std::istringstream lis(line);
542  int i = 0;
543  while (lis >> word) {
544  t_new[i++] = static_cast<Real>(std::stod(word));
545  }
546  }
547 
548  for (int lev = 0; lev <= finest_level; ++lev) {
549  // read in level 'lev' BoxArray from Header
550  BoxArray ba;
551  ba.readFrom(is);
552  GotoNextLine(is);
553 
554  // create a distribution mapping
555  DistributionMapping dm { ba, ParallelDescriptor::NProcs() };
556 
557  MakeNewLevelFromScratch (lev, t_new[lev], ba, dm);
558  }
559 
560  // ncomp is only valid after we MakeNewLevelFromScratch (asks micro how many vars)
561  // NOTE: Data is written over ncomp, so check that we match the header file
562  int ncomp_cons = vars_new[0][Vars::cons].nComp();
563 
564  // NOTE: QKE was removed so this is for backward compatibility
565  AMREX_ASSERT((chk_ncomp_cons==ncomp_cons) || ((chk_ncomp_cons-1)==ncomp_cons));
566  //
567  // See if we have a written separate file that tells how many components and how many ghost cells
568  // we have of the base state
569  //
570  // If we can't find the file, then set the number of components to the original number = 3
571  //
572  int ncomp_base_to_read = 3;
573  IntVect ng_base = IntVect{1};
574  {
575  std::string BaseStateFile(restart_chkfile + "/num_base_state_comps");
576 
577  if (amrex::FileExists(BaseStateFile))
578  {
579  Vector<char> BaseStatefileCharPtr;
580  ParallelDescriptor::ReadAndBcastFile(BaseStateFile, BaseStatefileCharPtr);
581  std::string BaseStatefileCharPtrString(BaseStatefileCharPtr.dataPtr());
582 
583  // We set this to the default value of 3 but allow it be larger if th0 and qv0 were written
584  std::istringstream isb(BaseStatefileCharPtrString, std::istringstream::in);
585  isb >> ncomp_base_to_read;
586  isb >> ng_base;
587  }
588  }
589 
590  // read in the MultiFab data
591  for (int lev = 0; lev <= finest_level; ++lev)
592  {
593  // NOTE: For backward compatibility (chk file has QKE)
594  if ((chk_ncomp_cons-1)==ncomp_cons) {
595  MultiFab cons(grids[lev],dmap[lev],chk_ncomp_cons,0);
596  VisMF::Read(cons, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Cell"));
597 
598  // Copy up to RhoKE_comp
599  MultiFab::Copy(vars_new[lev][Vars::cons],cons,0,0,(RhoKE_comp+1),0);
600 
601  // Only if we have a PBL model do we need to copy QKE is src to KE in dst
602  if ( (solverChoice.turbChoice[lev].pbl_type == PBLType::MYNN25) ||
603  (solverChoice.turbChoice[lev].pbl_type == PBLType::MYNNEDMF) ) {
604  MultiFab::Copy(vars_new[lev][Vars::cons],cons,(RhoKE_comp+1),RhoKE_comp,1,0);
605  vars_new[lev][Vars::cons].mult(myhalf,RhoKE_comp,1,0);
606  }
607 
608  // Copy other components
609  int ncomp_remainder = ncomp_cons - (RhoKE_comp + 1);
610  MultiFab::Copy(vars_new[lev][Vars::cons],cons,(RhoKE_comp+2),(RhoKE_comp+1),ncomp_remainder,0);
611 
612  vars_new[lev][Vars::cons].setBndry(Real(1.0e34));
613  } else {
614  MultiFab cons(grids[lev],dmap[lev],ncomp_cons,0);
615  VisMF::Read(cons, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Cell"));
616  MultiFab::Copy(vars_new[lev][Vars::cons],cons,0,0,ncomp_cons,0);
617  vars_new[lev][Vars::cons].setBndry(Real(1.0e34));
618  }
619 
620  MultiFab xvel(convert(grids[lev],IntVect(1,0,0)),dmap[lev],1,0);
621  VisMF::Read(xvel, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "XFace"));
622  MultiFab::Copy(vars_new[lev][Vars::xvel],xvel,0,0,1,0);
623  vars_new[lev][Vars::xvel].setBndry(Real(1.0e34));
624 
625  MultiFab yvel(convert(grids[lev],IntVect(0,1,0)),dmap[lev],1,0);
626  VisMF::Read(yvel, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "YFace"));
627  MultiFab::Copy(vars_new[lev][Vars::yvel],yvel,0,0,1,0);
628  vars_new[lev][Vars::yvel].setBndry(Real(1.0e34));
629 
630  MultiFab zvel(convert(grids[lev],IntVect(0,0,1)),dmap[lev],1,0);
631  VisMF::Read(zvel, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "ZFace"));
632  MultiFab::Copy(vars_new[lev][Vars::zvel],zvel,0,0,1,0);
633  vars_new[lev][Vars::zvel].setBndry(Real(1.0e34));
634 
635  if (solverChoice.anelastic[lev] == 1) {
636  MultiFab ppinc(grids[lev],dmap[lev],1,0);
637  VisMF::Read(ppinc, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "PP_Inc"));
638  MultiFab::Copy(pp_inc[lev],ppinc,0,0,1,0);
639  pp_inc[lev].FillBoundary(geom[lev].periodicity());
640 
641  MultiFab gpx(convert(grids[lev],IntVect(1,0,0)),dmap[lev],1,0);
642  VisMF::Read(gpx, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Gpx"));
643  MultiFab::Copy(gradp[lev][GpVars::gpx],gpx,0,0,1,0);
644  gradp[lev][GpVars::gpx].FillBoundary(geom[lev].periodicity());
645 
646  MultiFab gpy(convert(grids[lev],IntVect(0,1,0)),dmap[lev],1,0);
647  VisMF::Read(gpy, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Gpy"));
648  MultiFab::Copy(gradp[lev][GpVars::gpy],gpy,0,0,1,0);
649  gradp[lev][GpVars::gpy].FillBoundary(geom[lev].periodicity());
650 
651  MultiFab gpz(convert(grids[lev],IntVect(0,0,1)),dmap[lev],1,0);
652  VisMF::Read(gpz, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Gpz"));
653  MultiFab::Copy(gradp[lev][GpVars::gpz],gpz,0,0,1,0);
654  gradp[lev][GpVars::gpz].FillBoundary(geom[lev].periodicity());
655  }
656 
657  // Note that we read the ghost cells of the base state (unlike above)
658 
659  // The original base state only had 3 components and 1 ghost cell -- we read this
660  // here to be consistent with the old style
661  MultiFab base(grids[lev],dmap[lev],ncomp_base_to_read,ng_base);
662  VisMF::Read(base, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "BaseState"));
663 
664  MultiFab::Copy(base_state[lev],base,0,0,ncomp_base_to_read,ng_base);
665 
666  // Create theta0 from p0, rh0
667  if (ncomp_base_to_read < 4) {
668  for (MFIter mfi(base_state[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
669  {
670  // We only compute theta_0 on valid cells since we will impose domain BC's after restart
671  const Box& bx = mfi.tilebox();
672  Array4<Real> const& fab = base_state[lev].array(mfi);
673  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
674  {
676  / fab(i,j,k,BaseState::r0_comp);
677  });
678  }
679  }
680  // Default theta0 to 0
681  if (ncomp_base_to_read < 5) {
682  for (MFIter mfi(base_state[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
683  {
684  // We only compute theta_0 on valid cells since we will impose domain BC's after restart
685  const Box& bx = mfi.tilebox();
686  Array4<Real> const& fab = base_state[lev].array(mfi);
687  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
688  {
689  fab(i,j,k,BaseState::qv0_comp) = zero;
690  });
691  }
692  }
693  base_state[lev].FillBoundary(geom[lev].periodicity());
694 
695  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
696  // Note that we also read the ghost cells of z_phys_nd
697  IntVect ng = z_phys_nd[lev]->nGrowVect();
698  MultiFab z_height(convert(grids[lev],IntVect(1,1,1)),dmap[lev],1,ng);
699  VisMF::Read(z_height, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Z_Phys_nd"));
700  MultiFab::Copy(*z_phys_nd[lev],z_height,0,0,1,ng);
702 
703  // Compute the min dz and pass to the micro model
704  Real dzmin = get_dzmin_terrain(*z_phys_nd[lev]);
705  micro->Set_dzmin(lev, dzmin);
706 
707  if (SolverChoice::mesh_type == MeshType::VariableDz) {
708  MultiFab z_slab(convert(ba2d[lev],IntVect(1,1,1)),dmap[lev],1,0);
709  int klo = geom[lev].Domain().smallEnd(2);
710  for (MFIter mfi(z_slab); mfi.isValid(); ++mfi) {
711  Box nbx = mfi.tilebox();
712  Array4<Real const> const& z_arr = z_phys_nd[lev]->const_array(mfi);
713  Array4<Real > const& z_slab_arr = z_slab.array(mfi);
714  ParallelFor(nbx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
715  {
716  z_slab_arr(i,j,k) = z_arr(i,j,klo);
717  });
718  }
719  Real z_min = z_slab.min(0);
720  Real z_max = z_slab.max(0);
721 
722  auto dz = geom[lev].CellSize()[2];
723  if (z_max - z_min < Real(1.e-8) * dz) {
724  SolverChoice::set_mesh_type(MeshType::StretchedDz);
725  if (verbose > 0) {
726  amrex::Print() << "Resetting mesh type to StretchedDz since terrain is flat" << std::endl;
727  }
728  }
729  }
730  }
731 
732  // Read in the moisture model restart variables
733  std::vector<int> qmoist_indices;
734  std::vector<std::string> qmoist_names;
735  micro->Get_Qmoist_Restart_Vars(lev, solverChoice, qmoist_indices, qmoist_names);
736  int qmoist_nvar = static_cast<int>(qmoist_indices.size());
737  for (int var = 0; var < qmoist_nvar; var++) {
738  const int ncomp = 1;
739  IntVect ng_moist = qmoist[lev][qmoist_indices[var]]->nGrowVect();
740  MultiFab moist_vars(grids[lev],dmap[lev],ncomp,ng_moist);
741  VisMF::Read(moist_vars, amrex::MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", qmoist_names[var]));
742  MultiFab::Copy(*(qmoist[lev][qmoist_indices[var]]),moist_vars,0,0,ncomp,ng_moist);
743  }
744 
745 #if defined(ERF_USE_WINDFARM)
746  if(solverChoice.windfarm_type == WindFarmType::Fitch or
747  solverChoice.windfarm_type == WindFarmType::EWP or
748  solverChoice.windfarm_type == WindFarmType::SimpleAD){
749  IntVect ng = Nturb[lev].nGrowVect();
750  MultiFab mf_Nturb(grids[lev],dmap[lev],1,ng);
751  VisMF::Read(mf_Nturb, amrex::MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "NumTurb"));
752  MultiFab::Copy(Nturb[lev],mf_Nturb,0,0,1,ng);
753  }
754 #endif
755 
756  // Read the LSM data
757  if (solverChoice.lsm_type != LandSurfaceType::None) {
758  amrex::Print() << "Reading LSM variables" << std::endl;
759  for (int ivar(0); ivar<lsm_data[lev].size(); ++ivar) {
760  BoxArray ba = lsm_data[lev][ivar]->boxArray();
761  DistributionMapping dm = lsm_data[lev][ivar]->DistributionMap();
762  IntVect ng = lsm_data[lev][ivar]->nGrowVect();
763  int nvar = lsm_data[lev][ivar]->nComp();
764  MultiFab lsm_vars(ba,dm,nvar,ng);
765  VisMF::Read(lsm_vars, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "LsmData" + std::to_string(ivar)));
766  MultiFab::Copy(*(lsm_data[lev][ivar]),lsm_vars,0,0,nvar,ng);
767  }
768  for (int iflux(0); iflux<lsm_flux[lev].size(); ++iflux) {
769  BoxArray ba = lsm_flux[lev][iflux]->boxArray();
770  DistributionMapping dm = lsm_flux[lev][iflux]->DistributionMap();
771  IntVect ng = lsm_flux[lev][iflux]->nGrowVect();
772  int nvar = lsm_flux[lev][iflux]->nComp();
773  MultiFab lsm_vars(ba,dm,nvar,ng);
774  VisMF::Read(lsm_vars, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "LsmFlux" + std::to_string(iflux)));
775  MultiFab::Copy(*(lsm_flux[lev][iflux]),lsm_vars,0,0,nvar,ng);
776  }
777  }
778 
779  // Read the radiation heating rates
780  std::string RadFileName(restart_chkfile + "/Level_0/Qrad_H");
781  if ((solverChoice.rad_type != RadiationType::None) && amrex::FileExists(RadFileName)) {
782  amrex::Print() << "Reading radiation heating rates" << std::endl;
783  int nrad = qheating_rates[lev]->nComp();
784  MultiFab mf_rad(grids[lev],dmap[lev],nrad,0);
785  VisMF::Read(mf_rad, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Qrad"));
786  MultiFab::Copy(*qheating_rates[lev],mf_rad,0,0,nrad,0);
787  }
788 
789  IntVect ng = mapfac[lev][MapFacType::m_x]->nGrowVect();
790  MultiFab mf_m(ba2d[lev],dmap[lev],1,ng);
791 
792  std::string MapFacMFileName(restart_chkfile + "/Level_0/MapFactor_mx_H");
793  if (amrex::FileExists(MapFacMFileName)) {
794  VisMF::Read(mf_m, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "MapFactor_mx"));
795  } else {
796  VisMF::Read(mf_m, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "MapFactor_m"));
797  }
798  MultiFab::Copy(*mapfac[lev][MapFacType::m_x],mf_m,0,0,1,ng);
799 
800 #if 0
802  VisMF::Read(mf_m, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "MapFactor_my"));
803  MultiFab::Copy(*mapfac[lev][MapFacType::m_y],mf_m,0,0,1,ng);
804  }
805 #endif
806 
807  ng = mapfac[lev][MapFacType::u_x]->nGrowVect();
808  MultiFab mf_u(convert(ba2d[lev],IntVect(1,0,0)),dmap[lev],1,ng);
809 
810  std::string MapFacUFileName(restart_chkfile + "/Level_0/MapFactor_ux_H");
811  if (amrex::FileExists(MapFacUFileName)) {
812  VisMF::Read(mf_u, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "MapFactor_ux"));
813  } else {
814  VisMF::Read(mf_u, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "MapFactor_u"));
815  }
816  MultiFab::Copy(*mapfac[lev][MapFacType::u_x],mf_u,0,0,1,ng);
817 
818 #if 0
820  VisMF::Read(mf_u, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "MapFactor_uy"));
821  MultiFab::Copy(*mapfac[lev][MapFacType::u_y],mf_u,0,0,1,ng);
822  }
823 #endif
824 
825  ng = mapfac[lev][MapFacType::v_x]->nGrowVect();
826  MultiFab mf_v(convert(ba2d[lev],IntVect(0,1,0)),dmap[lev],1,ng);
827 
828  std::string MapFacVFileName(restart_chkfile + "/Level_0/MapFactor_vx_H");
829  if (amrex::FileExists(MapFacVFileName)) {
830  VisMF::Read(mf_v, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "MapFactor_vx"));
831  } else {
832  VisMF::Read(mf_v, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "MapFactor_v"));
833  }
834  MultiFab::Copy(*mapfac[lev][MapFacType::v_x],mf_v,0,0,1,ng);
835 
836 #if 0
838  VisMF::Read(mf_v, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "MapFactor_vy"));
839  MultiFab::Copy(*mapfac[lev][MapFacType::v_y],mf_v,0,0,1,ng);
840  }
841 #endif
842 
843 
844  // NOTE: We read MOST data in ReadCheckpointFileMOST (see below)!
845 
846  // See if we wrote out SST data
847  std::string FirstSSTFileName(restart_chkfile + "/Level_0/SST_0_H");
848  if (amrex::FileExists(FirstSSTFileName))
849  {
850  amrex::Print() << "Reading SST data" << std::endl;
851  int ntimes = 1;
852  ng = vars_new[lev][Vars::cons].nGrowVect(); ng[2]=0;
853  MultiFab sst_at_t(ba2d[lev],dmap[lev],1,ng);
854  sst_lev[lev][0] = std::make_unique<MultiFab>(ba2d[lev],dmap[lev],1,ng);
855  for (int nt(0); nt<ntimes; ++nt) {
856  VisMF::Read(sst_at_t, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_",
857  "SST_" + std::to_string(nt)));
858  MultiFab::Copy(*sst_lev[lev][nt],sst_at_t,0,0,1,ng);
859  }
860  }
861 
862  // See if we wrote out TSK data
863  std::string FirstTSKFileName(restart_chkfile + "/Level_0/TSK_0_H");
864  if (amrex::FileExists(FirstTSKFileName))
865  {
866  amrex::Print() << "Reading TSK data" << std::endl;
867  int ntimes = 1;
868  ng = vars_new[lev][Vars::cons].nGrowVect(); ng[2]=0;
869  MultiFab tsk_at_t(ba2d[lev],dmap[lev],1,ng);
870  tsk_lev[lev][0] = std::make_unique<MultiFab>(ba2d[lev],dmap[lev],1,ng);
871  for (int nt(0); nt<ntimes; ++nt) {
872  VisMF::Read(tsk_at_t, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_",
873  "TSK_" + std::to_string(nt)));
874  MultiFab::Copy(*tsk_lev[lev][nt],tsk_at_t,0,0,1,ng);
875  }
876  }
877 
878  std::string LMaskFileName(restart_chkfile + "/Level_0/LMASK_0_H");
879  if (amrex::FileExists(LMaskFileName))
880  {
881  amrex::Print() << "Reading LMASK data" << std::endl;
882  int ntimes = 1;
883  ng = vars_new[lev][Vars::cons].nGrowVect(); ng[2]=0;
884  MultiFab lmask_at_t(ba2d[lev],dmap[lev],1,ng);
885  for (int nt(0); nt<ntimes; ++nt) {
886  VisMF::Read(lmask_at_t, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_",
887  "LMASK_" + std::to_string(nt)));
888  for (MFIter mfi(lmask_at_t); mfi.isValid(); ++mfi) {
889  const Box& bx = mfi.growntilebox();
890  Array4<int> const& dst_arr = lmask_lev[lev][nt]->array(mfi);
891  Array4<Real> const& src_arr = lmask_at_t.array(mfi);
892  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
893  {
894  dst_arr(i,j,k) = int(src_arr(i,j,k));
895  });
896  }
897  }
898  } else {
899  // Allow idealized cases over water, used to set lmask
900  ParmParse pp("erf");
901  int is_land;
902  if (pp.query("is_land", is_land, lev)) {
903  if (is_land == 1) {
904  amrex::Print() << "Level " << lev << " is land" << std::endl;
905  } else if (is_land == 0) {
906  amrex::Print() << "Level " << lev << " is water" << std::endl;
907  } else {
908  Error("is_land should be 0 or 1");
909  }
910  lmask_lev[lev][0]->setVal(is_land);
911  } else {
912  // Default to land everywhere if not specified
913  lmask_lev[lev][0]->setVal(1);
914  }
915  lmask_lev[lev][0]->FillBoundary(geom[lev].periodicity());
916  }
917 
918  IntVect ngv = ng; ngv[2] = 0;
919 
920  // Read lat/lon if it exists
921  std::string LatFileName(restart_chkfile + "/Level_0/LAT_H");
922  if (amrex::FileExists(LatFileName)) {
923  amrex::Print() << "Reading Lat/Lon variables" << std::endl;
924  MultiFab lat(ba2d[lev],dmap[lev],1,ngv);
925  MultiFab lon(ba2d[lev],dmap[lev],1,ngv);
926  VisMF::Read(lat, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "LAT"));
927  VisMF::Read(lon, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "LON"));
928  lat_m[lev] = std::make_unique<MultiFab>(ba2d[lev],dmap[lev],1,ngv);
929  lon_m[lev] = std::make_unique<MultiFab>(ba2d[lev],dmap[lev],1,ngv);
930  MultiFab::Copy(*lat_m[lev],lat,0,0,1,ngv);
931  MultiFab::Copy(*lon_m[lev],lon,0,0,1,ngv);
932  }
933 
934 #ifdef ERF_USE_NETCDF
935  // Read sinPhi and cosPhi if it exists
936  std::string VarCorFileName(restart_chkfile + "/Level_0/SinPhi_H");
937  if (amrex::FileExists(VarCorFileName)) {
938  amrex::Print() << "Reading Coriolis factors" << std::endl;
939  MultiFab sphi(ba2d[lev],dmap[lev],1,ngv);
940  MultiFab cphi(ba2d[lev],dmap[lev],1,ngv);
941  VisMF::Read(sphi, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "SinPhi"));
942  VisMF::Read(cphi, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "CosPhi"));
943  sinPhi_m[lev] = std::make_unique<MultiFab>(ba2d[lev],dmap[lev],1,ngv);
944  cosPhi_m[lev] = std::make_unique<MultiFab>(ba2d[lev],dmap[lev],1,ngv);
945  MultiFab::Copy(*sinPhi_m[lev],sphi,0,0,1,ngv);
946  MultiFab::Copy(*cosPhi_m[lev],cphi,0,0,1,ngv);
947  }
948 
949  if (solverChoice.use_real_bcs && solverChoice.init_type == InitType::WRFInput) {
950  if (lev == 0) {
951  amrex::Print() << "Reading C1H/C2H/MUB/PHB variables at level " << lev << std::endl;
952  MultiFab tmp1d(ba1d[0],dmap[0],1,0);
953 
954  VisMF::Read(tmp1d, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "C1H"));
955  MultiFab::Copy(*wrf_C1H,tmp1d,0,0,1,0);
956 
957  VisMF::Read(tmp1d, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "C2H"));
958  MultiFab::Copy(*wrf_C2H,tmp1d,0,0,1,0);
959 
960  MultiFab tmp2d(ba2d[0],dmap[0],1,wrf_MUB->nGrowVect());
961 
962  VisMF::Read(tmp2d, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "MUB"));
963  MultiFab::Copy(*wrf_MUB,tmp2d,0,0,1,wrf_MUB->nGrowVect());
964 
965  ng = IntVect(1,1,0);
966  MultiFab tmp3d(convert(grids[0],IntVect(0,0,1)),dmap[0],1,ng);
967  wrf_PHB = std::make_unique<MultiFab>(convert(grids[0],IntVect(0,0,1)),dmap[0],1,ng);
968  VisMF::Read(tmp3d, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "PHB"));
969  MultiFab::Copy(*wrf_PHB,tmp3d,0,0,1,ng);
970  }
971  }
972 #endif
973  } // for lev
974 
975 #ifdef ERF_USE_PARTICLES
976  restartTracers((ParGDBBase*)GetParGDB(),restart_chkfile);
977  if (Microphysics::modelType(solverChoice.moisture_type) == MoistureModelType::Lagrangian) {
978  dynamic_cast<LagrangianMicrophysics&>(*micro).restartParticles((ParGDBBase*)GetParGDB(),restart_chkfile);
979  }
980 #endif
981 
982 #if 0
983 #ifdef ERF_USE_NETCDF
984  // Read bdy_data files
985  if ( ((solverChoice.init_type==InitType::WRFInput) || (solverChoice.init_type==InitType::Metgrid)) &&
987  {
988  int ioproc = ParallelDescriptor::IOProcessorNumber(); // I/O rank
989  int num_time;
990  int num_var;
991  Vector<Box> bx_v;
992  if (ParallelDescriptor::IOProcessor()) {
993  // Open header file and read from it
994  std::ifstream bdy_h_file(MultiFabFileFullPrefix(0, restart_chkfile, "Level_", "bdy_H"));
995  bdy_h_file >> num_time;
996  bdy_h_file >> num_var;
997  bdy_h_file >> start_bdy_time;
998  bdy_h_file >> bdy_time_interval;
999  bdy_h_file >> real_width;
1000  bx_v.resize(4*num_var);
1001  for (int ivar(0); ivar<num_var; ++ivar) {
1002  bdy_h_file >> bx_v[4*ivar ];
1003  bdy_h_file >> bx_v[4*ivar+1];
1004  bdy_h_file >> bx_v[4*ivar+2];
1005  bdy_h_file >> bx_v[4*ivar+3];
1006  }
1007 
1008  // IO size the FABs
1009  bdy_data_xlo.resize(num_time);
1010  bdy_data_xhi.resize(num_time);
1011  bdy_data_ylo.resize(num_time);
1012  bdy_data_yhi.resize(num_time);
1013  for (int itime(0); itime<num_time; ++itime) {
1014  bdy_data_xlo[itime].resize(num_var);
1015  bdy_data_xhi[itime].resize(num_var);
1016  bdy_data_ylo[itime].resize(num_var);
1017  bdy_data_yhi[itime].resize(num_var);
1018  for (int ivar(0); ivar<num_var; ++ivar) {
1019  bdy_data_xlo[itime][ivar].resize(bx_v[4*ivar ]);
1020  bdy_data_xhi[itime][ivar].resize(bx_v[4*ivar+1]);
1021  bdy_data_ylo[itime][ivar].resize(bx_v[4*ivar+2]);
1022  bdy_data_yhi[itime][ivar].resize(bx_v[4*ivar+3]);
1023  }
1024  }
1025 
1026  // Open data file and read from it
1027  std::ifstream bdy_d_file(MultiFabFileFullPrefix(0, restart_chkfile, "Level_", "bdy_D"));
1028  for (int itime(0); itime<num_time; ++itime) {
1029  for (int ivar(0); ivar<num_var; ++ivar) {
1030  bdy_data_xlo[itime][ivar].readFrom(bdy_d_file);
1031  bdy_data_xhi[itime][ivar].readFrom(bdy_d_file);
1032  bdy_data_ylo[itime][ivar].readFrom(bdy_d_file);
1033  bdy_data_yhi[itime][ivar].readFrom(bdy_d_file);
1034  }
1035  }
1036  } // IO
1037 
1038  // Broadcast the data
1039  ParallelDescriptor::Barrier();
1040  ParallelDescriptor::Bcast(&start_bdy_time,1,ioproc);
1041  ParallelDescriptor::Bcast(&bdy_time_interval,1,ioproc);
1042  ParallelDescriptor::Bcast(&real_width,1,ioproc);
1043  ParallelDescriptor::Bcast(&num_time,1,ioproc);
1044  ParallelDescriptor::Bcast(&num_var,1,ioproc);
1045 
1046  // Everyone size their boxes
1047  bx_v.resize(4*num_var);
1048 
1049  ParallelDescriptor::Bcast(bx_v.dataPtr(),bx_v.size(),ioproc);
1050 
1051  // Everyone but IO size their FABs
1052  if (!ParallelDescriptor::IOProcessor()) {
1053  bdy_data_xlo.resize(num_time);
1054  bdy_data_xhi.resize(num_time);
1055  bdy_data_ylo.resize(num_time);
1056  bdy_data_yhi.resize(num_time);
1057  for (int itime(0); itime<num_time; ++itime) {
1058  bdy_data_xlo[itime].resize(num_var);
1059  bdy_data_xhi[itime].resize(num_var);
1060  bdy_data_ylo[itime].resize(num_var);
1061  bdy_data_yhi[itime].resize(num_var);
1062  for (int ivar(0); ivar<num_var; ++ivar) {
1063  bdy_data_xlo[itime][ivar].resize(bx_v[4*ivar ]);
1064  bdy_data_xhi[itime][ivar].resize(bx_v[4*ivar+1]);
1065  bdy_data_ylo[itime][ivar].resize(bx_v[4*ivar+2]);
1066  bdy_data_yhi[itime][ivar].resize(bx_v[4*ivar+3]);
1067  }
1068  }
1069  }
1070 
1071  for (int itime(0); itime<num_time; ++itime) {
1072  for (int ivar(0); ivar<num_var; ++ivar) {
1073  ParallelDescriptor::Bcast(bdy_data_xlo[itime][ivar].dataPtr(),bdy_data_xlo[itime][ivar].box().numPts(),ioproc);
1074  ParallelDescriptor::Bcast(bdy_data_xhi[itime][ivar].dataPtr(),bdy_data_xhi[itime][ivar].box().numPts(),ioproc);
1075  ParallelDescriptor::Bcast(bdy_data_ylo[itime][ivar].dataPtr(),bdy_data_ylo[itime][ivar].box().numPts(),ioproc);
1076  ParallelDescriptor::Bcast(bdy_data_yhi[itime][ivar].dataPtr(),bdy_data_yhi[itime][ivar].box().numPts(),ioproc);
1077  }
1078  }
1079  } // init_type == WRFInput or Metgrid
1080 #endif
1081 #endif
1082 }
static void GotoNextLine(std::istream &is)
Definition: ERF_Checkpoint.cpp:16
void MakeNewLevelFromScratch(int lev, amrex::Real time, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm) override
Definition: ERF_MakeNewLevel.cpp:25
static void set_mesh_type(MeshType new_mesh_type)
Definition: ERF_DataStruct.H:1126
Here is the call graph for this function:

◆ ReadCheckpointFileSurfaceLayer()

void ERF::ReadCheckpointFileSurfaceLayer ( )

ERF function for reading additional data for MOST from a checkpoint file during restart.

This is called after the ABLMost object is instantiated.

1129 {
1130  for (int lev = 0; lev <= finest_level; ++lev)
1131  {
1132  amrex::Print() << "Reading MOST variables" << std::endl;
1133 
1134  IntVect ng(1,1,0);
1135  MultiFab m_var(ba2d[lev],dmap[lev],1,ng);
1136  MultiFab* dst = nullptr;
1137 
1138  // U*
1139  std::string UstarFileName(restart_chkfile + "/Level_0/Ustar_H");
1140  if (amrex::FileExists(UstarFileName)) {
1141  dst = m_SurfaceLayer->get_u_star(lev);
1142  VisMF::Read(m_var, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Ustar"));
1143  MultiFab::Copy(*dst,m_var,0,0,1,ng);
1144  }
1145 
1146  // W*
1147  std::string WstarFileName(restart_chkfile + "/Level_0/Wstar_H");
1148  if (amrex::FileExists(WstarFileName)) {
1149  dst = m_SurfaceLayer->get_w_star(lev);
1150  VisMF::Read(m_var, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Wstar"));
1151  MultiFab::Copy(*dst,m_var,0,0,1,ng);
1152  }
1153 
1154  // T*
1155  std::string TstarFileName(restart_chkfile + "/Level_0/Tstar_H");
1156  if (amrex::FileExists(TstarFileName)) {
1157  dst = m_SurfaceLayer->get_t_star(lev);
1158  VisMF::Read(m_var, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Tstar"));
1159  MultiFab::Copy(*dst,m_var,0,0,1,ng);
1160  }
1161 
1162  // Q*
1163  std::string QstarFileName(restart_chkfile + "/Level_0/Qstar_H");
1164  if (amrex::FileExists(QstarFileName)) {
1165  dst = m_SurfaceLayer->get_q_star(lev);
1166  VisMF::Read(m_var, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Qstar"));
1167  MultiFab::Copy(*dst,m_var,0,0,1,ng);
1168  }
1169 
1170  // Olen
1171  std::string OlenFileName(restart_chkfile + "/Level_0/Olen_H");
1172  if (amrex::FileExists(OlenFileName)) {
1173  dst = m_SurfaceLayer->get_olen(lev);
1174  VisMF::Read(m_var, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Olen"));
1175  MultiFab::Copy(*dst,m_var,0,0,1,ng);
1176  }
1177 
1178  // Qsurf
1179  std::string QsurfFileName(restart_chkfile + "/Level_0/Qsurf_H");
1180  if (amrex::FileExists(QsurfFileName)) {
1181  dst = m_SurfaceLayer->get_q_surf(lev);
1182  VisMF::Read(m_var, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Qsurf"));
1183  MultiFab::Copy(*dst,m_var,0,0,1,ng);
1184  }
1185 
1186  // PBLH
1187  std::string PBLHFileName(restart_chkfile + "/Level_0/PBLH_H");
1188  if (amrex::FileExists(PBLHFileName)) {
1189  dst = m_SurfaceLayer->get_pblh(lev);
1190  VisMF::Read(m_var, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "PBLH"));
1191  MultiFab::Copy(*dst,m_var,0,0,1,ng);
1192  }
1193 
1194  // Z0
1195  std::string Z0FileName(restart_chkfile + "/Level_0/Z0_H");
1196  if (amrex::FileExists(Z0FileName)) {
1197  dst = m_SurfaceLayer->get_z0(lev);
1198  VisMF::Read(m_var, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Z0"));
1199  MultiFab::Copy(*dst,m_var,0,0,1,ng);
1200  }
1201  }
1202 }

◆ ReadParameters()

void ERF::ReadParameters ( )
private
2401 {
2402  std::string prob_name = "Undefined";
2403  ParmParse pp_pn("erf");
2404  pp_pn.queryAdd("prob_name", prob_name);
2405  Print() << "Problem name (from inputs file) is: "
2406  << " \"" << prob_name << "\" " << std::endl;
2407 
2408  ParmParse pp(pp_prefix);
2409  ParmParse pp_amr("amr");
2410  {
2411  pp.query("regrid_level_0_on_restart", regrid_level_0_on_restart);
2412  pp.query("regrid_int", regrid_int);
2413  pp.query("check_file", check_file);
2414 
2415  // The regression tests use "amr.restart" and "amr.m_check_int" so we allow
2416  // for those or "erf.restart" / "erf.m_check_int" with the former taking
2417  // precedence if both are specified
2418  pp.query("check_int", m_check_int);
2419  pp.query("check_per", m_check_per);
2420  pp_amr.query("check_int", m_check_int);
2421  pp_amr.query("check_per", m_check_per);
2422 
2423  pp.query("restart", restart_chkfile);
2424  pp_amr.query("restart", restart_chkfile);
2425 
2426  // Verbosity
2427  pp.query("v", verbose);
2428  pp.query("mg_v", mg_verbose);
2429  pp.query("use_fft", use_fft);
2430 #ifndef ERF_USE_FFT
2431  if (use_fft) {
2432  Abort("You must build with USE_FFT in order to set use_fft = true in your inputs file");
2433  }
2434 #endif
2435 
2436  // Check for NaNs?
2437  pp.query("check_for_nans", check_for_nans);
2438 
2439  // Frequency of diagnostic output
2440  pp.query("sum_interval", sum_interval);
2441  pp.query("sum_period" , sum_per);
2442 
2443  pp.query("pert_interval", pert_interval);
2444 
2445  // Time step controls
2446  pp.query("cfl", cfl);
2447  pp.query("substepping_cfl", sub_cfl);
2448  pp.query("init_shrink", init_shrink);
2449  pp.query("change_max", change_max);
2450  pp.query("dt_max_initial", dt_max_initial);
2451  pp.query("dt_max", dt_max);
2452 
2453  fixed_dt.resize(max_level+1,-one);
2454  fixed_fast_dt.resize(max_level+1,-one);
2455 
2456  pp.query("fixed_dt", fixed_dt[0]);
2457  pp.query("fixed_fast_dt", fixed_fast_dt[0]);
2458 
2459  int nlevs_max = max_level + 1;
2460  istep.resize(nlevs_max, 0);
2461  nsubsteps.resize(nlevs_max, 1);
2462  // This is the default
2463  for (int lev = 1; lev <= max_level; ++lev) {
2464  nsubsteps[lev] = MaxRefRatio(lev-1);
2465  }
2466 
2467  if (max_level > 0) {
2468  ParmParse pp_erf("erf");
2469  int count = pp_erf.countval("dt_ref_ratio");
2470  if (count > 0) {
2471  Vector<int> nsub;
2472  nsub.resize(nlevs_max, 0);
2473  if (count == 1) {
2474  pp_erf.queryarr("dt_ref_ratio", nsub, 0, 1);
2475  for (int lev = 1; lev <= max_level; ++lev) {
2476  nsubsteps[lev] = nsub[0];
2477  }
2478  } else {
2479  pp_erf.queryarr("dt_ref_ratio", nsub, 0, max_level);
2480  for (int lev = 1; lev <= max_level; ++lev) {
2481  nsubsteps[lev] = nsub[lev-1];
2482  }
2483  }
2484  }
2485  }
2486 
2487  // Make sure we do this after we have defined nsubsteps above
2488  for (int lev = 1; lev <= max_level; lev++)
2489  {
2490  fixed_dt[lev] = fixed_dt[lev-1] / static_cast<Real>(nsubsteps[lev]);
2491  fixed_fast_dt[lev] = fixed_fast_dt[lev-1] / static_cast<Real>(nsubsteps[lev]);
2492  }
2493 
2494  pp.query("fixed_mri_dt_ratio", fixed_mri_dt_ratio);
2495 
2496  // We use this to keep track of how many boxes we read in from WRF initialization
2497  num_files_at_level.resize(max_level+1,0);
2498 
2499  // We use this to keep track of how many boxes are specified thru the refinement indicators
2500  num_boxes_at_level.resize(max_level+1,0);
2501  boxes_at_level.resize(max_level+1);
2502 
2503  // We always have exactly one file at level 0
2504  num_boxes_at_level[0] = 1;
2505  boxes_at_level[0].resize(1);
2506  boxes_at_level[0][0] = geom[0].Domain();
2507 
2508 #ifdef ERF_USE_NETCDF
2509  nc_init_file.resize(max_level+1);
2510  have_read_nc_init_file.resize(max_level+1);
2511 
2512  // NetCDF wrfinput initialization files -- possibly multiple files at each of multiple levels
2513  // but we always have exactly one file at level 0
2514  for (int lev = 0; lev <= max_level; lev++) {
2515  const std::string nc_file_names = Concatenate("nc_init_file_",lev,1);
2516  if (pp.contains(nc_file_names.c_str())) {
2517  int num_files = pp.countval(nc_file_names.c_str());
2518  num_files_at_level[lev] = num_files;
2519  nc_init_file[lev].resize(num_files);
2520  have_read_nc_init_file[lev].resize(num_files);
2521  pp.queryarr(nc_file_names.c_str(), nc_init_file[lev],0,num_files);
2522  for (int j = 0; j < num_files; j++) {
2523  Print() << "Reading NC init file names at level " << lev << " and index " << j << " : " << nc_init_file[lev][j] << std::endl;
2524  have_read_nc_init_file[lev][j] = 0;
2525  } // j
2526  } // if pp.contains
2527  } // lev
2528 
2529  // NetCDF wrfbdy lateral boundary file
2530  if (pp.query("nc_bdy_file", nc_bdy_file)) {
2531  Print() << "Reading NC bdy file name " << nc_bdy_file << std::endl;
2532  }
2533 
2534  // NetCDF wrflow lateral boundary file
2535  if (pp.query("nc_low_file", nc_low_file)) {
2536  Print() << "Reading NC low file name " << nc_low_file << std::endl;
2537  }
2538 
2539 #endif
2540 
2541  // Options for vertical interpolation of met_em*.nc data.
2542  pp.query("metgrid_debug_quiescent", metgrid_debug_quiescent);
2543  pp.query("metgrid_debug_isothermal", metgrid_debug_isothermal);
2544  pp.query("metgrid_debug_dry", metgrid_debug_dry);
2545  pp.query("metgrid_debug_psfc", metgrid_debug_psfc);
2546  pp.query("metgrid_debug_msf", metgrid_debug_msf);
2547  pp.query("metgrid_interp_theta", metgrid_interp_theta);
2548  pp.query("metgrid_basic_linear", metgrid_basic_linear);
2549  pp.query("metgrid_use_below_sfc", metgrid_use_below_sfc);
2550  pp.query("metgrid_use_sfc", metgrid_use_sfc);
2551  pp.query("metgrid_retain_sfc", metgrid_retain_sfc);
2552  pp.query("metgrid_proximity", metgrid_proximity);
2553  pp.query("metgrid_order", metgrid_order);
2554  pp.query("metgrid_force_sfc_k", metgrid_force_sfc_k);
2555 
2556  // Set default to FullState for now ... later we will try Perturbation
2557  interpolation_type = StateInterpType::FullState;
2558  pp.query_enum_case_insensitive("interpolation_type" ,interpolation_type);
2559 
2560  PlotFileType plotfile3d_type_temp = PlotFileType::None;
2561  pp.query_enum_case_insensitive("plotfile_type" ,plotfile3d_type_temp);
2562  pp.query_enum_case_insensitive("plotfile_type_1",plotfile3d_type_1);
2563  pp.query_enum_case_insensitive("plotfile_type_2",plotfile3d_type_2);
2564 
2565  PlotFileType plotfile2d_type_temp = PlotFileType::None;
2566  pp.query_enum_case_insensitive("plotfile2d_type" ,plotfile2d_type_temp);
2567  pp.query_enum_case_insensitive("plotfile2d_type_1",plotfile2d_type_1);
2568  pp.query_enum_case_insensitive("plotfile2d_type_2",plotfile2d_type_2);
2569  //
2570  // This option is for backward consistency -- if only plotfile_type is set,
2571  // then it will be used for both 1 and 2 if and only if they are not set
2572  //
2573  // Default is native amrex if no type is specified
2574  //
2575  if (plotfile3d_type_temp == PlotFileType::None) {
2576  if (plotfile3d_type_1 == PlotFileType::None) {
2577  plotfile3d_type_1 = PlotFileType::Amrex;
2578  }
2579  if (plotfile3d_type_2 == PlotFileType::None) {
2580  plotfile3d_type_2 = PlotFileType::Amrex;
2581  }
2582  } else {
2583  if (plotfile3d_type_1 == PlotFileType::None) {
2584  plotfile3d_type_1 = plotfile3d_type_temp;
2585  } else {
2586  Abort("You must set either plotfile_type or plotfile_type_1, not both");
2587  }
2588  if (plotfile3d_type_2 == PlotFileType::None) {
2589  plotfile3d_type_2 = plotfile3d_type_temp;
2590  } else {
2591  Abort("You must set either plotfile_type or plotfile_type_2, not both");
2592  }
2593  }
2594  if (plotfile2d_type_temp == PlotFileType::None) {
2595  if (plotfile2d_type_1 == PlotFileType::None) {
2596  plotfile2d_type_1 = PlotFileType::Amrex;
2597  }
2598  if (plotfile2d_type_2 == PlotFileType::None) {
2599  plotfile2d_type_2 = PlotFileType::Amrex;
2600  }
2601  } else {
2602  if (plotfile2d_type_1 == PlotFileType::None) {
2603  plotfile2d_type_1 = plotfile2d_type_temp;
2604  } else {
2605  Abort("You must set either plotfile2d_type or plotfile2d_type_1, not both");
2606  }
2607  if (plotfile2d_type_2 == PlotFileType::None) {
2608  plotfile2d_type_2 = plotfile2d_type_temp;
2609  } else {
2610  Abort("You must set either plotfile2d_type or plotfile2d_type_2, not both");
2611  }
2612  }
2613 #ifndef ERF_USE_NETCDF
2614  if (plotfile3d_type_1 == PlotFileType::Netcdf ||
2615  plotfile3d_type_2 == PlotFileType::Netcdf ||
2616  plotfile2d_type_1 == PlotFileType::Netcdf ||
2617  plotfile2d_type_2 == PlotFileType::Netcdf) {
2618  Abort("Plotfile type = Netcdf is not allowed without USE_NETCDF = TRUE");
2619  }
2620 #endif
2621 
2622  pp.query("plot_file_1" , plot3d_file_1);
2623  pp.query("plot_file_2" , plot3d_file_2);
2624  pp.query("plot2d_file_1", plot2d_file_1);
2625  pp.query("plot2d_file_2", plot2d_file_2);
2626 
2627  pp.query("plot_int_1" , m_plot3d_int_1);
2628  pp.query("plot_int_2" , m_plot3d_int_2);
2629  pp.query("plot_per_1" , m_plot3d_per_1);
2630  pp.query("plot_per_2" , m_plot3d_per_2);
2631 
2632  pp.query("plot2d_int_1" , m_plot2d_int_1);
2633  pp.query("plot2d_int_2" , m_plot2d_int_2);
2634  pp.query("plot2d_per_1", m_plot2d_per_1);
2635  pp.query("plot2d_per_2", m_plot2d_per_2);
2636 
2637  pp.query("subvol_file", subvol_file);
2638 
2639  // Should we use format like plt1970-01-01_00:00:Real(00.000000) (if true) or plt00001 (if false)
2640  pp.query("use_real_time_in_pltname", use_real_time_in_pltname);
2641 
2642  // If use_real_time_in_pltname is false, how many digits should we use for the timestep?
2643  pp.query("file_name_digits", file_name_digits);
2644 
2645  // Default if subvol_int not specified
2646  m_subvol_int.resize(1); m_subvol_int[0] = -1;
2647  m_subvol_per.resize(1); m_subvol_per[0] = -one;
2648  last_subvol_step.resize(1);
2649  last_subvol_time.resize(1);
2650 
2651  int nsi = pp.countval("subvol_int");
2652  int nsr = pp.countval("subvol_per");
2653 
2654  // We must specify only subvol_int OR subvol_per
2655  AMREX_ALWAYS_ASSERT (!(nsi > 0 && nsr > 0));
2656 
2657  int nsub = -1;
2658  if (nsi > 0 || nsr > 0) {
2659  ParmParse pp_sv("erf.subvol");
2660  int n1 = pp_sv.countval("origin"); int n2 = pp_sv.countval("nxnynz"); int n3 = pp_sv.countval("dxdydz");
2661  if (n1 != n2 || n1 != n3 || n2 != n3) {
2662  Abort("WriteSubvolume: must have same number of entries in origin, nxnynz, and dxdydz.");
2663  }
2664  if ( n1%AMREX_SPACEDIM != 0) {
2665  Abort("WriteSubvolume: origin, nxnynz, and dxdydz must have multiples of AMReX_SPACEDIM");
2666  }
2667  nsub = n1/AMREX_SPACEDIM;
2668  m_subvol_int.resize(nsub);
2669  last_subvol_step.resize(nsub);
2670  last_subvol_time.resize(nsub);
2671  m_subvol_int.resize(nsub);
2672  m_subvol_per.resize(nsub);
2673  }
2674 
2675  if (nsi > 0) {
2676  for (int i = 1; i < nsub; i++) m_subvol_per[i] = -one;
2677  if ( nsi == 1) {
2678  m_subvol_int[0] = -1;
2679  pp.get("subvol_int" , m_subvol_int[0]);
2680  } else if ( nsi == nsub) {
2681  pp.getarr("subvol_int" , m_subvol_int);
2682  } else {
2683  Abort("There must either be a single value of subvol_int or one for every subdomain");
2684  }
2685  }
2686 
2687  if (nsr > 0) {
2688  for (int i = 1; i < nsub; i++) m_subvol_int[i] = -static_cast<int>(one);
2689  if ( nsr == 1) {
2690  m_subvol_per[0] = -one;
2691  pp.get("subvol_per" , m_subvol_per[0]);
2692  } else if ( nsr == nsub) {
2693  pp.getarr("subvol_per" , m_subvol_per);
2694  } else {
2695  Abort("There must either be a single value of subvol_per or one for every subdomain");
2696  }
2697  }
2698 
2699  setSubVolVariables("subvol_sampling_vars",subvol3d_var_names);
2700 
2701  pp.query("expand_plotvars_to_unif_rr",m_expand_plotvars_to_unif_rr);
2702 
2703  pp.query("plot_face_vels",m_plot_face_vels);
2704 
2705  if ( (m_plot3d_int_1 > 0 && m_plot3d_per_1 > 0) ||
2706  (m_plot3d_int_2 > 0 && m_plot3d_per_2 > zero) ) {
2707  Abort("Must choose only one of plot_int or plot_per");
2708  }
2709  if ( (m_plot2d_int_1 > 0 && m_plot2d_per_1 > 0) ||
2710  (m_plot2d_int_2 > 0 && m_plot2d_per_2 > zero) ) {
2711  Abort("Must choose only one of plot_int or plot_per");
2712  }
2713 
2714  pp.query("profile_int", profile_int);
2715  pp.query("destag_profiles", destag_profiles);
2716 
2717  pp.query("plot_lsm", plot_lsm);
2718 #ifdef ERF_USE_RRTMGP
2719  pp.query("plot_rad", plot_rad);
2720 #endif
2721  pp.query("profile_rad_int", rad_datalog_int);
2722 
2723  pp.query("output_1d_column", output_1d_column);
2724  pp.query("column_per", column_per);
2725  pp.query("column_interval", column_interval);
2726  pp.query("column_loc_x", column_loc_x);
2727  pp.query("column_loc_y", column_loc_y);
2728  pp.query("column_file_name", column_file_name);
2729 
2730  // Sampler output frequency
2731  pp.query("line_sampling_per", line_sampling_per);
2732  pp.query("line_sampling_interval", line_sampling_interval);
2733  pp.query("plane_sampling_per", plane_sampling_per);
2734  pp.query("plane_sampling_interval", plane_sampling_interval);
2735 
2736  // Specify information about outputting planes of data
2737  pp.query("output_bndry_planes", output_bndry_planes);
2738  pp.query("bndry_output_planes_interval", bndry_output_planes_interval);
2739  pp.query("bndry_output_planes_per", bndry_output_planes_per);
2740  pp.query("bndry_output_start_time", bndry_output_planes_start_time);
2741 
2742  // Specify whether ingest boundary planes of data
2743  pp.query("input_bndry_planes", input_bndry_planes);
2744 
2745  // Query the total width for wrfbdy interior ghost cells
2746  pp.query("real_width", real_width);
2747 
2748  // If using real boundaries, do we extrapolate w (or set to 0)
2749  pp.query("real_extrap_w", real_extrap_w);
2750 
2751  // Query the set and total widths for crse-fine interior ghost cells
2752  pp.query("cf_width", cf_width);
2753  pp.query("cf_set_width", cf_set_width);
2754 
2755  // AmrMesh iterate on grids?
2756  bool iterate(true);
2757  pp_amr.query("iterate_grids",iterate);
2758  if (!iterate) SetIterateToFalse();
2759  }
2760 
2761 #ifdef ERF_USE_PARTICLES
2762  readTracersParams();
2763 #endif
2764 
2765  solverChoice.init_params(max_level,pp_prefix);
2766 
2767  {
2768  ParmParse pp_no_prefix; // Traditionally, max_step and stop_time do not have prefix.
2769  pp_no_prefix.query("max_step", max_step);
2770  if (max_step < 0) {
2771  max_step = std::numeric_limits<int>::max();
2772  }
2773 
2774  std::string start_datetime, stop_datetime;
2775  if (pp_no_prefix.query("start_datetime", start_datetime)) {
2776  if (start_datetime.length() == 16) { // YYYY-MM-DD HH:MM
2777  start_datetime += ":00"; // add seconds
2778  }
2779  if (start_datetime.length() != 19) {
2780  Print() << "Got start_datetime = \"" << start_datetime
2781  << "\", format should be " << datetime_format << std::endl;
2782  exit(0);
2783  }
2784  start_time = static_cast<amrex::Real>(getEpochTime(start_datetime, datetime_format));
2785 
2786 #ifdef ERF_USE_NETCDF
2787  if (solverChoice.init_type == InitType::WRFInput) {
2788  // This is the start time as written in the wrfinput file
2789  Real start_time_from_wrfinput = read_start_time_from_wrfinput(0, nc_init_file[0][0]);
2790  if (start_time != start_time_from_wrfinput) {
2791  amrex::Print() << "start_datetime from inputs file = " << start_time <<
2792  " does not match SIMULATION START DATE from wrfinput = " <<
2793  start_time_from_wrfinput << std::endl;
2794  amrex::Abort();
2795  }
2796  } else if (solverChoice.init_type == InitType::Metgrid) {
2797  // This is the start time as written in the metgrid file
2798  Real start_time_from_metgrid = read_start_time_from_metgrid(0, nc_init_file[0][0]);
2799  if (start_time != start_time_from_metgrid) {
2800  amrex::Print() << "start_datetime from inputs file = " << start_time <<
2801  " does not match SIMULATION START DATE from metgrid = " <<
2802  start_time_from_metgrid << std::endl;
2803  amrex::Abort();
2804  }
2805  }
2806 #endif
2807  Print() << "Start datetime : " << start_datetime << std::endl;
2808 
2809  use_datetime = true;
2810 
2811  } else {
2812 
2813 #ifdef ERF_USE_NETCDF
2814  if (solverChoice.init_type == InitType::WRFInput) {
2815  // This is the start time as written in the wrfinput file
2816  Real start_time_from_wrfinput = read_start_time_from_wrfinput(0, nc_init_file[0][0]);
2817  start_time = start_time_from_wrfinput;
2818 
2819  use_datetime = true;
2820 
2821  if (pp_no_prefix.query("start_time", start_time)) {
2822  amrex::Print() << "start_time should not be set from inputs file; we are reading SIMULATION START DATE from wrfinput" << std::endl;
2823  amrex::Abort();
2824  }
2825  } else if (solverChoice.init_type == InitType::Metgrid) {
2826  // This is the start time as written in the metgrid file
2827  Real start_time_from_metgrid = read_start_time_from_metgrid(0, nc_init_file[0][0]);
2828  start_time = start_time_from_metgrid;
2829 
2830  use_datetime = true;
2831 
2832  if (pp_no_prefix.query("start_time", start_time)) {
2833  amrex::Print() << "start_time should not be set from inputs file; we are reading SIMULATION START DATE from metgrid" << std::endl;
2834  amrex::Abort();
2835  }
2836  }
2837 #endif
2838  }
2839 
2840  if (pp_no_prefix.query("stop_datetime", stop_datetime)) {
2841  if (stop_datetime.length() == 16) { // YYYY-MM-DD HH:MM
2842  stop_datetime += ":00"; // add seconds
2843  }
2844  if (stop_datetime.length() != 19) {
2845  Print() << "Got stop_datetime = \"" << stop_datetime
2846  << "\", format should be " << datetime_format << std::endl;
2847  exit(0);
2848  }
2849 
2850  stop_time = static_cast<amrex::Real>(getEpochTime(stop_datetime, datetime_format));
2851  Print() << "Stop datetime : " << start_datetime << std::endl;
2852 
2853  } else {
2854 
2855  if (pp_no_prefix.query("stop_time", stop_time)) {
2856  Print() << "Maximum simulation length based on stop_time: " << stop_time << " s (elapsed) " << std::endl;
2857  amrex::Print() <<" Adding stop time " << stop_time << " to start_time " << start_time << std::endl;
2858  stop_time += start_time;
2859  }
2860  }
2861  }
2862 
2863 #ifndef ERF_USE_NETCDF
2864  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(( (solverChoice.init_type != InitType::WRFInput) &&
2865  (solverChoice.init_type != InitType::Metgrid ) &&
2866  (solverChoice.init_type != InitType::NCFile ) ),
2867  "init_type cannot be 'WRFInput', 'Metgrid' or 'NCFile' if we don't build with netcdf!");
2868 #endif
2869 
2870  // Query the canopy model file name
2871  std::string forestfile;
2872  solverChoice.do_forest_drag = pp.query("forest_file", forestfile);
2874  for (int lev = 0; lev <= max_level; ++lev) {
2875  m_forest_drag[lev] = std::make_unique<ForestDrag>(forestfile);
2876  }
2877  }
2878 
2879  // If init from WRFInput or Metgrid make sure a valid file name is present at level zero
2880  // We allow for the possibility that finer levels may use native refinement rather than reading from a file
2881  if ((solverChoice.init_type == InitType::WRFInput) ||
2882  (solverChoice.init_type == InitType::Metgrid) ||
2883  (solverChoice.init_type == InitType::NCFile) ) {
2884  int num_files = static_cast<int>(nc_init_file[0].size());
2885  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(num_files>0, "A file name must be present at level 0 for init type WRFInput, Metgrid or NCFile.");
2886  for (int j = 0; j < num_files; j++) {
2887  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(!nc_init_file[0][j].empty(), "Valid file name must be present at level 0 for init type WRFInput, Metgrid or NCFile.");
2888  } //j
2889  } // InitType
2890 
2891  // What type of land surface model to use
2892  // NOTE: Must be checked after init_params
2893  if (solverChoice.lsm_type == LandSurfaceType::SLM) {
2894  lsm.SetModel<SLM>();
2895  Print() << "SLM land surface model!\n";
2896  } else if (solverChoice.lsm_type == LandSurfaceType::MM5) {
2897  lsm.SetModel<MM5>();
2898  Print() << "MM5 land surface model!\n";
2899 #ifdef ERF_USE_NOAHMP
2900  } else if (solverChoice.lsm_type == LandSurfaceType::NOAHMP) {
2901  lsm.SetModel<NOAHMP>();
2902  Print() << "Noah-MP land surface model!\n";
2903 #endif
2904  } else if (solverChoice.lsm_type == LandSurfaceType::None) {
2905  lsm.SetModel<NullSurf>();
2906  Print() << "Null land surface model!\n";
2907  } else {
2908  Abort("Dont know this LandSurfaceType!") ;
2909  }
2910 
2911  if (verbose > 0) {
2912  solverChoice.display(max_level,pp_prefix);
2913  }
2914 
2916 }
AMREX_GPU_HOST AMREX_FORCE_INLINE std::time_t getEpochTime(const std::string &dateTime, const std::string &dateTimeFormat)
Definition: ERF_EpochTime.H:34
bool metgrid_basic_linear
Definition: ERF.H:1289
bool metgrid_debug_msf
Definition: ERF.H:1287
std::string plot2d_file_2
Definition: ERF.H:1112
std::string plot3d_file_1
Definition: ERF.H:1109
bool plot_rad
Definition: ERF.H:925
bool m_plot_face_vels
Definition: ERF.H:1127
std::string plot3d_file_2
Definition: ERF.H:1110
int regrid_int
Definition: ERF.H:1102
bool metgrid_retain_sfc
Definition: ERF.H:1292
int file_name_digits
Definition: ERF.H:1265
bool metgrid_use_sfc
Definition: ERF.H:1291
amrex::Vector< int > num_files_at_level
Definition: ERF.H:832
bool metgrid_debug_quiescent
Definition: ERF.H:1283
bool metgrid_interp_theta
Definition: ERF.H:1288
bool regrid_level_0_on_restart
Definition: ERF.H:1106
int metgrid_force_sfc_k
Definition: ERF.H:1295
void setSubVolVariables(const std::string &pp_subvol_var_names, amrex::Vector< std::string > &subvol_var_names)
Definition: ERF_WriteSubvolume.cpp:9
bool real_extrap_w
Definition: ERF.H:1277
bool metgrid_use_below_sfc
Definition: ERF.H:1290
std::string subvol_file
Definition: ERF.H:1113
amrex::Real metgrid_proximity
Definition: ERF.H:1293
std::string plot2d_file_1
Definition: ERF.H:1111
bool metgrid_debug_dry
Definition: ERF.H:1285
bool metgrid_debug_isothermal
Definition: ERF.H:1284
bool use_real_time_in_pltname
Definition: ERF.H:1266
bool metgrid_debug_psfc
Definition: ERF.H:1286
void ParameterSanityChecks()
Definition: ERF.cpp:2920
bool m_expand_plotvars_to_unif_rr
Definition: ERF.H:1114
std::string check_file
Definition: ERF.H:1136
int metgrid_order
Definition: ERF.H:1294
bool plot_lsm
Definition: ERF.H:1129
void SetModel()
Definition: ERF_LandSurface.H:29
Definition: ERF_MM5.H:26
Definition: ERF_NOAHMP.H:84
Definition: ERF_NullSurf.H:8
Definition: ERF_SLM.H:26
void display(int max_level, std::string pp_prefix)
Definition: ERF_DataStruct.H:910
void init_params(int max_level, std::string pp_prefix)
Definition: ERF_DataStruct.H:143
Here is the call graph for this function:

◆ ReadVelsOnlyFromCheckpointFile()

void ERF::ReadVelsOnlyFromCheckpointFile ( int  lev_to_fill,
std::string &  chkfile_for_vels 
)

ERF function for reading data from a checkpoint file during restart.

1089 {
1090  Print() << "Reading vels only from native checkpoint " << chkfile_for_vels << " at level " << lev_to_fill << "\n";
1091 
1092  // Header
1093  std::string File(chkfile_for_vels + "/Header");
1094 
1095  VisMF::IO_Buffer io_buffer(VisMF::GetIOBufferSize());
1096 
1097  Vector<char> fileCharPtr;
1098  ParallelDescriptor::ReadAndBcastFile(File, fileCharPtr);
1099  std::string fileCharPtrString(fileCharPtr.dataPtr());
1100  std::istringstream is(fileCharPtrString, std::istringstream::in);
1101 
1102  AMREX_ALWAYS_ASSERT(lev_to_fill >= 0 && lev_to_fill <= finest_level);
1103 
1104  int lev = lev_to_fill;
1105 
1106  MultiFab xvel(convert(grids[lev],IntVect(1,0,0)),dmap[lev],1,0);
1107  VisMF::Read(xvel, MultiFabFileFullPrefix(lev, chkfile_for_vels, "Level_", "XFace"));
1108  MultiFab::Copy(vars_new[lev][Vars::xvel],xvel,0,0,1,0);
1109  vars_new[lev][Vars::xvel].setBndry(Real(1.0e34));
1110 
1111  MultiFab yvel(convert(grids[lev],IntVect(0,1,0)),dmap[lev],1,0);
1112  VisMF::Read(yvel, MultiFabFileFullPrefix(lev, chkfile_for_vels, "Level_", "YFace"));
1113  MultiFab::Copy(vars_new[lev][Vars::yvel],yvel,0,0,1,0);
1114  vars_new[lev][Vars::yvel].setBndry(Real(1.0e34));
1115 
1116  MultiFab zvel(convert(grids[lev],IntVect(0,0,1)),dmap[lev],1,0);
1117  VisMF::Read(zvel, MultiFabFileFullPrefix(lev, chkfile_for_vels, "Level_", "ZFace"));
1118  MultiFab::Copy(vars_new[lev][Vars::zvel],zvel,0,0,1,0);
1119  vars_new[lev][Vars::zvel].setBndry(Real(1.0e34));
1120 }
Here is the call graph for this function:

◆ refinement_criteria_setup()

void ERF::refinement_criteria_setup ( )
private

Function to define the refinement criteria based on user input

465 {
466  if (max_level > 0)
467  {
468  ParmParse pp(pp_prefix);
469  Vector<std::string> refinement_indicators;
470  pp.queryarr("refinement_indicators",refinement_indicators,0,pp.countval("refinement_indicators"));
471 
472  for (int i=0; i<refinement_indicators.size(); ++i)
473  {
474  std::string ref_prefix = pp_prefix + "." + refinement_indicators[i];
475 
476  ParmParse ppr(ref_prefix);
477  RealBox realbox;
478  int lev_for_box;
479 
480  int num_real_lo = ppr.countval("in_box_lo");
481  int num_indx_lo = ppr.countval("in_box_lo_indices");
482  int num_indx_lo_crse = ppr.countval("in_box_lo_indices_crse");
483 
484  int num_real_hi = ppr.countval("in_box_hi");
485  int num_indx_hi = ppr.countval("in_box_hi_indices");
486  int num_indx_hi_crse = ppr.countval("in_box_hi_indices_crse");
487 
488  AMREX_ALWAYS_ASSERT( (num_real_lo == num_real_hi) && (num_real_lo == 0 || num_real_lo >= 2) );
489  AMREX_ALWAYS_ASSERT( (num_indx_lo == num_indx_hi) && (num_indx_lo == 0 || num_indx_lo >= 2) );
490  AMREX_ALWAYS_ASSERT( (num_indx_lo_crse == num_indx_hi_crse) && (num_indx_lo_crse == 0 || num_indx_lo_crse >= 2) );
491 
492  // Problem low and high (in real not index space) are the same at all levels
493  const Real* plo = geom[0].ProbLo();
494  const Real* phi = geom[0].ProbHi();
495  if ( !((num_real_lo >= AMREX_SPACEDIM-1 && num_indx_lo == 0 && num_indx_lo_crse == 0) ||
496  (num_indx_lo >= AMREX_SPACEDIM-1 && num_real_lo == 0 && num_indx_lo_crse == 0) ||
497  (num_indx_lo == 0 && num_real_lo == 0 && num_indx_lo_crse == 0) ||
498  (num_indx_lo_crse >= AMREX_SPACEDIM-1 && num_real_lo == 0 && num_indx_lo == 0)
499  ) )
500  {
501  amrex::Abort("Must only specify box for refinement using real OR index space with fine/coarse grid indices");
502  }
503 
504  if (num_real_lo > 0) {
505  std::vector<Real> rbox_lo(3), rbox_hi(3);
506  lev_for_box = max_level;
507  ppr.query("max_level",lev_for_box);
508 
509  if (lev_for_box > 0 && lev_for_box <= max_level)
510  {
511  if (n_error_buf[0] != IntVect::TheZeroVector()) {
512  amrex::Abort("Don't use n_error_buf > 0 when setting the box explicitly");
513  }
514 
515  ppr.getarr("in_box_lo",rbox_lo,0,num_real_lo);
516  ppr.getarr("in_box_hi",rbox_hi,0,num_real_hi);
517 
518  if (rbox_lo[0] < plo[0]) rbox_lo[0] = plo[0];
519  if (rbox_lo[1] < plo[1]) rbox_lo[1] = plo[1];
520  if (rbox_hi[0] > phi[0]) rbox_hi[0] = phi[0];
521  if (rbox_hi[1] > phi[1]) rbox_hi[1] = phi[1];
522  if (num_real_lo < AMREX_SPACEDIM) {
523  rbox_lo[2] = plo[2];
524  rbox_hi[2] = phi[2];
525  }
526 
527  const Box& domain = geom[lev_for_box].Domain();
528 
529  realbox = RealBox(&(rbox_lo[0]),&(rbox_hi[0]));
530 
531  Print() << "Realbox read in and intersected laterally with domain is " << realbox << std::endl;
532 
533  num_boxes_at_level[lev_for_box] += 1;
534 
535  int ilo, jlo, klo;
536  int ihi, jhi, khi;
537  const auto* dx = geom[lev_for_box].CellSize();
538  ilo = static_cast<int>((rbox_lo[0] - plo[0])/dx[0]);
539  jlo = static_cast<int>((rbox_lo[1] - plo[1])/dx[1]);
540  ihi = static_cast<int>((rbox_hi[0] - plo[0])/dx[0]-1);
541  jhi = static_cast<int>((rbox_hi[1] - plo[1])/dx[1]-1);
542  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
543  // Search for k indices corresponding to nominal grid
544  // AGL heights
545  klo = domain.smallEnd(2) - 1;
546  khi = domain.smallEnd(2) - 1;
547 
548  if (rbox_lo[2] <= zlevels_stag[lev_for_box][domain.smallEnd(2)])
549  {
550  klo = domain.smallEnd(2);
551  }
552  else
553  {
554  for (int k=domain.smallEnd(2); k<=domain.bigEnd(2)+1; ++k) {
555  if (zlevels_stag[lev_for_box][k] > rbox_lo[2]) {
556  klo = k-1;
557  break;
558  }
559  }
560  }
561  AMREX_ASSERT(klo >= domain.smallEnd(2));
562 
563  if (rbox_hi[2] >= zlevels_stag[lev_for_box][domain.bigEnd(2)+1])
564  {
565  khi = domain.bigEnd(2);
566  }
567  else
568  {
569  for (int k=klo+1; k<=domain.bigEnd(2)+1; ++k) {
570  if (zlevels_stag[lev_for_box][k] > rbox_hi[2]) {
571  khi = k-1;
572  break;
573  }
574  }
575  }
576  AMREX_ASSERT((khi <= domain.bigEnd(2)) && (khi > klo));
577 
578  // Need to update realbox because tagging is based on
579  // the initial _un_deformed grid
580  realbox = RealBox(plo[0]+ ilo *dx[0], plo[1]+ jlo *dx[1], plo[2]+ klo *dx[2],
581  plo[0]+(ihi+1)*dx[0], plo[1]+(jhi+1)*dx[1], plo[2]+(khi+1)*dx[2]);
582  } else {
583  klo = static_cast<int>((rbox_lo[2] - plo[2])/dx[2]);
584  khi = static_cast<int>((rbox_hi[2] - plo[2])/dx[2]-1);
585  }
586 
587  // Snap box indices to ref_ratio alignment (round lo down, hi up)
588  {
589  const auto& rr = ref_ratio[lev_for_box-1];
590  auto snap_lo = [](int idx, int r) { return idx - (idx % r + r) % r; };
591  auto snap_hi = [](int idx_p1, int r) { // idx_p1 = ihi+1
592  int rem = idx_p1 % r;
593  return (rem == 0) ? idx_p1 - 1 : idx_p1 + (r - rem) - 1;
594  };
595  int ilo_old = ilo, jlo_old = jlo, klo_old = klo;
596  int ihi_old = ihi, jhi_old = jhi, khi_old = khi;
597  ilo = snap_lo(ilo, rr[0]);
598  jlo = snap_lo(jlo, rr[1]);
599  klo = snap_lo(klo, rr[2]);
600  ihi = snap_hi(ihi+1, rr[0]);
601  jhi = snap_hi(jhi+1, rr[1]);
602  khi = snap_hi(khi+1, rr[2]);
603  if (ilo != ilo_old || ihi != ihi_old ||
604  jlo != jlo_old || jhi != jhi_old ||
605  klo != klo_old || khi != khi_old) {
606  amrex::Print() << "Refinement box indices snapped to ref_ratio alignment:\n"
607  << " ilo: " << ilo_old << " -> " << ilo
608  << " ihi: " << ihi_old << " -> " << ihi
609  << " jlo: " << jlo_old << " -> " << jlo
610  << " jhi: " << jhi_old << " -> " << jhi
611  << " klo: " << klo_old << " -> " << klo
612  << " khi: " << khi_old << " -> " << khi << "\n";
613  }
614  }
615 
616  Box bx(IntVect(ilo,jlo,klo),IntVect(ihi,jhi,khi));
617 
618  bool using_pbl = (solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::MYJ ||
619  solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::MYNN25 ||
620  solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::MYNNEDMF ||
621  solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::YSU ||
622  solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::MRF);
623 
624  if ( using_pbl && ( (rbox_lo[2] > plo[2]) || (rbox_hi[2] < phi[2]) ) ) {
625  amrex::Print() << "PBL models need refinement boxes that go from the bottom to the top of the domain for calculation of PBLH" << std::endl;
626  amrex::Print() << "Please set in_box_lo to geometry.prob_lo in z and in_box_hi to geometry.prob_hi in z and try again" << std::endl;
627  amrex::Abort();
628  }
629 
630  boxes_at_level[lev_for_box].push_back(bx);
631  Print() << "Saving in 'boxes at level' as " << bx << std::endl;
632  } // (lev_for_box > 0 && lev_for_box <= max_level)
633 
634  if (solverChoice.init_type == InitType::WRFInput) {
635  amrex::Print() << "Size of num_boxes " << num_boxes_at_level.size() << std::endl;
636  amrex::Print() << "Size of num_files " << num_files_at_level.size() << std::endl;
637  amrex::Print() << "Consider lev_for_box = " << lev_for_box << std::endl;
638  amrex::Print() << "Number of boxes at level " << num_boxes_at_level[lev_for_box] << std::endl;
639  amrex::Print() << "Number of available files " << num_files_at_level[lev_for_box] << std::endl;
640  if (num_boxes_at_level[lev_for_box] != num_files_at_level[lev_for_box]) {
641  amrex::Print() << "Will need to rely on refinement criteria from inputs file" << std::endl;
642  }
643  }
644 
645  } else if (num_indx_lo > 0) {
646 
647  std::vector<int> box_lo(3), box_hi(3);
648  ppr.get("max_level",lev_for_box);
649  if (lev_for_box > 0 && lev_for_box <= max_level)
650  {
651  if (n_error_buf[0] != IntVect::TheZeroVector()) {
652  amrex::Abort("Don't use n_error_buf > 0 when setting the box explicitly");
653  }
654 
655  ppr.getarr("in_box_lo_indices",box_lo,0,num_indx_lo);
656  ppr.getarr("in_box_hi_indices",box_hi,0,num_indx_hi);
657 
658  if (num_indx_lo < AMREX_SPACEDIM) {
659  box_lo[2] = geom[lev_for_box].Domain().smallEnd(2);
660  box_hi[2] = geom[lev_for_box].Domain().bigEnd(2);
661  }
662 
663  Box bx(IntVect(box_lo[0],box_lo[1],box_lo[2]),IntVect(box_hi[0],box_hi[1],box_hi[2]));
664  const Box& domain = geom[lev_for_box].Domain();
665 
666  if (!domain.contains(bx)) {
667  amrex::Print() << "\n";
668  amrex::Print() << "Box specified is " << bx << std::endl;
669  amrex::Print() << "But domain at level is " << domain << std::endl;
670  amrex::Error("Specified box doesn't fit in the domain");
671  }
672 
673  const auto* dx = geom[lev_for_box].CellSize();
674  realbox = RealBox(plo[0]+ box_lo[0] *dx[0], plo[1]+ box_lo[1] *dx[1], plo[2]+ box_lo[2] *dx[2],
675  plo[0]+(box_hi[0]+1)*dx[0], plo[1]+(box_hi[1]+1)*dx[1], plo[2]+(box_hi[2]+1)*dx[2]);
676 
677  Print() << "Reading " << bx << " at level " << lev_for_box << std::endl;
678  num_boxes_at_level[lev_for_box] += 1;
679 
680  // Snap box indices to ref_ratio alignment (round lo down, hi up)
681  {
682  const auto& rr = ref_ratio[lev_for_box-1];
683  auto snap_lo_fn = [](int idx, int r) { return idx - (idx % r + r) % r; };
684  auto snap_hi_fn = [](int idx_p1, int r) {
685  int rem = idx_p1 % r;
686  return (rem == 0) ? idx_p1 - 1 : idx_p1 + (r - rem) - 1;
687  };
688  int lo_old[3] = {box_lo[0], box_lo[1], box_lo[2]};
689  int hi_old[3] = {box_hi[0], box_hi[1], box_hi[2]};
690  box_lo[0] = snap_lo_fn(box_lo[0], rr[0]);
691  box_lo[1] = snap_lo_fn(box_lo[1], rr[1]);
692  box_lo[2] = snap_lo_fn(box_lo[2], rr[2]);
693  box_hi[0] = snap_hi_fn(box_hi[0]+1, rr[0]);
694  box_hi[1] = snap_hi_fn(box_hi[1]+1, rr[1]);
695  box_hi[2] = snap_hi_fn(box_hi[2]+1, rr[2]);
696  if (box_lo[0] != lo_old[0] || box_hi[0] != hi_old[0] ||
697  box_lo[1] != lo_old[1] || box_hi[1] != hi_old[1] ||
698  box_lo[2] != lo_old[2] || box_hi[2] != hi_old[2]) {
699  amrex::Print() << "Refinement box indices snapped to ref_ratio alignment:\n"
700  << " ilo: " << lo_old[0] << " -> " << box_lo[0]
701  << " ihi: " << hi_old[0] << " -> " << box_hi[0]
702  << " jlo: " << lo_old[1] << " -> " << box_lo[1]
703  << " jhi: " << hi_old[1] << " -> " << box_hi[1]
704  << " klo: " << lo_old[2] << " -> " << box_lo[2]
705  << " khi: " << hi_old[2] << " -> " << box_hi[2] << "\n";
706  }
707  bx = Box(IntVect(box_lo[0],box_lo[1],box_lo[2]),
708  IntVect(box_hi[0],box_hi[1],box_hi[2]));
709  }
710 
711  bool using_pbl = (solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::MYJ ||
712  solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::MYNN25 ||
713  solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::MYNNEDMF ||
714  solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::YSU ||
715  solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::MRF);
716 
717  if ( using_pbl && ( (box_lo[2] > 0) || (box_hi[2] < domain.bigEnd(2)) ) ) {
718  amrex::Print() << "PBL models need refinement boxes that go from the bottom to the top of the domain for calculation of PBLH" << std::endl;
719  amrex::Print() << "Please set in_box_lo_indices to 0 in z and in_box_hi_indices to amr.n_cell-1 in z and try again" << std::endl;
720  amrex::Abort();
721  }
722 
723  boxes_at_level[lev_for_box].push_back(bx);
724  Print() << "Saving in 'boxes at level' as " << bx << std::endl;
725  } // lev
726 
727  if (solverChoice.init_type == InitType::WRFInput) {
728  if ( (num_files_at_level[lev_for_box] > 0) &&
729  (num_boxes_at_level[lev_for_box] != num_files_at_level[lev_for_box]) ) {
730  amrex::Error("Number of boxes doesn't match number of input files");
731 
732  }
733  }
734 
735  } else if (num_indx_lo_crse > 0) {
736 
737  std::vector<int> box_lo(3), box_hi(3);
738  ppr.get("max_level",lev_for_box);
739  if (lev_for_box > 0 && lev_for_box <= max_level)
740  {
741  if (n_error_buf[0] != IntVect::TheZeroVector()) {
742  amrex::Abort("Don't use n_error_buf > 0 when setting the box explicitly");
743  }
744 
745  ppr.getarr("in_box_lo_indices_crse",box_lo,0,num_indx_lo_crse);
746  ppr.getarr("in_box_hi_indices_crse",box_hi,0,num_indx_hi_crse);
747 
748  if (num_indx_lo_crse < AMREX_SPACEDIM) {
749  box_lo[2] = geom[lev_for_box-1].Domain().smallEnd(2);
750  box_hi[2] = geom[lev_for_box-1].Domain().bigEnd(2);
751  }
752 
753  Box bx(IntVect(box_lo[0],box_lo[1],box_lo[2]),IntVect(box_hi[0],box_hi[1],box_hi[2]));
754 
755  if (!geom[lev_for_box-1].Domain().contains(bx)) {
756  amrex::Print() << "\n";
757  amrex::Print() << "(Coarse) Box specified is " << bx << std::endl;
758  amrex::Print() << "But (coarse) domain at level is " << geom[lev_for_box-1].Domain() << std::endl;
759  amrex::Error("Specified box doesn't fit in the domain");
760  }
761 
762  bx.refine(ref_ratio[lev_for_box-1]);
763 
764  const auto* dx = geom[lev_for_box-1].CellSize();
765 
766  realbox = RealBox(plo[0]+ box_lo[0] *dx[0], plo[1]+ box_lo[1] *dx[1], plo[2]+ box_lo[2] *dx[2],
767  plo[0]+(box_hi[0]+1)*dx[0], plo[1]+(box_hi[1]+1)*dx[1], plo[2]+(box_hi[2]+1)*dx[2]);
768 
769  Print() << "Reading " << bx << " at level " << lev_for_box << std::endl;
770  num_boxes_at_level[lev_for_box] += 1;
771  bool using_pbl = (solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::MYJ ||
772  solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::MYNN25 ||
773  solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::MYNNEDMF ||
774  solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::YSU ||
775  solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::MRF);
776 
777  const Box& domain = geom[lev_for_box].Domain();
778  if ( using_pbl && ( (box_lo[2] > 0) || (box_hi[2] < domain.bigEnd(2)) ) ) {
779  amrex::Print() << "PBL models need refinement boxes that go from the bottom to the top of the domain for calculation of PBLH" << std::endl;
780  amrex::Print() << "Please set in_box_lo_indices_crse to 0 in z and in_box_hi_indices_crse to amr.n_cell-1 in z and try again" << std::endl;
781  amrex::Abort();
782  }
783 
784  boxes_at_level[lev_for_box].push_back(bx);
785  Print() << "Saving in 'boxes at level' as " << bx << std::endl;
786  } // lev
787 
788  if (solverChoice.init_type == InitType::WRFInput) {
789  if ( (num_files_at_level[lev_for_box] > 0) &&
790  (num_boxes_at_level[lev_for_box] != num_files_at_level[lev_for_box]) ) {
791  amrex::Error("Number of boxes doesn't match number of input files");
792 
793  }
794  }
795  }
796  AMRErrorTagInfo info;
797 
798  if (realbox.ok()) {
799  info.SetRealBox(realbox);
800  }
801 
802  if (ppr.countval("start_time") > 0) {
803  Real ref_min_time; ppr.get("start_time",ref_min_time);
804  info.SetMinTime(ref_min_time);
805  }
806 
807  if (ppr.countval("end_time") > 0) {
808  Real ref_max_time; ppr.get("end_time",ref_max_time);
809  info.SetMaxTime(ref_max_time);
810  }
811 
812  if (ppr.countval("max_level") > 0) {
813  int ref_max_level; ppr.get("max_level",ref_max_level);
814  info.SetMaxLevel(ref_max_level);
815  }
816 
817  // Read field_name once and validate moisture-field requests against
818  // the active moisture model so an unsupported field aborts at setup
819  // rather than after the first regrid.
820  std::string field;
821  if (ppr.countval("field_name") > 0) {
822  ppr.get("field_name", field);
823  auto is_moist_field = [](const std::string& f) {
824  return f == "qv" || f == "qc" || f == "qi" ||
825  f == "qr" || f == "qs" || f == "qg" || f == "qt";
826  };
827  if (is_moist_field(field)) {
828  const auto& mi = solverChoice.moisture_indices;
829  int comp = -1;
830  if (field == "qv") { comp = mi.qv; }
831  else if (field == "qc") { comp = mi.qc; }
832  else if (field == "qi") { comp = mi.qi; }
833  else if (field == "qr") { comp = mi.qr; }
834  else if (field == "qs") { comp = mi.qs; }
835  else if (field == "qg") { comp = mi.qg; }
836  else if (field == "qt") {
837  comp = (mi.qc >= 0 || mi.qi >= 0 || mi.qr >= 0 ||
838  mi.qs >= 0 || mi.qg >= 0) ? 0 : -1;
839  }
840  if (comp < 0) {
841  amrex::Abort("Refinement field_name '" + field +
842  "' is not available for the configured moisture model");
843  }
844  }
845  }
846 
847  if (ppr.countval("value_greater")) {
848  int num_val = ppr.countval("value_greater");
849  Vector<Real> value(num_val);
850  ppr.getarr("value_greater",value,0,num_val);
851  ref_tags.push_back(AMRErrorTag(value,AMRErrorTag::GREATER,field,info));
852  }
853  else if (ppr.countval("value_less"))
854  {
855  int num_val = ppr.countval("value_less");
856  Vector<Real> value(num_val);
857  ppr.getarr("value_less",value,0,num_val);
858  ref_tags.push_back(AMRErrorTag(value,AMRErrorTag::LESS,field,info));
859  }
860  else if (ppr.countval("adjacent_difference_greater"))
861  {
862  int num_val = ppr.countval("adjacent_difference_greater");
863  Vector<Real> value(num_val);
864  ppr.getarr("adjacent_difference_greater",value,0,num_val);
865  ref_tags.push_back(AMRErrorTag(value,AMRErrorTag::GRAD,field,info));
866  }
867  else if (realbox.ok())
868  {
869  ref_tags.push_back(AMRErrorTag(info));
870  }
871  else if ( (lev_for_box > 0) && (refinement_indicators[i] != "storm_tracker") )
872  {
873  Abort(std::string("Unrecognized refinement indicator for " + refinement_indicators[i]).c_str());
874  }
875  } // loop over criteria
876  } // if max_level > 0
877 }
real(c_double), private rr
Definition: ERF_module_mp_morr_two_moment.F90:224
Here is the call graph for this function:

◆ remake_zphys()

void ERF::remake_zphys ( int  lev,
std::unique_ptr< amrex::MultiFab > &  temp_zphys_nd 
)
799 {
800  if (solverChoice.init_type != InitType::WRFInput && solverChoice.init_type != InitType::Metgrid)
801  {
802  if (lev > 0)
803  {
804  //
805  // First interpolate from coarser level
806  // NOTE: this interpolater assumes that ALL ghost cells of the coarse MultiFab
807  // have been pre-filled - this includes ghost cells both inside and outside
808  // the domain
809  //
810  InterpFromCoarseLevel(*temp_zphys_nd, z_phys_nd[lev]->nGrowVect(),
811  IntVect(0,0,0), // do NOT fill ghost cells outside the domain
812  *z_phys_nd[lev-1], 0, 0, 1,
813  geom[lev-1], geom[lev],
814  refRatio(lev-1), &node_bilinear_interp,
816 
817  // This recomputes the fine values using the bottom terrain at the fine resolution,
818  // and also fills values of z_phys_nd outside the domain
819  make_terrain_fitted_coords(lev,geom[lev],*temp_zphys_nd,zlevels_stag[lev],phys_bc_type);
820 
821  std::swap(temp_zphys_nd, z_phys_nd[lev]);
822  } // lev > 0
823  } else {
824  if (lev > 0)
825  {
826  //
827  // First interpolate from coarser level
828  // NOTE: this interpolater assumes that ALL ghost cells of the coarse MultiFab
829  // have been pre-filled - this includes ghost cells both inside and outside
830  // the domain
831  //
832  InterpFromCoarseLevel(*temp_zphys_nd, z_phys_nd[lev]->nGrowVect(),
833  z_phys_nd[lev]->nGrowVect(), // DO fill ghost cells outside the domain
834  *z_phys_nd[lev-1], 0, 0, 1,
835  geom[lev-1], geom[lev],
836  refRatio(lev-1), &node_bilinear_interp,
838 
839  std::swap(temp_zphys_nd, z_phys_nd[lev]);
840  } // lev > 0
841  }
842 
843  if (solverChoice.terrain_type == TerrainType::ImmersedForcing ||
844  solverChoice.buildings_type == BuildingsType::ImmersedForcing) {
845  //
846  // This assumes we have already remade the EBGeometry
847  //
848  terrain_blanking[lev]->setVal(one);
849  MultiFab::Subtract(*terrain_blanking[lev], EBFactory(lev).getVolFrac(), 0, 0, 1, z_phys_nd[lev]->nGrowVect());
850  }
851 
852  // Compute the min dz and pass to the micro model
853  Real dzmin = get_dzmin_terrain(*z_phys_nd[lev]);
854  micro->Set_dzmin(lev, dzmin);
855 }
Here is the call graph for this function:

◆ RemakeLevel()

void ERF::RemakeLevel ( int  lev,
amrex::Real  time,
const amrex::BoxArray &  ba,
const amrex::DistributionMapping &  dm 
)
override
535 {
536  //
537  // Note that "time" here is elapsed time
538  //
539  if (verbose) {
540  amrex::Print() <<" REMAKING WITH NEW BA AT LEVEL " << lev << " " << ba << std::endl;
541  }
542 
543  AMREX_ALWAYS_ASSERT(solverChoice.terrain_type != TerrainType::MovingFittedMesh);
544 
545  BoxArray ba_old(vars_new[lev][Vars::cons].boxArray());
546  DistributionMapping dm_old(vars_new[lev][Vars::cons].DistributionMap());
547 
548  if (verbose) {
549  amrex::Print() <<" OLD BA AT LEVEL " << lev << " " << ba_old << std::endl;
550  }
551 
552  //
553  // Re-define subdomain at this level within the domain such that
554  // 1) all boxes in a given subdomain are "connected"
555  // 2) no boxes in a subdomain touch any boxes in any other subdomain
556  //
557  subdomains[lev].clear();
558  make_subdomains(ba.simplified_list(), subdomains[lev]);
559 
560  int ncomp_cons = vars_new[lev][Vars::cons].nComp();
561  IntVect ngrow_state = vars_new[lev][Vars::cons].nGrowVect();
562 
563  int ngrow_vels = ComputeGhostCells(solverChoice);
564 
565  Vector<MultiFab> temp_lev_new(Vars::NumTypes);
566  Vector<MultiFab> temp_lev_old(Vars::NumTypes);
567  MultiFab temp_base_state;
568 
569  std::unique_ptr<MultiFab> temp_zphys_nd;
570 
571  //********************************************************************************************
572  // This allocates all kinds of things, including but not limited to: solution arrays,
573  // terrain arrays and metrics, and base state.
574  // *******************************************************************************************
575  init_stuff(lev, ba, dm, temp_lev_new, temp_lev_old, temp_base_state, temp_zphys_nd);
576 
577  // ********************************************************************************************
578  // Build the data structures for terrain-related quantities
579  // ********************************************************************************************
580  if ( solverChoice.terrain_type == TerrainType::EB ||
581  solverChoice.terrain_type == TerrainType::ImmersedForcing ||
582  solverChoice.buildings_type == BuildingsType::ImmersedForcing)
583  {
584  const amrex::EB2::IndexSpace& ebis = amrex::EB2::IndexSpace::top();
585  const EB2::Level& eb_level = ebis.getLevel(geom[lev]);
586  if (solverChoice.terrain_type == TerrainType::EB) {
587  eb[lev]->make_all_factories(lev, geom[lev], ba, dm, eb_level);
588  } else if (solverChoice.terrain_type == TerrainType::ImmersedForcing ||
589  solverChoice.buildings_type == BuildingsType::ImmersedForcing) {
590  eb[lev]->make_cc_factory(lev, geom[lev], ba, dm, eb_level);
591  }
592  }
593  remake_zphys(lev, temp_zphys_nd);
595 
596  // ********************************************************************************************
597  // Make sure that detJ and z_phys_cc are the average of the data on a finer level if there is one
598  // Note that this shouldn't be necessary because the fine grid is created by interpolation
599  // from the coarse ... but just in case ...
600  // ********************************************************************************************
601  if ( (SolverChoice::mesh_type != MeshType::ConstantDz) && (solverChoice.coupling_type == CouplingType::TwoWay) ) {
602  for (int crse_lev = lev-1; crse_lev >= 0; crse_lev--) {
603  average_down( *detJ_cc[crse_lev+1], *detJ_cc[crse_lev], 0, 1, refRatio(crse_lev));
604  average_down(*z_phys_cc[crse_lev+1], *z_phys_cc[crse_lev], 0, 1, refRatio(crse_lev));
605  }
606  }
607 
608  // ********************************************************************************************
609  // Build the data structures for canopy model (depends upon z_phys)
610  // ********************************************************************************************
612  m_forest_drag[lev]->define_drag_field(ba, dm, geom[lev], z_phys_cc[lev].get(), z_phys_nd[lev].get());
613  }
614 
615  // *****************************************************************************************************
616  // Create the physbcs objects (after initializing the terrain but before calling FillCoarsePatch
617  // *****************************************************************************************************
618  make_physbcs(lev);
619 
620  // ********************************************************************************************
621  // Update the base state at this level by interpolation from coarser level AND copy
622  // from previous (pre-regrid) base_state array
623  // ********************************************************************************************
624  if (lev > 0) {
625  Interpolater* mapper = &cell_cons_interp;
626 
627  Vector<MultiFab*> fmf = {&base_state[lev ], &base_state[lev ]};
628  Vector<MultiFab*> cmf = {&base_state[lev-1], &base_state[lev-1]};
629  Vector<Real> ftime = {time, time};
630  Vector<Real> ctime = {time, time};
631 
632  // Call FillPatch which ASSUMES that all ghost cells at lev-1 have already been filled
633  FillPatchTwoLevels(temp_base_state, temp_base_state.nGrowVect(), IntVect(0,0,0),
634  time, cmf, ctime, fmf, ftime,
635  0, 0, temp_base_state.nComp(), geom[lev-1], geom[lev],
636  refRatio(lev-1), mapper, domain_bcs_type,
638 
639  // Impose bc's outside the domain
640  (*physbcs_base[lev])(temp_base_state,0,temp_base_state.nComp(),base_state[lev].nGrowVect());
641 
642  // *************************************************************************************************
643  // This will fill the temporary MultiFabs with data from vars_new
644  // NOTE: the momenta here are only used as scratch space, the momenta themselves are not fillpatched
645  // NOTE: we must create the new base state before calling FillPatch because we will
646  // interpolate perturbational quantities
647  // *************************************************************************************************
648  FillPatchFineLevel(lev, time, {&temp_lev_new[Vars::cons],&temp_lev_new[Vars::xvel],
649  &temp_lev_new[Vars::yvel],&temp_lev_new[Vars::zvel]},
650  {&temp_lev_new[Vars::cons],&rU_new[lev],&rV_new[lev],&rW_new[lev]},
651  base_state[lev], temp_base_state, false);
652  } else {
653  temp_base_state.ParallelCopy(base_state[lev],0,0,base_state[lev].nComp(),
654  base_state[lev].nGrowVect(),base_state[lev].nGrowVect());
655  temp_lev_new[Vars::cons].ParallelCopy(vars_new[lev][Vars::cons],0,0,ncomp_cons,ngrow_state,ngrow_state);
656  temp_lev_new[Vars::xvel].ParallelCopy(vars_new[lev][Vars::xvel],0,0, 1,ngrow_vels,ngrow_vels);
657  temp_lev_new[Vars::yvel].ParallelCopy(vars_new[lev][Vars::yvel],0,0, 1,ngrow_vels,ngrow_vels);
658 
659  temp_lev_new[Vars::zvel].setVal(0.);
660  temp_lev_new[Vars::zvel].ParallelCopy(vars_new[lev][Vars::zvel],0,0, 1,
661  IntVect(ngrow_vels,ngrow_vels,0),IntVect(ngrow_vels,ngrow_vels,0));
662  }
663 
664  // Now swap the pointers since we needed both old and new in the FillPatch
665  std::swap(temp_base_state, base_state[lev]);
666 
667  // ********************************************************************************************
668  // Copy from new into old just in case
669  // ********************************************************************************************
670  MultiFab::Copy(temp_lev_old[Vars::cons],temp_lev_new[Vars::cons],0,0,ncomp_cons,ngrow_state);
671  MultiFab::Copy(temp_lev_old[Vars::xvel],temp_lev_new[Vars::xvel],0,0, 1,ngrow_vels);
672  MultiFab::Copy(temp_lev_old[Vars::yvel],temp_lev_new[Vars::yvel],0,0, 1,ngrow_vels);
673  MultiFab::Copy(temp_lev_old[Vars::zvel],temp_lev_new[Vars::zvel],0,0, 1,IntVect(ngrow_vels,ngrow_vels,0));
674 
675  // ********************************************************************************************
676  // Now swap the pointers
677  // ********************************************************************************************
678  for (int var_idx = 0; var_idx < Vars::NumTypes; ++var_idx) {
679  std::swap(temp_lev_new[var_idx], vars_new[lev][var_idx]);
680  std::swap(temp_lev_old[var_idx], vars_old[lev][var_idx]);
681  }
682 
683  //
684  // Note that t_new = time here is elapsed time
685  //
686  t_new[lev] = time;
687  t_old[lev] = time - Real(1.e200);
688 
689  // ********************************************************************************************
690  // Build the data structures for calculating diffusive/turbulent terms
691  // ********************************************************************************************
692  update_diffusive_arrays(lev, ba, dm);
693 
694  //********************************************************************************************
695  // Microphysics
696  // *******************************************************************************************
697  int q_size = micro->Get_Qmoist_Size(lev);
698  qmoist[lev].resize(q_size);
699  micro->Define(lev, solverChoice);
700  if (solverChoice.moisture_type != MoistureType::None)
701  {
702  micro->Init(lev, vars_new[lev][Vars::cons],
703  grids[lev], Geom(lev), zero,
704  z_phys_nd[lev], detJ_cc[lev]); // dummy dt value
705  }
706  for (int mvar(0); mvar<qmoist[lev].size(); ++mvar) {
707  qmoist[lev][mvar] = micro->Get_Qmoist_Ptr(lev,mvar);
708  }
709 
710  //********************************************************************************************
711  // Radiation
712  // *******************************************************************************************
713  if (solverChoice.rad_type != RadiationType::None)
714  {
715  rad[lev]->Init(geom[lev], ba, &vars_new[lev][Vars::cons]);
716  }
717 
718  // ********************************************************************************************
719  // Initialize the integrator class
720  // ********************************************************************************************
722 
723  // We need to re-define the FillPatcher if the grids have changed
724  if (lev > 0 && cf_width >= 0) {
725  bool ba_changed = (ba != ba_old);
726  bool dm_changed = (dm != dm_old);
727  if (ba_changed || dm_changed) {
729  }
730  }
731 
732  // These calls are done in AmrCore::regrid if this is a regrid at lev > 0
733  // For a level 0 regrid we must explicitly do them here
734  if (lev == 0) {
735  // Define grids[lev] to be ba
736  SetBoxArray(lev, ba);
737 
738  // Define dmap[lev] to be dm
739  SetDistributionMap(lev, dm);
740  }
741 
742  // ********************************************************************************************
743  // Initialize the 2D data structures
744  // ********************************************************************************************
745  // NOTE: 2D MFs must be filled before SurfaceLayer is defined since SL class uses sst/tsk
746  // Clear the 2D arrays
747  if (sst_lev[lev][0]) {
748  for (int n = 0; n < sst_lev[lev].size(); n++) {
749  sst_lev[lev][n].reset();
750  }
751  }
752  if (tsk_lev[lev][0]) {
753  for (int n = 0; n < tsk_lev[lev].size(); n++) {
754  tsk_lev[lev][n].reset();
755  }
756  }
757  if (lat_m[lev]) {
758  lat_m[lev].reset();
759  }
760  if (lon_m[lev]) {
761  lon_m[lev].reset();
762  }
763  if (sinPhi_m[lev]) {
764  sinPhi_m[lev].reset();
765  }
766  if (cosPhi_m[lev]) {
767  cosPhi_m[lev].reset();
768  }
769 
770  //
771  // Interpolate the 2D arrays at the lower boundary. We assume that since we created
772  // them by interpolation it is ok just to recreate them by interpolation.
773  // Note that ba2d is constructed already in init_stuff, but we have not yet defined dmap[lev]
774  // so we must explicitly pass dm.
775  Interp2DArrays(lev,ba2d[lev],dm);
776 
777  // ********************************************************************************************
778  // Update the SurfaceLayer arrays at this level
779  // ********************************************************************************************
780  if (phys_bc_type[Orientation(Direction::z,Orientation::low)] == ERF_BC::surface_layer) {
781  int nlevs = finest_level+1;
782  Vector<MultiFab*> mfv_old = {&vars_old[lev][Vars::cons], &vars_old[lev][Vars::xvel],
783  &vars_old[lev][Vars::yvel], &vars_old[lev][Vars::zvel]};
784  m_SurfaceLayer->make_SurfaceLayer_at_level(lev,nlevs,
785  mfv_old, Theta_prim[lev], Qv_prim[lev],
786  Qr_prim[lev], z_phys_nd[lev],
787  Hwave[lev].get(),Lwave[lev].get(),eddyDiffs_lev[lev].get(),
789  sst_lev[lev], tsk_lev[lev], lmask_lev[lev]);
790  }
791 
792  // ********************************************************************************************
793  // Set up the Rayleigh damping vectors at this (new) level
794  // ********************************************************************************************
797  {
799  }
800 
801  // Particle redistribute handled in timeStep() after regrid() completes.
802  // Calling it here causes stale-grid crashes.
803 }
void remake_zphys(int lev, std::unique_ptr< amrex::MultiFab > &temp_zphys_nd)
Definition: ERF_MakeNewArrays.cpp:798
Here is the call graph for this function:

◆ restart()

void ERF::restart ( )
2211 {
2212  auto dRestartTime0 = amrex::second();
2213 
2215 
2217  //
2218  // Coarsening before we split the grids ensures that each resulting
2219  // grid will have an even number of cells in each direction.
2220  //
2221  BoxArray new_ba(amrex::coarsen(Geom(0).Domain(),2));
2222  //
2223  // Now split up into list of grids within max_grid_size[0] limit.
2224  //
2225  new_ba.maxSize(max_grid_size[0]/2);
2226  //
2227  // Now refine these boxes back to level zero
2228  //
2229  new_ba.refine(2);
2230 
2231  if (refine_grid_layout) {
2232  ChopGrids(0, new_ba, ParallelDescriptor::NProcs());
2233  }
2234 
2235  if (new_ba != grids[0]) {
2236  DistributionMapping new_dm(new_ba);
2237  RemakeLevel(0,t_new[0],new_ba,new_dm);
2238  }
2239  }
2240 
2241 #ifdef ERF_USE_PARTICLES
2242  // We call this here without knowing whether the particles have already been initialized or not
2243  initializeTracers((ParGDBBase*)GetParGDB(),z_phys_nd,t_new[0]);
2244 #endif
2245 
2246  Real cur_time = t_new[0];
2247  if (m_check_per > zero) {last_check_file_time = cur_time;}
2248  if (m_plot2d_per_1 > zero) {last_plot2d_file_time_1 = std::floor(cur_time/m_plot2d_per_1) * m_plot2d_per_1;}
2249  if (m_plot2d_per_2 > zero) {last_plot2d_file_time_2 = std::floor(cur_time/m_plot2d_per_2) * m_plot2d_per_2;}
2250  if (m_plot3d_per_1 > zero) {last_plot3d_file_time_1 = std::floor(cur_time/m_plot3d_per_1) * m_plot3d_per_1;}
2251  if (m_plot3d_per_2 > zero) {last_plot3d_file_time_2 = std::floor(cur_time/m_plot3d_per_2) * m_plot3d_per_2;}
2252 
2258 
2259  if (verbose > 0)
2260  {
2261  auto dRestartTime = amrex::second() - dRestartTime0;
2262  ParallelDescriptor::ReduceRealMax(dRestartTime,ParallelDescriptor::IOProcessorNumber());
2263  amrex::Print() << "Restart time = " << dRestartTime << " seconds." << '\n';
2264  }
2265 }
void RemakeLevel(int lev, amrex::Real time, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm) override
Definition: ERF_MakeNewLevel.cpp:534
void ReadCheckpointFile()
Definition: ERF_Checkpoint.cpp:471

◆ sample_lines()

void ERF::sample_lines ( int  lev,
amrex::Real  time,
amrex::IntVect  cell,
amrex::MultiFab &  mf 
)

Utility function for sampling data along a line along the z-dimension at the (x,y) indices specified and writes it to an output file.

Parameters
levCurrent level
timeCurrent time
cellIntVect containing the x,y-dimension indices to sample along z
mfMultiFab from which we sample the data
565 {
566  int ifile = 0;
567 
568  const int ncomp = mf.nComp(); // cell-centered state vars
569 
570  MultiFab mf_vels(grids[lev], dmap[lev], AMREX_SPACEDIM, 0);
571  average_face_to_cellcenter(mf_vels, 0,
572  Array<const MultiFab*,3>{&vars_new[lev][Vars::xvel],&vars_new[lev][Vars::yvel],&vars_new[lev][Vars::zvel]});
573 
574  //
575  // Sample the data at a line (in direction "dir") in space
576  // In this case we sample in the vertical direction so dir = 2
577  // The "k" value of "cell" is ignored
578  //
579  int dir = 2;
580  MultiFab my_line = get_line_data(mf, dir, cell);
581  MultiFab my_line_vels = get_line_data(mf_vels, dir, cell);
582  MultiFab my_line_tau11 = get_line_data(*Tau[lev][TauType::tau11], dir, cell);
583  MultiFab my_line_tau12 = get_line_data(*Tau[lev][TauType::tau12], dir, cell);
584  MultiFab my_line_tau13 = get_line_data(*Tau[lev][TauType::tau13], dir, cell);
585  MultiFab my_line_tau22 = get_line_data(*Tau[lev][TauType::tau22], dir, cell);
586  MultiFab my_line_tau23 = get_line_data(*Tau[lev][TauType::tau23], dir, cell);
587  MultiFab my_line_tau33 = get_line_data(*Tau[lev][TauType::tau33], dir, cell);
588 
589  for (MFIter mfi(my_line, false); mfi.isValid(); ++mfi)
590  {
591  // HERE DO WHATEVER YOU WANT TO THE DATA BEFORE WRITING
592 
593  std::ostream& sample_log = SampleLineLog(ifile);
594  if (sample_log.good()) {
595  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << time;
596  const auto& my_line_arr = my_line[0].const_array();
597  const auto& my_line_vels_arr = my_line_vels[0].const_array();
598  const auto& my_line_tau11_arr = my_line_tau11[0].const_array();
599  const auto& my_line_tau12_arr = my_line_tau12[0].const_array();
600  const auto& my_line_tau13_arr = my_line_tau13[0].const_array();
601  const auto& my_line_tau22_arr = my_line_tau22[0].const_array();
602  const auto& my_line_tau23_arr = my_line_tau23[0].const_array();
603  const auto& my_line_tau33_arr = my_line_tau33[0].const_array();
604  const Box& my_box = my_line[0].box();
605  const int klo = my_box.smallEnd(2);
606  const int khi = my_box.bigEnd(2);
607  int i = cell[0];
608  int j = cell[1];
609  for (int n = 0; n < ncomp; n++) {
610  for (int k = klo; k <= khi; k++) {
611  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << my_line_arr(i,j,k,n);
612  }
613  }
614  for (int n = 0; n < AMREX_SPACEDIM; n++) {
615  for (int k = klo; k <= khi; k++) {
616  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << my_line_vels_arr(i,j,k,n);
617  }
618  }
619  for (int k = klo; k <= khi; k++) {
620  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << my_line_tau11_arr(i,j,k);
621  }
622  for (int k = klo; k <= khi; k++) {
623  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << my_line_tau12_arr(i,j,k);
624  }
625  for (int k = klo; k <= khi; k++) {
626  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << my_line_tau13_arr(i,j,k);
627  }
628  for (int k = klo; k <= khi; k++) {
629  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << my_line_tau22_arr(i,j,k);
630  }
631  for (int k = klo; k <= khi; k++) {
632  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << my_line_tau23_arr(i,j,k);
633  }
634  for (int k = klo; k <= khi; k++) {
635  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << my_line_tau33_arr(i,j,k);
636  }
637  sample_log << std::endl;
638  } // if good
639  } // mfi
640 }
const int datwidth
Definition: ERF.H:1066
AMREX_FORCE_INLINE std::ostream & SampleLineLog(int i)
Definition: ERF.H:1505
const int datprecision
Definition: ERF.H:1067

◆ sample_points()

void ERF::sample_points ( int  lev,
amrex::Real  time,
amrex::IntVect  cell,
amrex::MultiFab &  mf 
)

Utility function for sampling MultiFab data at a specified cell index.

Parameters
levLevel for the associated MultiFab data
timeCurrent time
cellIntVect containing the indexes for the cell where we want to sample
mfMultiFab from which we wish to sample data
529 {
530  int ifile = 0;
531 
532  //
533  // Sample the data at a single point in space
534  //
535  int ncomp = mf.nComp();
536  Vector<Real> my_point = get_cell_data(mf, cell);
537 
538  if (!my_point.empty()) {
539 
540  // HERE DO WHATEVER YOU WANT TO THE DATA BEFORE WRITING
541 
542  std::ostream& sample_log = SamplePointLog(ifile);
543  if (sample_log.good()) {
544  sample_log << std::setw(datwidth) << time;
545  for (int i = 0; i < ncomp; ++i)
546  {
547  sample_log << std::setw(datwidth) << my_point[i];
548  }
549  sample_log << std::endl;
550  } // if good
551  } // only write from processor that holds the cell
552 }
AMREX_FORCE_INLINE std::ostream & SamplePointLog(int i)
Definition: ERF.H:1491

◆ SampleLine()

amrex::IntVect& ERF::SampleLine ( int  i)
inlineprivate
1532  {
1533  return sampleline[i];
1534  }

◆ SampleLineLog()

AMREX_FORCE_INLINE std::ostream& ERF::SampleLineLog ( int  i)
inlineprivate
1506  {
1507  return *samplelinelog[i];
1508  }

◆ SampleLineLogName()

std::string ERF::SampleLineLogName ( int  i) const
inlineprivatenoexcept

The filename of the ith samplelinelog file.

1665 { return samplelinelogname[i]; }

◆ SamplePoint()

amrex::IntVect& ERF::SamplePoint ( int  i)
inlineprivate
1519  {
1520  return samplepoint[i];
1521  }

◆ SamplePointLog()

AMREX_FORCE_INLINE std::ostream& ERF::SamplePointLog ( int  i)
inlineprivate
1492  {
1493  return *sampleptlog[i];
1494  }

◆ SamplePointLogName()

std::string ERF::SamplePointLogName ( int  i) const
inlineprivatenoexcept

The filename of the ith sampleptlog file.

1662 { return sampleptlogname[i]; }

◆ setPlotVariables()

void ERF::setPlotVariables ( const std::string &  pp_plot_var_names,
amrex::Vector< std::string > &  plot_var_names 
)
private
29 {
30  ParmParse pp(pp_prefix);
31 
32  if (pp.contains(pp_plot_var_names.c_str()))
33  {
34  std::string nm;
35 
36  int nPltVars = pp.countval(pp_plot_var_names.c_str());
37 
38  for (int i = 0; i < nPltVars; i++)
39  {
40  pp.get(pp_plot_var_names.c_str(), nm, i);
41 
42  // Add the named variable to our list of plot variables
43  // if it is not already in the list
44  if (!containerHasElement(plot_var_names, nm)) {
45  plot_var_names.push_back(nm);
46  }
47  }
48  } else {
49  //
50  // The default is to add none of the variables to the list
51  //
52  plot_var_names.clear();
53  }
54 
55  // Get state variables in the same order as we define them,
56  // since they may be in any order in the input list
57  Vector<std::string> tmp_plot_names;
58 
59  for (int i = 0; i < cons_names.size(); ++i) {
60  if ( containerHasElement(plot_var_names, cons_names[i]) ) {
61  if (solverChoice.moisture_type == MoistureType::None) {
62  if (cons_names[i] != "rhoQ1" && cons_names[i] != "rhoQ2" && cons_names[i] != "rhoQ3" &&
63  cons_names[i] != "rhoQ4" && cons_names[i] != "rhoQ5" && cons_names[i] != "rhoQ6")
64  {
65  tmp_plot_names.push_back(cons_names[i]);
66  }
67  } else if (solverChoice.moisture_type == MoistureType::Kessler) { // allow rhoQ1, rhoQ2, rhoQ3
68  if (cons_names[i] != "rhoQ4" && cons_names[i] != "rhoQ5" && cons_names[i] != "rhoQ6")
69  {
70  tmp_plot_names.push_back(cons_names[i]);
71  }
72  } else if ( (solverChoice.moisture_type == MoistureType::SatAdj) ||
73  (solverChoice.moisture_type == MoistureType::SAM_NoPrecip_NoIce) ||
74  (solverChoice.moisture_type == MoistureType::Kessler_NoRain) ) { // allow rhoQ1, rhoQ2
75  if (cons_names[i] != "rhoQ3" && cons_names[i] != "rhoQ4" &&
76  cons_names[i] != "rhoQ5" && cons_names[i] != "rhoQ6")
77  {
78  tmp_plot_names.push_back(cons_names[i]);
79  }
80  } else if ( (solverChoice.moisture_type == MoistureType::Morrison_NoIce) ||
81  (solverChoice.moisture_type == MoistureType::SAM_NoIce ) ) { // allow rhoQ1, rhoQ2, rhoQ4
82  if (cons_names[i] != "rhoQ3" && cons_names[i] != "rhoQ5" && cons_names[i] != "rhoQ6")
83  {
84  tmp_plot_names.push_back(cons_names[i]);
85  }
86  } else
87  {
88  // For moisture_type SAM, Morrison and WSM6 we have all six variables
89  tmp_plot_names.push_back(cons_names[i]);
90  }
91  }
92  }
93 
94  // check for velocity since it's not in cons_names
95  // if we are asked for any velocity component, we will need them all
96  if (containerHasElement(plot_var_names, "x_velocity") ||
97  containerHasElement(plot_var_names, "y_velocity") ||
98  containerHasElement(plot_var_names, "z_velocity")) {
99  tmp_plot_names.push_back("x_velocity");
100  tmp_plot_names.push_back("y_velocity");
101  tmp_plot_names.push_back("z_velocity");
102  }
103 
104  //
105  // If the model we are running doesn't have the variable listed in the inputs file,
106  // just ignore it rather than aborting
107  //
108  for (int i = 0; i < derived_names.size(); ++i) {
109  if ( containerHasElement(plot_var_names, derived_names[i]) ) {
110  bool ok_to_add = ( (solverChoice.terrain_type == TerrainType::ImmersedForcing || solverChoice.buildings_type == BuildingsType::ImmersedForcing ) ||
111  (derived_names[i] != "terrain_IB_mask") );
112  ok_to_add &= ( (SolverChoice::terrain_type == TerrainType::StaticFittedMesh) ||
113  (SolverChoice::terrain_type == TerrainType::MovingFittedMesh) ||
114  (derived_names[i] != "detJ") );
115  ok_to_add &= ( (SolverChoice::terrain_type == TerrainType::StaticFittedMesh) ||
116  (SolverChoice::terrain_type == TerrainType::MovingFittedMesh) ||
117  (derived_names[i] != "z_phys") );
118 #ifndef ERF_USE_WINDFARM
119  ok_to_add &= (derived_names[i] != "SMark0" && derived_names[i] != "SMark1");
120 #endif
121  if (ok_to_add)
122  {
123  if (solverChoice.moisture_type == MoistureType::None) { // no moist quantities allowed
124  if (derived_names[i] != "qv" && derived_names[i] != "qc" && derived_names[i] != "qrain" &&
125  derived_names[i] != "qi" && derived_names[i] != "qsnow" && derived_names[i] != "qgraup" &&
126  derived_names[i] != "qt" && derived_names[i] != "qn" && derived_names[i] != "qp" &&
127  derived_names[i] != "rain_accum" && derived_names[i] != "snow_accum" && derived_names[i] != "graup_accum")
128  {
129  tmp_plot_names.push_back(derived_names[i]);
130  }
131  } else if ( (solverChoice.moisture_type == MoistureType::Kessler ) ||
132  (solverChoice.moisture_type == MoistureType::Morrison_NoIce) ||
133  (solverChoice.moisture_type == MoistureType::SAM_NoIce ) ) { // allow qv, qc, qrain
134  if (derived_names[i] != "qi" && derived_names[i] != "qsnow" && derived_names[i] != "qgraup" &&
135  derived_names[i] != "snow_accum" && derived_names[i] != "graup_accum")
136  {
137  tmp_plot_names.push_back(derived_names[i]);
138  }
139  } else if ( (solverChoice.moisture_type == MoistureType::SatAdj) ||
140  (solverChoice.moisture_type == MoistureType::SAM_NoPrecip_NoIce) ||
141  (solverChoice.moisture_type == MoistureType::Kessler_NoRain) ||
142  (solverChoice.moisture_type == MoistureType::MoistNoCondensation) ) { // allow qv, qc
143  if (derived_names[i] != "qrain" && derived_names[i] != "qi" && derived_names[i] != "qsnow" &&
144  derived_names[i] != "qgraup" && derived_names[i] != "qp" &&
145  derived_names[i] != "rain_accum" && derived_names[i] != "snow_accum" && derived_names[i] != "graup_accum")
146  {
147  tmp_plot_names.push_back(derived_names[i]);
148  }
149  } else
150  {
151  // For moisture_type SAM and Morrison we have all moist quantities
152  tmp_plot_names.push_back(derived_names[i]);
153  }
154  } // use_terrain?
155  } // hasElement
156  }
157 
158 #ifdef ERF_USE_WINDFARM
159  for (int i = 0; i < derived_names.size(); ++i) {
160  if ( containerHasElement(plot_var_names, derived_names[i]) ) {
161  if(solverChoice.windfarm_type == WindFarmType::Fitch or solverChoice.windfarm_type == WindFarmType::EWP) {
162  if(derived_names[i] == "num_turb" or derived_names[i] == "SMark0") {
163  tmp_plot_names.push_back(derived_names[i]);
164  }
165  }
166  if( solverChoice.windfarm_type == WindFarmType::SimpleAD or
167  solverChoice.windfarm_type == WindFarmType::GeneralAD ) {
168  if(derived_names[i] == "num_turb" or derived_names[i] == "SMark0" or derived_names[i] == "SMark1") {
169  tmp_plot_names.push_back(derived_names[i]);
170  }
171  }
172  }
173  }
174 #endif
175 
176 #ifdef ERF_USE_PARTICLES
177  const auto& particles_namelist( particleData.getNamesUnalloc() );
178  for (auto it = particles_namelist.cbegin(); it != particles_namelist.cend(); ++it) {
179  std::string tmp( (*it)+"_count" );
180  if (containerHasElement(plot_var_names, tmp) ) {
181  tmp_plot_names.push_back(tmp);
182  }
183  }
184 #endif
185 
186  plot_var_names = tmp_plot_names;
187 }
const amrex::Vector< std::string > derived_names
Definition: ERF.H:1155
const amrex::Vector< std::string > cons_names
Definition: ERF.H:1146
Here is the call graph for this function:

◆ setPlotVariables2D()

void ERF::setPlotVariables2D ( const std::string &  pp_plot_var_names,
amrex::Vector< std::string > &  plot_var_names 
)
private
191 {
192  ParmParse pp(pp_prefix);
193 
194  if (pp.contains(pp_plot_var_names.c_str()))
195  {
196  std::string nm;
197 
198  int nPltVars = pp.countval(pp_plot_var_names.c_str());
199 
200  for (int i = 0; i < nPltVars; i++)
201  {
202  pp.get(pp_plot_var_names.c_str(), nm, i);
203 
204  // Add the named variable to our list of plot variables
205  // if it is not already in the list
206  if (!containerHasElement(plot_var_names, nm)) {
207  plot_var_names.push_back(nm);
208  }
209  }
210  } else {
211  //
212  // The default is to add none of the variables to the list
213  //
214  plot_var_names.clear();
215  }
216 
217  // Get state variables in the same order as we define them,
218  // since they may be in any order in the input list
219  Vector<std::string> tmp_plot_names;
220 
221  // 2D plot variables
222  for (int i = 0; i < derived_names_2d.size(); ++i) {
223  if (containerHasElement(plot_var_names, derived_names_2d[i]) ) {
224  tmp_plot_names.push_back(derived_names_2d[i]);
225  }
226  }
227 
228  plot_var_names = tmp_plot_names;
229 }
const amrex::Vector< std::string > derived_names_2d
Definition: ERF.H:1200
Here is the call graph for this function:

◆ setRayleighRefFromSounding()

void ERF::setRayleighRefFromSounding ( bool  restarting)
private

Set Rayleigh mean profiles from input sounding.

Sets the Rayleigh Damping averaged quantities from an externally supplied input sounding data file.

Parameters
[in]restartingBoolean parameter that indicates whether we are currently restarting from a checkpoint file.
84 {
85  // If we are restarting then we haven't read the input_sounding file yet
86  // so we need to read it here
87  // TODO: should we store this information in the checkpoint file instead?
88  if (restarting) {
90  for (int n = 0; n < input_sounding_data.n_sounding_files; n++) {
92  }
93  }
94 
95  const Real* z_inp_sound = input_sounding_data.z_inp_sound[0].dataPtr();
96  const Real* U_inp_sound = input_sounding_data.U_inp_sound[0].dataPtr();
97  const Real* V_inp_sound = input_sounding_data.V_inp_sound[0].dataPtr();
98  const Real* theta_inp_sound = input_sounding_data.theta_inp_sound[0].dataPtr();
99  const int inp_sound_size = input_sounding_data.size(0);
100 
101  int refine_fac{1};
102  for (int lev = 0; lev <= finest_level; lev++)
103  {
104  const int klo = geom[lev].Domain().smallEnd(2);
105  const int khi = geom[lev].Domain().bigEnd(2);
106  const int Nz = khi - klo + 1;
107 
108  Vector<Real> zcc(Nz);
109  Vector<Real> zlevels_sub(zlevels_stag[0].begin()+klo/refine_fac,
110  zlevels_stag[0].begin()+khi/refine_fac+2);
111  expand_and_interpolate_1d(zcc, zlevels_sub, refine_fac, true);
112 #if 0
113  amrex::AllPrint() << "lev="<<lev<<" : (refine_fac="<<refine_fac<<",klo="<<klo<<",khi="<<khi<<") ";
114  for (int k = 0; k < zlevels_sub.size(); k++) { amrex::AllPrint() << zlevels_sub[k] << " "; }
115  amrex::AllPrint() << " --> ";
116  for (int k = 0; k < Nz; k++) { amrex::AllPrint() << zcc[k] << " "; }
117  amrex::AllPrint() << std::endl;
118 #endif
119 
120  for (int k = 0; k < Nz; k++)
121  {
122  h_rayleigh_ptrs[lev][Rayleigh::ubar][k] = interpolate_1d(z_inp_sound, U_inp_sound, zcc[k], inp_sound_size);
123  h_rayleigh_ptrs[lev][Rayleigh::vbar][k] = interpolate_1d(z_inp_sound, V_inp_sound, zcc[k], inp_sound_size);
125  h_rayleigh_ptrs[lev][Rayleigh::thetabar][k] = interpolate_1d(z_inp_sound, theta_inp_sound, zcc[k], inp_sound_size);
126  }
127 
128  // Copy from host version to device version
129  Gpu::copy(Gpu::hostToDevice, h_rayleigh_ptrs[lev][Rayleigh::ubar].begin(), h_rayleigh_ptrs[lev][Rayleigh::ubar].end(),
130  d_rayleigh_ptrs[lev][Rayleigh::ubar].begin());
131  Gpu::copy(Gpu::hostToDevice, h_rayleigh_ptrs[lev][Rayleigh::vbar].begin(), h_rayleigh_ptrs[lev][Rayleigh::vbar].end(),
132  d_rayleigh_ptrs[lev][Rayleigh::vbar].begin());
133  Gpu::copy(Gpu::hostToDevice, h_rayleigh_ptrs[lev][Rayleigh::wbar].begin(), h_rayleigh_ptrs[lev][Rayleigh::wbar].end(),
134  d_rayleigh_ptrs[lev][Rayleigh::wbar].begin());
135  Gpu::copy(Gpu::hostToDevice, h_rayleigh_ptrs[lev][Rayleigh::thetabar].begin(), h_rayleigh_ptrs[lev][Rayleigh::thetabar].end(),
136  d_rayleigh_ptrs[lev][Rayleigh::thetabar].begin());
137 
138  if (lev < finest_level) {
139  refine_fac *= ref_ratio[lev][2];
140  }
141  }
142 }
AMREX_FORCE_INLINE void expand_and_interpolate_1d(amrex::Vector< amrex::Real > &znew, const amrex::Vector< amrex::Real > &zorig, int refine_fac, bool destag=false)
Definition: ERF_Interpolation_1D.H:85
amrex::Vector< amrex::Vector< amrex::Real > > theta_inp_sound
Definition: ERF_InputSoundingData.H:404
amrex::Vector< amrex::Vector< amrex::Real > > z_inp_sound
Definition: ERF_InputSoundingData.H:404
amrex::Vector< amrex::Vector< amrex::Real > > U_inp_sound
Definition: ERF_InputSoundingData.H:404
amrex::Vector< amrex::Vector< amrex::Real > > V_inp_sound
Definition: ERF_InputSoundingData.H:404
int size(int itime) const
Definition: ERF_InputSoundingData.H:379
Here is the call graph for this function:

◆ setRecordDataInfo()

void ERF::setRecordDataInfo ( int  i,
const std::string &  filename 
)
inlineprivate
1562  {
1563  if (amrex::ParallelDescriptor::IOProcessor())
1564  {
1565  datalog[i] = std::make_unique<std::fstream>();
1566  datalog[i]->open(filename.c_str(),std::ios::out|std::ios::app);
1567  if (!datalog[i]->good()) {
1568  amrex::FileOpenFailed(filename);
1569  }
1570  }
1571  amrex::ParallelDescriptor::Barrier("ERF::setRecordDataInfo");
1572  }

◆ setRecordDerDataInfo()

void ERF::setRecordDerDataInfo ( int  i,
const std::string &  filename 
)
inlineprivate
1575  {
1576  if (amrex::ParallelDescriptor::IOProcessor())
1577  {
1578  der_datalog[i] = std::make_unique<std::fstream>();
1579  der_datalog[i]->open(filename.c_str(),std::ios::out|std::ios::app);
1580  if (!der_datalog[i]->good()) {
1581  amrex::FileOpenFailed(filename);
1582  }
1583  }
1584  amrex::ParallelDescriptor::Barrier("ERF::setRecordDerDataInfo");
1585  }

◆ setRecordEnergyDataInfo()

void ERF::setRecordEnergyDataInfo ( int  i,
const std::string &  filename 
)
inlineprivate
1588  {
1589  if (amrex::ParallelDescriptor::IOProcessor())
1590  {
1591  tot_e_datalog[i] = std::make_unique<std::fstream>();
1592  tot_e_datalog[i]->open(filename.c_str(),std::ios::out|std::ios::app);
1593  if (!tot_e_datalog[i]->good()) {
1594  amrex::FileOpenFailed(filename);
1595  }
1596  }
1597  amrex::ParallelDescriptor::Barrier("ERF::setRecordEnergyDataInfo");
1598  }

◆ setRecordSampleLineInfo()

void ERF::setRecordSampleLineInfo ( int  i,
int  lev,
amrex::IntVect &  cell,
const std::string &  filename 
)
inlineprivate
1618  {
1619  amrex::MultiFab dummy(grids[lev],dmap[lev],1,0);
1620  for (amrex::MFIter mfi(dummy); mfi.isValid(); ++mfi)
1621  {
1622  const amrex::Box& bx = mfi.validbox();
1623  if (bx.contains(cell)) {
1624  samplelinelog[i] = std::make_unique<std::fstream>();
1625  samplelinelog[i]->open(filename.c_str(),std::ios::out|std::ios::app);
1626  if (!samplelinelog[i]->good()) {
1627  amrex::FileOpenFailed(filename);
1628  }
1629  }
1630  }
1631  amrex::ParallelDescriptor::Barrier("ERF::setRecordSampleLineInfo");
1632  }

◆ setRecordSamplePointInfo()

void ERF::setRecordSamplePointInfo ( int  i,
int  lev,
amrex::IntVect &  cell,
const std::string &  filename 
)
inlineprivate
1601  {
1602  amrex::MultiFab dummy(grids[lev],dmap[lev],1,0);
1603  for (amrex::MFIter mfi(dummy); mfi.isValid(); ++mfi)
1604  {
1605  const amrex::Box& bx = mfi.validbox();
1606  if (bx.contains(cell)) {
1607  sampleptlog[i] = std::make_unique<std::fstream>();
1608  sampleptlog[i]->open(filename.c_str(),std::ios::out|std::ios::app);
1609  if (!sampleptlog[i]->good()) {
1610  amrex::FileOpenFailed(filename);
1611  }
1612  }
1613  }
1614  amrex::ParallelDescriptor::Barrier("ERF::setRecordSamplePointInfo");
1615  }

◆ setSpongeRefFromSounding()

void ERF::setSpongeRefFromSounding ( bool  restarting)
private

Set sponge mean profiles from input sounding.

Sets the sponge damping averaged quantities from an externally supplied input sponge data file.

Parameters
[in]restartingBoolean parameter that indicates whether we are currently restarting from a checkpoint file.
66 {
67  // If we are restarting then we haven't read the input_sponge file yet
68  // so we need to read it here
69  // TODO: should we store this information in the checkpoint file instead?
70  if (restarting) {
72  }
73 
74  const Real* z_inp_sponge = input_sponge_data.z_inp_sponge.dataPtr();
75  const Real* U_inp_sponge = input_sponge_data.U_inp_sponge.dataPtr();
76  const Real* V_inp_sponge = input_sponge_data.V_inp_sponge.dataPtr();
77  const int inp_sponge_size = input_sponge_data.size();
78 
79  for (int lev = 0; lev <= finest_level; lev++)
80  {
81  const int khi = geom[lev].Domain().bigEnd()[2];
82  Vector<Real> zcc(khi+1);
83 
84  if (z_phys_cc[lev]) {
85  // use_terrain=1
86  // calculate the damping strength based on the max height at each k
88  } else {
89  const auto *const prob_lo = geom[lev].ProbLo();
90  const auto *const dx = geom[lev].CellSize();
91  for (int k = 0; k <= khi; k++)
92  {
93  zcc[k] = prob_lo[2] + (k+myhalf) * dx[2];
94  }
95  }
96 
97  for (int k = 0; k <= khi; k++)
98  {
99  h_sponge_ptrs[lev][Sponge::ubar_sponge][k] = interpolate_1d(z_inp_sponge, U_inp_sponge, zcc[k], inp_sponge_size);
100  h_sponge_ptrs[lev][Sponge::vbar_sponge][k] = interpolate_1d(z_inp_sponge, V_inp_sponge, zcc[k], inp_sponge_size);
101  }
102 
103  // Copy from host version to device version
104  Gpu::copy(Gpu::hostToDevice, h_sponge_ptrs[lev][Sponge::ubar_sponge].begin(), h_sponge_ptrs[lev][Sponge::ubar_sponge].end(),
105  d_sponge_ptrs[lev][Sponge::ubar_sponge].begin());
106  Gpu::copy(Gpu::hostToDevice, h_sponge_ptrs[lev][Sponge::vbar_sponge].begin(), h_sponge_ptrs[lev][Sponge::vbar_sponge].end(),
107  d_sponge_ptrs[lev][Sponge::vbar_sponge].begin());
108  }
109 }
AMREX_FORCE_INLINE void reduce_to_max_per_height(amrex::Vector< amrex::Real > &v, std::unique_ptr< amrex::MultiFab > &mf)
Definition: ERF_ParFunctions.H:8
amrex::Vector< amrex::Real > V_inp_sponge
Definition: ERF_InputSpongeData.H:111
amrex::Vector< amrex::Real > z_inp_sponge
Definition: ERF_InputSpongeData.H:111
amrex::Vector< amrex::Real > U_inp_sponge
Definition: ERF_InputSpongeData.H:111
int size() const
Definition: ERF_InputSpongeData.H:99
Here is the call graph for this function:

◆ setSubVolVariables()

void ERF::setSubVolVariables ( const std::string &  pp_subvol_var_names,
amrex::Vector< std::string > &  subvol_var_names 
)
private
11 {
12  ParmParse pp(pp_prefix);
13 
14  std::string nm;
15 
16  int nSubVolVars = pp.countval(pp_subvol_var_names.c_str());
17 
18  // We pre-populate the list with velocities, but allow these to be over-written
19  // by user input
20  if (nSubVolVars == 0)
21  {
22  subvol_var_names.push_back("x_velocity");
23  subvol_var_names.push_back("y_velocity");
24  subvol_var_names.push_back("z_velocity");
25 
26  } else {
27  for (int i = 0; i < nSubVolVars; i++)
28  {
29  pp.get(pp_subvol_var_names.c_str(), nm, i);
30 
31  // Add the named variable to our list of subvol variables
32  // if it is not already in the list
33  if (!containerHasElement(subvol_var_names, nm)) {
34  subvol_var_names.push_back(nm);
35  }
36  }
37  }
38 
39  // Get state variables in the same order as we define them,
40  // since they may be in any order in the input list
41  Vector<std::string> tmp_plot_names;
42 
43  for (int i = 0; i < cons_names.size(); ++i) {
44  if ( containerHasElement(subvol_var_names, cons_names[i]) ) {
45  if (solverChoice.moisture_type == MoistureType::None) {
46  if (cons_names[i] != "rhoQ1" && cons_names[i] != "rhoQ2" && cons_names[i] != "rhoQ3" &&
47  cons_names[i] != "rhoQ4" && cons_names[i] != "rhoQ5" && cons_names[i] != "rhoQ6")
48  {
49  tmp_plot_names.push_back(cons_names[i]);
50  }
51  } else if (solverChoice.moisture_type == MoistureType::Kessler) { // allow rhoQ1, rhoQ2, rhoQ3
52  if (cons_names[i] != "rhoQ4" && cons_names[i] != "rhoQ5" && cons_names[i] != "rhoQ6")
53  {
54  tmp_plot_names.push_back(cons_names[i]);
55  }
56  } else if ( (solverChoice.moisture_type == MoistureType::SatAdj) ||
57  (solverChoice.moisture_type == MoistureType::SAM_NoPrecip_NoIce) ||
58  (solverChoice.moisture_type == MoistureType::Kessler_NoRain) ) { // allow rhoQ1, rhoQ2
59  if (cons_names[i] != "rhoQ3" && cons_names[i] != "rhoQ4" &&
60  cons_names[i] != "rhoQ5" && cons_names[i] != "rhoQ6")
61  {
62  tmp_plot_names.push_back(cons_names[i]);
63  }
64  } else if ( (solverChoice.moisture_type == MoistureType::Morrison_NoIce) ||
65  (solverChoice.moisture_type == MoistureType::SAM_NoIce ) ) { // allow rhoQ1, rhoQ2, rhoQ4
66  if (cons_names[i] != "rhoQ3" && cons_names[i] != "rhoQ5" && cons_names[i] != "rhoQ6")
67  {
68  tmp_plot_names.push_back(cons_names[i]);
69  }
70  } else
71  {
72  // For moisture_type SAM and Morrison we have all six variables
73  tmp_plot_names.push_back(cons_names[i]);
74  }
75  }
76  }
77 
78  // Check for velocity since it's not in cons_names
79  if (containerHasElement(subvol_var_names, "x_velocity")) {
80  tmp_plot_names.push_back("x_velocity");
81  }
82  if (containerHasElement(subvol_var_names, "y_velocity")) {
83  tmp_plot_names.push_back("y_velocity");
84  }
85  if (containerHasElement(subvol_var_names, "z_velocity")) {
86  tmp_plot_names.push_back("z_velocity");
87  }
88 
89  //
90  // If the model we are running doesn't have the variable listed in the inputs file,
91  // just ignore it rather than aborting
92  //
93  for (int i = 0; i < derived_subvol_names.size(); ++i) {
94  if ( containerHasElement(subvol_var_names, derived_names[i]) ) {
95  bool ok_to_add = ( (solverChoice.terrain_type == TerrainType::ImmersedForcing) ||
96  (derived_names[i] != "terrain_IB_mask") );
97  ok_to_add &= ( (SolverChoice::terrain_type == TerrainType::StaticFittedMesh) ||
98  (SolverChoice::terrain_type == TerrainType::MovingFittedMesh) ||
99  (derived_names[i] != "detJ") );
100  ok_to_add &= ( (SolverChoice::terrain_type == TerrainType::StaticFittedMesh) ||
101  (SolverChoice::terrain_type == TerrainType::MovingFittedMesh) ||
102  (derived_names[i] != "z_phys") );
103  if (ok_to_add)
104  {
105  if (solverChoice.moisture_type == MoistureType::None) { // no moist quantities allowed
106  if (derived_names[i] != "qv" && derived_names[i] != "qc" && derived_names[i] != "qrain" &&
107  derived_names[i] != "qi" && derived_names[i] != "qsnow" && derived_names[i] != "qgraup" &&
108  derived_names[i] != "qt" && derived_names[i] != "qn" && derived_names[i] != "qp" &&
109  derived_names[i] != "rain_accum" && derived_names[i] != "snow_accum" && derived_names[i] != "graup_accum")
110  {
111  tmp_plot_names.push_back(derived_names[i]);
112  }
113  } else if ( (solverChoice.moisture_type == MoistureType::Kessler ) ||
114  (solverChoice.moisture_type == MoistureType::Morrison_NoIce) ||
115  (solverChoice.moisture_type == MoistureType::SAM_NoIce ) ) { // allow qv, qc, qrain
116  if (derived_names[i] != "qi" && derived_names[i] != "qsnow" && derived_names[i] != "qgraup" &&
117  derived_names[i] != "snow_accum" && derived_names[i] != "graup_accum")
118  {
119  tmp_plot_names.push_back(derived_names[i]);
120  }
121  } else if ( (solverChoice.moisture_type == MoistureType::SatAdj) ||
122  (solverChoice.moisture_type == MoistureType::SAM_NoPrecip_NoIce) ||
123  (solverChoice.moisture_type == MoistureType::Kessler_NoRain) ) { // allow qv, qc
124  if (derived_names[i] != "qrain" &&
125  derived_names[i] != "qi" && derived_names[i] != "qsnow" && derived_names[i] != "qgraup" &&
126  derived_names[i] != "qp" &&
127  derived_names[i] != "rain_accum" && derived_names[i] != "snow_accum" && derived_names[i] != "graup_accum")
128  {
129  tmp_plot_names.push_back(derived_names[i]);
130  }
131  } else
132  {
133  // For moisture_type SAM and Morrison we have all moist quantities
134  tmp_plot_names.push_back(derived_names[i]);
135  }
136  } // use_terrain?
137  } // hasElement
138  }
139 
140  subvol_var_names = tmp_plot_names;
141 }
const amrex::Vector< std::string > derived_subvol_names
Definition: ERF.H:1210
Here is the call graph for this function:

◆ solve_with_gmres()

void ERF::solve_with_gmres ( int  lev,
const amrex::Box &  subdomain,
amrex::MultiFab &  rhs,
amrex::MultiFab &  p,
amrex::Array< amrex::MultiFab, AMREX_SPACEDIM > &  fluxes,
amrex::MultiFab &  ax_sub,
amrex::MultiFab &  ay_sub,
amrex::MultiFab &  az_sub,
amrex::MultiFab &  ,
amrex::MultiFab &  znd_sub 
)

Solve the Poisson equation using FFT-preconditioned GMRES

16 {
17 #ifdef ERF_USE_FFT
18  BL_PROFILE("ERF::solve_with_gmres()");
19 
22 
23  auto const dom_lo = lbound(Geom(lev).Domain());
24  auto const dom_hi = ubound(Geom(lev).Domain());
25 
26  auto const sub_lo = lbound(subdomain);
27  auto const sub_hi = ubound(subdomain);
28 
29  auto dx = Geom(lev).CellSizeArray();
30 
31  Geometry my_geom;
32 
33  Array<int,AMREX_SPACEDIM> is_per; is_per[0] = 0; is_per[1] = 0; is_per[2] = 0;
34  if (Geom(lev).isPeriodic(0) && sub_lo.x == dom_lo.x && sub_hi.x == dom_hi.x) { is_per[0] = 1;}
35  if (Geom(lev).isPeriodic(1) && sub_lo.y == dom_lo.y && sub_hi.y == dom_hi.y) { is_per[1] = 1;}
36 
37  int coord_sys = 0;
38 
39  // If subdomain == domain then we pass Geom(lev) to the FFT solver
40  if (subdomain == Geom(lev).Domain()) {
41  my_geom.define(Geom(lev).Domain(), Geom(lev).ProbDomain(), coord_sys, is_per);
42  } else {
43  // else we create a new geometry based only on the subdomain
44  // The information in my_geom used by the FFT routines is:
45  // 1) my_geom.Domain()
46  // 2) my_geom.CellSize()
47  // 3) my_geom.isAllPeriodic() / my_geom.periodicity()
48  RealBox rb( sub_lo.x *dx[0], sub_lo.y *dx[1], sub_lo.z *dx[2],
49  (sub_hi.x+1)*dx[0], (sub_hi.y+1)*dx[1], (sub_hi.z+1)*dx[2]);
50  my_geom.define(subdomain, rb, coord_sys, is_per);
51  }
52 
53  amrex::GMRES<MultiFab, TerrainPoisson> gmsolver;
54 
55  TerrainPoisson tp(my_geom, rhs.boxArray(), rhs.DistributionMap(), domain_bc_type,
56  stretched_dz_d[lev], ax_sub, ay_sub, az_sub, dJ_sub, &znd_sub,
58 
59  gmsolver.define(tp);
60 
61  gmsolver.setVerbose(mg_verbose);
62 
63  gmsolver.setRestartLength(50);
64 
65  tp.usePrecond(true);
66 
67  gmsolver.solve(phi, rhs, reltol, abstol);
68 
69  tp.getFluxes(phi, fluxes);
70 
71  for (MFIter mfi(phi); mfi.isValid(); ++mfi)
72  {
73  Box xbx = mfi.nodaltilebox(0);
74  Box ybx = mfi.nodaltilebox(1);
75  const Array4<Real >& fx_ar = fluxes[0].array(mfi);
76  const Array4<Real >& fy_ar = fluxes[1].array(mfi);
77  const Array4<Real const>& mf_ux = mapfac[lev][MapFacType::u_x]->const_array(mfi);
78  const Array4<Real const>& mf_vy = mapfac[lev][MapFacType::v_y]->const_array(mfi);
80  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
81  {
82  fx_ar(i,j,k) *= mf_ux(i,j,0);
83  },
84  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
85  {
86  fy_ar(i,j,k) *= mf_vy(i,j,0);
87  });
88  } // mfi
89 #else
90  amrex::ignore_unused(lev, rhs, phi, fluxes, ax_sub, ay_sub, az_sub, dJ_sub, znd_sub);
91 #endif
92 
93  // ****************************************************************************
94  // Impose bc's on pprime
95  // ****************************************************************************
96  ImposeBCsOnPhi(lev, phi, subdomain);
97 }
void ImposeBCsOnPhi(int lev, amrex::MultiFab &phi, const amrex::Box &subdomain)
Definition: ERF_ImposeBCsOnPhi.cpp:12
Here is the call graph for this function:

◆ sum_derived_quantities()

void ERF::sum_derived_quantities ( double  time)
178 {
179  if (verbose <= 0 || NumDerDataLogs() <= 0) return;
180 
181  int lev = 0;
182 
183  AMREX_ALWAYS_ASSERT(lev == 0);
184 
185  auto& mfx0 = *mapfac[0][MapFacType::m_x];
186  auto& mfy0 = *mapfac[0][MapFacType::m_x];
187  auto& dJ0 = *detJ_cc[0];
188 
189  // ************************************************************************
190  // WARNING: we are not filling ghost cells other than periodic outside the domain
191  // ************************************************************************
192 
193  MultiFab mf_cc_vel(grids[lev], dmap[lev], AMREX_SPACEDIM, IntVect(1,1,1));
194  mf_cc_vel.setVal(0.); // We just do this to avoid uninitialized values
195 
196  // Average all three components of velocity (on faces) to the cell center
197  average_face_to_cellcenter(mf_cc_vel,0,
198  Array<const MultiFab*,3>{&vars_new[lev][Vars::xvel],
199  &vars_new[lev][Vars::yvel],
200  &vars_new[lev][Vars::zvel]});
201  mf_cc_vel.FillBoundary(geom[lev].periodicity());
202 
203  if (!geom[lev].isPeriodic(0) || !geom[lev].isPeriodic(1) || !geom[lev].isPeriodic(2)) {
204  amrex::Warning("Ghost cells outside non-periodic physical boundaries are not filled -- vel set to 0 there");
205  }
206 
207  MultiFab r_wted_magvelsq(grids[lev], dmap[lev], AMREX_SPACEDIM, IntVect(0,0,0));
208  MultiFab unwted_magvelsq(grids[lev], dmap[lev], AMREX_SPACEDIM, IntVect(0,0,0));
209  MultiFab enstrophysq(grids[lev], dmap[lev], AMREX_SPACEDIM, IntVect(1,1,1));
210  MultiFab theta_mf(grids[lev], dmap[lev], AMREX_SPACEDIM, IntVect(0,0,0));
211 
212 #ifdef _OPENMP
213 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
214 #endif
215  for (MFIter mfi(unwted_magvelsq, TilingIfNotGPU()); mfi.isValid(); ++mfi)
216  {
217  const Box& bx = mfi.tilebox();
218  auto& src_fab = mf_cc_vel[mfi];
219 
220  auto& dest1_fab = unwted_magvelsq[mfi];
221  // NOTE: we send in src_fab where we should
222  derived::erf_dermagvelsq(bx, dest1_fab, 0, 1, src_fab, (*z_phys_cc[lev])[mfi], Geom(lev), t_new[0], nullptr, lev);
223 
224  auto& dest2_fab = enstrophysq[mfi];
225  derived::erf_derenstrophysq(bx, dest2_fab, 0, 1, src_fab, (*z_phys_cc[lev])[mfi], Geom(lev), t_new[0], nullptr, lev);
226  }
227 
228  // Copy the MF holding 1/2(u^2 + v^2 + w^2) into the MF that will hold 1/2 rho (u^2 + v^2 + w^2)d
229  MultiFab::Copy(r_wted_magvelsq, unwted_magvelsq, 0, 0, 1, 0);
230 
231  // Multiply the MF holding 1/2(u^2 + v^2 + w^2) by rho to get 1/2 rho (u^2 + v^2 + w^2)
232  MultiFab::Multiply(r_wted_magvelsq, vars_new[lev][Vars::cons], 0, 0, 1, 0);
233 
234  // Copy the MF holding (rho theta) into "theta_mf"
235  MultiFab::Copy(theta_mf, vars_new[lev][Vars::cons], RhoTheta_comp, 0, 1, 0);
236 
237  // Divide (rho theta) by rho to get theta in the MF "theta_mf"
238  MultiFab::Divide(theta_mf, vars_new[lev][Vars::cons], Rho_comp, 0, 1, 0);
239 
240  Real unwted_avg = volWgtSumMF(lev, unwted_magvelsq, 0, dJ0, mfx0, mfy0, false);
241  Real r_wted_avg = volWgtSumMF(lev, r_wted_magvelsq, 0, dJ0, mfx0, mfy0, false);
242  Real enstrsq_avg = volWgtSumMF(lev, enstrophysq, 0, dJ0, mfx0, mfy0, false);
243  Real theta_avg = volWgtSumMF(lev, theta_mf, 0, dJ0, mfx0, mfy0, false);
244 
245  // Get volume including terrain (consistent with volWgtSumMF routine)
246  MultiFab volume(grids[lev], dmap[lev], 1, 0);
247  auto const& dx = geom[lev].CellSizeArray();
248  Real cell_vol = dx[0]*dx[1]*dx[2];
249  volume.setVal(cell_vol);
250  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
251  MultiFab::Multiply(volume, *detJ_cc[lev], 0, 0, 1, 0);
252  }
253 #ifdef _OPENMP
254 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
255 #endif
256  for (MFIter mfi(volume, TilingIfNotGPU()); mfi.isValid(); ++mfi)
257  {
258  const Box& tbx = mfi.tilebox();
259  auto dst = volume.array(mfi);
260  const auto& mfx = mapfac[lev][MapFacType::m_x]->const_array(mfi);
261  const auto& mfy = mapfac[lev][MapFacType::m_y]->const_array(mfi);
262  ParallelFor(tbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
263  {
264  dst(i,j,k) /= (mfx(i,j,0)*mfy(i,j,0));
265  });
266  }
267  Real vol = volume.sum();
268 
269  unwted_avg /= vol;
270  r_wted_avg /= vol;
271  enstrsq_avg /= vol;
272  theta_avg /= vol;
273 
274  const int nfoo = 4;
275  Real foo[nfoo] = {unwted_avg,r_wted_avg,enstrsq_avg,theta_avg};
276 #ifdef AMREX_LAZY
277  Lazy::QueueReduction([=]() mutable {
278 #endif
279  ParallelDescriptor::ReduceRealSum(
280  foo, nfoo, ParallelDescriptor::IOProcessorNumber());
281 
282  if (ParallelDescriptor::IOProcessor()) {
283  int i = 0;
284  unwted_avg = foo[i++];
285  r_wted_avg = foo[i++];
286  enstrsq_avg = foo[i++];
287  theta_avg = foo[i++];
288 
289  std::ostream& data_log_der = DerDataLog(0);
290 
291  if (time == zero) {
292  data_log_der << std::setw(datwidth) << " time";
293  data_log_der << std::setw(datwidth) << " ke_den";
294  data_log_der << std::setw(datwidth) << " velsq";
295  data_log_der << std::setw(datwidth) << " enstrophy";
296  data_log_der << std::setw(datwidth) << " int_energy";
297  data_log_der << std::endl;
298  }
299  data_log_der << std::setw(datwidth) << std::setprecision(timeprecision) << time;
300  data_log_der << std::setw(datwidth) << std::setprecision(datprecision) << unwted_avg;
301  data_log_der << std::setw(datwidth) << std::setprecision(datprecision) << r_wted_avg;
302  data_log_der << std::setw(datwidth) << std::setprecision(datprecision) << enstrsq_avg;
303  data_log_der << std::setw(datwidth) << std::setprecision(datprecision) << theta_avg;
304  data_log_der << std::endl;
305 
306  } // if IOProcessor
307 #ifdef AMREX_LAZY
308  }
309 #endif
310 }
AMREX_FORCE_INLINE std::ostream & DerDataLog(int i)
Definition: ERF.H:1469
const int timeprecision
Definition: ERF.H:1068
AMREX_FORCE_INLINE int NumDerDataLogs() noexcept
Definition: ERF.H:1483
void erf_dermagvelsq(const Box &bx, FArrayBox &derfab, int dcomp, int ncomp, const FArrayBox &datfab, const FArrayBox &, const Geometry &, Real, const int *, const int)
Definition: ERF_Derive.cpp:507
void erf_derenstrophysq(const Box &bx, FArrayBox &derfab, int dcomp, int ncomp, const FArrayBox &datfab, const FArrayBox &zcc_fab, const Geometry &geomdata, Real, const int *, const int)
Definition: ERF_Derive.cpp:443
Here is the call graph for this function:

◆ sum_energy_quantities()

void ERF::sum_energy_quantities ( double  time)
314 {
315  if ( (verbose <= 0) || (tot_e_datalog.size() < 1) ) { return; }
316 
317  int lev = 0;
318 
319  auto& mfx0 = *mapfac[0][MapFacType::m_x];
320  auto& mfy0 = *mapfac[0][MapFacType::m_x];
321  auto& dJ0 = *detJ_cc[0];
322 
323  AMREX_ALWAYS_ASSERT(lev == 0);
324 
325  bool local = true;
326 
327  // ************************************************************************
328  // WARNING: we are not filling ghost cells other than periodic outside the domain
329  // ************************************************************************
330 
331  MultiFab mf_cc_vel(grids[lev], dmap[lev], AMREX_SPACEDIM, IntVect(1,1,1));
332  mf_cc_vel.setVal(0.); // We just do this to avoid uninitialized values
333 
334  // Average all three components of velocity (on faces) to the cell center
335  average_face_to_cellcenter(mf_cc_vel,0,
336  Array<const MultiFab*,3>{&vars_new[lev][Vars::xvel],
337  &vars_new[lev][Vars::yvel],
338  &vars_new[lev][Vars::zvel]});
339  mf_cc_vel.FillBoundary(geom[lev].periodicity());
340 
341  if (!geom[lev].isPeriodic(0) || !geom[lev].isPeriodic(1) || !geom[lev].isPeriodic(2)) {
342  amrex::Warning("Ghost cells outside non-periodic physical boundaries are not filled -- vel set to 0 there");
343  }
344 
345  MultiFab tot_mass (grids[lev], dmap[lev], AMREX_SPACEDIM, IntVect(0,0,0));
346  MultiFab tot_energy(grids[lev], dmap[lev], AMREX_SPACEDIM, IntVect(0,0,0));
347 
348  auto const& dx = geom[lev].CellSizeArray();
349  bool is_moist = (solverChoice.moisture_type != MoistureType::None);
350 
351 #ifdef _OPENMP
352 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
353 #endif
354  for (MFIter mfi(tot_mass, TilingIfNotGPU()); mfi.isValid(); ++mfi)
355  {
356  const Box& bx = mfi.tilebox();
357 
358  const Array4<Real>& cc_vel_arr = mf_cc_vel.array(mfi);
359  const Array4<Real>& tot_mass_arr = tot_mass.array(mfi);
360  const Array4<Real>& tot_energy_arr = tot_energy.array(mfi);
361  const Array4<const Real>& cons_arr = vars_new[lev][Vars::cons].const_array(mfi);
362  const Array4<const Real>& z_arr = (z_phys_nd[lev]) ? z_phys_nd[lev]->const_array(mfi) :
363  Array4<const Real>{};
364  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
365  {
366  Real Qv = (is_moist) ? cons_arr(i,j,k,RhoQ1_comp) : zero;
367  Real Qc = (is_moist) ? cons_arr(i,j,k,RhoQ2_comp) : zero;
368  Real Qt = Qv + Qc;
369  Real Rhod = cons_arr(i,j,k,Rho_comp);
370  Real Rhot = Rhod * (one + Qt);
371  Real Temp = getTgivenRandRTh(Rhod, cons_arr(i,j,k,RhoTheta_comp), Qv);
372  Real TKE = myhalf * ( cc_vel_arr(i,j,k,0)*cc_vel_arr(i,j,k,0)
373  + cc_vel_arr(i,j,k,1)*cc_vel_arr(i,j,k,1)
374  + cc_vel_arr(i,j,k,2)*cc_vel_arr(i,j,k,2) );
375  Real zval = (z_arr) ? z_arr(i,j,k) : Real(k)*dx[2];
376 
377  Real Cv = Cp_d - R_d;
378  Real Cvv = Cp_v - R_v;
379  Real Cpv = Cp_v;
380 
381  tot_mass_arr(i,j,k) = Rhot;
382  tot_energy_arr(i,j,k) = Rhod * ( (Cv + Cvv*Qv + Cpv*Qc)*Temp - L_v*Qc
383  + (one + Qt)*TKE + (one + Qt)*CONST_GRAV*zval );
384 
385  });
386 
387  }
388 
389  Real tot_mass_avg = volWgtSumMF(lev, tot_mass , 0, dJ0, mfx0, mfy0, false, local);
390  Real tot_energy_avg = volWgtSumMF(lev, tot_energy, 0, dJ0, mfx0, mfy0, false, local);
391 
392  // Get volume including terrain (consistent with volWgtSumMF routine)
393  MultiFab volume(grids[lev], dmap[lev], 1, 0);
394  Real cell_vol = dx[0]*dx[1]*dx[2];
395  volume.setVal(cell_vol);
396  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
397  MultiFab::Multiply(volume, *detJ_cc[lev], 0, 0, 1, 0);
398  }
399 #ifdef _OPENMP
400 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
401 #endif
402  for (MFIter mfi(volume, TilingIfNotGPU()); mfi.isValid(); ++mfi)
403  {
404  const Box& tbx = mfi.tilebox();
405  auto dst = volume.array(mfi);
406  const auto& mfx = mapfac[lev][MapFacType::m_x]->const_array(mfi);
407  const auto& mfy = mapfac[lev][MapFacType::m_y]->const_array(mfi);
408  ParallelFor(tbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
409  {
410  dst(i,j,k) /= (mfx(i,j,0)*mfy(i,j,0));
411  });
412  }
413  Real vol = volume.sum();
414 
415  // Divide by the volume
416  tot_mass_avg /= vol;
417  tot_energy_avg /= vol;
418 
419  const int nfoo = 2;
420  Real foo[nfoo] = {tot_mass_avg,tot_energy_avg};
421 #ifdef AMREX_LAZY
422  Lazy::QueueReduction([=]() mutable {
423 #endif
424  ParallelDescriptor::ReduceRealSum(
425  foo, nfoo, ParallelDescriptor::IOProcessorNumber());
426 
427  if (ParallelDescriptor::IOProcessor()) {
428  int i = 0;
429  tot_mass_avg = foo[i++];
430  tot_energy_avg = foo[i++];
431 
432  std::ostream& data_log_energy = *tot_e_datalog[0];
433 
434  if (time == zero) {
435  data_log_energy << std::setw(datwidth) << " time";
436  data_log_energy << std::setw(datwidth) << " tot_mass";
437  data_log_energy << std::setw(datwidth) << " tot_energy";
438  data_log_energy << std::endl;
439  }
440  data_log_energy << std::setw(datwidth) << std::setprecision(timeprecision) << time;
441  data_log_energy << std::setw(datwidth) << std::setprecision(datprecision) << tot_mass_avg;
442  data_log_energy << std::setw(datwidth) << std::setprecision(datprecision) << tot_energy_avg;
443  data_log_energy << std::endl;
444 
445  } // if IOProcessor
446 #ifdef AMREX_LAZY
447  }
448 #endif
449 }
constexpr amrex::Real R_v
Definition: ERF_Constants.H:30
constexpr amrex::Real Cp_d
Definition: ERF_Constants.H:31
constexpr amrex::Real CONST_GRAV
Definition: ERF_Constants.H:40
constexpr amrex::Real Cp_v
Definition: ERF_Constants.H:32
constexpr amrex::Real R_d
Definition: ERF_Constants.H:29
constexpr amrex::Real L_v
Definition: ERF_Constants.H:35
Here is the call graph for this function:

◆ sum_integrated_quantities()

void ERF::sum_integrated_quantities ( double  time)

Computes the integrated quantities on the grid such as the total scalar and total mass quantities. Prints and writes to output file.

Parameters
timeCurrent time
16 {
17  BL_PROFILE("ERF::sum_integrated_quantities()");
18 
19  if (verbose <= 0)
20  return;
21 
22  // Single level sum
23  Real mass_sl;
24 
25  // Multilevel sums
26  Real mass_ml = zero;
27  Real rhth_ml = zero;
28  Real scal_ml = zero;
29  Real mois_ml = zero;
30 
31  bool local = true;
32 
33  auto& mfx0 = *mapfac[0][MapFacType::m_x];
34  auto& mfy0 = *mapfac[0][MapFacType::m_x];
35  auto& dJ0 = *detJ_cc[0];
36 
37  mass_sl = volWgtSumMF(0,vars_new[0][Vars::cons],Rho_comp,dJ0,mfx0,mfy0,false,local);
38 
39  for (int lev = 0; lev <= finest_level; lev++) {
40  auto& mfx = *mapfac[lev][MapFacType::m_x];
41  auto& mfy = *mapfac[lev][MapFacType::m_x];
42  auto& dJ = *detJ_cc[lev];
43  mass_ml += volWgtSumMF(lev,vars_new[lev][Vars::cons],Rho_comp,dJ,mfx,mfy,true);
44  }
45 
46  Real rhth_sl = volWgtSumMF(0,vars_new[0][Vars::cons], RhoTheta_comp,dJ0,mfx0,mfy0,false);
47  Real scal_sl = volWgtSumMF(0,vars_new[0][Vars::cons],RhoScalar_comp,dJ0,mfx0,mfy0,false);
48  Real mois_sl = zero;
49  if (solverChoice.moisture_type != MoistureType::None) {
50  int n_qstate_into_total = micro->Get_Qstate_Moist_Size() - micro->Get_Qstate_Moist_NumConc_Size();
51  for (int qoff(0); qoff<n_qstate_into_total; ++qoff) {
52  mois_sl += volWgtSumMF(0,vars_new[0][Vars::cons],RhoQ1_comp+qoff,dJ0,mfx0,mfy0,false);
53  }
54  }
55 
56  for (int lev = 0; lev <= finest_level; lev++) {
57  auto& mfx = *mapfac[lev][MapFacType::m_x];
58  auto& mfy = *mapfac[lev][MapFacType::m_x];
59  auto& dJ = *detJ_cc[lev];
60  rhth_ml += volWgtSumMF(lev,vars_new[lev][Vars::cons], RhoTheta_comp,dJ,mfx,mfy,true);
61  scal_ml += volWgtSumMF(lev,vars_new[lev][Vars::cons],RhoScalar_comp,dJ,mfx,mfy,true);
62  if (solverChoice.moisture_type != MoistureType::None) {
63  int n_qstate_into_total = micro->Get_Qstate_Moist_Size() - micro->Get_Qstate_Moist_NumConc_Size();
64  for (int qoff(0); qoff<n_qstate_into_total; ++qoff) {
65  mois_ml += volWgtSumMF(lev,vars_new[lev][Vars::cons],RhoQ1_comp+qoff,dJ,mfx,mfy,false);
66  }
67  }
68  }
69 
70  Gpu::HostVector<Real> h_avg_ustar; h_avg_ustar.resize(1);
71  Gpu::HostVector<Real> h_avg_tstar; h_avg_tstar.resize(1);
72  Gpu::HostVector<Real> h_avg_olen; h_avg_olen.resize(1);
73  if ((m_SurfaceLayer != nullptr) && (NumDataLogs() > 0)) {
74  Box domain = geom[0].Domain();
75  int zdir = 2;
76  h_avg_ustar = sumToLine(*m_SurfaceLayer->get_u_star(0),0,1,domain,zdir);
77  h_avg_tstar = sumToLine(*m_SurfaceLayer->get_t_star(0),0,1,domain,zdir);
78  h_avg_olen = sumToLine(*m_SurfaceLayer->get_olen(0) ,0,1,domain,zdir);
79 
80  // Divide by the total number of cells we are averaging over
81  Real area_z = static_cast<Real>(domain.length(0)*domain.length(1));
82  h_avg_ustar[0] /= area_z;
83  h_avg_tstar[0] /= area_z;
84  h_avg_olen[0] /= area_z;
85 
86  } else {
87  h_avg_ustar[0] = zero;
88  h_avg_tstar[0] = zero;
89  h_avg_olen[0] = zero;
90  }
91 
92  const int nfoo = 8;
93  Real foo[nfoo] = {mass_sl,rhth_sl,scal_sl,mois_sl,mass_ml,rhth_ml,scal_ml,mois_ml};
94 #ifdef AMREX_LAZY
95  Lazy::QueueReduction([=]() mutable {
96 #endif
97  ParallelDescriptor::ReduceRealSum(
98  foo, nfoo, ParallelDescriptor::IOProcessorNumber());
99 
100  if (ParallelDescriptor::IOProcessor()) {
101  int i = 0;
102  mass_sl = foo[i++];
103  rhth_sl = foo[i++];
104  scal_sl = foo[i++];
105  mois_sl = foo[i++];
106  mass_ml = foo[i++];
107  rhth_ml = foo[i++];
108  scal_ml = foo[i++];
109  mois_ml = foo[i++];
110 
111  Print() << '\n';
112  Print() << "TIME= " << std::setw(datwidth) << std::setprecision(timeprecision) << std::left << time << '\n';
113  if (finest_level == 0) {
114 #if 1
115  Print() << " MASS = " << mass_sl << '\n';
116 #else
117  Print() << " PERT MASS = " << mass_sl << '\n';
118 #endif
119  Print() << " RHO THETA = " << rhth_sl << '\n';
120  if (solverChoice.transport_scalar) { Print() << " RHO SCALAR = " << scal_sl << '\n'; }
121  if (solverChoice.moisture_type != MoistureType::None) { Print() << " RHO QTOTAL = " << mois_sl << '\n'; }
122  } else {
123 #if 1
124  Print() << " MASS SL/ML = " << mass_sl << " " << mass_ml << '\n';
125 #else
126  Print() << " PERT MASS SL/ML = " << mass_sl << " " << mass_ml << '\n';
127 #endif
128  Print() << " RHO THETA SL/ML = " << rhth_sl << " " << rhth_ml << '\n';
129  if (solverChoice.transport_scalar) { Print() << " RHO SCALAR SL/ML = " << scal_sl << " " << scal_ml << '\n'; }
130  if (solverChoice.moisture_type != MoistureType::None) { Print() << " RHO QTOTAL SL/ML = " << mois_sl << " " << mois_ml << '\n'; }
131  }
132 
133  // The first data log only holds scalars
134  if (NumDataLogs() > 0)
135  {
136  int n_d = 0;
137  std::ostream& data_log1 = DataLog(n_d);
138  if (data_log1.good()) {
139  if (time == zero) {
140  data_log1 << std::setw(datwidth) << " time";
141  data_log1 << std::setw(datwidth) << " u_star";
142  data_log1 << std::setw(datwidth) << " t_star";
143  data_log1 << std::setw(datwidth) << " olen";
144  data_log1 << std::endl;
145  } // time = 0
146 
147  // Write the quantities at this time
148  data_log1 << std::setw(datwidth) << std::setprecision(timeprecision) << time;
149  data_log1 << std::setw(datwidth) << std::setprecision(datprecision) << h_avg_ustar[0];
150  data_log1 << std::setw(datwidth) << std::setprecision(datprecision) << h_avg_tstar[0];
151  data_log1 << std::setw(datwidth) << std::setprecision(datprecision) << h_avg_olen[0];
152  data_log1 << std::endl;
153  } // if good
154  } // loop over i
155  } // if IOProcessor
156 #ifdef AMREX_LAZY
157  });
158 #endif
159 
160  // This is just an alias for convenience
161  int lev = 0;
162  if (NumSamplePointLogs() > 0 && NumSamplePoints() > 0) {
163  for (int i = 0; i < NumSamplePoints(); ++i)
164  {
165  sample_points(lev, time, SamplePoint(i), vars_new[lev][Vars::cons]);
166  }
167  }
168  if (NumSampleLineLogs() > 0 && NumSampleLines() > 0) {
169  for (int i = 0; i < NumSampleLines(); ++i)
170  {
171  sample_lines(lev, time, SampleLine(i), vars_new[lev][Vars::cons]);
172  }
173  }
174 }
AMREX_FORCE_INLINE int NumSampleLineLogs() noexcept
Definition: ERF.H:1512
AMREX_FORCE_INLINE int NumSamplePointLogs() noexcept
Definition: ERF.H:1498
amrex::IntVect & SampleLine(int i)
Definition: ERF.H:1531
AMREX_FORCE_INLINE int NumSamplePoints() noexcept
Definition: ERF.H:1525
AMREX_FORCE_INLINE int NumSampleLines() noexcept
Definition: ERF.H:1538
amrex::IntVect & SamplePoint(int i)
Definition: ERF.H:1518
void sample_points(int lev, amrex::Real time, amrex::IntVect cell, amrex::MultiFab &mf)
Definition: ERF_WriteScalarProfiles.cpp:528
AMREX_FORCE_INLINE std::ostream & DataLog(int i)
Definition: ERF.H:1462
AMREX_FORCE_INLINE int NumDataLogs() noexcept
Definition: ERF.H:1476
void sample_lines(int lev, amrex::Real time, amrex::IntVect cell, amrex::MultiFab &mf)
Definition: ERF_WriteScalarProfiles.cpp:564
bool transport_scalar
Definition: ERF_DataStruct.H:1244

◆ SurfaceDataInterpolation()

void ERF::SurfaceDataInterpolation ( const int  nlevs,
const amrex::Real  time,
amrex::Vector< std::unique_ptr< amrex::MultiFab >> &  z_phys_nd,
bool  regrid_forces_file_read 
)
146 {
147 
148  static amrex::Vector<Real> next_read_forecast_time;
149  static amrex::Vector<Real> last_read_forecast_time;
150 
151  const int nlevs = a_z_phys_nd.size();
152 
153  Real hindcast_data_interval = solverChoice.hindcast_data_interval_in_hrs*Real(3600.0);
154 
155  // Initialize static vectors once
156  if (next_read_forecast_time.empty()) {
157  next_read_forecast_time.resize(nlevs, -one);
158  last_read_forecast_time.resize(nlevs, -one);
159  Print() << "Initializing the time vector values here by " << lev << std::endl;
160  }
161 
162  if (next_read_forecast_time[lev] < zero) {
163  int next_multiple = static_cast<int>(time / hindcast_data_interval);
164  next_read_forecast_time[lev] = next_multiple * hindcast_data_interval;
165  last_read_forecast_time[lev] = next_read_forecast_time[lev];
166  }
167 
168  if (time >= next_read_forecast_time[lev] or regrid_forces_file_read) {
169 
170  Print() << "Data reading happening at level " << lev << std::endl;
171 
172  std::string folder = solverChoice.hindcast_surface_data_dir;
173 
174  // Check if folder exists and is a directory
175  if (!fs::exists(folder) || !fs::is_directory(folder)) {
176  throw std::runtime_error("Error: Folder '" + folder + "' does not exist or is not a directory.");
177  }
178 
179  std::vector<std::string> bin_files;
180 
181  for (const auto& entry : fs::directory_iterator(folder)) {
182  if (!entry.is_regular_file()) continue;
183 
184  std::string fname = entry.path().filename().string();
185  if (fname.size() >= 4 && fname.substr(fname.size() - 4) == ".bin") {
186  bin_files.push_back(entry.path().string());
187  }
188  }
189  std::sort(bin_files.begin(), bin_files.end());
190 
191  // Check if no .bin files were found
192  if (bin_files.empty()) {
193  throw std::runtime_error("Error: No .bin files found in folder '" + folder + "'.");
194  }
195 
196  std::string filename1, filename2;
197 
198  int idx1 = static_cast<int>(time / hindcast_data_interval);
199  int idx2 = static_cast<int>(time / hindcast_data_interval)+1;
200  Print() << "Reading surface data " << time << " " << idx1 << " " << idx2 <<" " << bin_files.size() << std::endl;
201 
202  if (idx2 >= static_cast<int>(bin_files.size())) {
203  throw std::runtime_error("Error: Not enough .bin files to cover time " + std::to_string(time));
204  }
205 
206  filename1 = bin_files[idx1];
207  filename2 = bin_files[idx2];
208 
211 
212  // Create the time-interpolated forecast state
213  //CreateForecastStateMultiFabs(forecast_state_interp);
214  if(!regrid_forces_file_read){
215  last_read_forecast_time[lev] = next_read_forecast_time[lev];
216  next_read_forecast_time[lev] += hindcast_data_interval;
217  Print() << "Next forecast time getting updated here " << std::endl;
218  }
219  }
220 
221  Real prev_read_time = last_read_forecast_time[lev];
222  Real alpha1 = one - (time - prev_read_time)/hindcast_data_interval;
223  Real alpha2 = one - alpha1;
224 
225  amrex::Print()<< "The values of alpha1 and alpha2 are " << alpha1 << " "<< alpha2 <<std::endl;
226 
227  if (alpha1 < zero || alpha1 > one ||
228  alpha2 < zero || alpha2 > one)
229  {
230  std::stringstream ss;
231  ss << "Interpolation weights for hindcast files are incorrect: "
232  << "alpha1 = " << alpha1 << ", alpha2 = " << alpha2;
233  Abort(ss.str());
234  }
235 
236  /*MultiFab& mf_surf_interp = surface_state_interp[lev];
237 
238  // Fill the time-interpolated forecast states
239  MultiFab::LinComb(surface_state_interp[lev],
240  alpha1, surface_state_1[lev], 0,
241  alpha2, surface_state_2[lev], 0,
242  0, mf_surf_interp.nComp(), mf_surf_interp.nGrow());
243 
244  std::string pltname = "plt_interp_surface";
245  Vector<std::string> varnames_plot_mf = {"ls_mask", "SST"};
246 
247  const MultiFab& src = vars_new[0][0];
248 
249  MultiFab plot_mf(src.boxArray(),
250  src.DistributionMap(),
251  2, 0);
252 
253  plot_mf.setVal(0.0);
254 
255  for (MFIter mfi(plot_mf); mfi.isValid(); ++mfi) {
256  const Array4<Real> &plot_mf_arr = plot_mf.array(mfi);
257  const Array4<Real> &surf_mf_arr = surface_state_1[0].array(mfi);
258 
259  const Box& bx = mfi.validbox();
260 
261  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
262  plot_mf_arr(i,j,k,0) = surf_mf_arr(i,j,0);
263  plot_mf_arr(i,j,k,1) = surf_mf_arr(i,j,1);
264  });
265  }
266 
267  WriteSingleLevelPlotfile(
268  pltname,
269  plot_mf,
270  varnames_plot_mf,
271  geom[0],
272  time,
273  0 // level
274  );*/
275 }
void FillSurfaceStateMultiFabs(const int lev, const std::string &filename, amrex::Vector< amrex::MultiFab > &surface_state)
Definition: ERF_SurfaceDataInterpolation.cpp:19
std::string hindcast_surface_data_dir
Definition: ERF_DataStruct.H:1330
amrex::Real hindcast_data_interval_in_hrs
Definition: ERF_DataStruct.H:1331

◆ timeStep()

void ERF::timeStep ( int  lev,
double  time,
int  iteration 
)
private

Function that coordinates the evolution across levels – this calls Advance to do the actual advance at this level, then recursively calls itself at finer levels

Parameters
[in]levlevel of refinement (coarsest level is 0)
[in]timestart time for time advance
[in]iterationtime step counter
18 {
19  //
20  // We need to FillPatch the coarse level before assessing whether to regrid
21  // We have not done the swap yet so we fill the "new" which will become the "old"
22  //
23  MultiFab& S_new = vars_new[lev][Vars::cons];
24  MultiFab& U_new = vars_new[lev][Vars::xvel];
25  MultiFab& V_new = vars_new[lev][Vars::yvel];
26  MultiFab& W_new = vars_new[lev][Vars::zvel];
27 
28 #ifdef ERF_USE_NETCDF
29  //
30  // Since we now only read in a subset of the time slices in wrfbdy and
31  // wrflowinp, we need to check whether it's time to read in more.
32  //
33  bool use_moist = (solverChoice.moisture_type != MoistureType::None);
34  if (solverChoice.use_real_bcs && (lev==0))
35  {
36  MultiFab r_hse(base_state[lev], make_alias, BaseState::r0_comp, 1);
37  Array<MultiFab*, AMREX_SPACEDIM> area_vec = {ax[lev].get(), ay[lev].get(), az[lev].get()};
38 
39  int ntimes = bdy_data_xlo.size();
40  Real time_since_start_bdy = time + start_time - start_bdy_time;
41  int n_time_old = std::min(static_cast<int>( (time_since_start_bdy ) / bdy_time_interval), ntimes-1);
42  int n_time_new = std::min(static_cast<int>( (time_since_start_bdy+dt[lev]) / bdy_time_interval), ntimes-1);
43 
44  for (int itime = 0; itime < ntimes; itime++)
45  {
46  /*
47  if (bdy_data_xlo[itime].size() > 0) {
48  amrex::Print() << "HAVE BDY DATA AT TIME " << itime << std::endl;
49  } else {
50  amrex::Print() << " NO BDY DATA AT TIME " << itime << std::endl;
51  }
52  */
53 
54  // Note that we never release itime == 0 because it is used for the spatial interpolation at later times
55  bool clear_itime = (itime > 0 && itime < n_time_old);
56 
57  if (clear_itime && bdy_data_xlo[itime].size() > 0) {
58  bdy_data_xlo[itime].clear();
59  bdy_data_xhi[itime].clear();
60  bdy_data_ylo[itime].clear();
61  bdy_data_yhi[itime].clear();
62  //amrex::Print() << "CLEAR BDY DATA AT TIME " << itime << std::endl;
63  }
64 
65  bool need_itime = (itime >= n_time_old && itime <= n_time_new+1);
66  //if (need_itime) { amrex::Print() << "NEED BDY DATA AT TIME " << itime << std::endl; }
67 
68  if (bdy_data_xlo[itime].size() == 0 && need_itime) {
69  bool is_anelastic = (solverChoice.anelastic[0] == 1);
70  read_and_convert_from_wrfbdy(itime,nc_bdy_file,bdy_data_xlo,bdy_data_xhi,bdy_data_ylo,bdy_data_yhi,
73  r_hse, area_vec, geom[lev], use_moist, domain_bcs_type,
74  real_width, bdy_time_interval, is_anelastic);
75  }
76  } // itime
77  } // use_real_bcs && lev == 0
78 
79  if (!nc_low_file.empty() && (lev==0))
80  {
81  int ntimes = low_data_zlo.size();
82  Real time_since_start_low = time + start_time - start_low_time;
83  int n_time_old = std::min(static_cast<int>( (time_since_start_low ) / low_time_interval), ntimes-1);
84  int n_time_new = std::min(static_cast<int>( (time_since_start_low+dt[lev]) / low_time_interval), ntimes-1);
85 
86  for (int itime = 0; itime < ntimes; itime++)
87  {
88  /*
89  if (low_data_zlo[itime].size() > 0) {
90  amrex::Print() << "HAVE LOW DATA AT TIME " << itime << std::endl;
91  } else {
92  amrex::Print() << " NO LOW DATA AT TIME " << itime << std::endl;
93  }
94  */
95 
96  bool clear_itime = (itime < n_time_old);
97 
98  if (clear_itime && low_data_zlo[itime].size() > 0) {
99  low_data_zlo[itime].clear();
100  //amrex::Print() << "CLEAR LOW DATA AT TIME " << itime << std::endl;
101  }
102 
103  bool need_itime = (itime >= n_time_old && itime <= n_time_new+1);
104  //if (need_itime) { amrex::Print() << "NEED LOW DATA AT TIME " << itime << std::endl; }
105 
106  if (low_data_zlo[itime].size() == 0 && need_itime) {
107  read_from_wrflow(itime, nc_low_file, geom[lev].Domain(), low_data_zlo);
108 
109  update_sst_tsk(itime, geom[lev], ba2d[lev],
110  sst_lev[lev], tsk_lev[lev],
111  m_SurfaceLayer, low_data_zlo,
112  S_new, *mf_PSFC[lev],
113  solverChoice.rdOcp, lmask_lev[lev][0], use_moist);
114  }
115  } // itime
116  } // have nc_low_file && lev == 0
117 #endif
118 
119  //
120  // NOTE: the momenta here are not fillpatched (they are only used as scratch space)
121  //
122  if (lev == 0) {
123  FillPatchCrseLevel(lev, time, {&S_new, &U_new, &V_new, &W_new});
124  } else if (lev < finest_level) {
125  FillPatchFineLevel(lev, time, {&S_new, &U_new, &V_new, &W_new},
126  {&S_new, &rU_new[lev], &rV_new[lev], &rW_new[lev]},
127  base_state[lev], base_state[lev]);
128  }
129 
130  if (regrid_int > 0) // We may need to regrid
131  {
132  // help keep track of whether a level was already regridded
133  // from a coarser level call to regrid
134  static Vector<int> last_regrid_step(max_level+1, 0);
135 
136  // regrid changes level "lev+1" so we don't regrid on max_level
137  // also make sure we don't regrid fine levels again if
138  // it was taken care of during a coarser regrid
139  if (lev < max_level)
140  {
141  if ( (istep[lev] % regrid_int == 0) && (istep[lev] > last_regrid_step[lev]) )
142  {
143  // regrid could add newly refine levels (if finest_level < max_level)
144  // so we save the previous finest level index
145  int old_finest = finest_level;
146 
147  if (solverChoice.coupling_type == CouplingType::TwoWay &&
148  solverChoice.moisture_type != MoistureType::None &&
149  Microphysics::modelType(solverChoice.moisture_type) == MoistureModelType::Lagrangian &&
150  finest_level >= 1) {
151  micro->AverageDownMicroVars(finest_level);
152  for (int flev = finest_level-1; flev >= lev; --flev) {
154  }
155  }
156 
157  regrid(lev, time);
158 
159 #ifdef ERF_USE_PARTICLES
160  particleData.Redistribute(z_phys_nd);
161 #endif
162 
163  // mark that we have regridded this level already
164  for (int k = lev; k <= finest_level; ++k) {
165  last_regrid_step[k] = istep[k];
166  }
167 
168  // if there are newly created levels, set the time step
169  for (int k = old_finest+1; k <= finest_level; ++k) {
170  dt[k] = dt[k-1] / static_cast<Real>(nsubsteps[k]);
171  }
172  } // if
173  } // lev
174  }
175 
176  // Update what we call "old" and "new" time
177  t_old[lev] = t_new[lev];
178  t_new[lev] += dt[lev];
179 
180  if (Verbose()) {
181  amrex::Print() << "[Level " << lev << " step " << istep[lev]+1 << "] ";
182  amrex::Print() << std::setprecision(timeprecision)
183  << "ADVANCE from elapsed time = " << t_old[lev] << " to " << t_new[lev]
184  << " with dt = " << dt[lev] << std::endl;
185  }
186 
187 #ifdef ERF_USE_WW3_COUPLING
188  amrex::Print() << " About to call send_to_ww3 from ERF_Timestep" << std::endl;
189  send_to_ww3(lev);
190  amrex::Print() << " About to call read_waves from ERF_Timestep" << std::endl;
191  read_waves(lev);
192  //send_to_ww3(lev);
193  //read_waves(lev);
194  //send_to_ww3(lev);
195 #endif
196 
197  // Advance a single level for a single time step
198  Advance(lev, time, dt[lev], istep[lev], nsubsteps[lev]);
199 
200  ++istep[lev];
201 
202  if (Verbose()) {
203  amrex::Print() << "[Level " << lev << " step " << istep[lev] << "] ";
204  amrex::Print() << "Advanced " << CountCells(lev) << " cells" << std::endl;
205  }
206 
207  if (lev < finest_level)
208  {
209  // recursive call for next-finer level
210  for (int i = 1; i <= nsubsteps[lev+1]; ++i)
211  {
212  Real strt_time_for_fine = time + (i-1)*dt[lev+1];
213  timeStep(lev+1, strt_time_for_fine, i);
214  }
215  }
216 
217  if ( verbose && lev == 0 && solverChoice.moisture_type != MoistureType::None) {
218  amrex::Print() << "Cloud fraction " << time << " " << cloud_fraction(time) << std::endl;
219  }
220 }
void Advance(int lev, amrex::Real time, amrex::Real dt_lev, int iteration, int ncycle)
Definition: ERF_Advance.cpp:20

Referenced by EvolveOneStep().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ turbPert_amplitude()

void ERF::turbPert_amplitude ( const int  lev)
private
34 {
35  // Accessing data
36  auto& lev_new = vars_new[lev];
37 
38  // Creating local data
39  int ncons = lev_new[Vars::cons].nComp();
40  MultiFab cons_data(lev_new[Vars::cons], make_alias, 0, ncons);
41 
42  // Defining BoxArray type
43  auto m_ixtype = cons_data.boxArray().ixType();
44 
45 #ifdef _OPENMP
46 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
47 #endif
48  for (MFIter mfi(lev_new[Vars::cons], TileNoZ()); mfi.isValid(); ++mfi) {
49  const Box &bx = mfi.validbox();
50  const auto &cons_pert_arr = cons_data.array(mfi); // Address of perturbation array
51  const amrex::Array4<const amrex::Real> &pert_cell = turbPert.pb_cell[lev].array(mfi); // per-cell perturbation stored in structure
52 
53  turbPert.apply_tpi(lev, bx, RhoTheta_comp, m_ixtype, cons_pert_arr, pert_cell);
54  } // mfi
55 }
Here is the call graph for this function:

◆ turbPert_update()

void ERF::turbPert_update ( const int  lev,
const amrex::Real  dt 
)
private
13 {
14  // Accessing data
15  auto& lev_new = vars_new[lev];
16 
17  // Create aliases to state data to pass to calc_tpi_update
18  int ncons = lev_new[Vars::cons].nComp();
19  MultiFab cons_data(lev_new[Vars::cons], make_alias, 0, ncons);
20  MultiFab xvel_data(lev_new[Vars::xvel], make_alias, 0, 1);
21  MultiFab yvel_data(lev_new[Vars::yvel], make_alias, 0, 1);
22 
23  // Computing perturbation update time
24  turbPert.calc_tpi_update(lev, local_dt, xvel_data, yvel_data, cons_data);
25 
26  Print() << "Successfully initialized turbulent perturbation update time and amplitude at level "
27  << lev << " with type: " << turbPert.pt_type[lev] << "\n";
28 }
amrex::Vector< int > pt_type
Definition: ERF_TurbPertStruct.H:658

◆ update_diffusive_arrays()

void ERF::update_diffusive_arrays ( int  lev,
const amrex::BoxArray &  ba,
const amrex::DistributionMapping &  dm 
)
private
528 {
529  // ********************************************************************************************
530  // Diffusive terms
531  // ********************************************************************************************
532  bool l_use_eb = (SolverChoice::terrain_type == TerrainType::EB);
533  bool l_use_terrain = (SolverChoice::terrain_type != TerrainType::None && !l_use_eb);
534  bool l_use_kturb = solverChoice.turbChoice[lev].use_kturb;
535  bool l_use_diff = ( (solverChoice.diffChoice.molec_diff_type != MolecDiffType::None) ||
536  l_use_kturb );
537  bool l_need_SmnSmn = solverChoice.turbChoice[lev].use_keqn;
538  bool l_use_moist = ( solverChoice.moisture_type != MoistureType::None );
539  bool l_rotate = ( solverChoice.use_rotate_surface_flux );
540 
541  bool l_implicit_diff = (solverChoice.vert_implicit_fac[0] > 0 ||
544 
545  bool l_eb_surface_layer = (l_use_eb && solverChoice.ebChoice.eb_boundary_type == EBBoundaryType::SurfaceLayer);
546 
547  BoxArray ba12 = convert(ba, IntVect(1,1,0));
548  BoxArray ba13 = convert(ba, IntVect(1,0,1));
549  BoxArray ba23 = convert(ba, IntVect(0,1,1));
550 
551  Tau[lev].resize(9);
552  Tau_corr[lev].resize(3);
553 
554  // Always resize Tau_EB structure, even if not used, because other code checks nullptr
555  Tau_EB[lev].resize(2); // tau_eb13 and tau_eb23
556  for (int comp = 0; comp < 2; ++comp) {
557  Tau_EB[lev][comp].resize(3); // xface, yface, zface
558  }
559 
560  if (l_use_diff) {
561  //
562  // NOTE: We require ghost cells in the vertical when allowing grids that don't
563  // cover the entire vertical extent of the domain at this level
564  //
565  for (int i = 0; i < 3; i++) {
566  Tau[lev][i] = std::make_unique<MultiFab>( ba , dm, 1, IntVect(1,1,1) );
567  }
568  Tau[lev][TauType::tau12] = std::make_unique<MultiFab>( ba12, dm, 1, IntVect(1,1,1) );
569  Tau[lev][TauType::tau13] = std::make_unique<MultiFab>( ba13, dm, 1, IntVect(1,1,1) );
570  Tau[lev][TauType::tau23] = std::make_unique<MultiFab>( ba23, dm, 1, IntVect(1,1,1) );
571  Tau[lev][TauType::tau12]->setVal(zero);
572  Tau[lev][TauType::tau13]->setVal(zero);
573  Tau[lev][TauType::tau23]->setVal(zero);
574  if (l_use_terrain) {
575  Tau[lev][TauType::tau21] = std::make_unique<MultiFab>( ba12, dm, 1, IntVect(1,1,1) );
576  Tau[lev][TauType::tau31] = std::make_unique<MultiFab>( ba13, dm, 1, IntVect(1,1,1) );
577  Tau[lev][TauType::tau32] = std::make_unique<MultiFab>( ba23, dm, 1, IntVect(1,1,1) );
578  Tau[lev][TauType::tau21]->setVal(zero);
579  Tau[lev][TauType::tau31]->setVal(zero);
580  Tau[lev][TauType::tau32]->setVal(zero);
581  } else if (l_implicit_diff) {
582  Tau[lev][TauType::tau31] = std::make_unique<MultiFab>( ba13, dm, 1, IntVect(1,1,1) );
583  Tau[lev][TauType::tau32] = std::make_unique<MultiFab>( ba23, dm, 1, IntVect(1,1,1) );
584  Tau[lev][TauType::tau31]->setVal(zero);
585  Tau[lev][TauType::tau32]->setVal(zero);
586  } else {
587  Tau[lev][TauType::tau21] = nullptr;
588  Tau[lev][TauType::tau31] = nullptr;
589  Tau[lev][TauType::tau32] = nullptr;
590  }
591 
592  // EB diffusive stresses - allocate for all three staggered grids
593  if (l_eb_surface_layer) {
594  Tau_EB[lev][EBTauType::tau_eb13][EBGridType::xface] = std::make_unique<MultiFab>( convert(ba,IntVect(1,0,0)), dm, 1, IntVect(1,1,1) );
595  Tau_EB[lev][EBTauType::tau_eb13][EBGridType::yface] = std::make_unique<MultiFab>( convert(ba,IntVect(0,1,0)), dm, 1, IntVect(1,1,1) );
596  Tau_EB[lev][EBTauType::tau_eb13][EBGridType::zface] = std::make_unique<MultiFab>( convert(ba,IntVect(0,0,1)), dm, 1, IntVect(1,1,1) );
597  Tau_EB[lev][EBTauType::tau_eb13][EBGridType::xface]->setVal(0.);
598  Tau_EB[lev][EBTauType::tau_eb13][EBGridType::yface]->setVal(0.);
599  Tau_EB[lev][EBTauType::tau_eb13][EBGridType::zface]->setVal(0.);
600 
601  Tau_EB[lev][EBTauType::tau_eb23][EBGridType::xface] = std::make_unique<MultiFab>( convert(ba,IntVect(1,0,0)), dm, 1, IntVect(1,1,1) );
602  Tau_EB[lev][EBTauType::tau_eb23][EBGridType::yface] = std::make_unique<MultiFab>( convert(ba,IntVect(0,1,0)), dm, 1, IntVect(1,1,1) );
603  Tau_EB[lev][EBTauType::tau_eb23][EBGridType::zface] = std::make_unique<MultiFab>( convert(ba,IntVect(0,0,1)), dm, 1, IntVect(1,1,1) );
604  Tau_EB[lev][EBTauType::tau_eb23][EBGridType::xface]->setVal(0.);
605  Tau_EB[lev][EBTauType::tau_eb23][EBGridType::yface]->setVal(0.);
606  Tau_EB[lev][EBTauType::tau_eb23][EBGridType::zface]->setVal(0.);
607  } else {
608  for (int comp = 0; comp < 2; ++comp) {
609  for (int grid = 0; grid < 3; ++grid) {
610  Tau_EB[lev][comp][grid] = nullptr;
611  }
612  }
613  }
614 
615  if (l_implicit_diff && solverChoice.implicit_momentum_diffusion)
616  {
617  Tau_corr[lev][0] = std::make_unique<MultiFab>( ba13, dm, 1, IntVect(1,1,1) ); // Tau31
618  Tau_corr[lev][1] = std::make_unique<MultiFab>( ba23, dm, 1, IntVect(1,1,1) ); // Tau32
619  Tau_corr[lev][0]->setVal(zero);
620  Tau_corr[lev][1]->setVal(zero);
621 #ifdef ERF_IMPLICIT_W
622  Tau_corr[lev][2] = std::make_unique<MultiFab>( ba , dm, 1, IntVect(1,1,1) ); // Tau33
623  Tau_corr[lev][2]->setVal(zero);
624 #else
625  Tau_corr[lev][2] = nullptr;
626 #endif
627  } else {
628  Tau_corr[lev][0] = nullptr;
629  Tau_corr[lev][1] = nullptr;
630  Tau_corr[lev][2] = nullptr;
631  }
632 
633  SFS_hfx1_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(1,0,0)), dm, 1, IntVect(1,1,1) );
634  SFS_hfx2_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(0,1,0)), dm, 1, IntVect(1,1,1) );
635  SFS_hfx3_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(0,0,1)), dm, 1, IntVect(1,1,1) );
636  SFS_diss_lev[lev] = std::make_unique<MultiFab>( ba , dm, 1, IntVect(1,1,1) );
637  SFS_hfx1_lev[lev]->setVal(zero);
638  SFS_hfx2_lev[lev]->setVal(zero);
639  SFS_hfx3_lev[lev]->setVal(zero);
640  SFS_diss_lev[lev]->setVal(zero);
641 
642  // EB heat fluxes
643  if (l_use_eb) {
644  hfx3_EB[lev] = std::make_unique<MultiFab>( ba, dm, 1, IntVect(1,1,1) );
645  hfx3_EB[lev]->setVal(zero);
646  } else {
647  hfx3_EB[lev] = nullptr;
648  }
649 
650  if (l_use_moist) {
651  SFS_q1fx3_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(0,0,1)), dm, 1, IntVect(1,1,1) );
652  SFS_q2fx3_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(0,0,1)), dm, 1, IntVect(1,1,1) );
653  SFS_q1fx3_lev[lev]->setVal(zero);
654  SFS_q2fx3_lev[lev]->setVal(zero);
655  if (l_rotate) {
656  SFS_q1fx1_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(1,0,0)), dm, 1, IntVect(1,1,1) );
657  SFS_q1fx2_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(0,1,0)), dm, 1, IntVect(1,1,1) );
658  SFS_q1fx1_lev[lev]->setVal(zero);
659  SFS_q1fx2_lev[lev]->setVal(zero);
660  } else {
661  SFS_q1fx1_lev[lev] = nullptr;
662  SFS_q1fx2_lev[lev] = nullptr;
663  }
664  } else {
665  SFS_q1fx1_lev[lev] = nullptr;
666  SFS_q1fx2_lev[lev] = nullptr;
667  SFS_q1fx3_lev[lev] = nullptr;
668  SFS_q2fx3_lev[lev] = nullptr;
669  }
670  } else {
671  for (int i = 0; i < 9; i++) {
672  Tau[lev][i] = nullptr;
673  }
674  SFS_hfx1_lev[lev] = nullptr; SFS_hfx2_lev[lev] = nullptr; SFS_hfx3_lev[lev] = nullptr;
675  SFS_diss_lev[lev] = nullptr;
676  }
677 
678  if (l_use_kturb) {
679  eddyDiffs_lev[lev] = std::make_unique<MultiFab>(ba, dm, EddyDiff::NumDiffs, 2);
680  eddyDiffs_lev[lev]->setVal(zero);
681  if(l_need_SmnSmn) {
682  SmnSmn_lev[lev] = std::make_unique<MultiFab>( ba, dm, 1, 0 );
683  } else {
684  SmnSmn_lev[lev] = nullptr;
685  }
686  } else {
687  eddyDiffs_lev[lev] = nullptr;
688  SmnSmn_lev[lev] = nullptr;
689  }
690 }
@ tau_eb23
Definition: ERF_EBStruct.H:16
@ tau_eb13
Definition: ERF_EBStruct.H:16
@ yface
Definition: ERF_EBStruct.H:20
@ zface
Definition: ERF_EBStruct.H:20
@ xface
Definition: ERF_EBStruct.H:20
@ NumDiffs
Definition: ERF_IndexDefines.H:215
EBBoundaryType eb_boundary_type
Definition: ERF_EBStruct.H:59
EBChoice ebChoice
Definition: ERF_DataStruct.H:1136

◆ update_terrain_arrays()

void ERF::update_terrain_arrays ( int  lev)
859 {
860  if (SolverChoice::mesh_type == MeshType::StretchedDz ||
861  SolverChoice::mesh_type == MeshType::VariableDz) {
862  make_J(geom[lev],*z_phys_nd[lev],*detJ_cc[lev]);
863  make_areas(geom[lev],*z_phys_nd[lev],*ax[lev],*ay[lev],*az[lev]);
864  make_zcc(geom[lev],*z_phys_nd[lev],*z_phys_cc[lev]);
865  } else { // MeshType::ConstantDz
866  if (SolverChoice::terrain_type == TerrainType::EB) {
867  const auto& ebfact = *eb[lev]->get_const_factory();
868  const MultiFab& volfrac = ebfact.getVolFrac();
869  detJ_cc[lev] = std::make_unique<MultiFab>(volfrac, amrex::make_alias, 0, volfrac.nComp());
870  }
871  }
872 }
void make_areas(const Geometry &geom, MultiFab &z_phys_nd, MultiFab &ax, MultiFab &ay, MultiFab &az)
Definition: ERF_TerrainMetrics.cpp:561
void make_J(const Geometry &geom, MultiFab &z_phys_nd, MultiFab &detJ_cc)
Definition: ERF_TerrainMetrics.cpp:523
Here is the call graph for this function:

◆ volWgtColumnSum()

void ERF::volWgtColumnSum ( int  lev,
const amrex::MultiFab &  mf,
int  comp,
amrex::MultiFab &  mf_2d,
const amrex::MultiFab &  dJ 
)
84 {
85  BL_PROFILE("ERF::volWgtSumColumnMF()");
86 
87  mf_2d.setVal(0.);
88 
89  // The quantity that is conserved is not (rho S), but rather (rho S / m^2) where
90  // m is the map scale factor at cell centers
91 #ifdef _OPENMP
92 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
93 #endif
94  for (MFIter mfi(mf_to_be_summed, TilingIfNotGPU()); mfi.isValid(); ++mfi) {
95  const Box& bx = mfi.tilebox();
96  const auto dst_arr = mf_2d.array(mfi);
97  const auto src_arr = mf_to_be_summed.array(mfi);
98  if (SolverChoice::mesh_type == MeshType::ConstantDz) {
99  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
100  {
101  amrex::HostDevice::Atomic::Add(&dst_arr(i,j,0),src_arr(i,j,k,comp));
102  });
103  } else {
104  const auto& dJ_arr = dJ.const_array(mfi);
105  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
106  {
107  amrex::HostDevice::Atomic::Add(&dst_arr(i,j,0),src_arr(i,j,k,comp)*dJ_arr(i,j,k));
108  });
109  }
110  } // mfi
111 
112  auto const& dx = geom[lev].CellSizeArray();
113 
114  mf_2d.mult(dx[2]);
115 }
Here is the call graph for this function:

◆ volWgtSumMF()

Real ERF::volWgtSumMF ( int  lev,
const amrex::MultiFab &  mf,
int  comp,
const amrex::MultiFab &  dJ,
const amrex::MultiFab &  mfx,
const amrex::MultiFab &  mfy,
bool  finemask,
bool  local = true 
)

Utility function for computing a volume weighted sum of MultiFab data for a single component

Parameters
levCurrent level
mf_to_be_summed: MultiFab on which we do the volume weighted sum
dJ: volume weighting due to metric terms
mfmx: map factor in x-direction at cell centers
mfmy: map factor in y-direction at cell centers
comp: Index of the component we want to sum
finemask: If a finer level is available, determines whether we mask fine data
local: Boolean sets whether or not to reduce the sum over the domain (false) or compute sums local to each MPI rank (true)
25 {
26  BL_PROFILE("ERF::volWgtSumMF()");
27 
28  Real sum = zero;
29  MultiFab tmp(mf_to_be_summed.boxArray(), mf_to_be_summed.DistributionMap(), 1, 0);
30 
31  // The quantity that is conserved is not (rho S), but rather (rho S / m^2) where
32  // m is the map scale factor at cell centers
33 #ifdef _OPENMP
34 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
35 #endif
36  for (MFIter mfi(tmp, TilingIfNotGPU()); mfi.isValid(); ++mfi) {
37  const Box& bx = mfi.tilebox();
38  const auto dst_arr = tmp.array(mfi);
39  const auto src_arr = mf_to_be_summed.array(mfi);
40  const auto& mfx_arr = mfmx.const_array(mfi);
41  const auto& mfy_arr = mfmy.const_array(mfi);
42 
43  if (SolverChoice::terrain_type != TerrainType::EB) {
44  if (SolverChoice::mesh_type == MeshType::ConstantDz) {
45  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
46  {
47  dst_arr(i,j,k,0) = src_arr(i,j,k,comp) / (mfx_arr(i,j,0)*mfy_arr(i,j,0));
48  });
49  } else {
50  const auto& dJ_arr = dJ.const_array(mfi);
51  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
52  {
53  dst_arr(i,j,k,0) = src_arr(i,j,k,comp) * dJ_arr(i,j,k) / (mfx_arr(i,j,0)*mfy_arr(i,j,0));
54  });
55  }
56  } else {
57  const auto& dJ_arr = dJ.const_array(mfi);
58  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
59  {
60  dst_arr(i,j,k,0) = src_arr(i,j,k,comp) * dJ_arr(i,j,k);
61  });
62  }
63 
64  } // mfi
65 
66  if (lev < finest_level && finemask) {
67  MultiFab::Multiply(tmp, *fine_mask[lev+1].get(), 0, 0, 1, 0);
68  }
69 
70  // If local = true then "sum" will be the sum only over the FABs on each rank
71  // If local = false then "sum" will be the sum over the whole MultiFab, and will be broadcast to all ranks
72  sum = tmp.sum(0,local);
73 
74  auto const& dx = geom[lev].CellSizeArray();
75 
76  sum *= dx[0]*dx[1]*dx[2];
77 
78  return sum;
79 }
Here is the call graph for this function:

◆ WeatherDataInterpolation()

void ERF::WeatherDataInterpolation ( const int  nlevs,
const amrex::Real  time,
amrex::Vector< std::unique_ptr< amrex::MultiFab >> &  z_phys_nd,
bool  regrid_forces_file_read 
)
351 {
352 
353  static amrex::Vector<Real> next_read_forecast_time;
354  static amrex::Vector<Real> last_read_forecast_time;
355 
356  const int nlevs = static_cast<int>(a_z_phys_nd.size());
357 
358  Real hindcast_data_interval = solverChoice.hindcast_data_interval_in_hrs*Real(3600.0);
359 
360  // Initialize static vectors once
361  if (next_read_forecast_time.empty()) {
362  next_read_forecast_time.resize(nlevs, -one);
363  last_read_forecast_time.resize(nlevs, -one);
364  Print() << "Initializing the time vector values here by " << lev << std::endl;
365  }
366 
367  if (next_read_forecast_time[lev] < zero) {
368  int next_multiple = static_cast<int>(time / hindcast_data_interval);
369  next_read_forecast_time[lev] = next_multiple * hindcast_data_interval;
370  last_read_forecast_time[lev] = next_read_forecast_time[lev];
371  }
372 
373  if (time >= next_read_forecast_time[lev] or regrid_forces_file_read) {
374 
375  Print() << "Data reading happening at level " << lev << std::endl;
376 
377  std::string folder = solverChoice.hindcast_boundary_data_dir;
378 
379  // Check if folder exists and is a directory
380  if (!fs::exists(folder) || !fs::is_directory(folder)) {
381  throw std::runtime_error("Error: Folder '" + folder + "' does not exist or is not a directory.");
382  }
383 
384  std::vector<std::string> bin_files;
385 
386  for (const auto& entry : fs::directory_iterator(folder)) {
387  if (!entry.is_regular_file()) continue;
388 
389  std::string fname = entry.path().filename().string();
390  if (fname.size() >= 4 && fname.substr(fname.size() - 4) == ".bin") {
391  bin_files.push_back(entry.path().string());
392  }
393  }
394  std::sort(bin_files.begin(), bin_files.end());
395 
396  // Check if no .bin files were found
397  if (bin_files.empty()) {
398  throw std::runtime_error("Error: No .bin files found in folder '" + folder + "'.");
399  }
400 
401  std::string filename1, filename2;
402 
403  int idx1 = static_cast<int>(time / hindcast_data_interval);
404  int idx2 = static_cast<int>(time / hindcast_data_interval)+1;
405  Print() << "Reading weather data " << time << " " << idx1 << " " << idx2 <<" " << bin_files.size() << std::endl;
406 
407  if (idx2 >= static_cast<int>(bin_files.size())) {
408  throw std::runtime_error("Error: Not enough .bin files to cover time " + std::to_string(time));
409  }
410 
411  filename1 = bin_files[idx1];
412  filename2 = bin_files[idx2];
413 
414  FillForecastStateMultiFabs(lev, filename1, a_z_phys_nd[lev], forecast_state_1);
415  FillForecastStateMultiFabs(lev, filename2, a_z_phys_nd[lev], forecast_state_2);
416 
417  // Create the time-interpolated forecast state
418  //CreateForecastStateMultiFabs(forecast_state_interp);
419  if(!regrid_forces_file_read){
420  last_read_forecast_time[lev] = next_read_forecast_time[lev];
421  next_read_forecast_time[lev] += hindcast_data_interval;
422  Print() << "Next forecast time getting updated here " << std::endl;
423  }
424  }
425 
426  Real prev_read_time = last_read_forecast_time[lev];
427  Real alpha1 = one - (time - prev_read_time)/hindcast_data_interval;
428  Real alpha2 = one - alpha1;
429 
430  amrex::Print()<< "The values of alpha1 and alpha2 are " << alpha1 << " "<< alpha2 <<std::endl;
431 
432  if (alpha1 < zero || alpha1 > one ||
433  alpha2 < zero || alpha2 > one)
434  {
435  std::stringstream ss;
436  ss << "Interpolation weights for hindcast files are incorrect: "
437  << "alpha1 = " << alpha1 << ", alpha2 = " << alpha2;
438  Abort(ss.str());
439  }
440 
441  MultiFab& erf_mf_cons = forecast_state_interp[lev][Vars::cons];
442  MultiFab& erf_mf_xvel = forecast_state_interp[lev][Vars::xvel];
443  MultiFab& erf_mf_yvel = forecast_state_interp[lev][Vars::yvel];
444  //MultiFab& erf_mf_zvel = forecast_state_interp[0][Vars::zvel];
445  MultiFab& erf_mf_latlon = forecast_state_interp[lev][4];
446 
447  // Fill the time-interpolated forecast states
448  MultiFab::LinComb(forecast_state_interp[lev][Vars::cons],
449  alpha1, forecast_state_1[lev][Vars::cons], 0,
450  alpha2, forecast_state_2[lev][Vars::cons], 0,
451  0, erf_mf_cons.nComp(), forecast_state_interp[lev][Vars::cons].nGrow());
452  MultiFab::LinComb(forecast_state_interp[lev][Vars::xvel],
453  alpha1, forecast_state_1[lev][Vars::xvel], 0,
454  alpha2, forecast_state_2[lev][Vars::xvel], 0,
455  0, erf_mf_xvel.nComp(), forecast_state_interp[lev][Vars::xvel].nGrow());
456  MultiFab::LinComb(forecast_state_interp[lev][Vars::yvel],
457  alpha1, forecast_state_1[lev][Vars::yvel], 0,
458  alpha2, forecast_state_2[lev][Vars::yvel], 0,
459  0, erf_mf_yvel.nComp(), forecast_state_interp[lev][Vars::yvel].nGrow());
460  MultiFab::LinComb(forecast_state_interp[lev][4],
461  alpha1, forecast_state_1[lev][4], 0,
462  alpha2, forecast_state_2[lev][4], 0,
463  0, erf_mf_latlon.nComp(), forecast_state_interp[lev][4].nGrow());
464 
465  /*Vector<std::string> varnames_plot_mf = {
466  "rho", "rhotheta", "rhoqv", "rhoqc", "rhoqr", "xvel", "yvel", "zvel", "latitude", "longitude"
467  }; // Customize variable names
468 
469  std::string pltname = "plt_interp";
470 
471  MultiFab plot_mf(erf_mf_cons.boxArray(), erf_mf_cons.DistributionMap(),
472  10, 0);
473 
474  plot_mf.setVal(0.0);
475 
476  for (MFIter mfi(plot_mf); mfi.isValid(); ++mfi) {
477  const Array4<Real> &plot_mf_arr = plot_mf.array(mfi);
478  const Array4<Real> &erf_mf_cons_arr = erf_mf_cons.array(mfi);
479  const Array4<Real> &erf_mf_xvel_arr = erf_mf_xvel.array(mfi);
480  const Array4<Real> &erf_mf_yvel_arr = erf_mf_yvel.array(mfi);
481  const Array4<Real> &erf_mf_zvel_arr = erf_mf_zvel.array(mfi);
482  const Array4<Real> &erf_mf_latlon_arr = erf_mf_latlon.array(mfi);
483 
484  const Box& bx = mfi.validbox();
485 
486  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
487  plot_mf_arr(i,j,k,0) = erf_mf_cons_arr(i,j,k,Rho_comp);
488  plot_mf_arr(i,j,k,1) = erf_mf_cons_arr(i,j,k,RhoTheta_comp);
489  plot_mf_arr(i,j,k,2) = erf_mf_cons_arr(i,j,k,RhoQ1_comp);
490  plot_mf_arr(i,j,k,3) = erf_mf_cons_arr(i,j,k,RhoQ2_comp);
491  plot_mf_arr(i,j,k,4) = erf_mf_cons_arr(i,j,k,RhoQ3_comp);
492 
493  plot_mf_arr(i,j,k,5) = (erf_mf_xvel_arr(i,j,k,0) + erf_mf_xvel_arr(i+1,j,k,0))/two;
494  plot_mf_arr(i,j,k,6) = (erf_mf_yvel_arr(i,j,k,0) + erf_mf_yvel_arr(i,j+1,k,0))/two;
495  plot_mf_arr(i,j,k,7) = (erf_mf_zvel_arr(i,j,k,0) + erf_mf_zvel_arr(i,j,k+1,0))/two;
496 
497  plot_mf_arr(i,j,k,8) = erf_mf_latlon_arr(i,j,k,0);
498  plot_mf_arr(i,j,k,9) = erf_mf_latlon_arr(i,j,k,1);
499  });
500  }
501 
502 
503  WriteSingleLevelPlotfile(
504  pltname,
505  plot_mf,
506  varnames_plot_mf,
507  geom[0],
508  time,
509  0 // level
510  );*/
511 }
void FillForecastStateMultiFabs(const int lev, const std::string &filename, const std::unique_ptr< amrex::MultiFab > &z_phys_nd, amrex::Vector< amrex::Vector< amrex::MultiFab >> &forecast_state)
Definition: ERF_WeatherDataInterpolation.cpp:64
std::string hindcast_boundary_data_dir
Definition: ERF_DataStruct.H:1330

◆ Write2DPlotFile()

void ERF::Write2DPlotFile ( int  which,
PlotFileType  plotfile_type,
amrex::Vector< std::string >  plot_var_names 
)
2034 {
2035  const Vector<std::string> varnames = PlotFileVarNames(plot_var_names);
2036  const int ncomp_mf = static_cast<int>(varnames.size());
2037 
2038  if (ncomp_mf == 0) return;
2039 
2040  // Vector of MultiFabs for cell-centered data
2041  Vector<MultiFab> mf(finest_level+1);
2042  for (int lev = 0; lev <= finest_level; ++lev) {
2043  mf[lev].define(ba2d[lev], dmap[lev], ncomp_mf, 0);
2044  }
2045 
2046 
2047  // **********************************************************************************************
2048  // (Effectively) 2D arrays
2049  // **********************************************************************************************
2050  for (int lev = 0; lev <= finest_level; ++lev)
2051  {
2052  // Make sure getPgivenRTh and getTgivenRandRTh don't fail
2053  if (check_for_nans) {
2055  }
2056 
2057  int mf_comp = 0;
2058 
2059  // Set all components to zero in case they aren't defined below
2060  mf[lev].setVal(0.0);
2061 
2062  // Expose domain khi and klo at each level
2063  int klo = geom[lev].Domain().smallEnd(2);
2064  int khi = geom[lev].Domain().bigEnd(2);
2065 
2066  if (containerHasElement(plot_var_names, "z_surf")) {
2067 #ifdef _OPENMP
2068 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2069 #endif
2070  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2071  {
2072  const Box& bx = mfi.tilebox();
2073  const Array4<Real>& derdat = mf[lev].array(mfi);
2074  const Array4<const Real>& z_phys_arr = z_phys_nd[lev]->const_array(mfi);
2075  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2076  derdat(i, j, k, mf_comp) = Compute_Z_AtWFace(i, j, 0, z_phys_arr);
2077  });
2078  }
2079  mf_comp++;
2080  }
2081 
2082  if (containerHasElement(plot_var_names, "landmask")) {
2083 #ifdef _OPENMP
2084 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2085 #endif
2086  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2087  {
2088  const Box& bx = mfi.tilebox();
2089  const Array4<Real>& derdat = mf[lev].array(mfi);
2090  const Array4<const int>& lmask_arr = lmask_lev[lev][0]->const_array(mfi);
2091  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2092  derdat(i, j, k, mf_comp) = static_cast<Real>(lmask_arr(i, j, 0));
2093  });
2094  }
2095  mf_comp++;
2096  }
2097 
2098  if (containerHasElement(plot_var_names, "mapfac")) {
2099 #ifdef _OPENMP
2100 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2101 #endif
2102  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2103  {
2104  const Box& bx = mfi.tilebox();
2105  const Array4<Real>& derdat = mf[lev].array(mfi);
2106  const Array4<Real>& mf_m = mapfac[lev][MapFacType::m_x]->array(mfi);
2107  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2108  derdat(i ,j ,k, mf_comp) = mf_m(i,j,0);
2109  });
2110  }
2111  mf_comp++;
2112  }
2113 
2114  if (containerHasElement(plot_var_names, "lat_m")) {
2115  if (lat_m[lev]) {
2116 #ifdef _OPENMP
2117 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2118 #endif
2119  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2120  {
2121  const Box& bx = mfi.tilebox();
2122  const Array4<Real>& derdat = mf[lev].array(mfi);
2123  const Array4<Real>& data = lat_m[lev]->array(mfi);
2124  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2125  derdat(i, j, k, mf_comp) = data(i,j,0);
2126  });
2127  }
2128  }
2129  mf_comp++;
2130  } // lat_m
2131 
2132  if (containerHasElement(plot_var_names, "lon_m")) {
2133  if (lon_m[lev]) {
2134 #ifdef _OPENMP
2135 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2136 #endif
2137  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2138  {
2139  const Box& bx = mfi.tilebox();
2140  const Array4<Real>& derdat = mf[lev].array(mfi);
2141  const Array4<Real>& data = lon_m[lev]->array(mfi);
2142  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2143  derdat(i, j, k, mf_comp) = data(i,j,0);
2144  });
2145  }
2146  } else {
2147  mf[lev].setVal(0.0,mf_comp,1,0);
2148  }
2149 
2150  mf_comp++;
2151 
2152  } // lon_m
2153 
2154  ///////////////////////////////////////////////////////////////////////
2155  // These quantities are diagnosed by the surface layer
2156  if (containerHasElement(plot_var_names, "u_star")) {
2157 #ifdef _OPENMP
2158 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2159 #endif
2160  if (m_SurfaceLayer) {
2161  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2162  {
2163  const Box& bx = mfi.tilebox();
2164  const auto& derdat = mf[lev].array(mfi);
2165  const auto& ustar = m_SurfaceLayer->get_u_star(lev)->const_array(mfi);
2166  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2167  derdat(i, j, k, mf_comp) = ustar(i, j, 0);
2168  });
2169  }
2170  } else {
2171  mf[lev].setVal(-999,mf_comp,1,0);
2172  }
2173  mf_comp++;
2174  } // ustar
2175 
2176  if (containerHasElement(plot_var_names, "w_star")) {
2177 #ifdef _OPENMP
2178 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2179 #endif
2180  if (m_SurfaceLayer) {
2181  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2182  {
2183  const Box& bx = mfi.tilebox();
2184  const auto& derdat = mf[lev].array(mfi);
2185  const auto& ustar = m_SurfaceLayer->get_w_star(lev)->const_array(mfi);
2186  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2187  derdat(i, j, k, mf_comp) = ustar(i, j, 0);
2188  });
2189  }
2190  } else {
2191  mf[lev].setVal(-999,mf_comp,1,0);
2192  }
2193  mf_comp++;
2194  } // wstar
2195 
2196  if (containerHasElement(plot_var_names, "t_star")) {
2197 #ifdef _OPENMP
2198 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2199 #endif
2200  if (m_SurfaceLayer) {
2201  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2202  {
2203  const Box& bx = mfi.tilebox();
2204  const auto& derdat = mf[lev].array(mfi);
2205  const auto& ustar = m_SurfaceLayer->get_t_star(lev)->const_array(mfi);
2206  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2207  derdat(i, j, k, mf_comp) = ustar(i, j, 0);
2208  });
2209  }
2210  } else {
2211  mf[lev].setVal(-999,mf_comp,1,0);
2212  }
2213  mf_comp++;
2214  } // tstar
2215 
2216  if (containerHasElement(plot_var_names, "q_star")) {
2217 #ifdef _OPENMP
2218 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2219 #endif
2220  if (m_SurfaceLayer) {
2221  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2222  {
2223  const Box& bx = mfi.tilebox();
2224  const auto& derdat = mf[lev].array(mfi);
2225  const auto& ustar = m_SurfaceLayer->get_q_star(lev)->const_array(mfi);
2226  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2227  derdat(i, j, k, mf_comp) = ustar(i, j, 0);
2228  });
2229  }
2230  } else {
2231  mf[lev].setVal(-999,mf_comp,1,0);
2232  }
2233  mf_comp++;
2234  } // qstar
2235 
2236  if (containerHasElement(plot_var_names, "Olen")) {
2237 #ifdef _OPENMP
2238 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2239 #endif
2240  if (m_SurfaceLayer) {
2241  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2242  {
2243  const Box& bx = mfi.tilebox();
2244  const auto& derdat = mf[lev].array(mfi);
2245  const auto& ustar = m_SurfaceLayer->get_olen(lev)->const_array(mfi);
2246  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2247  derdat(i, j, k, mf_comp) = ustar(i, j, 0);
2248  });
2249  }
2250  } else {
2251  mf[lev].setVal(-999,mf_comp,1,0);
2252  }
2253  mf_comp++;
2254  } // Olen
2255 
2256  if (containerHasElement(plot_var_names, "pblh")) {
2257 #ifdef _OPENMP
2258 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2259 #endif
2260  if (m_SurfaceLayer) {
2261  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2262  {
2263  const Box& bx = mfi.tilebox();
2264  const auto& derdat = mf[lev].array(mfi);
2265  const auto& ustar = m_SurfaceLayer->get_pblh(lev)->const_array(mfi);
2266  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2267  derdat(i, j, k, mf_comp) = ustar(i, j, 0);
2268  });
2269  }
2270  } else {
2271  mf[lev].setVal(-999,mf_comp,1,0);
2272  }
2273  mf_comp++;
2274  } // pblh
2275 
2276  if (containerHasElement(plot_var_names, "t_surf")) {
2277 #ifdef _OPENMP
2278 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2279 #endif
2280  if (m_SurfaceLayer) {
2281  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2282  {
2283  const Box& bx = mfi.tilebox();
2284  const auto& derdat = mf[lev].array(mfi);
2285  const auto& tsurf = m_SurfaceLayer->get_t_surf(lev)->const_array(mfi);
2286  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2287  derdat(i, j, k, mf_comp) = tsurf(i, j, 0);
2288  });
2289  }
2290  } else {
2291  mf[lev].setVal(-999,mf_comp,1,0);
2292  }
2293  mf_comp++;
2294  } // tsurf
2295 
2296  if (containerHasElement(plot_var_names, "q_surf")) {
2297 #ifdef _OPENMP
2298 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2299 #endif
2300  if (m_SurfaceLayer) {
2301  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2302  {
2303  const Box& bx = mfi.tilebox();
2304  const auto& derdat = mf[lev].array(mfi);
2305  const auto& ustar = m_SurfaceLayer->get_q_surf(lev)->const_array(mfi);
2306  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2307  derdat(i, j, k, mf_comp) = ustar(i, j, 0);
2308  });
2309  }
2310  } else {
2311  mf[lev].setVal(-999,mf_comp,1,0);
2312  }
2313  mf_comp++;
2314  } // qsurf
2315 
2316  if (containerHasElement(plot_var_names, "z0")) {
2317 #ifdef _OPENMP
2318 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2319 #endif
2320  if (m_SurfaceLayer) {
2321  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2322  {
2323  const Box& bx = mfi.tilebox();
2324  const auto& derdat = mf[lev].array(mfi);
2325  const auto& ustar = m_SurfaceLayer->get_z0(lev)->const_array(mfi);
2326  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2327  derdat(i, j, k, mf_comp) = ustar(i, j, 0);
2328  });
2329  }
2330  } else {
2331  mf[lev].setVal(-999,mf_comp,1,0);
2332  }
2333  mf_comp++;
2334  } // z0
2335 
2336  if (containerHasElement(plot_var_names, "OLR")) {
2337 #ifdef _OPENMP
2338 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2339 #endif
2340  if (solverChoice.rad_type != RadiationType::None) {
2341  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2342  {
2343  const Box& bx = mfi.tilebox();
2344  const auto& derdat = mf[lev].array(mfi);
2345  const auto& olr = rad_fluxes[lev]->const_array(mfi);
2346  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2347  derdat(i, j, k, mf_comp) = olr(i, j, khi, 2);
2348  });
2349  }
2350  } else {
2351  mf[lev].setVal(-999,mf_comp,1,0);
2352  }
2353  mf_comp++;
2354  } // OLR
2355 
2356  if (containerHasElement(plot_var_names, "sens_flux")) {
2357 #ifdef _OPENMP
2358 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2359 #endif
2360  if (SFS_hfx3_lev[lev]) {
2361  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2362  {
2363  const Box& bx = mfi.tilebox();
2364  const auto& derdat = mf[lev].array(mfi);
2365  const auto& hfx_arr = SFS_hfx3_lev[lev]->const_array(mfi);
2366  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2367  derdat(i, j, k, mf_comp) = hfx_arr(i, j, klo);
2368  });
2369  }
2370  } else {
2371  mf[lev].setVal(-999,mf_comp,1,0);
2372  }
2373  mf_comp++;
2374  } // sens_flux
2375 
2376  if (containerHasElement(plot_var_names, "laten_flux")) {
2377 #ifdef _OPENMP
2378 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2379 #endif
2380  if (SFS_hfx3_lev[lev]) {
2381  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2382  {
2383  const Box& bx = mfi.tilebox();
2384  const auto& derdat = mf[lev].array(mfi);
2385  const auto& qfx_arr = SFS_q1fx3_lev[lev]->const_array(mfi);
2386  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2387  derdat(i, j, k, mf_comp) = qfx_arr(i, j, klo);
2388  });
2389  }
2390  } else {
2391  mf[lev].setVal(-999,mf_comp,1,0);
2392  }
2393  mf_comp++;
2394  } // laten_flux
2395 
2396  if (containerHasElement(plot_var_names, "surf_pres")) {
2397  bool moist = (solverChoice.moisture_type != MoistureType::None);
2398 #ifdef _OPENMP
2399 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2400 #endif
2401  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2402  {
2403  const Box& bx = mfi.tilebox();
2404  const auto& derdat = mf[lev].array(mfi);
2405  const auto& cons_arr = vars_new[lev][Vars::cons].const_array(mfi);
2406  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2407  auto rt = cons_arr(i,j,klo,RhoTheta_comp);
2408  auto qv = (moist) ? cons_arr(i,j,klo,RhoQ1_comp)/cons_arr(i,j,klo,Rho_comp)
2409  : zero;
2410  derdat(i, j, k, mf_comp) = getPgivenRTh(rt, qv);
2411  });
2412  }
2413  mf_comp++;
2414  } // surf_pres
2415 
2416  if (containerHasElement(plot_var_names, "integrated_qv")) {
2417  MultiFab mf_qv_int(mf[lev],make_alias,mf_comp,1);
2418  if (solverChoice.moisture_type != MoistureType::None) {
2419  volWgtColumnSum(lev, vars_new[lev][Vars::cons], RhoQ1_comp, mf_qv_int, *detJ_cc[lev]);
2420  } else {
2421  mf_qv_int.setVal(0.);
2422  }
2423  mf_comp++;
2424  }
2425  } // lev
2426 
2427  std::string plotfilename;
2428  if (which == 1) {
2429  plotfilename = Concatenate(plot2d_file_1, istep[0], file_name_digits);
2430  } else if (which == 2) {
2431  plotfilename = Concatenate(plot2d_file_2, istep[0], file_name_digits);
2432  }
2433 
2434  Vector<Geometry> my_geom(finest_level+1);
2435 
2436  Array<int,AMREX_SPACEDIM> is_per; is_per[0] = 0; is_per[1] = 0; is_per[2] = 0;
2437  if (geom[0].isPeriodic(0)) { is_per[0] = 1;}
2438  if (geom[0].isPeriodic(1)) { is_per[1] = 1;}
2439 
2440  int coord_sys = 0;
2441 
2442  for (int lev = 0; lev <= finest_level; lev++)
2443  {
2444  Box slab = makeSlab(geom[lev].Domain(),2,0);
2445  auto const slab_lo = lbound(slab);
2446  auto const slab_hi = ubound(slab);
2447 
2448  // Create a new geometry based only on the 2D slab
2449  Real dz = geom[lev].CellSize(2);
2450  RealBox rb = geom[lev].ProbDomain();
2451  rb.setLo(2, slab_lo.z *dz);
2452  rb.setHi(2, (slab_hi.z+1)*dz);
2453  my_geom[lev].define(slab, rb, coord_sys, is_per);
2454  }
2455 
2456  if (plotfile_type == PlotFileType::Amrex)
2457  {
2458  Print() << "Writing 2D native plotfile " << plotfilename << "\n";
2459  WriteMultiLevelPlotfile(plotfilename, finest_level+1,
2460  GetVecOfConstPtrs(mf),
2461  varnames, my_geom, t_new[0], istep, refRatio());
2462  writeJobInfo(plotfilename);
2463 
2464 #ifdef ERF_USE_NETCDF
2465  } else if (plotfile_type == PlotFileType::Netcdf) {
2466  int lev = 0;
2467  int l_which = 0;
2468  const Real* p_lo = my_geom[lev].ProbLo();
2469  const Real* p_hi = my_geom[lev].ProbHi();
2470  const auto dx = my_geom[lev].CellSize();
2471  writeNCPlotFile(lev, l_which, plotfilename, GetVecOfConstPtrs(mf), varnames, istep,
2472  {p_lo[0],p_lo[1],p_lo[2]},{p_hi[0],p_hi[1],dx[2]}, {dx[0],dx[1],dx[2]},
2473  my_geom[lev].Domain(), t_new[0], start_bdy_time, solverChoice, zlevels_stag[lev]);
2474 #endif
2475  } else {
2476  // Here we assume the plotfile_type is PlotFileType::None
2477  Print() << "Writing no 2D plotfile since plotfile_type is none" << std::endl;
2478  }
2479 }
void writeNCPlotFile(int lev, int which_subdomain, const std::string &dir, const Vector< const MultiFab * > &plotMF, const Vector< std::string > &plot_var_names, const Vector< int > &, Array< Real, AMREX_SPACEDIM > prob_lo, Array< Real, AMREX_SPACEDIM > prob_hi, Array< Real, AMREX_SPACEDIM > dx_in, const Box &subdomain, const Real time, const Real start_bdy_time, const SolverChoice &solverChoice, const Vector< Real > &zlevels_stag)
Definition: ERF_NCPlotFile.cpp:16
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_Z_AtWFace(const int &i, const int &j, const int &k, const amrex::Array4< const amrex::Real > &z_nd)
Definition: ERF_TerrainMetrics.H:376
static amrex::Vector< std::string > PlotFileVarNames(amrex::Vector< std::string > plot_var_names)
Definition: ERF_Plotfile.cpp:309
void writeJobInfo(const std::string &dir) const
Definition: ERF_WriteJobInfo.cpp:9

Referenced by EvolveOneStep().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Write3DPlotFile()

void ERF::Write3DPlotFile ( int  which,
PlotFileType  plotfile_type,
amrex::Vector< std::string >  plot_var_names 
)
322 {
323  auto dPlotTime0 = amrex::second();
324 
325  const Vector<std::string> varnames = PlotFileVarNames(plot_var_names);
326  const int ncomp_mf = static_cast<int>(varnames.size());
327 
328  int ncomp_cons = vars_new[0][Vars::cons].nComp();
329 
330  if (ncomp_mf == 0) return;
331 
332  // Lagrangian microphysics with AMR (TwoWay): bring fine-level moisture down
333  // to coarse cells so plotfiles at level 0 show the fine-deposit cloud.
334  if (Microphysics::modelType(solverChoice.moisture_type) == MoistureModelType::Lagrangian
335  && solverChoice.coupling_type == CouplingType::TwoWay
336  && finest_level >= 1) {
337  micro->AverageDownMicroVars(finest_level);
338  for (int flev = finest_level-1; flev >= 0; --flev) {
340  }
341  }
342 
343  // We Fillpatch here because some of the derived quantities require derivatives
344  // which require ghost cells to be filled. We do not need to call FillPatcher
345  // because we don't need to set interior fine points.
346  // NOTE: the momenta here are only used as scratch space, the momenta themselves are not fillpatched
347 
348  // Level 0 FillPatch
350  &vars_new[0][Vars::yvel], &vars_new[0][Vars::zvel]});
351 
352  for (int lev = 1; lev <= finest_level; ++lev) {
353  bool fillset = false;
354  FillPatchFineLevel(lev, t_new[lev], {&vars_new[lev][Vars::cons], &vars_new[lev][Vars::xvel],
355  &vars_new[lev][Vars::yvel], &vars_new[lev][Vars::zvel]},
356  {&vars_new[lev][Vars::cons], &rU_new[lev], &rV_new[lev], &rW_new[lev]},
357  base_state[lev], base_state[lev], fillset);
358  }
359 
360  // Get qmoist pointers if using moisture
361  bool use_moisture = (solverChoice.moisture_type != MoistureType::None);
362  for (int lev = 0; lev <= finest_level; ++lev) {
363  for (int mvar(0); mvar<qmoist[lev].size(); ++mvar) {
364  qmoist[lev][mvar] = micro->Get_Qmoist_Ptr(lev,mvar);
365  }
366  }
367 
368  // Vector of MultiFabs for cell-centered data
369  Vector<MultiFab> mf(finest_level+1);
370  for (int lev = 0; lev <= finest_level; ++lev) {
371  mf[lev].define(grids[lev], dmap[lev], ncomp_mf, 0);
372  }
373 
374  // Vector of MultiFabs for nodal data
375  Vector<MultiFab> mf_nd(finest_level+1);
376  if ( SolverChoice::mesh_type != MeshType::ConstantDz) {
377  for (int lev = 0; lev <= finest_level; ++lev) {
378  BoxArray nodal_grids(grids[lev]); nodal_grids.surroundingNodes();
379  mf_nd[lev].define(nodal_grids, dmap[lev], 3, 0);
380  mf_nd[lev].setVal(0.);
381  }
382  }
383 
384  // Vector of MultiFabs for face-centered velocity
385  Vector<MultiFab> mf_u(finest_level+1);
386  Vector<MultiFab> mf_v(finest_level+1);
387  Vector<MultiFab> mf_w(finest_level+1);
388  if (m_plot_face_vels) {
389  for (int lev = 0; lev <= finest_level; ++lev) {
390  BoxArray grid_stag_u(grids[lev]); grid_stag_u.surroundingNodes(0);
391  BoxArray grid_stag_v(grids[lev]); grid_stag_v.surroundingNodes(1);
392  BoxArray grid_stag_w(grids[lev]); grid_stag_w.surroundingNodes(2);
393  mf_u[lev].define(grid_stag_u, dmap[lev], 1, 0);
394  mf_v[lev].define(grid_stag_v, dmap[lev], 1, 0);
395  mf_w[lev].define(grid_stag_w, dmap[lev], 1, 0);
396  MultiFab::Copy(mf_u[lev],vars_new[lev][Vars::xvel],0,0,1,0);
397  MultiFab::Copy(mf_v[lev],vars_new[lev][Vars::yvel],0,0,1,0);
398  MultiFab::Copy(mf_w[lev],vars_new[lev][Vars::zvel],0,0,1,0);
399  }
400  }
401 
402  // Array of MultiFabs for cell-centered velocity
403  Vector<MultiFab> mf_cc_vel(finest_level+1);
404 
405  if (containerHasElement(plot_var_names, "x_velocity" ) ||
406  containerHasElement(plot_var_names, "y_velocity" ) ||
407  containerHasElement(plot_var_names, "z_velocity" ) ||
408  containerHasElement(plot_var_names, "magvel" ) ||
409  containerHasElement(plot_var_names, "helicity" ) ||
410  containerHasElement(plot_var_names, "local_helicity") ||
411  containerHasElement(plot_var_names, "vorticity_x" ) ||
412  containerHasElement(plot_var_names, "vorticity_y" ) ||
413  containerHasElement(plot_var_names, "vorticity_z" ) ) {
414 
415  for (int lev = 0; lev <= finest_level; ++lev) {
416  mf_cc_vel[lev].define(grids[lev], dmap[lev], AMREX_SPACEDIM, IntVect(1,1,1));
417  mf_cc_vel[lev].setVal(Real(-1.e20));
418  average_face_to_cellcenter(mf_cc_vel[lev],0,
419  Array<const MultiFab*,3>{&vars_new[lev][Vars::xvel],
420  &vars_new[lev][Vars::yvel],
421  &vars_new[lev][Vars::zvel]}, 1);
422  } // lev
423  } // if (vel or vort)
424 
425  // We need ghost cells if computing vorticity
426  if ( containerHasElement(plot_var_names, "vorticity_x")||
427  containerHasElement(plot_var_names, "vorticity_y") ||
428  containerHasElement(plot_var_names, "vorticity_z") )
429  {
430  amrex::Interpolater* mapper = &cell_cons_interp;
431  FillBdyCCVels(mf_cc_vel[0],geom[0]);
432  for (int lev = 1; lev <= finest_level; ++lev)
433  {
434  Vector<MultiFab*> fmf = {&(mf_cc_vel[lev]), &(mf_cc_vel[lev])};
435  Vector<Real> ftime = {t_new[lev], t_new[lev]};
436  Vector<MultiFab*> cmf = {&mf_cc_vel[lev-1], &mf_cc_vel[lev-1]};
437  Vector<Real> ctime = {t_new[lev], t_new[lev]};
438 
439  // Call FillPatch which ASSUMES that all ghost cells at lev-1 have already been filled
440  FillPatchTwoLevels(mf_cc_vel[lev], mf_cc_vel[lev].nGrowVect(), IntVect(0,0,0),
441  t_new[lev], cmf, ctime, fmf, ftime,
442  0, 0, mf_cc_vel[lev].nComp(), geom[lev-1], geom[lev],
443  refRatio(lev-1), mapper, domain_bcs_type,
445  FillBdyCCVels(mf_cc_vel[lev],geom[lev]);
446  } // lev
447  } // if (vort)
448 
449 
450  for (int lev = 0; lev <= finest_level; ++lev)
451  {
452  // Make sure getPgivenRTh and getTgivenRandRTh don't fail
453  if (check_for_nans) {
455  }
456 
457  int mf_comp = 0;
458 
459  BoxArray ba(vars_new[lev][Vars::cons].boxArray());
460  DistributionMapping dm = vars_new[lev][Vars::cons].DistributionMap();
461 
462  // First, copy any of the conserved state variables into the output plotfile
463  for (int i = 0; i < cons_names.size(); ++i) {
464  if (containerHasElement(plot_var_names, cons_names[i])) {
465  MultiFab::Copy(mf[lev],vars_new[lev][Vars::cons],i,mf_comp,1,0);
466  mf_comp++;
467  }
468  }
469 
470  // Next, check for velocities
471  if (containerHasElement(plot_var_names, "x_velocity")) {
472  MultiFab::Copy(mf[lev], mf_cc_vel[lev], 0, mf_comp, 1, 0);
473  mf_comp += 1;
474  }
475  if (containerHasElement(plot_var_names, "y_velocity")) {
476  MultiFab::Copy(mf[lev], mf_cc_vel[lev], 1, mf_comp, 1, 0);
477  mf_comp += 1;
478  }
479  if (containerHasElement(plot_var_names, "z_velocity")) {
480  MultiFab::Copy(mf[lev], mf_cc_vel[lev], 2, mf_comp, 1, 0);
481  mf_comp += 1;
482  }
483 
484  // Create multifabs for HSE and pressure fields used to derive other quantities
485  MultiFab r_hse(base_state[lev], make_alias, BaseState::r0_comp , 1);
486  MultiFab p_hse(base_state[lev], make_alias, BaseState::p0_comp , 1);
487  MultiFab th_hse(base_state[lev], make_alias, BaseState::th0_comp, 1);
488 
489  MultiFab pressure;
490 
491  if (solverChoice.anelastic[lev] == 0) {
492  if (containerHasElement(plot_var_names, "pressure") ||
493  containerHasElement(plot_var_names, "pert_pres") ||
494  containerHasElement(plot_var_names, "dpdx") ||
495  containerHasElement(plot_var_names, "dpdy") ||
496  containerHasElement(plot_var_names, "dpdz") ||
497  containerHasElement(plot_var_names, "eq_pot_temp") ||
498  containerHasElement(plot_var_names, "qsat"))
499  {
500  int ng = (containerHasElement(plot_var_names, "dpdx") || containerHasElement(plot_var_names, "dpdy") ||
501  containerHasElement(plot_var_names, "dpdz")) ? 1 : 0;
502 
503  // Allocate space for pressure
504  pressure.define(ba,dm,1,ng);
505 
506  if (ng > 0) {
507  // Default to p_hse as a way of filling ghost cells at domain boundaries
508  MultiFab::Copy(pressure,p_hse,0,0,1,1);
509  }
510 #ifdef _OPENMP
511 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
512 #endif
513  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
514  {
515  const Box& gbx = mfi.growntilebox(IntVect(ng,ng,0));
516 
517  const Array4<Real >& p_arr = pressure.array(mfi);
518  const Array4<Real const>& S_arr = vars_new[lev][Vars::cons].const_array(mfi);
519  const int ncomp = vars_new[lev][Vars::cons].nComp();
520 
521  ParallelFor(gbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
522  {
523  Real qv_for_p = (use_moisture && (ncomp > RhoQ1_comp)) ? S_arr(i,j,k,RhoQ1_comp)/S_arr(i,j,k,Rho_comp) : 0;
524  const Real rhotheta = S_arr(i,j,k,RhoTheta_comp);
525  p_arr(i, j, k) = getPgivenRTh(rhotheta,qv_for_p);
526  });
527  } // mfi
528  pressure.FillBoundary(geom[lev].periodicity());
529  } // compute compressible pressure
530  } // not anelastic
531  else {
532  if (containerHasElement(plot_var_names, "dpdx") ||
533  containerHasElement(plot_var_names, "dpdy") ||
534  containerHasElement(plot_var_names, "dpdz") ||
535  containerHasElement(plot_var_names, "eq_pot_temp") ||
536  containerHasElement(plot_var_names, "qsat"))
537  {
538  // Copy p_hse into pressure if using anelastic
539  pressure.define(ba,dm,1,0);
540  MultiFab::Copy(pressure,p_hse,0,0,1,0);
541  }
542  }
543 
544  // ***************************************************************************************
545  // Finally, check for any derived quantities and compute them, inserting
546  // them into our output multifab
547  // ***************************************************************************************
548  auto calculate_derived = [&](const std::string& der_name,
549  MultiFab& src_mf,
550  decltype(derived::erf_dernull)& der_function)
551  {
552  if (containerHasElement(plot_var_names, der_name)) {
553  MultiFab dmf(mf[lev], make_alias, mf_comp, 1);
554 #ifdef _OPENMP
555 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
556 #endif
557  for (MFIter mfi(dmf, TilingIfNotGPU()); mfi.isValid(); ++mfi)
558  {
559  const Box& bx = mfi.tilebox();
560  auto& dfab = dmf[mfi];
561  auto& sfab = src_mf[mfi];
562  auto& zfab = (*z_phys_cc[lev])[mfi];
563  der_function(bx, dfab, 0, 1, sfab, zfab, Geom(lev), t_new[0], nullptr, lev);
564  }
565 
566  mf_comp++;
567  }
568  }; // end calculate_derived
569  // ***************************************************************************************
570 
571  // *****************************************************************************************
572  // NOTE: All derived variables computed below **MUST MATCH THE ORDER** of "derived_names"
573  // defined in ERF.H
574  // *****************************************************************************************
575 
576  if (use_moisture) {
577  calculate_derived("temp", vars_new[lev][Vars::cons], derived::erf_dermoisttemp);
578  } else {
579  calculate_derived("temp", vars_new[lev][Vars::cons], derived::erf_dertemp);
580  }
581  calculate_derived("theta", vars_new[lev][Vars::cons], derived::erf_dertheta);
582  calculate_derived("KE", vars_new[lev][Vars::cons], derived::erf_derKE);
583  calculate_derived("scalar", vars_new[lev][Vars::cons], derived::erf_derscalar);
584  calculate_derived("soundspeed", vars_new[lev][Vars::cons], derived::erf_dersoundspeed);
585 
586  if (containerHasElement(plot_var_names, "reflectivity"))
587  {
588  if (solverChoice.moisture_type == MoistureType::Morrison ||
589  solverChoice.moisture_type == MoistureType::WSM6 ||
590  solverChoice.moisture_type == MoistureType::SAM) {
591  calculate_derived("reflectivity", vars_new[lev][Vars::cons], derived::erf_derreflectivity);
592  } else {
593  mf[lev].setVal(zero);
594  mf_comp++;
595  }
596  }
597 
598  if (containerHasElement(plot_var_names, "max_reflectivity"))
599  {
600  if (solverChoice.moisture_type == MoistureType::Morrison ||
601  solverChoice.moisture_type == MoistureType::WSM6 ||
602  solverChoice.moisture_type == MoistureType::SAM) {
603  calculate_derived("max_reflectivity", vars_new[lev][Vars::cons], derived::erf_dermaxreflectivity);
604  } else {
605  mf[lev].setVal(zero);
606  mf_comp++;
607  }
608  }
609 
610  if (solverChoice.moisture_type != MoistureType::None) {
611  calculate_derived("precipitable" , vars_new[lev][Vars::cons], derived::erf_derprecipitable);
612  }
613  calculate_derived("mucape" , vars_new[lev][Vars::cons], derived::erf_dermucape);
614 
615  calculate_derived("vorticity_x", mf_cc_vel[lev], derived::erf_dervortx);
616  calculate_derived("vorticity_y", mf_cc_vel[lev], derived::erf_dervorty);
617  calculate_derived("vorticity_z", mf_cc_vel[lev], derived::erf_dervortz);
618  calculate_derived("helicity", mf_cc_vel[lev], derived::erf_derhelicity);
619  calculate_derived("local_helicity", mf_cc_vel[lev], derived::erf_derlocalhelicity);
620  calculate_derived("magvel", mf_cc_vel[lev], derived::erf_dermagvel);
621 
622  if (containerHasElement(plot_var_names, "divU"))
623  {
624  MultiFab dmf(mf[lev], make_alias, mf_comp, 1);
625  Array<MultiFab const*, AMREX_SPACEDIM> u;
626  u[0] = &(vars_new[lev][Vars::xvel]);
627  u[1] = &(vars_new[lev][Vars::yvel]);
628  u[2] = &(vars_new[lev][Vars::zvel]);
629  compute_divergence (lev, dmf, u, geom[lev]);
630  mf_comp += 1;
631  }
632 
633  if (containerHasElement(plot_var_names, "pres_hse"))
634  {
635  MultiFab::Copy(mf[lev],p_hse,0,mf_comp,1,0);
636  mf_comp += 1;
637  }
638  if (containerHasElement(plot_var_names, "dens_hse"))
639  {
640  MultiFab::Copy(mf[lev],r_hse,0,mf_comp,1,0);
641  mf_comp += 1;
642  }
643  if (containerHasElement(plot_var_names, "theta_hse"))
644  {
645  MultiFab::Copy(mf[lev],th_hse,0,mf_comp,1,0);
646  mf_comp += 1;
647  }
648 
649  if (containerHasElement(plot_var_names, "pressure"))
650  {
651  if (solverChoice.anelastic[lev] == 1) {
652  MultiFab::Copy(mf[lev], p_hse, 0, mf_comp, 1, 0);
653  } else {
654  MultiFab::Copy(mf[lev], pressure, 0, mf_comp, 1, 0);
655  }
656 
657  mf_comp += 1;
658  }
659 
660  if (containerHasElement(plot_var_names, "pert_pres"))
661  {
662  if (solverChoice.anelastic[lev] == 1) {
663  MultiFab::Copy(mf[lev], pp_inc[lev], 0, mf_comp, 1, 0);
664  } else {
665  MultiFab::Copy(mf[lev], pressure, 0, mf_comp, 1, 0);
666  MultiFab::Subtract(mf[lev],p_hse,0,mf_comp,1,IntVect{0});
667  }
668  mf_comp += 1;
669  }
670 
671  if (containerHasElement(plot_var_names, "pert_dens"))
672  {
673 #ifdef _OPENMP
674 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
675 #endif
676  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
677  {
678  const Box& bx = mfi.tilebox();
679  const Array4<Real>& derdat = mf[lev].array(mfi);
680  const Array4<Real const>& S_arr = vars_new[lev][Vars::cons].const_array(mfi);
681  const Array4<Real const>& r0_arr = r_hse.const_array(mfi);
682  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
683  derdat(i, j, k, mf_comp) = S_arr(i,j,k,Rho_comp) - r0_arr(i,j,k);
684  });
685  }
686  mf_comp ++;
687  }
688 
689  if (containerHasElement(plot_var_names, "buoyancy"))
690  {
691  MultiFab qt(mf[lev].boxArray(), mf[lev].DistributionMap(), 1, 1);
692  MultiFab b(mf[lev].boxArray(), mf[lev].DistributionMap(), 1, 1);
693  MultiFab S_prim(mf[lev].boxArray(), mf[lev].DistributionMap(),
694  vars_new[lev][Vars::cons].nComp()-1, 1);
695 
696  int n_qstate_into_total = micro->Get_Qstate_Moist_Size() - micro->Get_Qstate_Moist_NumConc_Size();
697  qt.setVal(0.);
698  if (solverChoice.moisture_type != MoistureType::None) {
699  make_qt(vars_new[lev][Vars::cons], qt, n_qstate_into_total);
700  }
701  cons_to_prim(vars_new[lev][Vars::cons], S_prim, 1);
702 
703  make_buoyancy(lev, vars_new[lev], S_prim, qt, b, geom[lev], solverChoice, base_state[lev], n_qstate_into_total,
704  get_eb(lev), solverChoice.anelastic[lev]);
705  MultiFab::Copy(mf[lev], b, 0, mf_comp, 1, 0);
706  mf_comp ++;
707  }
708 
709  if (containerHasElement(plot_var_names, "eq_pot_temp"))
710  {
711 #ifdef _OPENMP
712 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
713 #endif
714  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
715  {
716  const Box& bx = mfi.tilebox();
717  const Array4<Real>& derdat = mf[lev].array(mfi);
718  const Array4<Real const>& S_arr = vars_new[lev][Vars::cons].const_array(mfi);
719  const Array4<Real const>& p_arr = pressure.const_array(mfi);
720  const int ncomp = vars_new[lev][Vars::cons].nComp();
721  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
722  Real qv = (use_moisture && (ncomp > RhoQ1_comp)) ? S_arr(i,j,k,RhoQ1_comp)/S_arr(i,j,k,Rho_comp) : zero;
723  Real qc = (use_moisture && (ncomp > RhoQ2_comp)) ? S_arr(i,j,k,RhoQ2_comp)/S_arr(i,j,k,Rho_comp) : zero;
724  Real T = getTgivenRandRTh(S_arr(i,j,k,Rho_comp), S_arr(i,j,k,RhoTheta_comp), qv);
725  Real fac = Cp_d + Cp_l*(qv + qc);
726  Real pv = erf_esatw(T)*Real(100.0);
727 
728  derdat(i, j, k, mf_comp) = T*std::pow((p_arr(i,j,k) - pv)/p_0, -R_d/fac)*std::exp(L_v*qv/(fac*T)) ;
729  });
730  }
731  mf_comp ++;
732  }
733 
734  if (containerHasElement(plot_var_names, "VPD"))
735  {
736 #ifdef _OPENMP
737 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
738 #endif
739  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
740  {
741  const Box& bx = mfi.tilebox();
742  const Array4<Real>& derdat = mf[lev].array(mfi);
743  const Array4<Real const>& S_arr = vars_new[lev][Vars::cons].const_array(mfi);
744  const Array4<Real const>& p_arr = pressure.const_array(mfi);
745  const int ncomp = vars_new[lev][Vars::cons].nComp();
746  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
747  {
748  const Real qv = (use_moisture && (ncomp > RhoQ1_comp)) ? S_arr(i,j,k,RhoQ1_comp)/S_arr(i,j,k,Rho_comp) : zero;
749 
750  const Real T = getTgivenRandRTh(S_arr(i,j,k,Rho_comp), S_arr(i,j,k,RhoTheta_comp), qv);
751  const Real e_sat = Real(100.0) * erf_esatw_cc(T);
752 
753  const Real P = p_arr(i,j,k);
754  const Real e_act = P * qv / (Real(0.622) + qv);
755 
756  derdat(i,j,k,mf_comp) = std::max(amrex::Real(0), e_sat - e_act) * Real(0.001);
757  });
758  }
759  mf_comp ++;
760  }
761 
762 #ifdef ERF_USE_WINDFARM
763  if ( containerHasElement(plot_var_names, "num_turb") and
764  (solverChoice.windfarm_type == WindFarmType::Fitch or solverChoice.windfarm_type == WindFarmType::EWP or
765  solverChoice.windfarm_type == WindFarmType::SimpleAD or solverChoice.windfarm_type == WindFarmType::GeneralAD) )
766  {
767  MultiFab::Copy(mf[lev],Nturb[lev],0,mf_comp,1,0);
768  mf_comp ++;
769  }
770 
771  if ( containerHasElement(plot_var_names, "SMark0") and
772  (solverChoice.windfarm_type == WindFarmType::Fitch or solverChoice.windfarm_type == WindFarmType::EWP or
773  solverChoice.windfarm_type == WindFarmType::SimpleAD or solverChoice.windfarm_type == WindFarmType::GeneralAD) )
774  {
775  MultiFab::Copy(mf[lev],SMark[lev],0,mf_comp,1,0);
776  mf_comp ++;
777  }
778 
779  if (containerHasElement(plot_var_names, "SMark1") and
780  (solverChoice.windfarm_type == WindFarmType::SimpleAD or solverChoice.windfarm_type == WindFarmType::GeneralAD))
781  {
782  MultiFab::Copy(mf[lev],SMark[lev],1,mf_comp,1,0);
783  mf_comp ++;
784  }
785 #endif
786 
787  // **********************************************************************************************
788  // Allocate space if we are computing any pressure gradients
789  // **********************************************************************************************
790 
791  Vector<MultiFab> gradp_temp; gradp_temp.resize(AMREX_SPACEDIM);
792  if (containerHasElement(plot_var_names, "dpdx") ||
793  containerHasElement(plot_var_names, "dpdy") ||
794  containerHasElement(plot_var_names, "dpdz") ||
795  containerHasElement(plot_var_names, "pres_hse_x") ||
796  containerHasElement(plot_var_names, "pres_hse_y"))
797  {
798  gradp_temp[GpVars::gpx].define(convert(ba, IntVect(1,0,0)), dm, 1, 1); gradp_temp[GpVars::gpx].setVal(0.);
799  gradp_temp[GpVars::gpy].define(convert(ba, IntVect(0,1,0)), dm, 1, 1); gradp_temp[GpVars::gpy].setVal(0.);
800  gradp_temp[GpVars::gpz].define(convert(ba, IntVect(0,0,1)), dm, 1, 1); gradp_temp[GpVars::gpz].setVal(0.);
801  }
802 
803  // **********************************************************************************************
804  // These are based on computing gradient of full pressure
805  // **********************************************************************************************
806 
807  if (solverChoice.anelastic[lev] == 0) {
808  if ( (containerHasElement(plot_var_names, "dpdx")) ||
809  (containerHasElement(plot_var_names, "dpdy")) ||
810  (containerHasElement(plot_var_names, "dpdz")) ) {
811  compute_gradp(pressure, geom[lev], *z_phys_nd[lev].get(), *z_phys_cc[lev].get(), mapfac[lev],
812  get_eb(lev), gradp_temp, solverChoice);
813  }
814  }
815 
816  if (containerHasElement(plot_var_names, "dpdx"))
817  {
818  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
819  {
820  const Box& bx = mfi.tilebox();
821  const Array4<Real >& derdat = mf[lev].array(mfi);
822  const Array4<Real const>& gpx_arr = (solverChoice.anelastic[lev] == 1) ?
823  gradp[lev][GpVars::gpx].array(mfi) : gradp_temp[GpVars::gpx].array(mfi);
824  const Array4<Real const>& mf_mx_arr = mapfac[lev][MapFacType::m_x]->const_array(mfi);
825  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
826  derdat(i ,j ,k, mf_comp) = myhalf * (gpx_arr(i+1,j,k) + gpx_arr(i,j,k)) * mf_mx_arr(i,j,0);
827  });
828  }
829  mf_comp ++;
830  } // dpdx
831  if (containerHasElement(plot_var_names, "dpdy"))
832  {
833  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
834  {
835  const Box& bx = mfi.tilebox();
836  const Array4<Real >& derdat = mf[lev].array(mfi);
837  const Array4<Real const>& gpy_arr = (solverChoice.anelastic[lev] == 1) ?
838  gradp[lev][GpVars::gpy].array(mfi) : gradp_temp[GpVars::gpy].array(mfi);
839  const Array4<Real const>& mf_my_arr = mapfac[lev][MapFacType::m_y]->const_array(mfi);
840  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
841  derdat(i ,j ,k, mf_comp) = myhalf * (gpy_arr(i,j+1,k) + gpy_arr(i,j,k)) * mf_my_arr(i,j,0);
842  });
843  }
844  mf_comp ++;
845  } // dpdy
846  if (containerHasElement(plot_var_names, "dpdz"))
847  {
848  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
849  {
850  const Box& bx = mfi.tilebox();
851  const Array4<Real >& derdat = mf[lev].array(mfi);
852  const Array4<Real const>& gpz_arr = (solverChoice.anelastic[lev] == 1) ?
853  gradp[lev][GpVars::gpz].array(mfi) : gradp_temp[GpVars::gpz].array(mfi);
854  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
855  derdat(i ,j ,k, mf_comp) = myhalf * (gpz_arr(i,j,k+1) + gpz_arr(i,j,k));
856  });
857  }
858  mf_comp ++;
859  } // dpdz
860 
861  // **********************************************************************************************
862  // These are based on computing gradient of basestate pressure
863  // **********************************************************************************************
864 
865  if ( (containerHasElement(plot_var_names, "pres_hse_x")) ||
866  (containerHasElement(plot_var_names, "pres_hse_y")) ) {
867  compute_gradp(p_hse, geom[lev], *z_phys_nd[lev].get(), *z_phys_cc[lev].get(), mapfac[lev],
868  get_eb(lev), gradp_temp, solverChoice);
869  }
870 
871  if (containerHasElement(plot_var_names, "pres_hse_x"))
872  {
873  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
874  {
875  const Box& bx = mfi.tilebox();
876  const Array4<Real >& derdat = mf[lev].array(mfi);
877  const Array4<Real const>& gpx_arr = gradp_temp[0].array(mfi);
878  const Array4<Real const>& mf_mx_arr = mapfac[lev][MapFacType::m_x]->const_array(mfi);
879  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
880  derdat(i ,j ,k, mf_comp) = myhalf * (gpx_arr(i+1,j,k) + gpx_arr(i,j,k)) * mf_mx_arr(i,j,0);
881  });
882  }
883  mf_comp += 1;
884  } // pres_hse_x
885 
886  if (containerHasElement(plot_var_names, "pres_hse_y"))
887  {
888  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
889  {
890  const Box& bx = mfi.tilebox();
891  const Array4<Real >& derdat = mf[lev].array(mfi);
892  const Array4<Real const>& gpy_arr = gradp_temp[1].array(mfi);
893  const Array4<Real const>& mf_my_arr = mapfac[lev][MapFacType::m_y]->const_array(mfi);
894  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
895  derdat(i ,j ,k, mf_comp) = myhalf * (gpy_arr(i,j+1,k) + gpy_arr(i,j,k)) * mf_my_arr(i,j,0);
896  });
897  }
898  mf_comp += 1;
899  } // pres_hse_y
900 
901  // **********************************************************************************************
902  // Metric terms
903  // **********************************************************************************************
904 
905  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
906  if (containerHasElement(plot_var_names, "z_phys"))
907  {
908  MultiFab::Copy(mf[lev],*z_phys_cc[lev],0,mf_comp,1,0);
909  mf_comp ++;
910  }
911 
912  if (containerHasElement(plot_var_names, "detJ"))
913  {
914  MultiFab::Copy(mf[lev],*detJ_cc[lev],0,mf_comp,1,0);
915  mf_comp ++;
916  }
917  } // use_terrain
918 
919  if (containerHasElement(plot_var_names, "mapfac")) {
920  amrex::Print() << "You are plotting a 3D version of mapfac; we suggest using the 2D plotfile instead" << std::endl;
921 #ifdef _OPENMP
922 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
923 #endif
924  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
925  {
926  const Box& bx = mfi.tilebox();
927  const Array4<Real>& derdat = mf[lev].array(mfi);
928  const Array4<Real>& mf_m = mapfac[lev][MapFacType::m_x]->array(mfi);
929  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
930  derdat(i ,j ,k, mf_comp) = mf_m(i,j,0);
931  });
932  }
933  mf_comp ++;
934  }
935 
936  if (containerHasElement(plot_var_names, "lat_m")) {
937  amrex::Print() << "You are plotting a 3D version of lat_m; we suggest using the 2D plotfile instead" << std::endl;
938  if (lat_m[lev]) {
939 #ifdef _OPENMP
940 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
941 #endif
942  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
943  {
944  const Box& bx = mfi.tilebox();
945  const Array4<Real>& derdat = mf[lev].array(mfi);
946  const Array4<Real>& data = lat_m[lev]->array(mfi);
947  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
948  derdat(i, j, k, mf_comp) = data(i,j,0);
949  });
950  }
951  } else {
952  mf[lev].setVal(0.0,mf_comp,1,0);
953  }
954  mf_comp++;
955  } // lat_m
956 
957  if (containerHasElement(plot_var_names, "lon_m")) {
958  amrex::Print() << "You are plotting a 3D version of lon_m; we suggest using the 2D plotfile instead" << std::endl;
959  if (lon_m[lev]) {
960 #ifdef _OPENMP
961 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
962 #endif
963  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
964  {
965  const Box& bx = mfi.tilebox();
966  const Array4<Real>& derdat = mf[lev].array(mfi);
967  const Array4<Real>& data = lon_m[lev]->array(mfi);
968  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
969  derdat(i, j, k, mf_comp) = data(i,j,0);
970  });
971  }
972  } else {
973  mf[lev].setVal(0.0,mf_comp,1,0);
974  }
975  mf_comp++;
976  } // lon_m
977 
979  if (containerHasElement(plot_var_names, "u_t_avg")) {
980 #ifdef _OPENMP
981 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
982 #endif
983  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
984  {
985  const Box& bx = mfi.tilebox();
986  const Array4<Real>& derdat = mf[lev].array(mfi);
987  const Array4<Real>& data = vel_t_avg[lev]->array(mfi);
988  const Real norm = t_avg_cnt[lev];
989  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
990  {
991  derdat(i ,j ,k, mf_comp) = data(i,j,k,0) / norm;
992  });
993  }
994  mf_comp ++;
995  }
996 
997  if (containerHasElement(plot_var_names, "v_t_avg")) {
998 #ifdef _OPENMP
999 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
1000 #endif
1001  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
1002  {
1003  const Box& bx = mfi.tilebox();
1004  const Array4<Real>& derdat = mf[lev].array(mfi);
1005  const Array4<Real>& data = vel_t_avg[lev]->array(mfi);
1006  const Real norm = t_avg_cnt[lev];
1007  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
1008  {
1009  derdat(i ,j ,k, mf_comp) = data(i,j,k,1) / norm;
1010  });
1011  }
1012  mf_comp ++;
1013  }
1014 
1015  if (containerHasElement(plot_var_names, "w_t_avg")) {
1016 #ifdef _OPENMP
1017 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
1018 #endif
1019  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
1020  {
1021  const Box& bx = mfi.tilebox();
1022  const Array4<Real>& derdat = mf[lev].array(mfi);
1023  const Array4<Real>& data = vel_t_avg[lev]->array(mfi);
1024  const Real norm = t_avg_cnt[lev];
1025  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
1026  {
1027  derdat(i ,j ,k, mf_comp) = data(i,j,k,2) / norm;
1028  });
1029  }
1030  mf_comp ++;
1031  }
1032 
1033  if (containerHasElement(plot_var_names, "umag_t_avg")) {
1034 #ifdef _OPENMP
1035 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
1036 #endif
1037  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
1038  {
1039  const Box& bx = mfi.tilebox();
1040  const Array4<Real>& derdat = mf[lev].array(mfi);
1041  const Array4<Real>& data = vel_t_avg[lev]->array(mfi);
1042  const Real norm = t_avg_cnt[lev];
1043  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
1044  {
1045  derdat(i ,j ,k, mf_comp) = data(i,j,k,3) / norm;
1046  });
1047  }
1048  mf_comp ++;
1049  }
1050  }
1051 
1052  if (containerHasElement(plot_var_names, "nut")) {
1053  MultiFab dmf(mf[lev], make_alias, mf_comp, 1);
1054  MultiFab cmf(vars_new[lev][Vars::cons], make_alias, 0, 1); // to provide rho only
1055 #ifdef _OPENMP
1056 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
1057 #endif
1058  for (MFIter mfi(dmf, TilingIfNotGPU()); mfi.isValid(); ++mfi)
1059  {
1060  const Box& bx = mfi.tilebox();
1061  auto prim = dmf[mfi].array();
1062  auto const cons = cmf[mfi].const_array();
1063  auto const diff = (*eddyDiffs_lev[lev])[mfi].const_array();
1064  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
1065  {
1066  const Real rho = cons(i, j, k, Rho_comp);
1067  const Real Kmv = diff(i, j, k, EddyDiff::Mom_v);
1068  prim(i,j,k) = Kmv / rho;
1069  });
1070  }
1071 
1072  mf_comp++;
1073  }
1074 
1075  if (containerHasElement(plot_var_names, "Kmv")) {
1076  MultiFab::Copy(mf[lev],*eddyDiffs_lev[lev],EddyDiff::Mom_v,mf_comp,1,0);
1077  mf_comp ++;
1078  }
1079  if (containerHasElement(plot_var_names, "Kmh")) {
1080  MultiFab::Copy(mf[lev],*eddyDiffs_lev[lev],EddyDiff::Mom_h,mf_comp,1,0);
1081  mf_comp ++;
1082  }
1083  if (containerHasElement(plot_var_names, "Khv")) {
1084  MultiFab::Copy(mf[lev],*eddyDiffs_lev[lev],EddyDiff::Theta_v,mf_comp,1,0);
1085  mf_comp ++;
1086  }
1087  if (containerHasElement(plot_var_names, "Khh")) {
1088  MultiFab::Copy(mf[lev],*eddyDiffs_lev[lev],EddyDiff::Theta_h,mf_comp,1,0);
1089  mf_comp ++;
1090  }
1091  if (containerHasElement(plot_var_names, "Lturb")) {
1092  MultiFab::Copy(mf[lev],*eddyDiffs_lev[lev],EddyDiff::Turb_lengthscale,mf_comp,1,0);
1093  mf_comp ++;
1094  }
1095  if (containerHasElement(plot_var_names, "walldist")) {
1096  MultiFab::Copy(mf[lev],*walldist[lev],0,mf_comp,1,0);
1097  mf_comp ++;
1098  }
1099  if (containerHasElement(plot_var_names, "diss")) {
1100  MultiFab::Copy(mf[lev],*SFS_diss_lev[lev],0,mf_comp,1,0);
1101  mf_comp ++;
1102  }
1103 
1104  // TODO: The size of the q variables can vary with different
1105  // moisture models. Therefore, certain components may
1106  // reside at different indices. For example, Kessler is
1107  // warm but precipitating. This puts qp at index three
1108  // However, SAM is cold and precipitating so qp is index Real(4.)
1109  // Need to built an external enum struct or a better pathway.
1110 
1111  // NOTE: Protect against accessing non-existent data
1112  if (use_moisture) {
1113  int n_qstate_moist = micro->Get_Qstate_Moist_Size();
1114  int n_qstate_moist_numconc = micro->Get_Qstate_Moist_NumConc_Size();
1115 
1116  // Moist density
1117  if(containerHasElement(plot_var_names, "moist_density"))
1118  {
1119  int n_start = RhoQ1_comp; // qv
1120  int n_end = RhoQ2_comp; // qc
1121  if (n_qstate_moist > 3) n_end = RhoQ3_comp; // qi
1122  MultiFab::Copy(mf[lev], vars_new[lev][Vars::cons], Rho_comp, mf_comp, 1, 0);
1123  for (int n_comp(n_start); n_comp <= n_end; ++n_comp) {
1124  MultiFab::Add(mf[lev], vars_new[lev][Vars::cons], n_comp, mf_comp, 1, 0);
1125  }
1126  mf_comp += 1;
1127  }
1128 
1129  if(containerHasElement(plot_var_names, "qv") && (n_qstate_moist >= 1))
1130  {
1131  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], RhoQ1_comp, mf_comp, 1, 0);
1132  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp , mf_comp, 1, 0);
1133  mf_comp += 1;
1134  }
1135 
1136  if(containerHasElement(plot_var_names, "qc") && (n_qstate_moist >= 2))
1137  {
1138  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], RhoQ2_comp, mf_comp, 1, 0);
1139  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp , mf_comp, 1, 0);
1140  mf_comp += 1;
1141  }
1142 
1143  if(containerHasElement(plot_var_names, "qi") && (n_qstate_moist >= 4))
1144  {
1145  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], RhoQ3_comp, mf_comp, 1, 0);
1146  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp , mf_comp, 1, 0);
1147  mf_comp += 1;
1148  }
1149 
1150  if(containerHasElement(plot_var_names, "qrain") && (n_qstate_moist >= 3))
1151  {
1152  int n_start = (n_qstate_moist > 3) ? RhoQ4_comp : RhoQ3_comp;
1153  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], n_start , mf_comp, 1, 0);
1154  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp, mf_comp, 1, 0);
1155  mf_comp += 1;
1156  }
1157 
1158  if(containerHasElement(plot_var_names, "qsnow") && (n_qstate_moist >= 5))
1159  {
1160  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], RhoQ5_comp, mf_comp, 1, 0);
1161  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp, mf_comp, 1, 0);
1162  mf_comp += 1;
1163  }
1164 
1165  if(containerHasElement(plot_var_names, "qgraup") && (n_qstate_moist >= 6))
1166  {
1167  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], RhoQ6_comp, mf_comp, 1, 0);
1168  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp, mf_comp, 1, 0);
1169  mf_comp += 1;
1170  }
1171 
1172  if(containerHasElement(plot_var_names, "nc") && (n_qstate_moist >= 7))
1173  {
1174  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], RhoQ7_comp, mf_comp, 1, 0);
1175  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp, mf_comp, 1, 0);
1176  mf_comp += 1;
1177  }
1178 
1179  if(containerHasElement(plot_var_names, "ni") && (n_qstate_moist >= 8))
1180  {
1181  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], RhoQ8_comp, mf_comp, 1, 0);
1182  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp, mf_comp, 1, 0);
1183  mf_comp += 1;
1184  }
1185 
1186  if(containerHasElement(plot_var_names, "nr") && (n_qstate_moist >= 9))
1187  {
1188  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], RhoQ9_comp, mf_comp, 1, 0);
1189  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp, mf_comp, 1, 0);
1190  mf_comp += 1;
1191  }
1192 
1193  if(containerHasElement(plot_var_names, "ns") && (n_qstate_moist >= 10))
1194  {
1195  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], RhoQ10_comp, mf_comp, 1, 0);
1196  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp, mf_comp, 1, 0);
1197  mf_comp += 1;
1198  }
1199 
1200  if(containerHasElement(plot_var_names, "ng") && (n_qstate_moist >= 11))
1201  {
1202  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], RhoQ11_comp, mf_comp, 1, 0);
1203  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp, mf_comp, 1, 0);
1204  mf_comp += 1;
1205  }
1206 
1207  // Precipitating + non-precipitating components
1208  //--------------------------------------------------------------------------
1209  if(containerHasElement(plot_var_names, "qt"))
1210  {
1211  int n_start = RhoQ1_comp; // qv
1212  int n_end = n_start + n_qstate_moist - n_qstate_moist_numconc;
1213  MultiFab::Copy(mf[lev], vars_new[lev][Vars::cons], n_start, mf_comp, 1, 0);
1214 
1215  for (int n_comp(n_start+1); n_comp < n_end; ++n_comp) {
1216  MultiFab::Add(mf[lev], vars_new[lev][Vars::cons], n_comp, mf_comp, 1, 0);
1217  }
1218 
1219  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp , mf_comp, 1, 0);
1220 
1221  mf_comp += 1;
1222  }
1223 
1224  // Non-precipitating components
1225  //--------------------------------------------------------------------------
1226  if (containerHasElement(plot_var_names, "qn"))
1227  {
1228  int n_start = RhoQ1_comp; // qv
1229  int n_end = RhoQ2_comp; // qc
1230  if (n_qstate_moist > 3) n_end = RhoQ3_comp; // qi
1231  MultiFab::Copy(mf[lev], vars_new[lev][Vars::cons], n_start, mf_comp, 1, 0);
1232  for (int n_comp(n_start+1); n_comp <= n_end; ++n_comp) {
1233  MultiFab::Add(mf[lev], vars_new[lev][Vars::cons], n_comp, mf_comp, 1, 0);
1234  }
1235  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp , mf_comp, 1, 0);
1236  mf_comp += 1;
1237  }
1238 
1239  // Precipitating components
1240  //--------------------------------------------------------------------------
1241  if(containerHasElement(plot_var_names, "qp") && (n_qstate_moist >= 3))
1242  {
1243  int n_start = (n_qstate_moist > 3) ? RhoQ4_comp : RhoQ3_comp;
1244  int n_end = ncomp_cons - 1 - n_qstate_moist_numconc;
1245  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], n_start, mf_comp, 1, 0);
1246  for (int n_comp(n_start+1); n_comp <= n_end; ++n_comp) {
1247  MultiFab::Add( mf[lev], vars_new[lev][Vars::cons], n_comp, mf_comp, 1, 0);
1248  }
1249  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp , mf_comp, 1, 0);
1250  mf_comp += 1;
1251  }
1252 
1253  if (containerHasElement(plot_var_names, "qsat"))
1254  {
1255 #ifdef _OPENMP
1256 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
1257 #endif
1258  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
1259  {
1260  const Box& bx = mfi.tilebox();
1261  const Array4<Real>& derdat = mf[lev].array(mfi);
1262  const Array4<Real const>& p_arr = pressure.array(mfi);
1263  const Array4<Real const>& S_arr = vars_new[lev][Vars::cons].const_array(mfi);
1264  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
1265  {
1266  Real qv = S_arr(i,j,k,RhoQ1_comp) / S_arr(i,j,k,Rho_comp);
1267  Real T = getTgivenRandRTh(S_arr(i,j,k,Rho_comp), S_arr(i,j,k,RhoTheta_comp), qv);
1268  Real p = p_arr(i,j,k) * Real(0.01);
1269  erf_qsatw(T, p, derdat(i,j,k,mf_comp));
1270  });
1271  }
1272  mf_comp ++;
1273  }
1274 
1275  if ( (solverChoice.moisture_type == MoistureType::Kessler) ||
1276  (solverChoice.moisture_type == MoistureType::Morrison_NoIce) ||
1277  (solverChoice.moisture_type == MoistureType::SAM_NoIce) )
1278  {
1279  if (containerHasElement(plot_var_names, "rain_accum"))
1280  {
1281  MultiFab::Copy(mf[lev],*(qmoist[lev][0]),0,mf_comp,1,0);
1282  mf_comp += 1;
1283  }
1284  if (containerHasElement(plot_var_names, "rel_humidity")) {
1285  Print() << "Warning: plot variable \"rel_humidity\" is not available with Kessler moisture model.\n";
1286  mf[lev].setVal(0.0, mf_comp, 1, 0);
1287  mf_comp += 1;
1288  }
1289  }
1290  else if ( (solverChoice.moisture_type == MoistureType::SAM) ||
1291  (solverChoice.moisture_type == MoistureType::Morrison) ||
1292  (solverChoice.moisture_type == MoistureType::WSM6) )
1293  {
1294  if (containerHasElement(plot_var_names, "rain_accum"))
1295  {
1296  MultiFab::Copy(mf[lev],*(qmoist[lev][0]),0,mf_comp,1,0);
1297  mf_comp += 1;
1298  }
1299  if (containerHasElement(plot_var_names, "snow_accum"))
1300  {
1301  MultiFab::Copy(mf[lev],*(qmoist[lev][1]),0,mf_comp,1,0);
1302  mf_comp += 1;
1303  }
1304  if (containerHasElement(plot_var_names, "graup_accum"))
1305  {
1306  MultiFab::Copy(mf[lev],*(qmoist[lev][2]),0,mf_comp,1,0);
1307  mf_comp += 1;
1308  }
1309  if (containerHasElement(plot_var_names, "rel_humidity")) {
1310  Print() << "Warning: plot variable \"rel_humidity\" is not available with SAM moisture model.\n";
1311  mf[lev].setVal(0.0, mf_comp, 1, 0);
1312  mf_comp += 1;
1313  }
1314  }
1315  else if(solverChoice.moisture_type == MoistureType::SuperDroplets)
1316  {
1317  if (containerHasElement(plot_var_names, "rain_accum")) {
1318  MultiFab::Copy(mf[lev],*(qmoist[lev][6]),0,mf_comp,1,0);
1319  mf_comp += 1;
1320  }
1321  if (containerHasElement(plot_var_names, "rel_humidity")) {
1322  MultiFab::Copy(mf[lev],*(qmoist[lev][5]),0,mf_comp,1,0);
1323  mf_comp += 1;
1324  }
1325  if (containerHasElement(plot_var_names, "condensation_rate")) {
1326  MultiFab::Copy(mf[lev],*(qmoist[lev][3]),0,mf_comp,1,0);
1327  mf_comp += 1;
1328  }
1329  }
1330 
1331  } // if use_moisture
1332 
1333  if (containerHasElement(plot_var_names, "terrain_IB_mask"))
1334  {
1335  MultiFab* terrain_blank = terrain_blanking[lev].get();
1336  MultiFab::Copy(mf[lev],*terrain_blank,0,mf_comp,1,0);
1337  mf_comp ++;
1338  }
1339 
1340  if (containerHasElement(plot_var_names, "volfrac")) {
1341  if ( solverChoice.terrain_type == TerrainType::EB ||
1342  solverChoice.terrain_type == TerrainType::ImmersedForcing)
1343  {
1344  MultiFab::Copy(mf[lev], EBFactory(lev).getVolFrac(), 0, mf_comp, 1, 0);
1345  } else {
1346  mf[lev].setVal(1.0, mf_comp, 1, 0);
1347  }
1348  mf_comp += 1;
1349  }
1350 
1351 #ifdef ERF_COMPUTE_ERROR
1352  // Next, check for error in velocities and if desired, output them -- note we output none or all, not just some
1353  if (containerHasElement(plot_var_names, "xvel_err") ||
1354  containerHasElement(plot_var_names, "yvel_err") ||
1355  containerHasElement(plot_var_names, "zvel_err"))
1356  {
1357  //
1358  // Moving terrain ANALYTICAL
1359  //
1360  Real H = geom[lev].ProbHi()[2];
1361  Real Ampl = Real(0.16);
1362  Real wavelength = Real(100.);
1363  Real kp = two * PI / wavelength;
1364  Real g = CONST_GRAV;
1365  Real omega = std::sqrt(g * kp);
1366  Real omega_t = omega * t_new[lev];
1367 
1368  const auto dx = geom[lev].CellSizeArray();
1369 
1370 #ifdef _OPENMP
1371 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
1372 #endif
1373  for (MFIter mfi(mf[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi)
1374  {
1375  const Box& bx = mfi.validbox();
1376  Box xbx(bx); xbx.surroundingNodes(0);
1377  const Array4<Real> xvel_arr = vars_new[lev][Vars::xvel].array(mfi);
1378  const Array4<Real> zvel_arr = vars_new[lev][Vars::zvel].array(mfi);
1379 
1380  const Array4<Real const>& z_nd = z_phys_nd[lev]->const_array(mfi);
1381 
1382  ParallelFor(xbx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
1383  {
1384  Real x = i * dx[0];
1385  Real z = fourth * (z_nd(i,j,k) + z_nd(i,j+1,k) + z_nd(i,j,k+1) + z_nd(i,j+1,k+1));
1386 
1387  Real z_base = Ampl * std::sin(kp * x - omega_t);
1388  z -= z_base;
1389 
1390  Real fac = std::cosh( kp * (z - H) ) / std::sinh(kp * H);
1391 
1392  xvel_arr(i,j,k) -= -Ampl * omega * fac * std::sin(kp * x - omega_t);
1393  });
1394 
1395  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
1396  {
1397  Real x = (i + myhalf) * dx[0];
1398  Real z = fourth * ( z_nd(i,j,k) + z_nd(i+1,j,k) + z_nd(i,j+1,k) + z_nd(i+1,j+1,k));
1399 
1400  Real z_base = Ampl * std::sin(kp * x - omega_t);
1401  z -= z_base;
1402 
1403  Real fac = std::sinh( kp * (z - H) ) / std::sinh(kp * H);
1404 
1405  zvel_arr(i,j,k) -= Ampl * omega * fac * std::cos(kp * x - omega_t);
1406  });
1407  }
1408 
1409  MultiFab temp_mf(mf[lev].boxArray(), mf[lev].DistributionMap(), AMREX_SPACEDIM, 0);
1410  average_face_to_cellcenter(temp_mf,0,
1411  Array<const MultiFab*,3>{&vars_new[lev][Vars::xvel],&vars_new[lev][Vars::yvel],&vars_new[lev][Vars::zvel]});
1412 
1413  if (containerHasElement(plot_var_names, "xvel_err")) {
1414  MultiFab::Copy(mf[lev],temp_mf,0,mf_comp,1,0);
1415  mf_comp += 1;
1416  }
1417  if (containerHasElement(plot_var_names, "yvel_err")) {
1418  MultiFab::Copy(mf[lev],temp_mf,1,mf_comp,1,0);
1419  mf_comp += 1;
1420  }
1421  if (containerHasElement(plot_var_names, "zvel_err")) {
1422  MultiFab::Copy(mf[lev],temp_mf,2,mf_comp,1,0);
1423  mf_comp += 1;
1424  }
1425 
1426  // Now restore the velocities to what they were
1427 #ifdef _OPENMP
1428 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
1429 #endif
1430  for (MFIter mfi(mf[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi)
1431  {
1432  const Box& bx = mfi.validbox();
1433  Box xbx(bx); xbx.surroundingNodes(0);
1434 
1435  const Array4<Real> xvel_arr = vars_new[lev][Vars::xvel].array(mfi);
1436  const Array4<Real> zvel_arr = vars_new[lev][Vars::zvel].array(mfi);
1437 
1438  const Array4<Real const>& z_nd = z_phys_nd[lev]->const_array(mfi);
1439 
1440  ParallelFor(xbx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
1441  {
1442  Real x = i * dx[0];
1443  Real z = fourth * (z_nd(i,j,k) + z_nd(i,j+1,k) + z_nd(i,j,k+1) + z_nd(i,j+1,k+1));
1444  Real z_base = Ampl * std::sin(kp * x - omega_t);
1445 
1446  z -= z_base;
1447 
1448  Real fac = std::cosh( kp * (z - H) ) / std::sinh(kp * H);
1449  xvel_arr(i,j,k) += -Ampl * omega * fac * std::sin(kp * x - omega_t);
1450  });
1451  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
1452  {
1453  Real x = (i + myhalf) * dx[0];
1454  Real z = fourth * ( z_nd(i,j,k) + z_nd(i+1,j,k) + z_nd(i,j+1,k) + z_nd(i+1,j+1,k));
1455  Real z_base = Ampl * std::sin(kp * x - omega_t);
1456 
1457  z -= z_base;
1458  Real fac = std::sinh( kp * (z - H) ) / std::sinh(kp * H);
1459 
1460  zvel_arr(i,j,k) += Ampl * omega * fac * std::cos(kp * x - omega_t);
1461  });
1462  }
1463  } // end xvel_err, yvel_err, zvel_err
1464 
1465  if (containerHasElement(plot_var_names, "pp_err"))
1466  {
1467  // Moving terrain ANALYTICAL
1468 #ifdef _OPENMP
1469 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
1470 #endif
1471  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
1472  {
1473  const Box& bx = mfi.tilebox();
1474  const Array4<Real>& derdat = mf[lev].array(mfi);
1475  const Array4<Real const>& p0_arr = p_hse.const_array(mfi);
1476  const Array4<Real const>& S_arr = vars_new[lev][Vars::cons].const_array(mfi);
1477 
1478  const auto dx = geom[lev].CellSizeArray();
1479  const Array4<Real const>& z_nd = z_phys_nd[lev]->const_array(mfi);
1480  const Array4<Real const>& p_arr = pressure.const_array(mfi);
1481  const Array4<Real const>& r0_arr = r_hse.const_array(mfi);
1482 
1483  Real H = geom[lev].ProbHi()[2];
1484  Real Ampl = Real(0.16);
1485  Real wavelength = Real(100.);
1486  Real kp = two * PI / wavelength;
1487  Real g = CONST_GRAV;
1488  Real omega = std::sqrt(g * kp);
1489  Real omega_t = omega * t_new[lev];
1490 
1491  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
1492  {
1493  derdat(i, j, k, mf_comp) = p_arr(i,j,k) - p0_arr(i,j,k);
1494 
1495  Real rho_hse = r0_arr(i,j,k);
1496 
1497  Real x = (i + myhalf) * dx[0];
1498  Real z = Real(0.125) * ( z_nd(i,j,k ) + z_nd(i+1,j,k ) + z_nd(i,j+1,k ) + z_nd(i+1,j+1,k )
1499  +z_nd(i,j,k+1) + z_nd(i+1,j,k+1) + z_nd(i,j+1,k+1) + z_nd(i+1,j+1,k+1) );
1500  Real z_base = Ampl * std::sin(kp * x - omega_t);
1501 
1502  z -= z_base;
1503  Real fac = std::cosh( kp * (z - H) ) / std::sinh(kp * H);
1504  Real pprime_exact = -(Ampl * omega * omega / kp) * fac *
1505  std::sin(kp * x - omega_t) * r0_arr(i,j,k);
1506 
1507  derdat(i,j,k,mf_comp) -= pprime_exact;
1508  });
1509  }
1510  mf_comp += 1;
1511  }
1512 #endif
1513 
1514  if (solverChoice.rad_type != RadiationType::None) {
1515  if (containerHasElement(plot_var_names, "qsrc_sw")) {
1516  MultiFab::Copy(mf[lev], *(qheating_rates[lev]), 0, mf_comp, 1, 0);
1517  mf_comp += 1;
1518  }
1519  if (containerHasElement(plot_var_names, "qsrc_lw")) {
1520  MultiFab::Copy(mf[lev], *(qheating_rates[lev]), 1, mf_comp, 1, 0);
1521  mf_comp += 1;
1522  }
1523  }
1524 
1525  // *****************************************************************************************
1526  // End of derived variables corresponding to "derived_names" in ERF.H
1527  //
1528  // Particles and microphysics can provide additional outputs, which are handled below.
1529  // *****************************************************************************************
1530 
1531 #ifdef ERF_USE_PARTICLES
1532  const auto& particles_namelist( particleData.getNames() );
1533 
1534  if (containerHasElement(plot_var_names, "tracer_particles_count")) {
1535  if (particles_namelist.size() == 0) {
1536  MultiFab temp_dat(mf[lev].boxArray(), mf[lev].DistributionMap(), 1, 0);
1537  temp_dat.setVal(0);
1538  MultiFab::Copy(mf[lev], temp_dat, 0, mf_comp, 1, 0);
1539  mf_comp += 1;
1540  } else {
1541  for (ParticlesNamesVector::size_type i = 0; i < particles_namelist.size(); i++) {
1542  if (containerHasElement(plot_var_names, std::string(particles_namelist[i]+"_count"))) {
1543  MultiFab temp_dat(mf[lev].boxArray(), mf[lev].DistributionMap(), 1, 0);
1544  temp_dat.setVal(0);
1545  if (particleData.HasSpecies(particles_namelist[i])) {
1546  particleData[particles_namelist[i]]->Increment(temp_dat, lev);
1547  }
1548  MultiFab::Copy(mf[lev], temp_dat, 0, mf_comp, 1, 0);
1549  mf_comp += 1;
1550  }
1551  }
1552  }
1553  }
1554 
1555  Vector<std::string> particle_mesh_plot_names(0);
1556  particleData.GetMeshPlotVarNames( particle_mesh_plot_names );
1557 
1558  for (int i = 0; i < particle_mesh_plot_names.size(); i++) {
1559  std::string plot_var_name(particle_mesh_plot_names[i]);
1560  if (containerHasElement(plot_var_names, plot_var_name) ) {
1561  MultiFab temp_dat(mf[lev].boxArray(), mf[lev].DistributionMap(), 1, 1);
1562  temp_dat.setVal(0);
1563  particleData.GetMeshPlotVar(plot_var_name, temp_dat, *z_phys_nd[lev], lev);
1564  MultiFab::Copy(mf[lev], temp_dat, 0, mf_comp, 1, 0);
1565  mf_comp += 1;
1566  }
1567  }
1568 #endif
1569 
1570  {
1571  Vector<std::string> microphysics_plot_names;
1572  micro->GetPlotVarNames(microphysics_plot_names);
1573  for (auto& plot_name : microphysics_plot_names) {
1574  if (containerHasElement(plot_var_names, plot_name)) {
1575  MultiFab temp_dat(mf[lev].boxArray(), mf[lev].DistributionMap(), 1, 1);
1576  temp_dat.setVal(0);
1577  micro->GetPlotVar(plot_name, temp_dat, lev);
1578  MultiFab::Copy(mf[lev], temp_dat, 0, mf_comp, 1, 0);
1579  mf_comp += 1;
1580  }
1581  }
1582  }
1583  } // lev
1584 
1585  if (solverChoice.terrain_type == TerrainType::EB)
1586  {
1587  for (int lev = 0; lev <= finest_level; ++lev) {
1588  EB_set_covered(mf[lev], zero);
1589  }
1590  }
1591 
1592  // Fill terrain distortion MF (nu_nd)
1593  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
1594  for (int lev(0); lev <= finest_level; ++lev) {
1595  MultiFab::Copy(mf_nd[lev],*z_phys_nd[lev],0,2,1,0);
1596  Real dz = Geom()[lev].CellSizeArray()[2];
1597  for (MFIter mfi(mf_nd[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
1598  const Box& bx = mfi.tilebox();
1599  Array4<Real> mf_arr = mf_nd[lev].array(mfi);
1600  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
1601  {
1602  mf_arr(i,j,k,2) -= k * dz;
1603  });
1604  }
1605  }
1606  }
1607 
1608  std::string plotfilename;
1609  std::string plotfilenameU;
1610  std::string plotfilenameV;
1611  std::string plotfilenameW;
1612 
1613  if (which == 1) {
1615  const std::string dt_format = "%Y-%m-%d_%H:%M:%S"; // ISO 8601 standard
1616  plotfilename = plot3d_file_1+"_"+getTimestamp(start_time+t_new[0], dt_format,false);
1617  } else {
1618  plotfilename = Concatenate(plot3d_file_1, istep[0], file_name_digits);
1619  }
1620  plotfilenameU = Concatenate(plot3d_file_1+"U", istep[0], file_name_digits);
1621  plotfilenameV = Concatenate(plot3d_file_1+"V", istep[0], file_name_digits);
1622  plotfilenameW = Concatenate(plot3d_file_1+"W", istep[0], file_name_digits);
1623  } else if (which == 2) {
1625  const std::string dt_format = "%Y-%m-%d_%H:%M:%S"; // ISO 8601 standard
1626  plotfilename = plot3d_file_2+"_"+getTimestamp(start_time+t_new[0], dt_format,false);
1627  } else {
1628  plotfilename = Concatenate(plot3d_file_2, istep[0], file_name_digits);
1629  }
1630  plotfilenameU = Concatenate(plot3d_file_2+"U", istep[0], file_name_digits);
1631  plotfilenameV = Concatenate(plot3d_file_2+"V", istep[0], file_name_digits);
1632  plotfilenameW = Concatenate(plot3d_file_2+"W", istep[0], file_name_digits);
1633  }
1634 
1635  // LSM writes it's own data
1636  if (which==1 && plot_lsm) {
1637  lsm.Plot_Lsm_Data(t_new[0], istep, refRatio());
1638  }
1639 
1640 #ifdef ERF_USE_RRTMGP
1641  /*
1642  // write additional RRTMGP data
1643  // TODO: currently single level only
1644  if (which==1 && plot_rad) {
1645  rad[0]->writePlotfile(plot_file_1, t_new[0], istep[0]);
1646  }
1647  */
1648 #endif
1649 
1650  // Single level
1651  if (finest_level == 0)
1652  {
1653  if (plotfile_type == PlotFileType::Amrex)
1654  {
1655  Print() << "Writing native 3D plotfile " << plotfilename << "\n";
1656  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
1657  WriteMultiLevelPlotfileWithTerrain(plotfilename, finest_level+1,
1658  GetVecOfConstPtrs(mf),
1659  GetVecOfConstPtrs(mf_nd),
1660  varnames,
1661  Geom(), t_new[0], istep, refRatio());
1662  } else {
1663  WriteMultiLevelPlotfile(plotfilename, finest_level+1,
1664  GetVecOfConstPtrs(mf),
1665  varnames,
1666  Geom(), t_new[0], istep, refRatio());
1667  }
1668  writeJobInfo(plotfilename);
1669 
1670  if (m_plot_face_vels) {
1671  Print() << "Writing face velocities" << std::endl;
1672  WriteMultiLevelPlotfile(plotfilenameU, finest_level+1,
1673  GetVecOfConstPtrs(mf_u),
1674  {"x_velocity_stag"},
1675  Geom(), t_new[0], istep, refRatio());
1676  WriteMultiLevelPlotfile(plotfilenameV, finest_level+1,
1677  GetVecOfConstPtrs(mf_v),
1678  {"y_velocity_stag"},
1679  Geom(), t_new[0], istep, refRatio());
1680  WriteMultiLevelPlotfile(plotfilenameW, finest_level+1,
1681  GetVecOfConstPtrs(mf_w),
1682  {"z_velocity_stag"},
1683  Geom(), t_new[0], istep, refRatio());
1684  }
1685 
1686 #ifdef ERF_USE_PARTICLES
1687  particleData.writePlotFile(plotfilename, z_phys_nd);
1688 #endif
1689 #ifdef ERF_USE_NETCDF
1690  } else if (plotfile_type == PlotFileType::Netcdf) {
1691  AMREX_ALWAYS_ASSERT(solverChoice.mesh_type != MeshType::VariableDz);
1692  int lev = 0;
1693  int l_which = 0;
1694  const Real* p_lo = geom[lev].ProbLo();
1695  const Real* p_hi = geom[lev].ProbHi();
1696  const auto dx = geom[lev].CellSize();
1697  writeNCPlotFile(lev, l_which, plotfilename, GetVecOfConstPtrs(mf), varnames, istep,
1698  {p_lo[0],p_lo[1],p_lo[2]},{p_hi[0],p_hi[1],p_hi[2]}, {dx[0],dx[1],dx[2]},
1699  geom[lev].Domain(), t_new[0], start_bdy_time, solverChoice, zlevels_stag[lev]);
1700 #endif
1701  } else {
1702  // Here we assume the plotfile_type is PlotFileType::None
1703  Print() << "Writing no 3D plotfile since plotfile_type is none" << std::endl;
1704  }
1705 
1706  } else { // Multilevel
1707 
1708  if (plotfile_type == PlotFileType::Amrex) {
1709 
1710  int lev0 = 0;
1711  int desired_ratio = std::max(std::max(ref_ratio[lev0][0],ref_ratio[lev0][1]),ref_ratio[lev0][2]);
1712  bool any_ratio_one = ( ( (ref_ratio[lev0][0] == 1) || (ref_ratio[lev0][1] == 1) ) ||
1713  (ref_ratio[lev0][2] == 1) );
1714  for (int lev = 1; lev < finest_level; lev++) {
1715  any_ratio_one = any_ratio_one ||
1716  ( ( (ref_ratio[lev][0] == 1) || (ref_ratio[lev][1] == 1) ) ||
1717  (ref_ratio[lev][2] == 1) );
1718  }
1719 
1720  if (any_ratio_one && m_expand_plotvars_to_unif_rr)
1721  {
1722  Vector<IntVect> r2(finest_level);
1723  Vector<Geometry> g2(finest_level+1);
1724  Vector<MultiFab> mf2(finest_level+1);
1725 
1726  mf2[0].define(grids[0], dmap[0], ncomp_mf, 0);
1727 
1728  // Copy level 0 as is
1729  MultiFab::Copy(mf2[0],mf[0],0,0,mf[0].nComp(),0);
1730 
1731  // Define a new multi-level array of Geometry's so that we pass the new "domain" at lev > 0
1732  Array<int,AMREX_SPACEDIM> periodicity =
1733  {Geom()[lev0].isPeriodic(0),Geom()[lev0].isPeriodic(1),Geom()[lev0].isPeriodic(2)};
1734  g2[lev0].define(Geom()[lev0].Domain(),&(Geom()[lev0].ProbDomain()),0,periodicity.data());
1735 
1736  r2[0] = IntVect(desired_ratio/ref_ratio[lev0][0],
1737  desired_ratio/ref_ratio[lev0][1],
1738  desired_ratio/ref_ratio[lev0][2]);
1739 
1740  for (int lev = 1; lev <= finest_level; ++lev) {
1741  if (lev > 1) {
1742  r2[lev-1][0] = r2[lev-2][0] * desired_ratio / ref_ratio[lev-1][0];
1743  r2[lev-1][1] = r2[lev-2][1] * desired_ratio / ref_ratio[lev-1][1];
1744  r2[lev-1][2] = r2[lev-2][2] * desired_ratio / ref_ratio[lev-1][2];
1745  }
1746 
1747  mf2[lev].define(refine(grids[lev],r2[lev-1]), dmap[lev], ncomp_mf, 0);
1748 
1749  // Set the new problem domain
1750  Box d2(Geom()[lev].Domain());
1751  d2.refine(r2[lev-1]);
1752 
1753  g2[lev].define(d2,&(Geom()[lev].ProbDomain()),0,periodicity.data());
1754  }
1755 
1756  //
1757  // We need to make a temporary that is the size of ncomp_mf
1758  // in order to not get an out of bounds error
1759  // even though the values will not be used
1760  //
1761  Vector<BCRec> temp_domain_bcs_type;
1762  temp_domain_bcs_type.resize(ncomp_mf);
1763 
1764  //
1765  // Do piecewise constant interpolation of mf into mf2
1766  //
1767  for (int lev = 1; lev <= finest_level; ++lev) {
1768  Interpolater* mapper_c = &pc_interp;
1769  InterpFromCoarseLevel(mf2[lev], t_new[lev], mf[lev],
1770  0, 0, ncomp_mf,
1771  geom[lev], g2[lev],
1773  r2[lev-1], mapper_c, temp_domain_bcs_type, 0);
1774  }
1775 
1776  // Define an effective ref_ratio which is isotropic to be passed into WriteMultiLevelPlotfile
1777  Vector<IntVect> rr(finest_level);
1778  for (int lev = 0; lev < finest_level; ++lev) {
1779  rr[lev] = IntVect(desired_ratio);
1780  }
1781 
1782  Print() << "Writing 3D plotfile " << plotfilename << "\n";
1783  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
1784  WriteMultiLevelPlotfileWithTerrain(plotfilename, finest_level+1,
1785  GetVecOfConstPtrs(mf2),
1786  GetVecOfConstPtrs(mf_nd),
1787  varnames,
1788  g2, t_new[0], istep, rr);
1789  } else {
1790  WriteMultiLevelPlotfile(plotfilename, finest_level+1,
1791  GetVecOfConstPtrs(mf2), varnames,
1792  g2, t_new[0], istep, rr);
1793  }
1794 
1795  } else {
1796  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
1797  WriteMultiLevelPlotfileWithTerrain(plotfilename, finest_level+1,
1798  GetVecOfConstPtrs(mf),
1799  GetVecOfConstPtrs(mf_nd),
1800  varnames,
1801  geom, t_new[0], istep, ref_ratio);
1802  } else {
1803  WriteMultiLevelPlotfile(plotfilename, finest_level+1,
1804  GetVecOfConstPtrs(mf), varnames,
1805  geom, t_new[0], istep, ref_ratio);
1806  }
1807  if (m_plot_face_vels) {
1808  Print() << "Writing face velocities" << std::endl;
1809  WriteMultiLevelPlotfile(plotfilenameU, finest_level+1,
1810  GetVecOfConstPtrs(mf_u),
1811  {"x_velocity_stag"},
1812  geom, t_new[0], istep, ref_ratio);
1813  WriteMultiLevelPlotfile(plotfilenameV, finest_level+1,
1814  GetVecOfConstPtrs(mf_v),
1815  {"y_velocity_stag"},
1816  geom, t_new[0], istep, ref_ratio);
1817  WriteMultiLevelPlotfile(plotfilenameW, finest_level+1,
1818  GetVecOfConstPtrs(mf_w),
1819  {"z_velocity_stag"},
1820  geom, t_new[0], istep, ref_ratio);
1821  }
1822  } // ref_ratio test
1823 
1824  writeJobInfo(plotfilename);
1825 
1826 #ifdef ERF_USE_PARTICLES
1827  particleData.writePlotFile(plotfilename, z_phys_nd);
1828 #endif
1829 
1830 #ifdef ERF_USE_NETCDF
1831  } else if (plotfile_type == PlotFileType::Netcdf) {
1832  AMREX_ALWAYS_ASSERT(solverChoice.mesh_type != MeshType::VariableDz);
1833  for (int lev = 0; lev <= finest_level; ++lev) {
1834  for (int which_box = 0; which_box < num_boxes_at_level[lev]; which_box++) {
1835  Box bounding_region = (lev == 0) ? geom[lev].Domain() : boxes_at_level[lev][which_box];
1836  const Real* p_lo = geom[lev].ProbLo();
1837  const Real* p_hi = geom[lev].ProbHi();
1838  const auto dx = geom[lev].CellSizeArray();
1839  writeNCPlotFile(lev, which_box, plotfilename, GetVecOfConstPtrs(mf), varnames, istep,
1840  {p_lo[0],p_lo[1],p_lo[2]},{p_hi[0],p_hi[1],p_hi[2]}, {dx[0],dx[1],dx[2]},
1841  bounding_region, t_new[0], start_bdy_time, solverChoice, zlevels_stag[lev]);
1842  }
1843  }
1844 #endif
1845  }
1846  } // end multi-level
1847 
1848  if (verbose > 0)
1849  {
1850  auto dPlotTime = amrex::second() - dPlotTime0;
1851  ParallelDescriptor::ReduceRealMax(dPlotTime,ParallelDescriptor::IOProcessorNumber());
1852  amrex::Print() << "3DPlotfile write time = " << dPlotTime << " seconds." << '\n';
1853  }
1854 }
constexpr amrex::Real PI
Definition: ERF_Constants.H:24
constexpr amrex::Real Cp_l
Definition: ERF_Constants.H:33
#define RhoQ4_comp
Definition: ERF_IndexDefines.H:45
#define RhoQ11_comp
Definition: ERF_IndexDefines.H:52
#define RhoQ9_comp
Definition: ERF_IndexDefines.H:50
#define RhoQ8_comp
Definition: ERF_IndexDefines.H:49
#define RhoQ7_comp
Definition: ERF_IndexDefines.H:48
#define RhoQ10_comp
Definition: ERF_IndexDefines.H:51
Real Ampl
Definition: ERF_InitCustomPert_MovingTerrain.H:4
Real H
Definition: ERF_InitCustomPert_MovingTerrain.H:7
Real wavelength
Definition: ERF_InitCustomPert_MovingTerrain.H:5
Real kp
Definition: ERF_InitCustomPert_MovingTerrain.H:8
void make_buoyancy(int lev, const Vector< MultiFab > &S_data, const MultiFab &S_prim, const MultiFab &qt, MultiFab &buoyancy, const Geometry geom, const SolverChoice &solverChoice, const MultiFab &base_state, const int n_qstate, const eb_ &ebfact, const int anelastic)
Definition: ERF_MakeBuoyancy.cpp:32
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void erf_qsatw(amrex::Real t, amrex::Real p, amrex::Real &qsatw)
Definition: ERF_MicrophysicsUtils.H:228
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_esatw(amrex::Real t, bool use_empirical=false)
Definition: ERF_MicrophysicsUtils.H:123
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_esatw_cc(amrex::Real t)
Definition: ERF_MicrophysicsUtils.H:62
static PhysBCFunctNoOp null_bc_for_fill
Definition: ERF_Plotfile.cpp:10
void FillBdyCCVels(amrex::MultiFab &mf_cc_vel, amrex::Geometry &lev_geom)
Definition: ERF_FillBdyCCVels.cpp:11
void WriteMultiLevelPlotfileWithTerrain(const std::string &plotfilename, int nlevels, const amrex::Vector< const amrex::MultiFab * > &mf, const amrex::Vector< const amrex::MultiFab * > &mf_nd, const amrex::Vector< std::string > &varnames, const amrex::Vector< amrex::Geometry > &my_geom, amrex::Real time, const amrex::Vector< int > &level_steps, const amrex::Vector< amrex::IntVect > &my_ref_ratio, const std::string &versionName="HyperCLaw-V1.1", const std::string &levelPrefix="Level_", const std::string &mfPrefix="Cell", const amrex::Vector< std::string > &extra_dirs=amrex::Vector< std::string >()) const
Definition: ERF_Plotfile.cpp:1857
void Plot_Lsm_Data(amrex::Real time, const amrex::Vector< int > &level_steps, const amrex::Vector< amrex::IntVect > &ref_ratio)
Definition: ERF_LandSurface.H:122
@ Turb_lengthscale
Definition: ERF_IndexDefines.H:214
@ Mom_h
Definition: ERF_IndexDefines.H:204
@ Theta_h
Definition: ERF_IndexDefines.H:205
@ P
Definition: ERF_IndexDefines.H:164
void erf_derKE(const Box &bx, FArrayBox &derfab, int, int, const FArrayBox &datfab, const FArrayBox &, const Geometry &, Real, const int *, const int)
Definition: ERF_Derive.cpp:342
void erf_dermoisttemp(const Box &bx, FArrayBox &derfab, int, int, const FArrayBox &datfab, const FArrayBox &, const Geometry &, Real, const int *, const int)
Definition: ERF_Derive.cpp:266
void erf_dertemp(const Box &bx, FArrayBox &derfab, int, int, const FArrayBox &datfab, const FArrayBox &, const Geometry &, Real, const int *, const int)
Definition: ERF_Derive.cpp:243
void erf_dersoundspeed(const Box &bx, FArrayBox &derfab, int, int, const FArrayBox &datfab, const FArrayBox &, const Geometry &, Real, const int *, const int)
Definition: ERF_Derive.cpp:209
void erf_derlocalhelicity(const Box &bx, FArrayBox &derfab, int dcomp, int, const FArrayBox &datfab, const FArrayBox &, const Geometry &geomdata, Real, const int *, const int)
Definition: ERF_Derive.cpp:614
void erf_dervorty(const Box &bx, FArrayBox &derfab, int dcomp, int ncomp, const FArrayBox &datfab, const FArrayBox &zcc_fab, const Geometry &geomdata, Real, const int *, const int)
Definition: ERF_Derive.cpp:386
void erf_dernull(const Box &, FArrayBox &, int, int, const FArrayBox &, const FArrayBox &, const Geometry &, Real, const int *, const int)
Definition: ERF_Derive.cpp:189
void erf_dermucape(const Box &bx, FArrayBox &derfab, int dcomp, int ncomp, const FArrayBox &datfab, const FArrayBox &zcc_fab, const Geometry &, Real, const int *, const int)
Definition: ERF_Derive.cpp:744
void erf_derreflectivity(const Box &bx, FArrayBox &derfab, int dcomp, int, const FArrayBox &datfab, const FArrayBox &, const Geometry &, Real, const int *, const int)
Definition: ERF_Derive.cpp:534
void erf_derprecipitable(const Box &bx, FArrayBox &derfab, int dcomp, int, const FArrayBox &datfab, const FArrayBox &zcc_fab, const Geometry &, Real, const int *, const int)
Definition: ERF_Derive.cpp:699
void erf_dervortx(const Box &bx, FArrayBox &derfab, int dcomp, int ncomp, const FArrayBox &datfab, const FArrayBox &zcc_fab, const Geometry &geomdata, Real, const int *, const int)
Definition: ERF_Derive.cpp:357
real(c_double), parameter g
Definition: ERF_module_model_constants.F90:19

Referenced by EvolveOneStep().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ write_1D_profiles()

void ERF::write_1D_profiles ( double  time)

Writes 1-dimensional averaged quantities as profiles to output log files at the given time.

Parameters
timeCurrent time
18 {
19  BL_PROFILE("ERF::write_1D_profiles()");
20 
21  if (NumDataLogs() > 1)
22  {
23  // Define the 1d arrays we will need
24  Gpu::HostVector<Real> h_avg_u, h_avg_v, h_avg_w;
25  Gpu::HostVector<Real> h_avg_rho, h_avg_th, h_avg_ksgs, h_avg_Kmv, h_avg_Khv;
26  Gpu::HostVector<Real> h_avg_qv, h_avg_qc, h_avg_qr, h_avg_wqv, h_avg_wqc, h_avg_wqr, h_avg_qi, h_avg_qs, h_avg_qg;
27  Gpu::HostVector<Real> h_avg_wthv;
28  Gpu::HostVector<Real> h_avg_uth, h_avg_vth, h_avg_wth, h_avg_thth;
29  Gpu::HostVector<Real> h_avg_uu, h_avg_uv, h_avg_uw, h_avg_vv, h_avg_vw, h_avg_ww;
30  Gpu::HostVector<Real> h_avg_uiuiu, h_avg_uiuiv, h_avg_uiuiw;
31  Gpu::HostVector<Real> h_avg_p, h_avg_pu, h_avg_pv, h_avg_pw;
32  Gpu::HostVector<Real> h_avg_tau11, h_avg_tau12, h_avg_tau13, h_avg_tau22, h_avg_tau23, h_avg_tau33;
33  Gpu::HostVector<Real> h_avg_sgshfx, h_avg_sgsq1fx, h_avg_sgsq2fx, h_avg_sgsdiss; // only output tau_{theta,w} and epsilon for now
34 
35  if (NumDataLogs() > 1) {
37  h_avg_u, h_avg_v, h_avg_w,
38  h_avg_rho, h_avg_th, h_avg_ksgs,
39  h_avg_Kmv, h_avg_Khv,
40  h_avg_qv, h_avg_qc, h_avg_qr,
41  h_avg_wqv, h_avg_wqc, h_avg_wqr,
42  h_avg_qi, h_avg_qs, h_avg_qg,
43  h_avg_uu, h_avg_uv, h_avg_uw, h_avg_vv, h_avg_vw, h_avg_ww,
44  h_avg_uth, h_avg_vth, h_avg_wth, h_avg_thth,
45  h_avg_uiuiu, h_avg_uiuiv, h_avg_uiuiw,
46  h_avg_p, h_avg_pu, h_avg_pv, h_avg_pw,
47  h_avg_wthv);
48  }
49 
50  if (NumDataLogs() > 3 && time > zero) {
51  derive_stress_profiles(h_avg_tau11, h_avg_tau12, h_avg_tau13,
52  h_avg_tau22, h_avg_tau23, h_avg_tau33,
53  h_avg_sgshfx, h_avg_sgsq1fx, h_avg_sgsq2fx,
54  h_avg_sgsdiss);
55  }
56 
57  int hu_size = h_avg_u.size();
58 
59  auto const& dx = geom[0].CellSizeArray();
60  if (ParallelDescriptor::IOProcessor()) {
61  if (NumDataLogs() > 1) {
62  std::ostream& data_log1 = DataLog(1);
63  if (data_log1.good()) {
64  // Write the quantities at this time
65  for (int k = 0; k < hu_size; k++) {
66  Real z;
67  if (zlevels_stag[0].size() > 1) {
68  z = myhalf * (zlevels_stag[0][k] + zlevels_stag[0][k+1]);
69  } else {
70  z = (k + myhalf)* dx[2];
71  }
72  data_log1 << std::setw(datwidth) << std::setprecision(timeprecision) << time << " "
73  << std::setw(datwidth) << std::setprecision(datprecision) << z << " "
74  << h_avg_u[k] << " " << h_avg_v[k] << " " << h_avg_w[k] << " "
75  << h_avg_rho[k] << " " << h_avg_th[k] << " " << h_avg_ksgs[k] << " "
76  << h_avg_Kmv[k] << " " << h_avg_Khv[k] << " "
77  << h_avg_qv[k] << " " << h_avg_qc[k] << " " << h_avg_qr[k] << " "
78  << h_avg_qi[k] << " " << h_avg_qs[k] << " " << h_avg_qg[k]
79  << std::endl;
80  } // loop over z
81  } // if good
82  } // NumDataLogs
83 
84  if (NumDataLogs() > 2) {
85  std::ostream& data_log2 = DataLog(2);
86  if (data_log2.good()) {
87  // Write the perturbational quantities at this time
88  for (int k = 0; k < hu_size; k++) {
89  Real z;
90  if (zlevels_stag[0].size() > 1) {
91  z = myhalf * (zlevels_stag[0][k] + zlevels_stag[0][k+1]);
92  } else {
93  z = (k + myhalf)* dx[2];
94  }
95  Real thv = h_avg_th[k] * (1 + Real(0.61)*h_avg_qv[k] - h_avg_qc[k] - h_avg_qr[k]);
96  data_log2 << std::setw(datwidth) << std::setprecision(timeprecision) << time << " "
97  << std::setw(datwidth) << std::setprecision(datprecision) << z << " "
98  << h_avg_uu[k] - h_avg_u[k]*h_avg_u[k] << " "
99  << h_avg_uv[k] - h_avg_u[k]*h_avg_v[k] << " "
100  << h_avg_uw[k] - h_avg_u[k]*h_avg_w[k] << " "
101  << h_avg_vv[k] - h_avg_v[k]*h_avg_v[k] << " "
102  << h_avg_vw[k] - h_avg_v[k]*h_avg_w[k] << " "
103  << h_avg_ww[k] - h_avg_w[k]*h_avg_w[k] << " "
104  << h_avg_uth[k] - h_avg_u[k]*h_avg_th[k] << " "
105  << h_avg_vth[k] - h_avg_v[k]*h_avg_th[k] << " "
106  << h_avg_wth[k] - h_avg_w[k]*h_avg_th[k] << " "
107  << h_avg_thth[k] - h_avg_th[k]*h_avg_th[k] << " "
108  // Note: <u'_i u'_i u'_j> = <u_i u_i u_j>
109  // - <u_i u_i> * <u_j>
110  // - 2*<u_i> * <u_i u_j>
111  // + 2*<u_i>*<u_i> * <u_j>
112  << h_avg_uiuiu[k]
113  - (h_avg_uu[k] + h_avg_vv[k] + h_avg_ww[k])*h_avg_u[k]
114  - 2*(h_avg_u[k]*h_avg_uu[k] + h_avg_v[k]*h_avg_uv[k] + h_avg_w[k]*h_avg_uw[k])
115  + 2*(h_avg_u[k]*h_avg_u[k] + h_avg_v[k]*h_avg_v[k] + h_avg_w[k]*h_avg_w[k])*h_avg_u[k]
116  << " " // (u'_i u'_i)u'
117  << h_avg_uiuiv[k]
118  - (h_avg_uu[k] + h_avg_vv[k] + h_avg_ww[k])*h_avg_v[k]
119  - 2*(h_avg_u[k]*h_avg_uv[k] + h_avg_v[k]*h_avg_vv[k] + h_avg_w[k]*h_avg_vw[k])
120  + 2*(h_avg_u[k]*h_avg_u[k] + h_avg_v[k]*h_avg_v[k] + h_avg_w[k]*h_avg_w[k])*h_avg_v[k]
121  << " " // (u'_i u'_i)v'
122  << h_avg_uiuiw[k]
123  - (h_avg_uu[k] + h_avg_vv[k] + h_avg_ww[k])*h_avg_w[k]
124  - 2*(h_avg_u[k]*h_avg_uw[k] + h_avg_v[k]*h_avg_vw[k] + h_avg_w[k]*h_avg_ww[k])
125  + 2*(h_avg_u[k]*h_avg_u[k] + h_avg_v[k]*h_avg_v[k] + h_avg_w[k]*h_avg_w[k])*h_avg_w[k]
126  << " " // (u'_i u'_i)w'
127  << h_avg_pu[k] - h_avg_p[k]*h_avg_u[k] << " "
128  << h_avg_pv[k] - h_avg_p[k]*h_avg_v[k] << " "
129  << h_avg_pw[k] - h_avg_p[k]*h_avg_w[k] << " "
130  << h_avg_wqv[k] - h_avg_qv[k]*h_avg_w[k] << " "
131  << h_avg_wqc[k] - h_avg_qc[k]*h_avg_w[k] << " "
132  << h_avg_wqr[k] - h_avg_qr[k]*h_avg_w[k] << " "
133  << h_avg_wthv[k] - h_avg_w[k]*thv
134  << std::endl;
135  } // loop over z
136  } // if good
137  } // NumDataLogs
138 
139  if (NumDataLogs() > 3 && time > zero) {
140  std::ostream& data_log3 = DataLog(3);
141  if (data_log3.good()) {
142  // Write the average stresses
143  for (int k = 0; k < hu_size; k++) {
144  Real z;
145  if (zlevels_stag[0].size() > 1) {
146  z = myhalf * (zlevels_stag[0][k] + zlevels_stag[0][k+1]);
147  } else {
148  z = (k + myhalf)* dx[2];
149  }
150  data_log3 << std::setw(datwidth) << std::setprecision(timeprecision) << time << " "
151  << std::setw(datwidth) << std::setprecision(datprecision) << z << " "
152  << h_avg_tau11[k] << " " << h_avg_tau12[k] << " " << h_avg_tau13[k] << " "
153  << h_avg_tau22[k] << " " << h_avg_tau23[k] << " " << h_avg_tau33[k] << " "
154  << h_avg_sgshfx[k] << " "
155  << h_avg_sgsq1fx[k] << " " << h_avg_sgsq2fx[k] << " "
156  << h_avg_sgsdiss[k]
157  << std::endl;
158  } // loop over z
159  } // if good
160  } // if (NumDataLogs() > 3)
161  } // if IOProcessor
162  } // if (NumDataLogs() > 1)
163 }
void derive_diag_profiles(double time, amrex::Gpu::HostVector< amrex::Real > &h_avg_u, amrex::Gpu::HostVector< amrex::Real > &h_avg_v, amrex::Gpu::HostVector< amrex::Real > &h_avg_w, amrex::Gpu::HostVector< amrex::Real > &h_avg_rho, amrex::Gpu::HostVector< amrex::Real > &h_avg_th, amrex::Gpu::HostVector< amrex::Real > &h_avg_ksgs, amrex::Gpu::HostVector< amrex::Real > &h_avg_Kmv, amrex::Gpu::HostVector< amrex::Real > &h_avg_Khv, amrex::Gpu::HostVector< amrex::Real > &h_avg_qv, amrex::Gpu::HostVector< amrex::Real > &h_avg_qc, amrex::Gpu::HostVector< amrex::Real > &h_avg_qr, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqv, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqc, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqr, amrex::Gpu::HostVector< amrex::Real > &h_avg_qi, amrex::Gpu::HostVector< amrex::Real > &h_avg_qs, amrex::Gpu::HostVector< amrex::Real > &h_avg_qg, amrex::Gpu::HostVector< amrex::Real > &h_avg_uu, amrex::Gpu::HostVector< amrex::Real > &h_avg_uv, amrex::Gpu::HostVector< amrex::Real > &h_avg_uw, amrex::Gpu::HostVector< amrex::Real > &h_avg_vv, amrex::Gpu::HostVector< amrex::Real > &h_avg_vw, amrex::Gpu::HostVector< amrex::Real > &h_avg_ww, amrex::Gpu::HostVector< amrex::Real > &h_avg_uth, amrex::Gpu::HostVector< amrex::Real > &h_avg_vth, amrex::Gpu::HostVector< amrex::Real > &h_avg_wth, amrex::Gpu::HostVector< amrex::Real > &h_avg_thth, amrex::Gpu::HostVector< amrex::Real > &h_avg_ku, amrex::Gpu::HostVector< amrex::Real > &h_avg_kv, amrex::Gpu::HostVector< amrex::Real > &h_avg_kw, amrex::Gpu::HostVector< amrex::Real > &h_avg_p, amrex::Gpu::HostVector< amrex::Real > &h_avg_pu, amrex::Gpu::HostVector< amrex::Real > &h_avg_pv, amrex::Gpu::HostVector< amrex::Real > &h_avg_pw, amrex::Gpu::HostVector< amrex::Real > &h_avg_wthv)
Definition: ERF_Write1DProfiles.cpp:190
void derive_stress_profiles(amrex::Gpu::HostVector< amrex::Real > &h_avg_tau11, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau12, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau13, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau22, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau23, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau33, amrex::Gpu::HostVector< amrex::Real > &h_avg_hfx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_q1fx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_q2fx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_diss)
Definition: ERF_Write1DProfiles.cpp:475

◆ write_1D_profiles_stag()

void ERF::write_1D_profiles_stag ( double  time)

Writes 1-dimensional averaged quantities as profiles to output log files at the given time.

Quantities are output at their native grid locations. Therefore, w and associated flux quantities <(•)'w'>, tau13, and tau23 (where '•' includes u, v, p, theta, ...) will be output at staggered heights (i.e., coincident with z faces) rather than cell-center heights to avoid performing additional averaging. Unstaggered (i.e., cell-centered) quantities are output alongside staggered quantities at the lower cell faces in the log file; these quantities will have a zero value at the big end, corresponding to k=Nz+one

The structure of file should follow ERF_Write1DProfiles.cpp

Parameters
timeCurrent time
26 {
27  BL_PROFILE("ERF::write_1D_profiles()");
28 
29  if (NumDataLogs() > 1)
30  {
31  // Define the 1d arrays we will need
32  Gpu::HostVector<Real> h_avg_u, h_avg_v, h_avg_w;
33  Gpu::HostVector<Real> h_avg_rho, h_avg_th, h_avg_ksgs, h_avg_Kmv, h_avg_Khv;
34  Gpu::HostVector<Real> h_avg_qv, h_avg_qc, h_avg_qr, h_avg_wqv, h_avg_wqc, h_avg_wqr, h_avg_qi, h_avg_qs, h_avg_qg;
35  Gpu::HostVector<Real> h_avg_wthv;
36  Gpu::HostVector<Real> h_avg_uth, h_avg_vth, h_avg_wth, h_avg_thth;
37  Gpu::HostVector<Real> h_avg_uu, h_avg_uv, h_avg_uw, h_avg_vv, h_avg_vw, h_avg_ww;
38  Gpu::HostVector<Real> h_avg_uiuiu, h_avg_uiuiv, h_avg_uiuiw;
39  Gpu::HostVector<Real> h_avg_p, h_avg_pu, h_avg_pv, h_avg_pw;
40  Gpu::HostVector<Real> h_avg_tau11, h_avg_tau12, h_avg_tau13, h_avg_tau22, h_avg_tau23, h_avg_tau33;
41  Gpu::HostVector<Real> h_avg_sgshfx, h_avg_sgsq1fx, h_avg_sgsq2fx, h_avg_sgsdiss; // only output tau_{theta,w} and epsilon for now
42 
43  if (NumDataLogs() > 1) {
45  h_avg_u, h_avg_v, h_avg_w,
46  h_avg_rho, h_avg_th, h_avg_ksgs,
47  h_avg_Kmv, h_avg_Khv,
48  h_avg_qv, h_avg_qc, h_avg_qr,
49  h_avg_wqv, h_avg_wqc, h_avg_wqr,
50  h_avg_qi, h_avg_qs, h_avg_qg,
51  h_avg_uu, h_avg_uv, h_avg_uw, h_avg_vv, h_avg_vw, h_avg_ww,
52  h_avg_uth, h_avg_vth, h_avg_wth, h_avg_thth,
53  h_avg_uiuiu, h_avg_uiuiv, h_avg_uiuiw,
54  h_avg_p, h_avg_pu, h_avg_pv, h_avg_pw,
55  h_avg_wthv);
56  }
57 
58  if (NumDataLogs() > 3 && time > zero) {
59  derive_stress_profiles_stag(h_avg_tau11, h_avg_tau12, h_avg_tau13,
60  h_avg_tau22, h_avg_tau23, h_avg_tau33,
61  h_avg_sgshfx, h_avg_sgsq1fx, h_avg_sgsq2fx,
62  h_avg_sgsdiss);
63  }
64 
65  int unstag_size = h_avg_w.size() - 1; // _un_staggered heights
66 
67  auto const& dx = geom[0].CellSizeArray();
68  if (ParallelDescriptor::IOProcessor()) {
69  if (NumDataLogs() > 1) {
70  std::ostream& data_log1 = DataLog(1);
71  if (data_log1.good()) {
72  // Write the quantities at this time
73  for (int k = 0; k < unstag_size; k++) {
74  Real z = (zlevels_stag[0].size() > 1) ? zlevels_stag[0][k] : k * dx[2];
75  data_log1 << std::setw(datwidth) << std::setprecision(timeprecision) << time << " "
76  << std::setw(datwidth) << std::setprecision(datprecision) << z << " "
77  << h_avg_u[k] << " " << h_avg_v[k] << " " << h_avg_w[k] << " "
78  << h_avg_rho[k] << " " << h_avg_th[k] << " " << h_avg_ksgs[k] << " "
79  << h_avg_Kmv[k] << " " << h_avg_Khv[k] << " "
80  << h_avg_qv[k] << " " << h_avg_qc[k] << " " << h_avg_qr[k] << " "
81  << h_avg_qi[k] << " " << h_avg_qs[k] << " " << h_avg_qg[k]
82  << std::endl;
83  } // loop over z
84  // Write top face values
85  Real z = (zlevels_stag[0].size() > 1) ? zlevels_stag[0][unstag_size] : unstag_size * dx[2];
86  data_log1 << std::setw(datwidth) << std::setprecision(timeprecision) << time << " "
87  << std::setw(datwidth) << std::setprecision(datprecision) << z << " "
88  << 0 << " " << 0 << " " << h_avg_w[unstag_size] << " "
89  << 0 << " " << 0 << " " << 0 << " " // rho, theta, ksgs
90  << 0 << " " << 0 << " " // Kmv, Khv
91  << 0 << " " << 0 << " " << 0 << " " // qv, qc, qr
92  << 0 << " " << 0 << " " << 0 // qi, qs, qg
93  << std::endl;
94  } // if good
95  } // NumDataLogs
96 
97  if (NumDataLogs() > 2) {
98  std::ostream& data_log2 = DataLog(2);
99  if (data_log2.good()) {
100  // Write the perturbational quantities at this time
101  // For surface values (k=0), assume w = uw = vw = ww = 0
102  Real w_cc = h_avg_w[1] / 2; // w at first cell center
103  Real uw_cc = h_avg_uw[1] / 2; // u*w at first cell center
104  Real vw_cc = h_avg_vw[1] / 2; // v*w at first cell center
105  Real ww_cc = h_avg_ww[1] / 2; // w*w at first cell center
106  data_log2 << std::setw(datwidth) << std::setprecision(timeprecision) << time << " "
107  << std::setw(datwidth) << std::setprecision(datprecision) << 0 << " "
108  << h_avg_uu[0] - h_avg_u[0]*h_avg_u[0] << " " // u'u'
109  << h_avg_uv[0] - h_avg_u[0]*h_avg_v[0] << " " // u'v'
110  << 0 << " " // u'w'
111  << h_avg_vv[0] - h_avg_v[0]*h_avg_v[0] << " " // v'v'
112  << 0 << " " // v'w'
113  << 0 << " " // w'w'
114  << h_avg_uth[0] - h_avg_u[0]*h_avg_th[0] << " " // u'th'
115  << h_avg_vth[0] - h_avg_v[0]*h_avg_th[0] << " " // v'th'
116  << 0 << " " // w'th'
117  << h_avg_thth[0] - h_avg_th[0]*h_avg_th[0] << " " // th'th'
118  << h_avg_uiuiu[0]
119  - (h_avg_uu[0] + h_avg_vv[0] + ww_cc)*h_avg_u[0]
120  - 2*(h_avg_u[0]*h_avg_uu[0] + h_avg_v[0]*h_avg_uv[0] + w_cc*uw_cc)
121  + 2*(h_avg_u[0]*h_avg_u[0] + h_avg_v[0]*h_avg_v[0] + w_cc*w_cc)*h_avg_u[0]
122  << " " // (u'_i u'_i)u'
123  << h_avg_uiuiv[0]
124  - (h_avg_uu[0] + h_avg_vv[0] + ww_cc)*h_avg_v[0]
125  - 2*(h_avg_u[0]*h_avg_uv[0] + h_avg_v[0]*h_avg_vv[0] + w_cc*vw_cc)
126  + 2*(h_avg_u[0]*h_avg_u[0] + h_avg_v[0]*h_avg_v[0] + w_cc*w_cc)*h_avg_v[0]
127  << " " // (u'_i u'_i)v'
128  << 0 << " " // (u'_i u'_i)w'
129  << h_avg_pu[0] - h_avg_p[0]*h_avg_u[0] << " " // p'u'
130  << h_avg_pv[0] - h_avg_p[0]*h_avg_v[0] << " " // p'v'
131  << 0 << " " // p'w'
132  << 0 << " " // qv'w'
133  << 0 << " " // qc'w'
134  << 0 << " " // qr'w'
135  << 0 // thv'w'
136  << std::endl;
137 
138  // For internal values, interpolate scalar quantities to faces
139  for (int k = 1; k < unstag_size; k++) {
140  Real z = (zlevels_stag[0].size() > 1) ? zlevels_stag[0][k] : k * dx[2];
141  Real uface = myhalf*(h_avg_u[k] + h_avg_u[k-1]);
142  Real vface = myhalf*(h_avg_v[k] + h_avg_v[k-1]);
143  Real thface = myhalf*(h_avg_th[k] + h_avg_th[k-1]);
144  Real pface = myhalf*(h_avg_p[k] + h_avg_p[k-1]);
145  Real qvface = myhalf*(h_avg_qv[k] + h_avg_qv[k-1]);
146  Real qcface = myhalf*(h_avg_qc[k] + h_avg_qc[k-1]);
147  Real qrface = myhalf*(h_avg_qr[k] + h_avg_qr[k-1]);
148  Real uuface = myhalf*(h_avg_uu[k] + h_avg_uu[k-1]);
149  Real vvface = myhalf*(h_avg_vv[k] + h_avg_vv[k-1]);
150  Real thvface = thface * (1 + Real(0.61)*qvface - qcface - qrface);
151  w_cc = myhalf*(h_avg_w[k-1] + h_avg_w[k]);
152  uw_cc = myhalf*(h_avg_uw[k-1] + h_avg_uw[k]);
153  vw_cc = myhalf*(h_avg_vw[k-1] + h_avg_vw[k]);
154  ww_cc = myhalf*(h_avg_ww[k-1] + h_avg_ww[k]);
155  data_log2 << std::setw(datwidth) << std::setprecision(timeprecision) << time << " "
156  << std::setw(datwidth) << std::setprecision(datprecision) << z << " "
157  << h_avg_uu[k] - h_avg_u[k]*h_avg_u[k] << " " // u'u'
158  << h_avg_uv[k] - h_avg_u[k]*h_avg_v[k] << " " // u'v'
159  << h_avg_uw[k] - uface*h_avg_w[k] << " " // u'w'
160  << h_avg_vv[k] - h_avg_v[k]*h_avg_v[k] << " " // v'v'
161  << h_avg_vw[k] - vface*h_avg_w[k] << " " // v'w'
162  << h_avg_ww[k] - h_avg_w[k]*h_avg_w[k] << " " // w'w'
163  << h_avg_uth[k] - h_avg_u[k]*h_avg_th[k] << " " // u'th'
164  << h_avg_vth[k] - h_avg_v[k]*h_avg_th[k] << " " // v'th'
165  << h_avg_wth[k] - h_avg_w[k]*thface << " " // w'th'
166  << h_avg_thth[k] - h_avg_th[k]*h_avg_th[k] << " " // th'th'
167  // Note: <u'_i u'_i u'_j> = <u_i u_i u_j>
168  // - <u_i u_i> * <u_j>
169  // - 2*<u_i> * <u_i u_j>
170  // + 2*<u_i>*<u_i> * <u_j>
171  << h_avg_uiuiu[k]
172  - (h_avg_uu[k] + h_avg_vv[k] + ww_cc)*h_avg_u[k]
173  - 2*(h_avg_u[k]*h_avg_uu[k] + h_avg_v[k]*h_avg_uv[k] + w_cc*uw_cc)
174  + 2*(h_avg_u[k]*h_avg_u[k] + h_avg_v[k]*h_avg_v[k] + w_cc*w_cc)*h_avg_u[k]
175  << " " // cell-centered (u'_i u'_i)u'
176  << h_avg_uiuiv[k]
177  - (h_avg_uu[k] + h_avg_vv[k] + ww_cc)*h_avg_v[k]
178  - 2*(h_avg_u[k]*h_avg_uv[k] + h_avg_v[k]*h_avg_vv[k] + w_cc*vw_cc)
179  + 2*(h_avg_u[k]*h_avg_u[k] + h_avg_v[k]*h_avg_v[k] + w_cc*w_cc)*h_avg_v[k]
180  << " " // cell-centered (u'_i u'_i)v'
181  << h_avg_uiuiw[k]
182  - (uuface + vvface + h_avg_ww[k])*h_avg_w[k]
183  - 2*(uface*h_avg_uw[k] + vface*h_avg_vw[k] + h_avg_w[k]*h_avg_ww[k])
184  + 2*(uface*uface + vface*vface + h_avg_w[k]*h_avg_w[k])*h_avg_w[k]
185  << " " // face-centered (u'_i u'_i)w'
186  << h_avg_pu[k] - h_avg_p[k]*h_avg_u[k] << " " // cell-centered p'u'
187  << h_avg_pv[k] - h_avg_p[k]*h_avg_v[k] << " " // cell-centered p'v'
188  << h_avg_pw[k] - pface*h_avg_w[k] << " " // face-centered p'w'
189  << h_avg_wqv[k] - qvface*h_avg_w[k] << " "
190  << h_avg_wqc[k] - qcface*h_avg_w[k] << " "
191  << h_avg_wqr[k] - qrface*h_avg_w[k] << " "
192  << h_avg_wthv[k] - thvface*h_avg_w[k]
193  << std::endl;
194  } // loop over z
195 
196  // Write top face values, extrapolating scalar quantities
197  const int k = unstag_size;
198  Real uface = Real(1.5)*h_avg_u[k-1] - myhalf*h_avg_u[k-2];
199  Real vface = Real(1.5)*h_avg_v[k-1] - myhalf*h_avg_v[k-2];
200  Real thface = Real(1.5)*h_avg_th[k-1] - myhalf*h_avg_th[k-2];
201  Real pface = Real(1.5)*h_avg_p[k-1] - myhalf*h_avg_p[k-2];
202  Real qvface = Real(1.5)*h_avg_qv[k-1] - myhalf*h_avg_qv[k-2];
203  Real qcface = Real(1.5)*h_avg_qc[k-1] - myhalf*h_avg_qc[k-2];
204  Real qrface = Real(1.5)*h_avg_qr[k-1] - myhalf*h_avg_qr[k-2];
205  Real uuface = Real(1.5)*h_avg_uu[k-1] - myhalf*h_avg_uu[k-2];
206  Real vvface = Real(1.5)*h_avg_vv[k-1] - myhalf*h_avg_vv[k-2];
207  Real thvface = thface * (1 + Real(0.61)*qvface - qcface - qrface);
208  Real z = (zlevels_stag[0].size() > 1) ? zlevels_stag[0][unstag_size] : unstag_size * dx[2];
209  data_log2 << std::setw(datwidth) << std::setprecision(timeprecision) << time << " "
210  << std::setw(datwidth) << std::setprecision(datprecision) << z << " "
211  << 0 << " " // u'u'
212  << 0 << " " // u'v'
213  << h_avg_uw[k] - uface*h_avg_w[k] << " " // u'w'
214  << 0 << " " // v'v'
215  << h_avg_vw[k] - vface*h_avg_w[k] << " " // v'w'
216  << h_avg_ww[k] - h_avg_w[k]*h_avg_w[k] << " " // w'w'
217  << 0 << " " // u'th'
218  << 0 << " " // v'th'
219  << h_avg_wth[k] - thface*h_avg_w[k] << " " // w'th'
220  << 0 << " " // th'th'
221  << 0 << " " // (u'_i u'_i)u'
222  << 0 << " " // (u'_i u'_i)v'
223  << h_avg_uiuiw[k]
224  - (uuface + vvface + h_avg_ww[k])*h_avg_w[k]
225  - 2*(uface*h_avg_uw[k] + vface*h_avg_vw[k] + h_avg_w[k]*h_avg_ww[k])
226  + 2*(uface*uface + vface*vface + h_avg_w[k]*h_avg_w[k])*h_avg_w[k]
227  << " " // (u'_i u'_i)w'
228  << 0 << " " // pu'
229  << 0 << " " // pv'
230  << h_avg_pw[k] - pface*h_avg_w[k] << " " // pw'
231  << h_avg_wqv[k] - qvface*h_avg_w[k] << " "
232  << h_avg_wqc[k] - qcface*h_avg_w[k] << " "
233  << h_avg_wqr[k] - qrface*h_avg_w[k] << " "
234  << h_avg_wthv[k] - thvface*h_avg_w[k]
235  << std::endl;
236  } // if good
237  } // NumDataLogs
238 
239  if (NumDataLogs() > 3 && time > zero) {
240  std::ostream& data_log3 = DataLog(3);
241  if (data_log3.good()) {
242  // Write the average stresses
243  for (int k = 0; k < unstag_size; k++) {
244  Real z = (zlevels_stag[0].size() > 1) ? zlevels_stag[0][k] : k * dx[2];
245  data_log3 << std::setw(datwidth) << std::setprecision(timeprecision) << time << " "
246  << std::setw(datwidth) << std::setprecision(datprecision) << z << " "
247  << h_avg_tau11[k] << " " << h_avg_tau12[k] << " " << h_avg_tau13[k] << " "
248  << h_avg_tau22[k] << " " << h_avg_tau23[k] << " " << h_avg_tau33[k] << " "
249  << h_avg_sgshfx[k] << " "
250  << h_avg_sgsq1fx[k] << " " << h_avg_sgsq2fx[k] << " "
251  << h_avg_sgsdiss[k]
252  << std::endl;
253  } // loop over z
254  // Write top face values
255  Real NANval = zero;
256  Real z = (zlevels_stag[0].size() > 1) ? zlevels_stag[0][unstag_size] : unstag_size * dx[2];
257  data_log3 << std::setw(datwidth) << std::setprecision(timeprecision) << time << " "
258  << std::setw(datwidth) << std::setprecision(datprecision) << z << " "
259  << NANval << " " << NANval << " " << h_avg_tau13[unstag_size] << " "
260  << NANval << " " << h_avg_tau23[unstag_size] << " " << NANval << " "
261  << h_avg_sgshfx[unstag_size] << " "
262  << h_avg_sgsq1fx[unstag_size] << " " << h_avg_sgsq2fx[unstag_size] << " "
263  << NANval
264  << std::endl;
265  } // if good
266  } // if (NumDataLogs() > 3)
267  } // if IOProcessor
268  } // if (NumDataLogs() > 1)
269 }
void derive_diag_profiles_stag(double time, amrex::Gpu::HostVector< amrex::Real > &h_avg_u, amrex::Gpu::HostVector< amrex::Real > &h_avg_v, amrex::Gpu::HostVector< amrex::Real > &h_avg_w, amrex::Gpu::HostVector< amrex::Real > &h_avg_rho, amrex::Gpu::HostVector< amrex::Real > &h_avg_th, amrex::Gpu::HostVector< amrex::Real > &h_avg_ksgs, amrex::Gpu::HostVector< amrex::Real > &h_avg_Kmv, amrex::Gpu::HostVector< amrex::Real > &h_avg_Khv, amrex::Gpu::HostVector< amrex::Real > &h_avg_qv, amrex::Gpu::HostVector< amrex::Real > &h_avg_qc, amrex::Gpu::HostVector< amrex::Real > &h_avg_qr, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqv, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqc, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqr, amrex::Gpu::HostVector< amrex::Real > &h_avg_qi, amrex::Gpu::HostVector< amrex::Real > &h_avg_qs, amrex::Gpu::HostVector< amrex::Real > &h_avg_qg, amrex::Gpu::HostVector< amrex::Real > &h_avg_uu, amrex::Gpu::HostVector< amrex::Real > &h_avg_uv, amrex::Gpu::HostVector< amrex::Real > &h_avg_uw, amrex::Gpu::HostVector< amrex::Real > &h_avg_vv, amrex::Gpu::HostVector< amrex::Real > &h_avg_vw, amrex::Gpu::HostVector< amrex::Real > &h_avg_ww, amrex::Gpu::HostVector< amrex::Real > &h_avg_uth, amrex::Gpu::HostVector< amrex::Real > &h_avg_vth, amrex::Gpu::HostVector< amrex::Real > &h_avg_wth, amrex::Gpu::HostVector< amrex::Real > &h_avg_thth, amrex::Gpu::HostVector< amrex::Real > &h_avg_ku, amrex::Gpu::HostVector< amrex::Real > &h_avg_kv, amrex::Gpu::HostVector< amrex::Real > &h_avg_kw, amrex::Gpu::HostVector< amrex::Real > &h_avg_p, amrex::Gpu::HostVector< amrex::Real > &h_avg_pu, amrex::Gpu::HostVector< amrex::Real > &h_avg_pv, amrex::Gpu::HostVector< amrex::Real > &h_avg_pw, amrex::Gpu::HostVector< amrex::Real > &h_avg_wthv)
Definition: ERF_Write1DProfiles_stag.cpp:296
void derive_stress_profiles_stag(amrex::Gpu::HostVector< amrex::Real > &h_avg_tau11, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau12, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau13, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau22, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau23, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau33, amrex::Gpu::HostVector< amrex::Real > &h_avg_hfx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_q1fx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_q2fx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_diss)
Definition: ERF_Write1DProfiles_stag.cpp:605

◆ writeBuildInfo()

void ERF::writeBuildInfo ( std::ostream &  os)
static
144 {
145  std::string PrettyLine = std::string(78, '=') + "\n";
146  std::string OtherLine = std::string(78, '-') + "\n";
147  std::string SkipSpace = std::string(8, ' ');
148 
149  // build information
150  os << PrettyLine;
151  os << " ERF Build Information\n";
152  os << PrettyLine;
153 
154  os << "build date: " << buildInfoGetBuildDate() << "\n";
155  os << "build machine: " << buildInfoGetBuildMachine() << "\n";
156  os << "build dir: " << buildInfoGetBuildDir() << "\n";
157  os << "AMReX dir: " << buildInfoGetAMReXDir() << "\n";
158 
159  os << "\n";
160 
161  os << "COMP: " << buildInfoGetComp() << "\n";
162  os << "COMP version: " << buildInfoGetCompVersion() << "\n";
163 
164  os << "C++ compiler: " << buildInfoGetCXXName() << "\n";
165  os << "C++ flags: " << buildInfoGetCXXFlags() << "\n";
166 
167  os << "\n";
168 
169  os << "Link flags: " << buildInfoGetLinkFlags() << "\n";
170  os << "Libraries: " << buildInfoGetLibraries() << "\n";
171 
172  os << "\n";
173 
174  for (int n = 1; n <= buildInfoGetNumModules(); n++) {
175  os << buildInfoGetModuleName(n) << ": "
176  << buildInfoGetModuleVal(n) << "\n";
177  }
178 
179  os << "\n";
180  const char* githash1 = buildInfoGetGitHash(1);
181  const char* githash2 = buildInfoGetGitHash(2);
182  if (strlen(githash1) > 0) {
183  os << "ERF git hash: " << githash1 << "\n";
184  }
185  if (strlen(githash2) > 0) {
186  os << "AMReX git hash: " << githash2 << "\n";
187  }
188 
189  const char* buildgithash = buildInfoGetBuildGitHash();
190  const char* buildgitname = buildInfoGetBuildGitName();
191  if (strlen(buildgithash) > 0) {
192  os << buildgitname << " git hash: " << buildgithash << "\n";
193  }
194 
195  os << "\n";
196  os << " ERF Compile time variables: \n";
197 
198  os << "\n";
199  os << " ERF Defines: \n";
200 #ifdef _OPENMP
201  os << std::setw(35) << std::left << "_OPENMP " << std::setw(6) << "ON"
202  << std::endl;
203 #else
204  os << std::setw(35) << std::left << "_OPENMP " << std::setw(6) << "OFF"
205  << std::endl;
206 #endif
207 
208 #ifdef MPI_VERSION
209  os << std::setw(35) << std::left << "MPI_VERSION " << std::setw(6)
210  << MPI_VERSION << std::endl;
211 #else
212  os << std::setw(35) << std::left << "MPI_VERSION " << std::setw(6)
213  << "UNDEFINED" << std::endl;
214 #endif
215 
216 #ifdef MPI_SUBVERSION
217  os << std::setw(35) << std::left << "MPI_SUBVERSION " << std::setw(6)
218  << MPI_SUBVERSION << std::endl;
219 #else
220  os << std::setw(35) << std::left << "MPI_SUBVERSION " << std::setw(6)
221  << "UNDEFINED" << std::endl;
222 #endif
223 
224  os << "\n\n";
225 }

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ WriteCheckpointFile()

void ERF::WriteCheckpointFile ( ) const

ERF function for writing a checkpoint file.

27 {
28  auto dCheckTime0 = amrex::second();
29 
30  // chk00010 write a checkpoint file with this root directory
31  // chk00010/Header this contains information you need to save (e.g., finest_level, t_new, etc.) and also
32  // the BoxArrays at each level
33  // chk00010/Level_0/
34  // chk00010/Level_1/
35  // etc. these subdirectories will hold the MultiFab data at each level of refinement
36 
37  // checkpoint file name, e.g., chk00010
38  const std::string& checkpointname = Concatenate(check_file,istep[0],file_name_digits);
39 
40  Print() << "Writing native checkpoint " << checkpointname << "\n";
41 
42  const int nlevels = finest_level+1;
43 
44  // ---- prebuild a hierarchy of directories
45  // ---- dirName is built first. if dirName exists, it is renamed. then build
46  // ---- dirName/subDirPrefix_0 .. dirName/subDirPrefix_nlevels-1
47  // ---- if callBarrier is true, call ParallelDescriptor::Barrier()
48  // ---- after all directories are built
49  // ---- ParallelDescriptor::IOProcessor() creates the directories
50  PreBuildDirectorHierarchy(checkpointname, "Level_", nlevels, true);
51 
52  int ncomp_cons = vars_new[0][Vars::cons].nComp();
53 
54  // write Header file
55  if (ParallelDescriptor::IOProcessor()) {
56 
57  std::string HeaderFileName(checkpointname + "/Header");
58  VisMF::IO_Buffer io_buffer(VisMF::IO_Buffer_Size);
59  std::ofstream HeaderFile;
60  HeaderFile.rdbuf()->pubsetbuf(io_buffer.dataPtr(), io_buffer.size());
61  HeaderFile.open(HeaderFileName.c_str(), std::ofstream::out |
62  std::ofstream::trunc |
63  std::ofstream::binary);
64  if(! HeaderFile.good()) {
65  FileOpenFailed(HeaderFileName);
66  }
67 
68  HeaderFile.precision(17);
69 
70  // write out title line
71  HeaderFile << "Checkpoint file for ERF\n";
72 
73  // write out finest_level
74  HeaderFile << finest_level << "\n";
75 
76  // write the number of components
77  // for each variable we store
78 
79  // conservative, cell-centered vars
80  HeaderFile << ncomp_cons << "\n";
81 
82  // x-velocity on faces
83  HeaderFile << 1 << "\n";
84 
85  // y-velocity on faces
86  HeaderFile << 1 << "\n";
87 
88  // z-velocity on faces
89  HeaderFile << 1 << "\n";
90 
91  // write out array of istep
92  for (int i = 0; i < istep.size(); ++i) {
93  HeaderFile << istep[i] << " ";
94  }
95  HeaderFile << "\n";
96 
97  // write out array of dt
98  for (int i = 0; i < dt.size(); ++i) {
99  HeaderFile << dt[i] << " ";
100  }
101  HeaderFile << "\n";
102 
103  // write out array of t_new
104  for (int i = 0; i < t_new.size(); ++i) {
105  HeaderFile << t_new[i] << " ";
106  }
107  HeaderFile << "\n";
108 
109  // write the BoxArray at each level
110  for (int lev = 0; lev <= finest_level; ++lev) {
111  boxArray(lev).writeOn(HeaderFile);
112  HeaderFile << '\n';
113  }
114 
115  // Write separate file that tells how many components we have of the base state
116  std::string BaseStateFileName(checkpointname + "/num_base_state_comps");
117  std::ofstream BaseStateFile;
118  BaseStateFile.open(BaseStateFileName.c_str(), std::ofstream::out |
119  std::ofstream::trunc |
120  std::ofstream::binary);
121  if(! BaseStateFile.good()) {
122  FileOpenFailed(BaseStateFileName);
123  } else {
124  // write out number of components in base state
125  BaseStateFile << BaseState::num_comps << "\n";
126  BaseStateFile << base_state[0].nGrowVect() << "\n";
127  }
128  }
129 
130  // write the MultiFab data to, e.g., chk00010/Level_0/
131  // Here we make copies of the MultiFab with no ghost cells
132  for (int lev = 0; lev <= finest_level; ++lev)
133  {
134  MultiFab cons(grids[lev],dmap[lev],ncomp_cons,0);
135  MultiFab::Copy(cons,vars_new[lev][Vars::cons],0,0,ncomp_cons,0);
136  VisMF::Write(cons, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Cell"));
137 
138  MultiFab xvel(convert(grids[lev],IntVect(1,0,0)),dmap[lev],1,0);
139  MultiFab::Copy(xvel,vars_new[lev][Vars::xvel],0,0,1,0);
140  VisMF::Write(xvel, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "XFace"));
141 
142  MultiFab yvel(convert(grids[lev],IntVect(0,1,0)),dmap[lev],1,0);
143  MultiFab::Copy(yvel,vars_new[lev][Vars::yvel],0,0,1,0);
144  VisMF::Write(yvel, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "YFace"));
145 
146  MultiFab zvel(convert(grids[lev],IntVect(0,0,1)),dmap[lev],1,0);
147  MultiFab::Copy(zvel,vars_new[lev][Vars::zvel],0,0,1,0);
148  VisMF::Write(zvel, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "ZFace"));
149 
150  if (solverChoice.anelastic[lev] == 1) {
151  MultiFab ppinc(grids[lev],dmap[lev],1,0);
152  MultiFab::Copy(ppinc,pp_inc[lev],0,0,1,0);
153  VisMF::Write(ppinc, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "PP_Inc"));
154 
155  MultiFab gpx(convert(grids[lev],IntVect(1,0,0)),dmap[lev],1,0);
156  MultiFab::Copy(gpx,gradp[lev][GpVars::gpx],0,0,1,0);
157  VisMF::Write(gpx, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Gpx"));
158 
159  MultiFab gpy(convert(grids[lev],IntVect(0,1,0)),dmap[lev],1,0);
160  MultiFab::Copy(gpy,gradp[lev][GpVars::gpy],0,0,1,0);
161  VisMF::Write(gpy, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Gpy"));
162 
163  MultiFab gpz(convert(grids[lev],IntVect(0,0,1)),dmap[lev],1,0);
164  MultiFab::Copy(gpz,gradp[lev][GpVars::gpz],0,0,1,0);
165  VisMF::Write(gpz, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Gpz"));
166  }
167 
168  // Note that we write the ghost cells of the base state (unlike above)
169  IntVect ng_base = base_state[lev].nGrowVect();
170  int ncomp_base = base_state[lev].nComp();
171  MultiFab base(grids[lev],dmap[lev],ncomp_base,ng_base);
172  MultiFab::Copy(base,base_state[lev],0,0,ncomp_base,ng_base);
173  VisMF::Write(base, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "BaseState"));
174 
175  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
176  // Note that we also write the ghost cells of z_phys_nd
177  IntVect ng = z_phys_nd[lev]->nGrowVect();
178  MultiFab z_height(convert(grids[lev],IntVect(1,1,1)),dmap[lev],1,ng);
179  MultiFab::Copy(z_height,*z_phys_nd[lev],0,0,1,ng);
180  VisMF::Write(z_height, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Z_Phys_nd"));
181  }
182 
183  // We must read and write qmoist with ghost cells because we don't directly impose BCs on these vars
184  // Write the moisture model restart variables
185  std::vector<int> qmoist_indices;
186  std::vector<std::string> qmoist_names;
187  micro->Get_Qmoist_Restart_Vars(lev, solverChoice, qmoist_indices, qmoist_names);
188  int qmoist_nvar = static_cast<int>(qmoist_indices.size());
189  for (int var = 0; var < qmoist_nvar; var++) {
190  const int ncomp = 1;
191  IntVect ng_moist = qmoist[lev][qmoist_indices[var]]->nGrowVect();
192  MultiFab moist_vars(grids[lev],dmap[lev],ncomp,ng_moist);
193  MultiFab::Copy(moist_vars,*(qmoist[lev][qmoist_indices[var]]),0,0,ncomp,ng_moist);
194  VisMF::Write(moist_vars, amrex::MultiFabFileFullPrefix(lev, checkpointname, "Level_", qmoist_names[var]));
195  }
196 
197 #if defined(ERF_USE_WINDFARM)
198  if(solverChoice.windfarm_type == WindFarmType::Fitch or
199  solverChoice.windfarm_type == WindFarmType::EWP or
200  solverChoice.windfarm_type == WindFarmType::SimpleAD){
201  IntVect ng_turb = Nturb[lev].nGrowVect();
202  MultiFab mf_Nturb(grids[lev],dmap[lev],1,ng_turb);
203  MultiFab::Copy(mf_Nturb,Nturb[lev],0,0,1,ng_turb);
204  VisMF::Write(mf_Nturb, amrex::MultiFabFileFullPrefix(lev, checkpointname, "Level_", "NumTurb"));
205  }
206 #endif
207 
208  // Write the LSM data
209  if (solverChoice.lsm_type != LandSurfaceType::None) {
210  for (int ivar(0); ivar<lsm_data[lev].size(); ++ivar) {
211  BoxArray ba = lsm_data[lev][ivar]->boxArray();
212  DistributionMapping dm = lsm_data[lev][ivar]->DistributionMap();
213  IntVect ng = lsm_data[lev][ivar]->nGrowVect();
214  int nvar = lsm_data[lev][ivar]->nComp();
215  MultiFab lsm_vars(ba,dm,nvar,ng);
216  MultiFab::Copy(lsm_vars,*(lsm_data[lev][ivar]),0,0,nvar,ng);
217  VisMF::Write(lsm_vars, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "LsmData" + std::to_string(ivar)));
218  }
219  for (int iflux(0); iflux<lsm_flux[lev].size(); ++iflux) {
220  BoxArray ba = lsm_flux[lev][iflux]->boxArray();
221  DistributionMapping dm = lsm_flux[lev][iflux]->DistributionMap();
222  IntVect ng = lsm_flux[lev][iflux]->nGrowVect();
223  int nvar = lsm_flux[lev][iflux]->nComp();
224  MultiFab lsm_vars(ba,dm,nvar,ng);
225  MultiFab::Copy(lsm_vars,*(lsm_flux[lev][iflux]),0,0,nvar,ng);
226  VisMF::Write(lsm_vars, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "LsmFlux" + std::to_string(iflux)));
227  }
228  }
229 
230  // Write the radiation heating rates
231  if ((solverChoice.rad_type != RadiationType::None) && (qheating_rates[lev])) {
232  int nrad = qheating_rates[lev]->nComp();
233  MultiFab mf_rad(grids[lev],dmap[lev],nrad,0);
234  MultiFab::Copy(mf_rad,*qheating_rates[lev],0,0,nrad,0);
235  VisMF::Write(mf_rad, amrex::MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Qrad"));
236  }
237 
238  IntVect ng = mapfac[lev][MapFacType::m_x]->nGrowVect();
239  MultiFab mf_m(ba2d[lev],dmap[lev],1,ng);
240  MultiFab::Copy(mf_m,*mapfac[lev][MapFacType::m_x],0,0,1,ng);
241  VisMF::Write(mf_m, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "MapFactor_mx"));
242 
243 #if 0
245  MultiFab::Copy(mf_m,*mapfac[lev][MapFacType::m_y],0,0,1,ng);
246  VisMF::Write(mf_m, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "MapFactor_my"));
247  }
248 #endif
249 
250  ng = mapfac[lev][MapFacType::u_x]->nGrowVect();
251  MultiFab mf_u(convert(ba2d[lev],IntVect(1,0,0)),dmap[lev],1,ng);
252  MultiFab::Copy(mf_u,*mapfac[lev][MapFacType::u_x],0,0,1,ng);
253  VisMF::Write(mf_u, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "MapFactor_ux"));
254 
255 #if 0
257  MultiFab::Copy(mf_u,*mapfac[lev][MapFacType::u_y],0,0,1,ng);
258  VisMF::Write(mf_u, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "MapFactor_uy"));
259  }
260 #endif
261 
262  ng = mapfac[lev][MapFacType::v_x]->nGrowVect();
263  MultiFab mf_v(convert(ba2d[lev],IntVect(0,1,0)),dmap[lev],1,ng);
264  MultiFab::Copy(mf_v,*mapfac[lev][MapFacType::v_x],0,0,1,ng);
265  VisMF::Write(mf_v, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "MapFactor_vx"));
266 
267 #if 0
269  MultiFab::Copy(mf_v,*mapfac[lev][MapFacType::v_y],0,0,1,ng);
270  VisMF::Write(mf_v, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "MapFactor_vy"));
271  }
272 #endif
273 
274  if (m_SurfaceLayer) {
275  amrex::Print() << "Writing SurfaceLayer variables at level " << lev << std::endl;
276  ng = IntVect(1,1,0);
277  MultiFab m_var(ba2d[lev],dmap[lev],1,ng);
278  MultiFab* src = nullptr;
279 
280  // U*
281  src = m_SurfaceLayer->get_u_star(lev);
282  MultiFab::Copy(m_var,*src,0,0,1,ng);
283  VisMF::Write(m_var, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Ustar"));
284 
285  // W*
286  src = m_SurfaceLayer->get_w_star(lev);
287  MultiFab::Copy(m_var,*src,0,0,1,ng);
288  VisMF::Write(m_var, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Wstar"));
289 
290  // T*
291  src = m_SurfaceLayer->get_t_star(lev);
292  MultiFab::Copy(m_var,*src,0,0,1,ng);
293  VisMF::Write(m_var, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Tstar"));
294 
295  // Q*
296  src = m_SurfaceLayer->get_q_star(lev);
297  MultiFab::Copy(m_var,*src,0,0,1,ng);
298  VisMF::Write(m_var, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Qstar"));
299 
300  // Olen
301  src = m_SurfaceLayer->get_olen(lev);
302  MultiFab::Copy(m_var,*src,0,0,1,ng);
303  VisMF::Write(m_var, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Olen"));
304 
305  // Qsurf
306  src = m_SurfaceLayer->get_q_surf(lev);
307  MultiFab::Copy(m_var,*src,0,0,1,ng);
308  VisMF::Write(m_var, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Qsurf"));
309 
310  // PBLH
311  src = m_SurfaceLayer->get_pblh(lev);
312  MultiFab::Copy(m_var,*src,0,0,1,ng);
313  VisMF::Write(m_var, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "PBLH"));
314 
315  // Z0
316  src = m_SurfaceLayer->get_z0(lev);
317  MultiFab::Copy(m_var,*src,0,0,1,ng);
318  VisMF::Write(m_var, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Z0"));
319  }
320 
321  if (sst_lev[lev][0]) {
322  int ntimes = 1;
323  ng = vars_new[lev][Vars::cons].nGrowVect(); ng[2]=0;
324  MultiFab sst_at_t(ba2d[lev],dmap[lev],1,ng);
325  for (int nt(0); nt<ntimes; ++nt) {
326  MultiFab::Copy(sst_at_t,*sst_lev[lev][nt],0,0,1,ng);
327  VisMF::Write(sst_at_t, MultiFabFileFullPrefix(lev, checkpointname, "Level_",
328  "SST_" + std::to_string(nt)));
329  }
330  }
331 
332  if (tsk_lev[lev][0]) {
333  int ntimes = 1;
334  ng = vars_new[lev][Vars::cons].nGrowVect(); ng[2]=0;
335  MultiFab tsk_at_t(ba2d[lev],dmap[lev],1,ng);
336  for (int nt(0); nt<ntimes; ++nt) {
337  MultiFab::Copy(tsk_at_t,*tsk_lev[lev][nt],0,0,1,ng);
338  VisMF::Write(tsk_at_t, MultiFabFileFullPrefix(lev, checkpointname, "Level_",
339  "TSK_" + std::to_string(nt)));
340  }
341  }
342 
343  {
344  int ntimes = 1;
345  ng = vars_new[lev][Vars::cons].nGrowVect(); ng[2]=0;
346  MultiFab lmask_at_t(ba2d[lev],dmap[lev],1,ng);
347  for (int nt(0); nt<ntimes; ++nt) {
348  for (MFIter mfi(lmask_at_t); mfi.isValid(); ++mfi) {
349  const Box& bx = mfi.growntilebox();
350  Array4<int> const& src_arr = lmask_lev[lev][nt]->array(mfi);
351  Array4<Real> const& dst_arr = lmask_at_t.array(mfi);
352  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
353  {
354  dst_arr(i,j,k) = Real(src_arr(i,j,k));
355  });
356  }
357  VisMF::Write(lmask_at_t, MultiFabFileFullPrefix(lev, checkpointname, "Level_",
358  "LMASK_" + std::to_string(nt)));
359  }
360  }
361 
362  IntVect ngv = ng; ngv[2] = 0;
363 
364  // Write lat/lon if it exists
365  if (lat_m[lev] && lon_m[lev]) {
366  amrex::Print() << "Writing Lat/Lon variables at level " << lev << std::endl;
367  MultiFab lat(ba2d[lev],dmap[lev],1,ngv);
368  MultiFab lon(ba2d[lev],dmap[lev],1,ngv);
369  MultiFab::Copy(lat,*lat_m[lev],0,0,1,ngv);
370  MultiFab::Copy(lon,*lon_m[lev],0,0,1,ngv);
371  VisMF::Write(lat, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "LAT"));
372  VisMF::Write(lon, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "LON"));
373  }
374 
375 
376 #ifdef ERF_USE_NETCDF
377  // Write sinPhi and cosPhi if it exists
378  if (cosPhi_m[lev] && sinPhi_m[lev] && solverChoice.variable_coriolis) {
379  amrex::Print() << "Writing Coriolis factors at level " << lev << std::endl;
380  MultiFab sphi(ba2d[lev],dmap[lev],1,ngv);
381  MultiFab cphi(ba2d[lev],dmap[lev],1,ngv);
382  MultiFab::Copy(sphi,*sinPhi_m[lev],0,0,1,ngv);
383  MultiFab::Copy(cphi,*cosPhi_m[lev],0,0,1,ngv);
384  VisMF::Write(sphi, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "SinPhi"));
385  VisMF::Write(cphi, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "CosPhi"));
386  }
387 
388  if (solverChoice.use_real_bcs && solverChoice.init_type == InitType::WRFInput) {
389  if (lev == 0) {
390  amrex::Print() << "Writing C1H/C2H/MUB/PHB variables at level " << lev << std::endl;
391  MultiFab tmp1d(ba1d[0],dmap[0],1,0);
392 
393  MultiFab::Copy(tmp1d,*wrf_C1H,0,0,1,0);
394  VisMF::Write(tmp1d, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "C1H"));
395 
396  MultiFab::Copy(tmp1d,*wrf_C2H,0,0,1,0);
397  VisMF::Write(tmp1d, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "C2H"));
398 
399  MultiFab tmp2d(ba2d[0],dmap[0],1,wrf_MUB->nGrowVect());
400 
401  MultiFab::Copy(tmp2d,*wrf_MUB,0,0,1,wrf_MUB->nGrowVect());
402  VisMF::Write(tmp2d, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "MUB"));
403 
404  ng = IntVect(1,1,0);
405  MultiFab tmp3d(convert(grids[0],IntVect(0,0,1)),dmap[0],1,ng);
406  MultiFab::Copy(tmp3d,*wrf_PHB,0,0,1,ng);
407  VisMF::Write(tmp3d, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "PHB"));
408  }
409  }
410 #endif
411  } // for lev
412 
413 #ifdef ERF_USE_PARTICLES
414  particleData.Checkpoint(checkpointname);
415 #endif
416 
417 #if 0
418 #ifdef ERF_USE_NETCDF
419  // Write bdy_data files
420  if ( ParallelDescriptor::IOProcessor() &&
421  ((solverChoice.init_type==InitType::WRFInput) || (solverChoice.init_type==InitType::Metgrid)) &&
423  {
424  // Vector dimensions
425  int num_time = bdy_data_xlo.size();
426  int num_var = bdy_data_xlo[0].size();
427 
428  // Open header file and write to it
429  std::ofstream bdy_h_file(MultiFabFileFullPrefix(0, checkpointname, "Level_", "bdy_H"));
430  bdy_h_file << std::setprecision(1) << std::fixed;
431  bdy_h_file << num_time << "\n";
432  bdy_h_file << num_var << "\n";
433  bdy_h_file << start_bdy_time << "\n";
434  bdy_h_file << bdy_time_interval << "\n";
435  bdy_h_file << real_width << "\n";
436  for (int ivar(0); ivar<num_var; ++ivar) {
437  bdy_h_file << bdy_data_xlo[0][ivar].box() << "\n";
438  bdy_h_file << bdy_data_xhi[0][ivar].box() << "\n";
439  bdy_h_file << bdy_data_ylo[0][ivar].box() << "\n";
440  bdy_h_file << bdy_data_yhi[0][ivar].box() << "\n";
441  }
442 
443  // Open data file and write to it
444  std::ofstream bdy_d_file(MultiFabFileFullPrefix(0, checkpointname, "Level_", "bdy_D"));
445  for (int itime(0); itime<num_time; ++itime) {
446  if (bdy_data_xlo[itime].size() > 0) {
447  for (int ivar(0); ivar<num_var; ++ivar) {
448  bdy_data_xlo[itime][ivar].writeOn(bdy_d_file,0,1);
449  bdy_data_xhi[itime][ivar].writeOn(bdy_d_file,0,1);
450  bdy_data_ylo[itime][ivar].writeOn(bdy_d_file,0,1);
451  bdy_data_yhi[itime][ivar].writeOn(bdy_d_file,0,1);
452  }
453  }
454  }
455  }
456 #endif
457 #endif
458 
459  if (verbose > 0)
460  {
461  auto dCheckTime = amrex::second() - dCheckTime0;
462  ParallelDescriptor::ReduceRealMax(dCheckTime,ParallelDescriptor::IOProcessorNumber());
463  amrex::Print() << "Checkpoint write time = " << dCheckTime << " seconds." << '\n';
464  }
465 }
bool variable_coriolis
Definition: ERF_DataStruct.H:1299

Referenced by EvolveOneStep().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ WriteGenericPlotfileHeaderWithTerrain()

void ERF::WriteGenericPlotfileHeaderWithTerrain ( std::ostream &  HeaderFile,
int  nlevels,
const amrex::Vector< amrex::BoxArray > &  bArray,
const amrex::Vector< std::string > &  varnames,
const amrex::Vector< amrex::Geometry > &  my_geom,
amrex::Real  time,
const amrex::Vector< int > &  level_steps,
const amrex::Vector< amrex::IntVect > &  my_ref_ratio,
const std::string &  versionName,
const std::string &  levelPrefix,
const std::string &  mfPrefix 
) const
1955 {
1956  AMREX_ALWAYS_ASSERT(nlevels <= bArray.size());
1957  AMREX_ALWAYS_ASSERT(nlevels <= my_ref_ratio.size()+1);
1958  AMREX_ALWAYS_ASSERT(nlevels <= level_steps.size());
1959 
1960  HeaderFile.precision(17);
1961 
1962  // ---- this is the generic plot file type name
1963  HeaderFile << versionName << '\n';
1964 
1965  HeaderFile << varnames.size() << '\n';
1966 
1967  for (int ivar = 0; ivar < varnames.size(); ++ivar) {
1968  HeaderFile << varnames[ivar] << "\n";
1969  }
1970  HeaderFile << AMREX_SPACEDIM << '\n';
1971  HeaderFile << my_time << '\n';
1972  HeaderFile << finest_level << '\n';
1973  for (int i = 0; i < AMREX_SPACEDIM; ++i) {
1974  HeaderFile << my_geom[0].ProbLo(i) << ' ';
1975  }
1976  HeaderFile << '\n';
1977  for (int i = 0; i < AMREX_SPACEDIM; ++i) {
1978  HeaderFile << my_geom[0].ProbHi(i) << ' ';
1979  }
1980  HeaderFile << '\n';
1981  for (int i = 0; i < finest_level; ++i) {
1982  HeaderFile << my_ref_ratio[i][0] << ' ';
1983  }
1984  HeaderFile << '\n';
1985  for (int i = 0; i <= finest_level; ++i) {
1986  HeaderFile << my_geom[i].Domain() << ' ';
1987  }
1988  HeaderFile << '\n';
1989  for (int i = 0; i <= finest_level; ++i) {
1990  HeaderFile << level_steps[i] << ' ';
1991  }
1992  HeaderFile << '\n';
1993  for (int i = 0; i <= finest_level; ++i) {
1994  for (int k = 0; k < AMREX_SPACEDIM; ++k) {
1995  HeaderFile << my_geom[i].CellSize()[k] << ' ';
1996  }
1997  HeaderFile << '\n';
1998  }
1999  HeaderFile << (int) my_geom[0].Coord() << '\n';
2000  HeaderFile << "0\n";
2001 
2002  for (int level = 0; level <= finest_level; ++level) {
2003  HeaderFile << level << ' ' << bArray[level].size() << ' ' << my_time << '\n';
2004  HeaderFile << level_steps[level] << '\n';
2005 
2006  const IntVect& domain_lo = my_geom[level].Domain().smallEnd();
2007  for (int i = 0; i < bArray[level].size(); ++i)
2008  {
2009  // Need to shift because the RealBox ctor we call takes the
2010  // physical location of index (0,0,0). This does not affect
2011  // the usual cases where the domain index starts with zero
2012  const Box& b = shift(bArray[level][i], -domain_lo);
2013  RealBox loc = RealBox(b, my_geom[level].CellSize(), my_geom[level].ProbLo());
2014  for (int n = 0; n < AMREX_SPACEDIM; ++n) {
2015  HeaderFile << loc.lo(n) << ' ' << loc.hi(n) << '\n';
2016  }
2017  }
2018 
2019  HeaderFile << MultiFabHeaderPath(level, levelPrefix, mfPrefix) << '\n';
2020  }
2021  HeaderFile << "1" << "\n";
2022  HeaderFile << "3" << "\n";
2023  HeaderFile << "amrexvec_nu_x" << "\n";
2024  HeaderFile << "amrexvec_nu_y" << "\n";
2025  HeaderFile << "amrexvec_nu_z" << "\n";
2026  std::string mf_nodal_prefix = "Nu_nd";
2027  for (int level = 0; level <= finest_level; ++level) {
2028  HeaderFile << MultiFabHeaderPath(level, levelPrefix, mf_nodal_prefix) << '\n';
2029  }
2030 }
Coord
Definition: ERF_DataStruct.H:92
Here is the call graph for this function:

◆ writeJobInfo()

void ERF::writeJobInfo ( const std::string &  dir) const
10 {
11  // job_info file with details about the run
12  std::ofstream jobInfoFile;
13  std::string FullPathJobInfoFile = dir;
14  FullPathJobInfoFile += "/job_info";
15  jobInfoFile.open(FullPathJobInfoFile.c_str(), std::ios::out);
16 
17  std::string PrettyLine = "==================================================="
18  "============================\n";
19  std::string OtherLine = "----------------------------------------------------"
20  "----------------------------\n";
21  std::string SkipSpace = " ";
22 
23  // job information
24  jobInfoFile << PrettyLine;
25  jobInfoFile << " ERF Job Information\n";
26  jobInfoFile << PrettyLine;
27 
28  jobInfoFile << "inputs file: " << inputs_name << "\n\n";
29 
30  jobInfoFile << "number of MPI processes: "
31  << ParallelDescriptor::NProcs() << "\n";
32 #ifdef _OPENMP
33  jobInfoFile << "number of threads: " << omp_get_max_threads() << "\n";
34 #endif
35 
36  jobInfoFile << "\n";
37  jobInfoFile << "CPU time used since start of simulation (CPU-hours): "
38  << getCPUTime() / Real(3600.0);
39 
40  jobInfoFile << "\n\n";
41 
42  if (use_datetime) {
43  const std::string dt_format = "%Y-%m-%d %H:%M:%S"; // ISO 8601 standard
44  jobInfoFile << "Simulation time: " << getTimestamp(start_time+t_new[0], dt_format) << "\n";
45  jobInfoFile << "\n\n";
46  }
47 
48  // plotfile information
49  jobInfoFile << PrettyLine;
50  jobInfoFile << " Plotfile Information\n";
51  jobInfoFile << PrettyLine;
52 
53  time_t now = time(nullptr);
54 
55  // Convert now to tm struct for local timezone
56  tm* localtm = localtime(&now);
57  jobInfoFile << "output data / time: " << asctime(localtm);
58 
59  std::string currentDir = FileSystem::CurrentPath();
60  jobInfoFile << "output dir: " << currentDir << "\n";
61 
62  jobInfoFile << "\n\n";
63 
64  // build information
65  jobInfoFile << PrettyLine;
66  jobInfoFile << " Build Information\n";
67  jobInfoFile << PrettyLine;
68 
69  jobInfoFile << "build date: " << buildInfoGetBuildDate() << "\n";
70  jobInfoFile << "build machine: " << buildInfoGetBuildMachine() << "\n";
71  jobInfoFile << "build dir: " << buildInfoGetBuildDir() << "\n";
72  jobInfoFile << "AMReX dir: " << buildInfoGetAMReXDir() << "\n";
73 
74  jobInfoFile << "\n";
75 
76  jobInfoFile << "COMP: " << buildInfoGetComp() << "\n";
77  jobInfoFile << "COMP version: " << buildInfoGetCompVersion() << "\n";
78 
79  jobInfoFile << "\n";
80 
81  for (int n = 1; n <= buildInfoGetNumModules(); n++) {
82  jobInfoFile << buildInfoGetModuleName(n) << ": "
83  << buildInfoGetModuleVal(n) << "\n";
84  }
85 
86  jobInfoFile << "\n";
87 
88  const char* githash1 = buildInfoGetGitHash(1);
89  const char* githash2 = buildInfoGetGitHash(2);
90  if (strlen(githash1) > 0) {
91  jobInfoFile << "ERF git hash: " << githash1 << "\n";
92  }
93  if (strlen(githash2) > 0) {
94  jobInfoFile << "AMReX git hash: " << githash2 << "\n";
95  }
96 
97  const char* buildgithash = buildInfoGetBuildGitHash();
98  const char* buildgitname = buildInfoGetBuildGitName();
99  if (strlen(buildgithash) > 0) {
100  jobInfoFile << buildgitname << " git hash: " << buildgithash << "\n";
101  }
102 
103  jobInfoFile << "\n\n";
104 
105  // grid information
106  jobInfoFile << PrettyLine;
107  jobInfoFile << " Grid Information\n";
108  jobInfoFile << PrettyLine;
109 
110  int f_lev = finest_level;
111 
112  for (int i = 0; i <= f_lev; i++) {
113  jobInfoFile << " level: " << i << "\n";
114  jobInfoFile << " number of boxes = " << grids[i].size() << "\n";
115  jobInfoFile << " maximum zones = ";
116  for (int n = 0; n < AMREX_SPACEDIM; n++) {
117  jobInfoFile << geom[i].Domain().length(n) << " ";
118  }
119  jobInfoFile << "\n\n";
120  }
121 
122  jobInfoFile << " Boundary conditions\n";
123 
124  jobInfoFile << " -x: " << domain_bc_type[0] << "\n";
125  jobInfoFile << " +x: " << domain_bc_type[3] << "\n";
126  jobInfoFile << " -y: " << domain_bc_type[1] << "\n";
127  jobInfoFile << " +y: " << domain_bc_type[4] << "\n";
128  jobInfoFile << " -z: " << domain_bc_type[2] << "\n";
129  jobInfoFile << " +z: " << domain_bc_type[5] << "\n";
130 
131  jobInfoFile << "\n\n";
132 
133  // runtime parameters
134  jobInfoFile << PrettyLine;
135  jobInfoFile << " Inputs File Parameters\n";
136  jobInfoFile << PrettyLine;
137 
138  ParmParse::dumpTable(jobInfoFile, true);
139  jobInfoFile.close();
140 }
std::string inputs_name
Definition: main.cpp:15
static amrex::Real getCPUTime()
Definition: ERF.H:1547
Here is the call graph for this function:

◆ WriteLinePlot()

void ERF::WriteLinePlot ( const std::string &  filename,
amrex::Vector< std::array< amrex::Real, 2 >> &  points_xy 
)
576 {
577  std::ofstream ofs(filename);
578  if (!ofs.is_open()) {
579  amrex::Print() << "Error: Could not open file " << filename << " for writing.\n";
580  return;
581  }
582 
583  ofs << std::setprecision(10) << std::scientific;
584  ofs << "# x y\n";
585 
586  for (const auto& p : points_xy) {
587  ofs << p[0] << " " << p[1] << "\n";
588  }
589 
590  ofs.close();
591 
592  amrex::Print() << "Line plot data written to " << filename << "\n";
593 }

◆ WriteMultiLevelPlotfileWithTerrain()

void ERF::WriteMultiLevelPlotfileWithTerrain ( const std::string &  plotfilename,
int  nlevels,
const amrex::Vector< const amrex::MultiFab * > &  mf,
const amrex::Vector< const amrex::MultiFab * > &  mf_nd,
const amrex::Vector< std::string > &  varnames,
const amrex::Vector< amrex::Geometry > &  my_geom,
amrex::Real  time,
const amrex::Vector< int > &  level_steps,
const amrex::Vector< amrex::IntVect > &  my_ref_ratio,
const std::string &  versionName = "HyperCLaw-V1.1",
const std::string &  levelPrefix = "Level_",
const std::string &  mfPrefix = "Cell",
const amrex::Vector< std::string > &  extra_dirs = amrex::Vector<std::string>() 
) const
1869 {
1870  BL_PROFILE("WriteMultiLevelPlotfileWithTerrain()");
1871 
1872  AMREX_ALWAYS_ASSERT(nlevels <= mf.size());
1873  AMREX_ALWAYS_ASSERT(nlevels <= rr.size()+1);
1874  AMREX_ALWAYS_ASSERT(nlevels <= level_steps.size());
1875  AMREX_ALWAYS_ASSERT(mf[0]->nComp() == varnames.size());
1876 
1877  bool callBarrier(false);
1878  PreBuildDirectorHierarchy(plotfilename, levelPrefix, nlevels, callBarrier);
1879  if (!extra_dirs.empty()) {
1880  for (const auto& d : extra_dirs) {
1881  const std::string ed = plotfilename+"/"+d;
1882  PreBuildDirectorHierarchy(ed, levelPrefix, nlevels, callBarrier);
1883  }
1884  }
1885  ParallelDescriptor::Barrier();
1886 
1887  if (ParallelDescriptor::MyProc() == ParallelDescriptor::NProcs()-1) {
1888  Vector<BoxArray> boxArrays(nlevels);
1889  for(int level(0); level < boxArrays.size(); ++level) {
1890  boxArrays[level] = mf[level]->boxArray();
1891  }
1892 
1893  auto f = [=,this]() {
1894  VisMF::IO_Buffer io_buffer(VisMF::IO_Buffer_Size);
1895  std::string HeaderFileName(plotfilename + "/Header");
1896  std::ofstream HeaderFile;
1897  HeaderFile.rdbuf()->pubsetbuf(io_buffer.dataPtr(), io_buffer.size());
1898  HeaderFile.open(HeaderFileName.c_str(), std::ofstream::out |
1899  std::ofstream::trunc |
1900  std::ofstream::binary);
1901  if( ! HeaderFile.good()) FileOpenFailed(HeaderFileName);
1902  WriteGenericPlotfileHeaderWithTerrain(HeaderFile, nlevels, boxArrays, varnames,
1903  my_geom, time, level_steps, rr, versionName,
1904  levelPrefix, mfPrefix);
1905  };
1906 
1907  if (AsyncOut::UseAsyncOut()) {
1908  AsyncOut::Submit(std::move(f));
1909  } else {
1910  f();
1911  }
1912  }
1913 
1914  std::string mf_nodal_prefix = "Nu_nd";
1915  for (int level = 0; level <= finest_level; ++level)
1916  {
1917  if (AsyncOut::UseAsyncOut()) {
1918  VisMF::AsyncWrite(*mf[level],
1919  MultiFabFileFullPrefix(level, plotfilename, levelPrefix, mfPrefix),
1920  true);
1921  VisMF::AsyncWrite(*mf_nd[level],
1922  MultiFabFileFullPrefix(level, plotfilename, levelPrefix, mf_nodal_prefix),
1923  true);
1924  } else {
1925  const MultiFab* data;
1926  std::unique_ptr<MultiFab> mf_tmp;
1927  if (mf[level]->nGrowVect() != 0) {
1928  mf_tmp = std::make_unique<MultiFab>(mf[level]->boxArray(),
1929  mf[level]->DistributionMap(),
1930  mf[level]->nComp(), 0, MFInfo(),
1931  mf[level]->Factory());
1932  MultiFab::Copy(*mf_tmp, *mf[level], 0, 0, mf[level]->nComp(), 0);
1933  data = mf_tmp.get();
1934  } else {
1935  data = mf[level];
1936  }
1937  VisMF::Write(*data , MultiFabFileFullPrefix(level, plotfilename, levelPrefix, mfPrefix));
1938  VisMF::Write(*mf_nd[level], MultiFabFileFullPrefix(level, plotfilename, levelPrefix, mf_nodal_prefix));
1939  }
1940  }
1941 }
void WriteGenericPlotfileHeaderWithTerrain(std::ostream &HeaderFile, int nlevels, const amrex::Vector< amrex::BoxArray > &bArray, const amrex::Vector< std::string > &varnames, const amrex::Vector< amrex::Geometry > &my_geom, amrex::Real time, const amrex::Vector< int > &level_steps, const amrex::Vector< amrex::IntVect > &my_ref_ratio, const std::string &versionName, const std::string &levelPrefix, const std::string &mfPrefix) const
Definition: ERF_Plotfile.cpp:1944
Here is the call graph for this function:

◆ WriteMyEBSurface()

void ERF::WriteMyEBSurface ( )

◆ writeNow()

bool ERF::writeNow ( double  cur_time,
const int  nstep,
const int  plot_int,
const amrex::Real  plot_per,
const amrex::Real  dt_0,
amrex::Real last_file_time 
)
3219 {
3220  bool write_now = false;
3221 
3222  if ( plot_int > 0) {
3223 
3224  write_now = (nstep % plot_int == 0);
3225 
3226  } else if (plot_per > zero) {
3227 
3228  amrex::Print() << "CUR NEXT PER " << cur_time << " " << next_file_time << " " << plot_per << std::endl;
3229 
3230  // Only write now if nstep newly matches the number of elapsed periods
3231  write_now = (cur_time > (next_file_time - Real(0.1)*dt_0));
3232  }
3233 
3234  return write_now;
3235 }

Referenced by EvolveOneStep().

Here is the caller graph for this function:

◆ WriteSubvolume()

void ERF::WriteSubvolume ( int  isub,
amrex::Vector< std::string >  subvol_var_names 
)
146 {
147  ParmParse pp("erf.subvol");
148 
149  Vector<Real> origin;
150  Vector< int> ncell;
151  Vector<Real> delta;
152 
153  // **************************************************************
154  // Read in the origin, number of cells in each dir, and resolution
155  // **************************************************************
156 
157  int lev_for_sub = 0;
158  int offset = isub * AMREX_SPACEDIM;
159 
160  pp.getarr("origin",origin,offset,AMREX_SPACEDIM);
161  pp.getarr("nxnynz", ncell,offset,AMREX_SPACEDIM);
162  pp.getarr("dxdydz", delta,offset,AMREX_SPACEDIM);
163 
164  bool found = false;
165  for (int i = 0; i <= finest_level; i++) {
166  if (!found) {
167  if (almostEqual(delta[offset+0],geom[i].CellSize(0)) &&
168  almostEqual(delta[offset+1],geom[i].CellSize(1)) &&
169  almostEqual(delta[offset+2],geom[i].CellSize(2)) ) {
170 
171  amrex::Print() << "WriteSubvolume:Resolution specified matches that of level " << i << std::endl;
172  found = true;
173  lev_for_sub = i;
174  }
175  }
176  }
177 
178  if (!found) {
179  amrex::Abort("Resolution specified for subvol does not match the resolution of any of the levels.");
180  }
181 
182 
183  // **************************************************************
184  // Now that we know which level we're at, we can figure out which (i,j,k) the origin corresponds to
185  // Note we use Real(1.0001) as a fudge factor since the division of two reals --> integer will do a floor
186  // **************************************************************
187  int i0 = static_cast<int>((origin[offset+0] - geom[lev_for_sub].ProbLo(0)) * Real(1.0001) / delta[offset+0]);
188  int j0 = static_cast<int>((origin[offset+1] - geom[lev_for_sub].ProbLo(1)) * Real(1.0001) / delta[offset+1]);
189  int k0 = static_cast<int>((origin[offset+2] - geom[lev_for_sub].ProbLo(2)) * Real(1.0001) / delta[offset+2]);
190 
191  found = false;
192  if (almostEqual(geom[lev_for_sub].ProbLo(0)+i0*delta[offset+0],origin[offset+0]) &&
193  almostEqual(geom[lev_for_sub].ProbLo(1)+j0*delta[offset+1],origin[offset+1]) &&
194  almostEqual(geom[lev_for_sub].ProbLo(2)+k0*delta[offset+2],origin[offset+2]) )
195  {
196  amrex::Print() << "WriteSubvolume:Specified origin is the lower left corner of cell " << IntVect(i0,j0,k0) << std::endl;
197  found = true;
198  }
199 
200  if (!found) {
201  amrex::Abort("Origin specified does not correspond to a node at this level.");
202  }
203 
204  Box domain(geom[lev_for_sub].Domain());
205 
206  Box bx(IntVect(i0,j0,k0),IntVect(i0+ncell[offset+0]-1,j0+ncell[offset+1]-1,k0+ncell[offset+2]-1));
207  amrex::Print() << "WriteSubvolume:Box requested is " << bx << std::endl;
208 
209  if (!domain.contains(bx))
210  {
211  amrex::Abort("WriteSubvolume:Box requested is larger than the existing domain");
212  }
213 
214  Vector<int> cs(AMREX_SPACEDIM);
215  int count = pp.countval("chunk_size");
216  if (count > 0) {
217  pp.queryarr("chunk_size",cs,0,AMREX_SPACEDIM);
218  } else {
219  cs[0] = max_grid_size[0][0];
220  cs[1] = max_grid_size[0][1];
221  cs[2] = max_grid_size[0][2];
222  }
223  IntVect chunk_size(cs[0],cs[1],cs[2]);
224 
225  BoxArray ba(bx);
226  ba.maxSize(chunk_size);
227 
228  amrex::Print() << "WriteSubvolume:BoxArray is " << ba << std::endl;
229 
230  Vector<std::string> varnames;
231  varnames.insert(varnames.end(), subvol_var_names.begin(), subvol_var_names.end());
232 
233  int ncomp_mf = subvol_var_names.size();
234 
235  DistributionMapping dm(ba);
236 
237  MultiFab mf(ba, dm, ncomp_mf, 0);
238 
239  int mf_comp = 0;
240 
241  // *****************************************************************************************
242 
243  // First, copy any of the conserved state variables into the output plotfile
244  for (int i = 0; i < cons_names.size(); ++i) {
245  if (containerHasElement(subvol_var_names, cons_names[i])) {
246  mf.ParallelCopy(vars_new[lev_for_sub][Vars::cons],i,mf_comp,1,1,0);
247  mf_comp++;
248  }
249  }
250 
251  // *****************************************************************************************
252 
253  if (containerHasElement(subvol_var_names, "x_velocity") ||
254  containerHasElement(subvol_var_names, "y_velocity") ||
255  containerHasElement(subvol_var_names, "z_velocity"))
256  {
257  MultiFab mf_cc_vel(grids[lev_for_sub], dmap[lev_for_sub], AMREX_SPACEDIM, 0);
258  average_face_to_cellcenter(mf_cc_vel,0,
259  Array<const MultiFab*,3>{&vars_new[lev_for_sub][Vars::xvel],
260  &vars_new[lev_for_sub][Vars::yvel],
261  &vars_new[lev_for_sub][Vars::zvel]});
262  if (containerHasElement(subvol_var_names, "x_velocity")) {
263  mf.ParallelCopy(mf_cc_vel,0,mf_comp,1,0,0);
264  mf_comp++;
265  }
266  if (containerHasElement(subvol_var_names, "y_velocity")) {
267  mf.ParallelCopy(mf_cc_vel,1,mf_comp,1,0,0);
268  mf_comp++;
269  }
270  if (containerHasElement(subvol_var_names, "z_velocity")) {
271  mf.ParallelCopy(mf_cc_vel,2,mf_comp,1,0,0);
272  mf_comp++;
273  }
274  }
275 
276  // *****************************************************************************************
277 
278  // Finally, check for any derived quantities and compute them, inserting
279  // them into our output multifab
280  auto calculate_derived = [&](const std::string& der_name,
281  MultiFab& src_mf,
282  decltype(derived::erf_dernull)& der_function)
283  {
284  if (containerHasElement(subvol_var_names, der_name)) {
285  MultiFab dmf(src_mf.boxArray(), src_mf.DistributionMap(), 1, 0);
286 #ifdef _OPENMP
287 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
288 #endif
289  for (MFIter mfi(dmf, TilingIfNotGPU()); mfi.isValid(); ++mfi)
290  {
291  const Box& tbx = mfi.tilebox();
292  auto& dfab = dmf[mfi];
293  auto& sfab = src_mf[mfi];
294  auto& zfab = (*z_phys_cc[lev_for_sub])[mfi];
295  der_function(tbx, dfab, 0, 1, sfab, zfab, Geom(lev_for_sub), t_new[0], nullptr, lev_for_sub);
296  }
297  mf.ParallelCopy(dmf,0,mf_comp,1,0,0);
298  mf_comp++;
299  }
300  };
301 
302  // *****************************************************************************************
303  // NOTE: All derived variables computed below **MUST MATCH THE ORDER** of "derived_names"
304  // defined in ERF.H
305  // *****************************************************************************************
306 
307  if (solverChoice.moisture_type != MoistureType::None) {
308  calculate_derived("temp", vars_new[lev_for_sub][Vars::cons], derived::erf_dermoisttemp);
309  } else {
310  calculate_derived("temp", vars_new[lev_for_sub][Vars::cons], derived::erf_dertemp);
311  }
312  calculate_derived("theta", vars_new[lev_for_sub][Vars::cons], derived::erf_dertheta);
313  calculate_derived("KE", vars_new[lev_for_sub][Vars::cons], derived::erf_derKE);
314  calculate_derived("scalar", vars_new[lev_for_sub][Vars::cons], derived::erf_derscalar);
315  calculate_derived("soundspeed", vars_new[lev_for_sub][Vars::cons], derived::erf_dersoundspeed);
316  if (solverChoice.moisture_type != MoistureType::None) {
317  calculate_derived("precipitable", vars_new[lev_for_sub][Vars::cons], derived::erf_derprecipitable);
318  calculate_derived("mucape", vars_new[lev_for_sub][Vars::cons], derived::erf_dermucape);
319  }
320 
321  // *****************************************************************************************
322 
323  Real time = t_new[lev_for_sub];
324 
325  std::string sf = subvol_file + "_" + std::to_string(isub);
326  std::string subvol_filename;
327 
329  const std::string dt_format = "%Y-%m-%d_%H:%M:%S"; // ISO 8601 standard
330  subvol_filename = sf + getTimestamp(start_time+time, dt_format);
331  } else {
332  subvol_filename = Concatenate(sf + "_", istep[0], file_name_digits);
333  }
334 
335  amrex::Print() <<"Writing subvolume into " << subvol_filename << std::endl;
336  WriteSingleLevelPlotfile(subvol_filename,mf,varnames,geom[lev_for_sub],time,istep[0]);
337 
338 }
real(c_double), private cs
Definition: ERF_module_mp_morr_two_moment.F90:203

Referenced by EvolveOneStep().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ WriteVTKPolyline()

void ERF::WriteVTKPolyline ( const std::string &  filename,
amrex::Vector< std::array< amrex::Real, 2 >> &  points_xy 
)
96 {
97  std::ofstream vtkfile(filename);
98  if (!vtkfile.is_open()) {
99  std::cerr << "Error: Cannot open file " << filename << std::endl;
100  return;
101  }
102 
103  int num_points = points_xy.size();
104  if (num_points == 0) {
105  vtkfile << "# vtk DataFile Version three\n";
106  vtkfile << "Storm Track\n";
107  vtkfile << "ASCII\n";
108  vtkfile << "DATASET POLYDATA\n";
109  vtkfile << "POINTS " << num_points << " float\n";
110  vtkfile.close();
111  return;
112  }
113  if (num_points < 2) {
114  points_xy.push_back(points_xy[0]);
115  }
116  num_points = points_xy.size();
117 
118  vtkfile << "# vtk DataFile Version three\n";
119  vtkfile << "Storm Track\n";
120  vtkfile << "ASCII\n";
121  vtkfile << "DATASET POLYDATA\n";
122 
123  // Write points (Z=0 assumed)
124  vtkfile << "POINTS " << num_points << " float\n";
125  for (const auto& pt : points_xy) {
126  vtkfile << pt[0] << " " << pt[1] << " Real(10000.0)\n";
127  }
128 
129  // Write polyline connectivity
130  vtkfile << "LINES 1 " << num_points + 1 << "\n";
131  vtkfile << num_points << " ";
132  for (int i = 0; i < num_points; ++i) {
133  vtkfile << i << " ";
134  }
135  vtkfile << "\n";
136 
137  vtkfile.close();
138 }

Member Data Documentation

◆ advflux_reg

amrex::Vector<amrex::YAFluxRegister*> ERF::advflux_reg
private

Referenced by getAdvFluxReg().

◆ avg_xmom

amrex::Vector<amrex::MultiFab> ERF::avg_xmom
private

◆ avg_ymom

amrex::Vector<amrex::MultiFab> ERF::avg_ymom
private

◆ avg_zmom

amrex::Vector<amrex::MultiFab> ERF::avg_zmom
private

◆ ax

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::ax
private

◆ ax_src

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::ax_src
private

◆ ay

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::ay
private

◆ ay_src

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::ay_src
private

◆ az

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::az
private

◆ az_src

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::az_src
private

◆ ba1d

amrex::Vector<amrex::BoxArray> ERF::ba1d
private

◆ ba2d

amrex::Vector<amrex::BoxArray> ERF::ba2d
private

Referenced by PackAtmosphericStates().

◆ base_state

amrex::Vector<amrex::MultiFab> ERF::base_state
private

◆ base_state_new

amrex::Vector<amrex::MultiFab> ERF::base_state_new
private

◆ bckgnd_state

amrex::Vector<amrex::Vector<amrex::MultiFab> > ERF::bckgnd_state

◆ bndry_output_planes_interval

int ERF::bndry_output_planes_interval = -1
staticprivate

◆ bndry_output_planes_per

Real ERF::bndry_output_planes_per = -one
staticprivate

◆ bndry_output_planes_start_time

Real ERF::bndry_output_planes_start_time = zero
staticprivate

◆ boxes_at_level

amrex::Vector<amrex::Vector<amrex::Box> > ERF::boxes_at_level
private

◆ cf_set_width

int ERF::cf_set_width {0}
private

◆ cf_width

int ERF::cf_width {0}
private

◆ cfl

Real ERF::cfl = Real(0.8)
staticprivate

◆ change_max

Real ERF::change_max = Real(1.1)
staticprivate

◆ check_file

std::string ERF::check_file {"chk"}
private

◆ check_for_nans

int ERF::check_for_nans = 0
staticprivate

◆ column_file_name

std::string ERF::column_file_name = "column_data.nc"
staticprivate

◆ column_interval

int ERF::column_interval = -1
staticprivate

◆ column_loc_x

Real ERF::column_loc_x = zero
staticprivate

◆ column_loc_y

Real ERF::column_loc_y = zero
staticprivate

◆ column_per

Real ERF::column_per = -one
staticprivate

◆ cons_names

const amrex::Vector<std::string> ERF::cons_names
private
Initial value:
{"density", "rhotheta", "rhoKE", "rhoadv_0",
"rhoQ1", "rhoQ2", "rhoQ3",
"rhoQ4", "rhoQ5", "rhoQ6",
"rhoQ7", "rhoQ8", "rhoQ9",
"rhoQ10", "rhoQ11"}

◆ cosPhi_m

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::cosPhi_m
private

◆ d_havg_density

amrex::Gpu::DeviceVector<amrex::Real> ERF::d_havg_density
private

◆ d_havg_pressure

amrex::Gpu::DeviceVector<amrex::Real> ERF::d_havg_pressure
private

◆ d_havg_qc

amrex::Gpu::DeviceVector<amrex::Real> ERF::d_havg_qc
private

◆ d_havg_qv

amrex::Gpu::DeviceVector<amrex::Real> ERF::d_havg_qv
private

◆ d_havg_temperature

amrex::Gpu::DeviceVector<amrex::Real> ERF::d_havg_temperature
private

◆ d_rayleigh_ptrs

amrex::Vector<amrex::Vector<amrex::Gpu::DeviceVector<amrex::Real> > > ERF::d_rayleigh_ptrs
private

◆ d_sinesq_ptrs

amrex::Vector<amrex::Gpu::DeviceVector<amrex::Real> > ERF::d_sinesq_ptrs
private

◆ d_sinesq_stag_ptrs

amrex::Vector<amrex::Gpu::DeviceVector<amrex::Real> > ERF::d_sinesq_stag_ptrs
private

◆ d_sponge_ptrs

amrex::Vector<amrex::Vector<amrex::Gpu::DeviceVector<amrex::Real> > > ERF::d_sponge_ptrs
private

◆ d_u_geos

amrex::Vector<amrex::Gpu::DeviceVector<amrex::Real> > ERF::d_u_geos
private

◆ d_v_geos

amrex::Vector<amrex::Gpu::DeviceVector<amrex::Real> > ERF::d_v_geos
private

◆ d_w_subsid

amrex::Vector<amrex::Gpu::DeviceVector<amrex::Real> > ERF::d_w_subsid
private

◆ datalog

amrex::Vector<std::unique_ptr<std::fstream> > ERF::datalog
private

◆ datalogname

amrex::Vector<std::string> ERF::datalogname
private

Referenced by DataLogName().

◆ datetime_format

const std::string ERF::datetime_format = "%Y-%m-%d %H:%M:%S"
private

◆ datprecision

const int ERF::datprecision = 6
private

◆ datwidth

const int ERF::datwidth = 14
private

◆ der_datalog

amrex::Vector<std::unique_ptr<std::fstream> > ERF::der_datalog
private

◆ der_datalogname

amrex::Vector<std::string> ERF::der_datalogname
private

Referenced by DerDataLogName().

◆ derived_names

const amrex::Vector<std::string> ERF::derived_names
private

◆ derived_names_2d

const amrex::Vector<std::string> ERF::derived_names_2d
private
Initial value:
{
"z_surf", "landmask", "mapfac", "lat_m", "lon_m",
"u_star", "w_star", "t_star", "q_star", "Olen", "pblh",
"t_surf", "q_surf", "z0", "OLR", "sens_flux", "laten_flux",
"surf_pres", "integrated_qv"
}

◆ derived_subvol_names

const amrex::Vector<std::string> ERF::derived_subvol_names {"soundspeed", "temp", "theta", "KE", "scalar"}
private

◆ destag_profiles

bool ERF::destag_profiles = true
private

◆ detJ_cc

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::detJ_cc
private

◆ detJ_cc_new

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::detJ_cc_new
private

◆ detJ_cc_src

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::detJ_cc_src
private

◆ domain_bc_type

amrex::Array<std::string,2*AMREX_SPACEDIM> ERF::domain_bc_type
private

◆ domain_bcs_type

amrex::Vector<amrex::BCRec> ERF::domain_bcs_type
private

◆ domain_bcs_type_d

amrex::Gpu::DeviceVector<amrex::BCRec> ERF::domain_bcs_type_d
private

◆ dt

amrex::Vector<amrex::Real> ERF::dt
private

Referenced by EvolveOneStep().

◆ dt_max

Real ERF::dt_max = Real(1.0e9)
staticprivate

◆ dt_max_initial

Real ERF::dt_max_initial = Real(2.0e100)
staticprivate

◆ dt_mri_ratio

amrex::Vector<long> ERF::dt_mri_ratio
private

◆ dz_min

amrex::Vector<amrex::Real> ERF::dz_min
private

◆ eb

amrex::Vector<std::unique_ptr<eb_> > ERF::eb
private

Referenced by EBFactory(), and get_eb().

◆ eddyDiffs_lev

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::eddyDiffs_lev
private

◆ file_name_digits

int ERF::file_name_digits = 5
private

◆ fine_mask

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::fine_mask
private

◆ finished_wave

bool ERF::finished_wave = false
private

◆ fixed_dt

amrex::Vector<amrex::Real> ERF::fixed_dt
private

◆ fixed_fast_dt

amrex::Vector<amrex::Real> ERF::fixed_fast_dt
private

◆ fixed_mri_dt_ratio

int ERF::fixed_mri_dt_ratio = 0
staticprivate

◆ forecast_state_1

amrex::Vector<amrex::Vector<amrex::MultiFab> > ERF::forecast_state_1

◆ forecast_state_2

amrex::Vector<amrex::Vector<amrex::MultiFab> > ERF::forecast_state_2

◆ forecast_state_interp

amrex::Vector<amrex::Vector<amrex::MultiFab> > ERF::forecast_state_interp

◆ FPr_c

amrex::Vector<ERFFillPatcher> ERF::FPr_c
private

◆ FPr_u

amrex::Vector<ERFFillPatcher> ERF::FPr_u
private

◆ FPr_v

amrex::Vector<ERFFillPatcher> ERF::FPr_v
private

◆ FPr_w

amrex::Vector<ERFFillPatcher> ERF::FPr_w
private

◆ gradp

amrex::Vector<amrex::Vector<amrex::MultiFab> > ERF::gradp
private

◆ h_havg_density

amrex::Vector<amrex::Real> ERF::h_havg_density
private

◆ h_havg_pressure

amrex::Vector<amrex::Real> ERF::h_havg_pressure
private

◆ h_havg_qc

amrex::Vector<amrex::Real> ERF::h_havg_qc
private

◆ h_havg_qv

amrex::Vector<amrex::Real> ERF::h_havg_qv
private

◆ h_havg_temperature

amrex::Vector<amrex::Real> ERF::h_havg_temperature
private

◆ h_rayleigh_ptrs

amrex::Vector<amrex::Vector<amrex::Vector<amrex::Real> > > ERF::h_rayleigh_ptrs
private

◆ h_sinesq_ptrs

amrex::Vector<amrex::Vector<amrex::Real> > ERF::h_sinesq_ptrs
private

◆ h_sinesq_stag_ptrs

amrex::Vector<amrex::Vector<amrex::Real> > ERF::h_sinesq_stag_ptrs
private

◆ h_sponge_ptrs

amrex::Vector<amrex::Vector<amrex::Vector<amrex::Real> > > ERF::h_sponge_ptrs
private

◆ h_u_geos

amrex::Vector< amrex::Vector<amrex::Real> > ERF::h_u_geos
private

◆ h_v_geos

amrex::Vector< amrex::Vector<amrex::Real> > ERF::h_v_geos
private

◆ h_w_subsid

amrex::Vector< amrex::Vector<amrex::Real> > ERF::h_w_subsid
private

◆ have_read_nc_init_file

Vector< Vector< int > > ERF::have_read_nc_init_file = {{0}}
staticprivate

◆ hfx3_EB

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::hfx3_EB
private

◆ hurricane_eye_track_latlon

amrex::Vector<std::array<amrex::Real, 2> > ERF::hurricane_eye_track_latlon

◆ hurricane_eye_track_xy

amrex::Vector<std::array<amrex::Real, 2> > ERF::hurricane_eye_track_xy

◆ hurricane_maxvel_vs_time

amrex::Vector<std::array<amrex::Real, 2> > ERF::hurricane_maxvel_vs_time

◆ hurricane_minpressure_vs_time

amrex::Vector<std::array<amrex::Real, 2> > ERF::hurricane_minpressure_vs_time

◆ hurricane_track_xy

amrex::Vector<std::array<amrex::Real, 2> > ERF::hurricane_track_xy

◆ hurricane_tracker_circle

amrex::Vector<std::array<amrex::Real, 2> > ERF::hurricane_tracker_circle

◆ Hwave

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::Hwave
private

◆ Hwave_onegrid

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::Hwave_onegrid
private

◆ init_shrink

Real ERF::init_shrink = one
staticprivate

◆ input_bndry_planes

int ERF::input_bndry_planes = 0
staticprivate

◆ input_sounding_data

InputSoundingData ERF::input_sounding_data
private

◆ input_sponge_data

InputSpongeData ERF::input_sponge_data
private

◆ interpolation_type

StateInterpType ERF::interpolation_type
staticprivate

◆ istep

amrex::Vector<int> ERF::istep
private

Referenced by EvolveOneStep().

◆ lagged_delta_rt

amrex::Vector<amrex::MultiFab> ERF::lagged_delta_rt
private

◆ land_type_lev

amrex::Vector<amrex::Vector<std::unique_ptr<amrex::iMultiFab> > > ERF::land_type_lev
private

◆ last_check_file_step

int ERF::last_check_file_step = -1
staticprivate

Referenced by EvolveOneStep().

◆ last_check_file_time

Real ERF::last_check_file_time = zero
staticprivate

Referenced by EvolveOneStep().

◆ last_plot2d_file_step_1

int ERF::last_plot2d_file_step_1 = -1
staticprivate

Referenced by EvolveOneStep().

◆ last_plot2d_file_step_2

int ERF::last_plot2d_file_step_2 = -1
staticprivate

Referenced by EvolveOneStep().

◆ last_plot2d_file_time_1

Real ERF::last_plot2d_file_time_1 = zero
staticprivate

Referenced by EvolveOneStep().

◆ last_plot2d_file_time_2

Real ERF::last_plot2d_file_time_2 = zero
staticprivate

Referenced by EvolveOneStep().

◆ last_plot3d_file_step_1

int ERF::last_plot3d_file_step_1 = -1
staticprivate

Referenced by EvolveOneStep().

◆ last_plot3d_file_step_2

int ERF::last_plot3d_file_step_2 = -1
staticprivate

Referenced by EvolveOneStep().

◆ last_plot3d_file_time_1

Real ERF::last_plot3d_file_time_1 = zero
staticprivate

Referenced by EvolveOneStep().

◆ last_plot3d_file_time_2

Real ERF::last_plot3d_file_time_2 = zero
staticprivate

Referenced by EvolveOneStep().

◆ last_subvol_step

amrex::Vector<int> ERF::last_subvol_step
private

Referenced by EvolveOneStep().

◆ last_subvol_time

amrex::Vector<amrex::Real> ERF::last_subvol_time
private

Referenced by EvolveOneStep().

◆ lat_m

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::lat_m
private

◆ line_sampler

std::unique_ptr<LineSampler> ERF::line_sampler = nullptr
private

◆ line_sampling_interval

int ERF::line_sampling_interval = -1
private

◆ line_sampling_per

amrex::Real ERF::line_sampling_per = -one
private

◆ lmask_lev

amrex::Vector<amrex::Vector<std::unique_ptr<amrex::iMultiFab> > > ERF::lmask_lev
private

◆ lon_m

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::lon_m
private

◆ lsm

LandSurface ERF::lsm
private

◆ lsm_data

amrex::Vector<amrex::Vector<amrex::MultiFab*> > ERF::lsm_data
private

◆ lsm_data_name

amrex::Vector<std::string> ERF::lsm_data_name
private

◆ lsm_flux

amrex::Vector<amrex::Vector<amrex::MultiFab*> > ERF::lsm_flux
private

◆ lsm_flux_name

amrex::Vector<std::string> ERF::lsm_flux_name
private

◆ Lwave

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::Lwave
private

◆ Lwave_onegrid

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::Lwave_onegrid
private

◆ m_bc_extdir_vals

amrex::Array<amrex::Array<amrex::Real, AMREX_SPACEDIM*2>, AMREX_SPACEDIM+NBCVAR_max> ERF::m_bc_extdir_vals
private

◆ m_bc_neumann_vals

amrex::Array<amrex::Array<amrex::Real, AMREX_SPACEDIM*2>, AMREX_SPACEDIM+NBCVAR_max> ERF::m_bc_neumann_vals
private

◆ m_bc_nonreflecting

amrex::Array<bool, AMREX_SPACEDIM*2> ERF::m_bc_nonreflecting = {{false}}
private

◆ m_check_int

int ERF::m_check_int = -1
private

Referenced by EvolveOneStep().

◆ m_check_per

amrex::Real ERF::m_check_per = -one
private

Referenced by EvolveOneStep().

◆ m_expand_plotvars_to_unif_rr

bool ERF::m_expand_plotvars_to_unif_rr = false
private

◆ m_forest_drag

amrex::Vector<std::unique_ptr<ForestDrag> > ERF::m_forest_drag
private

◆ m_plot2d_int_1

int ERF::m_plot2d_int_1 = -1
private

Referenced by EvolveOneStep().

◆ m_plot2d_int_2

int ERF::m_plot2d_int_2 = -1
private

Referenced by EvolveOneStep().

◆ m_plot2d_per_1

amrex::Real ERF::m_plot2d_per_1 = -one
private

Referenced by EvolveOneStep().

◆ m_plot2d_per_2

amrex::Real ERF::m_plot2d_per_2 = -one
private

Referenced by EvolveOneStep().

◆ m_plot3d_int_1

int ERF::m_plot3d_int_1 = -1
private

Referenced by EvolveOneStep().

◆ m_plot3d_int_2

int ERF::m_plot3d_int_2 = -1
private

Referenced by EvolveOneStep().

◆ m_plot3d_per_1

amrex::Real ERF::m_plot3d_per_1 = -one
private

Referenced by EvolveOneStep().

◆ m_plot3d_per_2

amrex::Real ERF::m_plot3d_per_2 = -one
private

Referenced by EvolveOneStep().

◆ m_plot_face_vels

bool ERF::m_plot_face_vels = false
private

◆ m_r2d

std::unique_ptr<ReadBndryPlanes> ERF::m_r2d = nullptr
private

◆ m_subvol_int

amrex::Vector<int> ERF::m_subvol_int
private

Referenced by EvolveOneStep().

◆ m_subvol_per

amrex::Vector<amrex::Real> ERF::m_subvol_per
private

Referenced by EvolveOneStep().

◆ m_SurfaceLayer

std::unique_ptr<SurfaceLayer> ERF::m_SurfaceLayer = nullptr
private

◆ m_w2d

std::unique_ptr<WriteBndryPlanes> ERF::m_w2d = nullptr
private

◆ mapfac

amrex::Vector<amrex::Vector<std::unique_ptr<amrex::MultiFab> > > ERF::mapfac
private

◆ max_step

int ERF::max_step = -1
private

◆ metgrid_basic_linear

bool ERF::metgrid_basic_linear {false}
private

◆ metgrid_debug_dry

bool ERF::metgrid_debug_dry {false}
private

◆ metgrid_debug_isothermal

bool ERF::metgrid_debug_isothermal {false}
private

◆ metgrid_debug_msf

bool ERF::metgrid_debug_msf {false}
private

◆ metgrid_debug_psfc

bool ERF::metgrid_debug_psfc {false}
private

◆ metgrid_debug_quiescent

bool ERF::metgrid_debug_quiescent {false}
private

◆ metgrid_force_sfc_k

int ERF::metgrid_force_sfc_k {6}
private

◆ metgrid_interp_theta

bool ERF::metgrid_interp_theta {false}
private

◆ metgrid_order

int ERF::metgrid_order {2}
private

◆ metgrid_proximity

amrex::Real ERF::metgrid_proximity {amrex::Real(500.0)}
private

◆ metgrid_retain_sfc

bool ERF::metgrid_retain_sfc {false}
private

◆ metgrid_use_below_sfc

bool ERF::metgrid_use_below_sfc {true}
private

◆ metgrid_use_sfc

bool ERF::metgrid_use_sfc {true}
private

◆ mf_PSFC

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::mf_PSFC
private

◆ mg_verbose

int ERF::mg_verbose = 0
staticprivate

◆ micro

std::unique_ptr<Microphysics> ERF::micro
private

◆ mri_integrator_mem

amrex::Vector<std::unique_ptr<MRISplitIntegrator<amrex::Vector<amrex::MultiFab> > > > ERF::mri_integrator_mem
private

◆ nc_bdy_file

std::string ERF::nc_bdy_file
staticprivate

◆ nc_init_file

Vector< Vector< std::string > > ERF::nc_init_file = {{""}}
staticprivate

◆ nc_low_file

std::string ERF::nc_low_file
staticprivate

◆ ng_dens_hse

int ERF::ng_dens_hse
staticprivate

◆ ng_pres_hse

int ERF::ng_pres_hse
staticprivate

◆ nsubsteps

amrex::Vector<int> ERF::nsubsteps
private

◆ num_boxes_at_level

amrex::Vector<int> ERF::num_boxes_at_level
private

◆ num_files_at_level

amrex::Vector<int> ERF::num_files_at_level
private

◆ output_1d_column

int ERF::output_1d_column = 0
staticprivate

◆ output_bndry_planes

int ERF::output_bndry_planes = 0
staticprivate

◆ pert_interval

int ERF::pert_interval = -1
staticprivate

◆ phys_bc_type

amrex::GpuArray<ERF_BC, AMREX_SPACEDIM*2> ERF::phys_bc_type
private

◆ physbcs_base

amrex::Vector<std::unique_ptr<ERFPhysBCFunct_base> > ERF::physbcs_base
private

◆ physbcs_cons

amrex::Vector<std::unique_ptr<ERFPhysBCFunct_cons> > ERF::physbcs_cons
private

◆ physbcs_u

amrex::Vector<std::unique_ptr<ERFPhysBCFunct_u> > ERF::physbcs_u
private

◆ physbcs_v

amrex::Vector<std::unique_ptr<ERFPhysBCFunct_v> > ERF::physbcs_v
private

◆ physbcs_w

amrex::Vector<std::unique_ptr<ERFPhysBCFunct_w> > ERF::physbcs_w
private

◆ plane_sampler

std::unique_ptr<PlaneSampler> ERF::plane_sampler = nullptr
private

◆ plane_sampling_interval

int ERF::plane_sampling_interval = -1
private

◆ plane_sampling_per

amrex::Real ERF::plane_sampling_per = -one
private

◆ plot2d_file_1

std::string ERF::plot2d_file_1 {"plt2d_1_"}
private

◆ plot2d_file_2

std::string ERF::plot2d_file_2 {"plt2d_2_"}
private

◆ plot2d_var_names_1

amrex::Vector<std::string> ERF::plot2d_var_names_1
private

Referenced by EvolveOneStep().

◆ plot2d_var_names_2

amrex::Vector<std::string> ERF::plot2d_var_names_2
private

Referenced by EvolveOneStep().

◆ plot3d_file_1

std::string ERF::plot3d_file_1 {"plt_1_"}
private

◆ plot3d_file_2

std::string ERF::plot3d_file_2 {"plt_2_"}
private

◆ plot3d_var_names_1

amrex::Vector<std::string> ERF::plot3d_var_names_1
private

Referenced by EvolveOneStep().

◆ plot3d_var_names_2

amrex::Vector<std::string> ERF::plot3d_var_names_2
private

Referenced by EvolveOneStep().

◆ plot_file_on_restart

bool ERF::plot_file_on_restart = true
staticprivate

◆ plot_lsm

bool ERF::plot_lsm = false
private

◆ plot_rad

bool ERF::plot_rad = false
private

◆ plotfile2d_type_1

PlotFileType ERF::plotfile2d_type_1 = PlotFileType::None
staticprivate

Referenced by EvolveOneStep().

◆ plotfile2d_type_2

PlotFileType ERF::plotfile2d_type_2 = PlotFileType::None
staticprivate

Referenced by EvolveOneStep().

◆ plotfile3d_type_1

PlotFileType ERF::plotfile3d_type_1 = PlotFileType::None
staticprivate

Referenced by EvolveOneStep().

◆ plotfile3d_type_2

PlotFileType ERF::plotfile3d_type_2 = PlotFileType::None
staticprivate

Referenced by EvolveOneStep().

◆ pp_inc

amrex::Vector<amrex::MultiFab> ERF::pp_inc
private

◆ pp_prefix

std::string ERF::pp_prefix {"erf"}

◆ previousCPUTimeUsed

Real ERF::previousCPUTimeUsed = zero
staticprivate

Referenced by getCPUTime().

◆ prob

std::unique_ptr<ProblemBase> ERF::prob = nullptr
private

◆ profile_int

int ERF::profile_int = -1
private

◆ qfx3_EB

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::qfx3_EB
private

◆ qheating_rates

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::qheating_rates
private

◆ qmoist

amrex::Vector<amrex::Vector<amrex::MultiFab*> > ERF::qmoist
private

◆ Qr_prim

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::Qr_prim
private

◆ Qv_prim

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::Qv_prim
private

◆ rad

amrex::Vector<std::unique_ptr<IRadiation> > ERF::rad
private

◆ rad_datalog_int

int ERF::rad_datalog_int = -1
private

◆ rad_fluxes

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::rad_fluxes
private

Referenced by PackAtmosphericStates().

◆ real_extrap_w

bool ERF::real_extrap_w {true}
private

◆ real_width

int ERF::real_width {0}
private

◆ ref_tags

Vector< AMRErrorTag > ERF::ref_tags
staticprivate

◆ regrid_int

int ERF::regrid_int = -1
private

◆ regrid_level_0_on_restart

bool ERF::regrid_level_0_on_restart = false
private

◆ restart_chkfile

std::string ERF::restart_chkfile = ""
private

◆ rhoqt_src

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::rhoqt_src
private

◆ rhotheta_src

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::rhotheta_src
private

◆ rU_new

amrex::Vector<amrex::MultiFab> ERF::rU_new
private

◆ rU_old

amrex::Vector<amrex::MultiFab> ERF::rU_old
private

◆ rV_new

amrex::Vector<amrex::MultiFab> ERF::rV_new
private

◆ rV_old

amrex::Vector<amrex::MultiFab> ERF::rV_old
private

◆ rW_new

amrex::Vector<amrex::MultiFab> ERF::rW_new
private

◆ rW_old

amrex::Vector<amrex::MultiFab> ERF::rW_old
private

◆ sampleline

amrex::Vector<amrex::IntVect> ERF::sampleline
private

Referenced by NumSampleLines(), and SampleLine().

◆ samplelinelog

amrex::Vector<std::unique_ptr<std::fstream> > ERF::samplelinelog
private

◆ samplelinelogname

amrex::Vector<std::string> ERF::samplelinelogname
private

Referenced by SampleLineLogName().

◆ samplepoint

amrex::Vector<amrex::IntVect> ERF::samplepoint
private

Referenced by NumSamplePoints(), and SamplePoint().

◆ sampleptlog

amrex::Vector<std::unique_ptr<std::fstream> > ERF::sampleptlog
private

◆ sampleptlogname

amrex::Vector<std::string> ERF::sampleptlogname
private

Referenced by SamplePointLogName().

◆ SFS_diss_lev

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::SFS_diss_lev
private

◆ SFS_hfx1_lev

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::SFS_hfx1_lev
private

◆ SFS_hfx2_lev

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::SFS_hfx2_lev
private

◆ SFS_hfx3_lev

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::SFS_hfx3_lev
private

◆ SFS_q1fx1_lev

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::SFS_q1fx1_lev
private

◆ SFS_q1fx2_lev

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::SFS_q1fx2_lev
private

◆ SFS_q1fx3_lev

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::SFS_q1fx3_lev
private

◆ SFS_q2fx3_lev

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::SFS_q2fx3_lev
private

◆ sinPhi_m

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::sinPhi_m
private

◆ SmnSmn_lev

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::SmnSmn_lev
private

◆ soil_type_lev

amrex::Vector<amrex::Vector<std::unique_ptr<amrex::iMultiFab> > > ERF::soil_type_lev
private

◆ solverChoice

SolverChoice ERF::solverChoice
staticprivate

◆ sst_lev

amrex::Vector<amrex::Vector<std::unique_ptr<amrex::MultiFab> > > ERF::sst_lev
private

◆ start_time

Real ERF::start_time = zero
staticprivate

Referenced by EvolveOneStep().

◆ startCPUTime

Real ERF::startCPUTime = zero
staticprivate

Referenced by getCPUTime().

◆ stop_time

Real ERF::stop_time = std::numeric_limits<amrex::Real>::max()
staticprivate

Referenced by EvolveOneStep().

◆ stretched_dz_d

amrex::Vector<amrex::Gpu::DeviceVector<amrex::Real> > ERF::stretched_dz_d
private

◆ stretched_dz_h

amrex::Vector<amrex::Vector<amrex::Real> > ERF::stretched_dz_h
private

◆ sub_cfl

Real ERF::sub_cfl = one
staticprivate

◆ subdomains

amrex::Vector<amrex::Vector<amrex::BoxArray> > ERF::subdomains
private

◆ subvol3d_var_names

amrex::Vector<std::string> ERF::subvol3d_var_names
private

Referenced by EvolveOneStep().

◆ subvol_file

std::string ERF::subvol_file {"subvol"}
private

◆ sum_interval

int ERF::sum_interval = -1
staticprivate

◆ sum_per

Real ERF::sum_per = -one
staticprivate

◆ surface_state_1

amrex::Vector<amrex::MultiFab> ERF::surface_state_1

◆ surface_state_2

amrex::Vector<amrex::MultiFab> ERF::surface_state_2

◆ surface_state_interp

amrex::Vector<amrex::MultiFab> ERF::surface_state_interp

◆ t_avg_cnt

amrex::Vector<amrex::Real> ERF::t_avg_cnt
private

◆ t_new

amrex::Vector<amrex::Real> ERF::t_new
private

Referenced by EvolveOneStep().

◆ t_old

amrex::Vector<amrex::Real> ERF::t_old
private

◆ Tau

amrex::Vector<amrex::Vector<std::unique_ptr<amrex::MultiFab> > > ERF::Tau
private

◆ Tau_corr

amrex::Vector<amrex::Vector<std::unique_ptr<amrex::MultiFab> > > ERF::Tau_corr
private

◆ Tau_EB

amrex::Vector<amrex::Vector<amrex::Vector<std::unique_ptr<amrex::MultiFab> > > > ERF::Tau_EB
private

◆ terrain_blanking

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::terrain_blanking
private

◆ th_bc_data

amrex::Vector<amrex::Gpu::DeviceVector<amrex::Real> > ERF::th_bc_data
private

◆ Theta_prim

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::Theta_prim
private

◆ thin_xforce

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::thin_xforce
private

◆ thin_yforce

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::thin_yforce
private

◆ thin_zforce

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::thin_zforce
private

◆ timeprecision

const int ERF::timeprecision = 13
private

◆ tot_e_datalog

amrex::Vector<std::unique_ptr<std::fstream> > ERF::tot_e_datalog
private

Referenced by setRecordEnergyDataInfo().

◆ tot_e_datalogname

amrex::Vector<std::string> ERF::tot_e_datalogname
private

◆ tsk_lev

amrex::Vector<amrex::Vector<std::unique_ptr<amrex::MultiFab> > > ERF::tsk_lev
private

◆ turbPert

TurbulentPerturbation ERF::turbPert
private

◆ urb_frac_lev

amrex::Vector<amrex::Vector<std::unique_ptr<amrex::MultiFab> > > ERF::urb_frac_lev
private

◆ use_datetime

bool ERF::use_datetime = false
private

◆ use_fft

bool ERF::use_fft = false
staticprivate

◆ use_real_time_in_pltname

bool ERF::use_real_time_in_pltname = false
private

◆ vars_new

amrex::Vector<amrex::Vector<amrex::MultiFab> > ERF::vars_new
private

Referenced by PackAtmosphericStates().

◆ vars_old

amrex::Vector<amrex::Vector<amrex::MultiFab> > ERF::vars_old
private

◆ vel_t_avg

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::vel_t_avg
private

◆ verbose

int ERF::verbose = 0
staticprivate

◆ walldist

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::walldist
private

◆ weather_forecast_data_1

amrex::Vector<amrex::MultiFab> ERF::weather_forecast_data_1

◆ weather_forecast_data_2

amrex::Vector<amrex::MultiFab> ERF::weather_forecast_data_2

◆ wrf_C1H

std::unique_ptr<amrex::MultiFab> ERF::wrf_C1H
private

◆ wrf_C2H

std::unique_ptr<amrex::MultiFab> ERF::wrf_C2H
private

◆ wrf_MUB

std::unique_ptr<amrex::MultiFab> ERF::wrf_MUB
private

◆ wrf_PHB

std::unique_ptr<amrex::MultiFab> ERF::wrf_PHB
private

◆ xflux_imask

amrex::Vector<std::unique_ptr<amrex::iMultiFab> > ERF::xflux_imask
private

◆ xvel_bc_data

amrex::Vector<amrex::Gpu::DeviceVector<amrex::Real> > ERF::xvel_bc_data
private

◆ yflux_imask

amrex::Vector<std::unique_ptr<amrex::iMultiFab> > ERF::yflux_imask
private

◆ yvel_bc_data

amrex::Vector<amrex::Gpu::DeviceVector<amrex::Real> > ERF::yvel_bc_data
private

◆ z_phys_cc

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::z_phys_cc
private

◆ z_phys_cc_src

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::z_phys_cc_src
private

◆ z_phys_nd

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::z_phys_nd
private

◆ z_phys_nd_new

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::z_phys_nd_new
private

◆ z_phys_nd_src

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::z_phys_nd_src
private

◆ z_t_rk

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::z_t_rk
private

◆ zflux_imask

amrex::Vector<std::unique_ptr<amrex::iMultiFab> > ERF::zflux_imask
private

◆ zlevels_stag

amrex::Vector<amrex::Vector<amrex::Real> > ERF::zlevels_stag
private

◆ zmom_crse_rhs

amrex::Vector<amrex::MultiFab> ERF::zmom_crse_rhs
private

◆ zvel_bc_data

amrex::Vector<amrex::Gpu::DeviceVector<amrex::Real> > ERF::zvel_bc_data
private

The documentation for this class was generated from the following files: