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 ()
 
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)
 
bool writeNow (const amrex::Real 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, amrex::Real time, amrex::Real dt_lev)
 
void sum_integrated_quantities (amrex::Real time)
 
void sum_derived_quantities (amrex::Real time)
 
void sum_energy_quantities (amrex::Real time)
 
void write_1D_profiles (amrex::Real time)
 
void write_1D_profiles_stag (amrex::Real time)
 
amrex::Real cloud_fraction (amrex::Real time)
 
void FillBdyCCVels (amrex::Vector< amrex::MultiFab > &mf_cc_vel, int levc=0)
 
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 (amrex::Real 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 (amrex::Real 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 &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_random_perturbations (const int lev, amrex::MultiFab &cons_pert, amrex::MultiFab &xvel_pert, amrex::MultiFab &yvel_pert, amrex::MultiFab &zvel_pert)
 
void apply_gaussian_smoothing_to_perturbations (const int lev, amrex::MultiFab &cons_pert, amrex::MultiFab &xvel_pert, amrex::MultiFab &yvel_pert, amrex::MultiFab &zvel_pert)
 
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)
 
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, amrex::Real 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
 
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_custom (int lev)
 
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, amrex::Real time, const amrex::Vector< amrex::MultiFab * > &mfs_vel, bool cons_only=false)
 
void FillPatchFineLevel (int lev, amrex::Real 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, amrex::Real 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)
 
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::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::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 = -1.0
 
amrex::Real m_plot3d_per_2 = -1.0
 
amrex::Real m_plot2d_per_1 = -1.0
 
amrex::Real m_plot2d_per_2 = -1.0
 
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 = -1.0
 
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 {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 > mf_C1H
 
std::unique_ptr< amrex::MultiFab > mf_C2H
 
std::unique_ptr< amrex::MultiFab > mf_MUB
 
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 = -1.0
 
amrex::Real plane_sampling_per = -1.0
 
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 = 0.0
 
static amrex::Real last_plot3d_file_time_2 = 0.0
 
static amrex::Real last_plot2d_file_time_1 = 0.0
 
static amrex::Real last_plot2d_file_time_2 = 0.0
 
static amrex::Real last_check_file_time = 0.0
 
static bool plot_file_on_restart = true
 
static amrex::Real start_time = 0.0
 
static amrex::Real stop_time = std::numeric_limits<amrex::Real>::max()
 
static amrex::Real cfl = 0.8
 
static amrex::Real sub_cfl = 1.0
 
static amrex::Real init_shrink = 1.0
 
static amrex::Real change_max = 1.1
 
static amrex::Real dt_max_initial = 2.0e100
 
static amrex::Real dt_max = 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 = -1.0
 
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 std::string sponge_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 = -1.0
 
static amrex::Real column_loc_x = 0.0
 
static amrex::Real column_loc_y = 0.0
 
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 = -1.0
 
static amrex::Real bndry_output_planes_start_time = 0.0
 
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 = 0.0
 
static amrex::Real previousCPUTimeUsed = 0.0
 

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(1.e34,U_new.nGrowVect());
41  V_new.setVal(1.e34,V_new.nGrowVect());
42  W_new.setVal(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(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
72  if (solverChoice.pert_type == PerturbationType::Source ||
73  solverChoice.pert_type == PerturbationType::Direct ||
74  solverChoice.pert_type == PerturbationType::CPM)
75  {
76  turbPert.calc_tpi_update(lev, dt_lev, U_old, V_old, S_old);
77  }
78 
79  // If PerturbationType::Direct or CPM is selected, directly add the computed perturbation
80  // on the conserved field
81  if (solverChoice.pert_type == PerturbationType::Direct ||
82  solverChoice.pert_type == PerturbationType::CPM)
83  {
84  auto m_ixtype = S_old.boxArray().ixType(); // Conserved term
85  for (MFIter mfi(S_old,TileNoZ()); mfi.isValid(); ++mfi) {
86  Box bx = mfi.tilebox();
87  const Array4<Real> &cell_data = S_old.array(mfi);
88  const Array4<const Real> &pert_cell = turbPert.pb_cell[lev].array(mfi);
89  turbPert.apply_tpi(lev, bx, RhoTheta_comp, m_ixtype, cell_data, pert_cell);
90  }
91  }
92 
93  // configure SurfaceLayer params if needed
94  if (phys_bc_type[Orientation(Direction::z,Orientation::low)] == ERF_BC::surface_layer) {
95  if (m_SurfaceLayer) {
96  IntVect ng = Theta_prim[lev]->nGrowVect();
97  MultiFab::Copy( *Theta_prim[lev], S_old, RhoTheta_comp, 0, 1, ng);
98  MultiFab::Divide(*Theta_prim[lev], S_old, Rho_comp , 0, 1, ng);
99  if (solverChoice.moisture_type != MoistureType::None) {
100  ng = Qv_prim[lev]->nGrowVect();
101 
102  MultiFab::Copy( *Qv_prim[lev], S_old, RhoQ1_comp, 0, 1, ng);
103  MultiFab::Divide(*Qv_prim[lev], S_old, Rho_comp , 0, 1, ng);
104 
105  if (solverChoice.moisture_indices.qr > -1) {
106  MultiFab::Copy( *Qr_prim[lev], S_old, solverChoice.moisture_indices.qr, 0, 1, ng);
107  MultiFab::Divide(*Qr_prim[lev], S_old, Rho_comp , 0, 1, ng);
108  } else {
109  Qr_prim[lev]->setVal(0.0);
110  }
111  }
112  // NOTE: std::swap above causes the field ptrs to be out of date.
113  // Reassign the field ptrs for MAC avg computation.
114  m_SurfaceLayer->update_mac_ptrs(lev, vars_old, Theta_prim, Qv_prim, Qr_prim);
115  m_SurfaceLayer->update_pblh(lev, vars_old, z_phys_cc[lev].get(),
117 
118 #ifdef ERF_USE_NETCDF
119  Real elapsed_time_since_start_low = time + (start_time - start_low_time);
120 #else
121  Real elapsed_time_since_start_low = time;
122 #endif
123  m_SurfaceLayer->update_fluxes(lev, elapsed_time_since_start_low,
124  S_old, z_phys_nd[lev], walldist[lev]);
125  }
126  }
127 
128 #if defined(ERF_USE_WINDFARM)
129  // **************************************************************************************
130  // Update the windfarm sources
131  // **************************************************************************************
132  if (solverChoice.windfarm_type != WindFarmType::None) {
133  advance_windfarm(Geom(lev), dt_lev, S_old,
134  U_old, V_old, W_old, vars_windfarm[lev],
135  Nturb[lev], SMark[lev], time);
136  }
137 
138 #endif
139 
140  // **************************************************************************************
141  // Update the radiation sources with the "old" state
142  // **************************************************************************************
143  advance_radiation(lev, S_old, dt_lev);
144 
145 #ifdef ERF_USE_SHOC
146  // **************************************************************************************
147  // Update the "old" state using SHOC
148  // **************************************************************************************
149  if (solverChoice.use_shoc) {
150  // Get SFC fluxes from SurfaceLayer
151  if (m_SurfaceLayer) {
152  Vector<const MultiFab*> mfs = {&S_old, &U_old, &V_old, &W_old};
153  m_SurfaceLayer->impose_SurfaceLayer_bcs(lev, mfs, Tau[lev],
154  SFS_hfx1_lev[lev].get() , SFS_hfx2_lev[lev].get() , SFS_hfx3_lev[lev].get(),
155  SFS_q1fx1_lev[lev].get(), SFS_q1fx2_lev[lev].get(), SFS_q1fx3_lev[lev].get(),
156  z_phys_nd[lev].get());
157  }
158 
159  // Get Shoc tendencies and update the state
160  Real* w_sub = (solverChoice.custom_w_subsidence) ? d_w_subsid[lev].data() : nullptr;
161  compute_shoc_tendencies(lev, &S_old, &U_old, &V_old, &W_old, w_sub,
162  Tau[lev][TauType::tau13].get(), Tau[lev][TauType::tau23].get(),
163  SFS_hfx3_lev[lev].get() , SFS_q1fx3_lev[lev].get() ,
164  eddyDiffs_lev[lev].get() , z_phys_nd[lev].get() ,
165  dt_lev);
166  }
167 #endif
168 
169  const BoxArray& ba = S_old.boxArray();
170  const DistributionMapping& dm = S_old.DistributionMap();
171 
172  int nvars = S_old.nComp();
173 
174  // Source array for conserved cell-centered quantities -- this will be filled
175  // in the call to make_sources in ERF_TI_slow_rhs_pre.H
176  MultiFab cc_source(ba,dm,nvars,1); cc_source.setVal(0.0);
177 
178  // Source arrays for momenta -- these will be filled
179  // in the call to make_mom_sources in ERF_TI_slow_rhs_pre.H
180  BoxArray ba_x(ba); ba_x.surroundingNodes(0);
181  MultiFab xmom_source(ba_x,dm,1,1); xmom_source.setVal(0.0);
182 
183  BoxArray ba_y(ba); ba_y.surroundingNodes(1);
184  MultiFab ymom_source(ba_y,dm,1,1); ymom_source.setVal(0.0);
185 
186  BoxArray ba_z(ba); ba_z.surroundingNodes(2);
187  MultiFab zmom_source(ba_z,dm,1,1); zmom_source.setVal(0.0);
188  MultiFab buoyancy(ba_z,dm,1,1); buoyancy.setVal(0.0);
189 
190  amrex::Vector<MultiFab> state_old;
191  amrex::Vector<MultiFab> state_new;
192 
193  // **************************************************************************************
194  // Here we define state_old and state_new which are to be advanced
195  // **************************************************************************************
196  // Initial solution
197  // Note that "old" and "new" here are relative to each RK stage.
198  state_old.push_back(MultiFab(S_old , amrex::make_alias, 0, nvars)); // cons
199  state_old.push_back(MultiFab(rU_old[lev], amrex::make_alias, 0, 1)); // xmom
200  state_old.push_back(MultiFab(rV_old[lev], amrex::make_alias, 0, 1)); // ymom
201  state_old.push_back(MultiFab(rW_old[lev], amrex::make_alias, 0, 1)); // zmom
202 
203  // Final solution
204  // state_new at the end of the last RK stage holds the t^{n+1} data
205  state_new.push_back(MultiFab(S_new , amrex::make_alias, 0, nvars)); // cons
206  state_new.push_back(MultiFab(rU_new[lev], amrex::make_alias, 0, 1)); // xmom
207  state_new.push_back(MultiFab(rV_new[lev], amrex::make_alias, 0, 1)); // ymom
208  state_new.push_back(MultiFab(rW_new[lev], amrex::make_alias, 0, 1)); // zmom
209 
210  // **************************************************************************************
211  // Tests on the reasonableness of the solution before the dycore
212  // **************************************************************************************
213  // Test for NaNs after dycore
214  if (check_for_nans > 1) {
215  if (verbose > 1) {
216  amrex::Print() << "Testing old state and vels for NaNs before dycore" << std::endl;
217  }
218  check_state_for_nans(S_old);
219  check_vels_for_nans(rU_old[lev],rV_old[lev],rW_old[lev]);
220  }
221 
222  // We only test on low temp if we have a moisture model because we are protecting against
223  // the test on low temp inside the moisture models
224  if (solverChoice.moisture_type != MoistureType::None) {
225  if (verbose > 1) {
226  amrex::Print() << "Testing on low temperature before dycore" << std::endl;
227  }
228  check_for_low_temp(S_old);
229  } else {
230  if (verbose > 1) {
231  amrex::Print() << "Testing on negative temperature before dycore" << std::endl;
232  }
234  }
235 
236  // **************************************************************************************
237  // Update the dycore
238  // **************************************************************************************
239  advance_dycore(lev, state_old, state_new,
240  U_old, V_old, W_old,
241  U_new, V_new, W_new,
242  cc_source, xmom_source, ymom_source, zmom_source, buoyancy,
243  Geom(lev), dt_lev, time);
244 
245  // **************************************************************************************
246  // Tests on the reasonableness of the solution after the dycore
247  // **************************************************************************************
248  // Test for NaNs after dycore
249  if (check_for_nans > 0) {
250  if (verbose > 1) {
251  amrex::Print() << "Testing new state and vels for NaNs after dycore" << std::endl;
252  }
253  check_state_for_nans(S_new);
254  check_vels_for_nans(rU_new[lev],rV_new[lev],rW_new[lev]);
255  }
256 
257  // We only test on low temp if we have a moisture model because we are protecting against
258  // the test on low temp inside the moisture models
259  if (solverChoice.moisture_type != MoistureType::None) {
260  if (verbose > 1) {
261  amrex::Print() << "Testing on low temperature after dycore" << std::endl;
262  }
263  check_for_low_temp(S_new);
264  } else {
265  // Otherwise we will test on negative (rhotheta) coming out of the dycore
266  if (verbose > 1) {
267  amrex::Print() << "Testing on negative temperature after dycore" << std::endl;
268  }
270  }
271 
272  // **************************************************************************************
273  // Update the microphysics (moisture)
274  // **************************************************************************************
276  {
277  advance_microphysics(lev, S_new, dt_lev, iteration, time);
278 
279  // Test for NaNs after microphysics
280  if (check_for_nans > 0) {
281  amrex::Print() << "Testing new state for NaNs after advance_microphysics" << std::endl;
282  check_state_for_nans(S_new);
283  }
284  }
285 
286  // **************************************************************************************
287  // Update the land surface model
288  // **************************************************************************************
289  advance_lsm(lev, S_new, U_new, V_new, dt_lev);
290 
291 #ifdef ERF_USE_PARTICLES
292  // **************************************************************************************
293  // Update the particle positions
294  // **************************************************************************************
295  evolveTracers( lev, dt_lev, vars_new, z_phys_nd );
296 #endif
297 
298  // ***********************************************************************************************
299  // Impose domain boundary conditions here so that in FillPatching the fine data we won't
300  // need to re-fill these
301  // ***********************************************************************************************
302  if (lev < finest_level) {
303  IntVect ngvect_vels = vars_new[lev][Vars::xvel].nGrowVect();
305  0,vars_new[lev][Vars::cons].nComp(),
306  vars_new[lev][Vars::cons].nGrowVect(),time,BCVars::cons_bc,true);
307  (*physbcs_u[lev])(vars_new[lev][Vars::xvel], vars_new[lev][Vars::xvel], vars_new[lev][Vars::yvel],
308  ngvect_vels,time,BCVars::xvel_bc,true);
309  (*physbcs_v[lev])(vars_new[lev][Vars::yvel], vars_new[lev][Vars::xvel], vars_new[lev][Vars::yvel],
310  ngvect_vels,time,BCVars::yvel_bc,true);
311  (*physbcs_w[lev])(vars_new[lev][Vars::zvel], vars_new[lev][Vars::xvel], vars_new[lev][Vars::yvel],
312  ngvect_vels,time,BCVars::zvel_bc,true);
313  }
314 
315  // **************************************************************************************
316  // Register old and new coarse data if we are at a level less than the finest level
317  // **************************************************************************************
318  if (lev < finest_level) {
319  if (cf_width > 0) {
320  // We must fill the ghost cells of these so that the parallel copy works correctly
321  state_old[IntVars::cons].FillBoundary(geom[lev].periodicity());
322  state_new[IntVars::cons].FillBoundary(geom[lev].periodicity());
323  FPr_c[lev].RegisterCoarseData({&state_old[IntVars::cons], &state_new[IntVars::cons]},
324  {time, time+dt_lev});
325  }
326 
327  if (cf_width >= 0) {
328  // We must fill the ghost cells of these so that the parallel copy works correctly
329  state_old[IntVars::xmom].FillBoundary(geom[lev].periodicity());
330  state_new[IntVars::xmom].FillBoundary(geom[lev].periodicity());
331  FPr_u[lev].RegisterCoarseData({&state_old[IntVars::xmom], &state_new[IntVars::xmom]},
332  {time, time+dt_lev});
333 
334  state_old[IntVars::ymom].FillBoundary(geom[lev].periodicity());
335  state_new[IntVars::ymom].FillBoundary(geom[lev].periodicity());
336  FPr_v[lev].RegisterCoarseData({&state_old[IntVars::ymom], &state_new[IntVars::ymom]},
337  {time, time+dt_lev});
338 
339  state_old[IntVars::zmom].FillBoundary(geom[lev].periodicity());
340  state_new[IntVars::zmom].FillBoundary(geom[lev].periodicity());
341  FPr_w[lev].RegisterCoarseData({&state_old[IntVars::zmom], &state_new[IntVars::zmom]},
342  {time, time+dt_lev});
343  }
344 
345  //
346  // Now create a MultiFab that holds (S_new - S_old) / dt from the coarse level interpolated
347  // on to the coarse/fine boundary at the fine resolution
348  //
349  Interpolater* mapper_f = &face_cons_linear_interp;
350 
351  // PhysBCFunctNoOp null_bc;
352  // MultiFab tempx(vars_new[lev+1][Vars::xvel].boxArray(),vars_new[lev+1][Vars::xvel].DistributionMap(),1,0);
353  // tempx.setVal(0.0);
354  // xmom_crse_rhs[lev+1].setVal(0.0);
355  // FPr_u[lev].FillSet(tempx , time , null_bc, domain_bcs_type);
356  // FPr_u[lev].FillSet(xmom_crse_rhs[lev+1], time+dt_lev, null_bc, domain_bcs_type);
357  // MultiFab::Subtract(xmom_crse_rhs[lev+1],tempx,0,0,1,IntVect{0});
358  // xmom_crse_rhs[lev+1].mult(1.0/dt_lev,0,1,0);
359 
360  // MultiFab tempy(vars_new[lev+1][Vars::yvel].boxArray(),vars_new[lev+1][Vars::yvel].DistributionMap(),1,0);
361  // tempy.setVal(0.0);
362  // ymom_crse_rhs[lev+1].setVal(0.0);
363  // FPr_v[lev].FillSet(tempy , time , null_bc, domain_bcs_type);
364  // FPr_v[lev].FillSet(ymom_crse_rhs[lev+1], time+dt_lev, null_bc, domain_bcs_type);
365  // MultiFab::Subtract(ymom_crse_rhs[lev+1],tempy,0,0,1,IntVect{0});
366  // ymom_crse_rhs[lev+1].mult(1.0/dt_lev,0,1,0);
367 
368  MultiFab temp_state(zmom_crse_rhs[lev+1].boxArray(),zmom_crse_rhs[lev+1].DistributionMap(),1,0);
369  InterpFromCoarseLevel(temp_state, IntVect{0}, IntVect{0}, state_old[IntVars::zmom], 0, 0, 1,
370  geom[lev], geom[lev+1], refRatio(lev), mapper_f, domain_bcs_type, BCVars::zvel_bc);
371  InterpFromCoarseLevel(zmom_crse_rhs[lev+1], IntVect{0}, IntVect{0}, state_new[IntVars::zmom], 0, 0, 1,
372  geom[lev], geom[lev+1], refRatio(lev), mapper_f, domain_bcs_type, BCVars::zvel_bc);
373  MultiFab::Subtract(zmom_crse_rhs[lev+1],temp_state,0,0,1,IntVect{0});
374  zmom_crse_rhs[lev+1].mult(1.0/dt_lev,0,1,0);
375  }
376 
377  // ***********************************************************************************************
378  // Update the time averaged velocities if they are requested
379  // ***********************************************************************************************
381  Time_Avg_Vel_atCC(dt[lev], t_avg_cnt[lev], vel_t_avg[lev].get(), U_new, V_new, W_new);
382  }
383 }
@ 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:853
amrex::Vector< std::unique_ptr< amrex::MultiFab > > walldist
Definition: ERF.H:957
static amrex::Real start_time
Definition: ERF.H:1040
void check_vels_for_nans(amrex::MultiFab const &xvel, amrex::MultiFab const &yvel, amrex::MultiFab const &zvel)
Definition: ERF.cpp:3146
amrex::Vector< ERFFillPatcher > FPr_u
Definition: ERF.H:903
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q1fx3_lev
Definition: ERF.H:926
amrex::Vector< amrex::Vector< amrex::MultiFab > > vars_new
Definition: ERF.H:818
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_hfx3_lev
Definition: ERF.H:924
amrex::Vector< ERFFillPatcher > FPr_v
Definition: ERF.H:904
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_hfx1_lev
Definition: ERF.H:924
eb_ const & get_eb(int lev) const noexcept
Definition: ERF.H:1627
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_cons > > physbcs_cons
Definition: ERF.H:840
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_cc
Definition: ERF.H:934
amrex::Vector< std::unique_ptr< amrex::MultiFab > > eddyDiffs_lev
Definition: ERF.H:910
static SolverChoice solverChoice
Definition: ERF.H:1171
amrex::Vector< ERFFillPatcher > FPr_c
Definition: ERF.H:902
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > Tau
Definition: ERF.H:908
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vel_t_avg
Definition: ERF.H:825
static int verbose
Definition: ERF.H:1206
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_w > > physbcs_w
Definition: ERF.H:843
amrex::Vector< amrex::MultiFab > base_state
Definition: ERF.H:968
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Qv_prim
Definition: ERF.H:848
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q1fx2_lev
Definition: ERF.H:926
amrex::Vector< amrex::MultiFab > rV_new
Definition: ERF.H:855
amrex::Vector< amrex::BCRec > domain_bcs_type
Definition: ERF.H:984
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Qr_prim
Definition: ERF.H:849
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_u > > physbcs_u
Definition: ERF.H:841
amrex::Vector< amrex::Real > t_avg_cnt
Definition: ERF.H:826
void FillPatchFineLevel(int lev, amrex::Real 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
amrex::Vector< amrex::MultiFab > rU_old
Definition: ERF.H:852
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Theta_prim
Definition: ERF.H:847
static int check_for_nans
Definition: ERF.H:1210
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_v > > physbcs_v
Definition: ERF.H:842
void check_state_for_nans(amrex::MultiFab const &S)
Definition: ERF.cpp:3127
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_nd
Definition: ERF.H:933
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:857
amrex::Vector< amrex::MultiFab > zmom_crse_rhs
Definition: ERF.H:861
void check_for_low_temp(amrex::MultiFab &S)
Definition: ERF.cpp:3173
void advance_lsm(int lev, amrex::MultiFab &cons_in, amrex::MultiFab &xvel_in, amrex::MultiFab &yvel_in, const amrex::Real &dt_advance)
Definition: ERF_AdvanceLSM.cpp:5
TurbulentPerturbation turbPert
Definition: ERF.H:1174
amrex::Vector< amrex::MultiFab > rW_old
Definition: ERF.H:856
void check_for_negative_theta(amrex::MultiFab &S)
Definition: ERF.cpp:3208
std::unique_ptr< SurfaceLayer > m_SurfaceLayer
Definition: ERF.H:1340
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_w_subsid
Definition: ERF.H:1291
amrex::Vector< ERFFillPatcher > FPr_w
Definition: ERF.H:905
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_hfx2_lev
Definition: ERF.H:924
amrex::Vector< amrex::Real > dt
Definition: ERF.H:812
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:900
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q1fx1_lev
Definition: ERF.H:926
amrex::GpuArray< ERF_BC, AMREX_SPACEDIM *2 > phys_bc_type
Definition: ERF.H:997
amrex::Vector< amrex::MultiFab > rV_old
Definition: ERF.H:854
amrex::Vector< amrex::Vector< amrex::MultiFab > > vars_old
Definition: ERF.H:819
const std::unique_ptr< amrex::EBFArrayBoxFactory > & get_const_factory() const noexcept
Definition: ERF_EB.H:46
@ zvel_bc
Definition: ERF_IndexDefines.H:89
@ yvel_bc
Definition: ERF_IndexDefines.H:88
@ cons_bc
Definition: ERF_IndexDefines.H:76
@ xvel_bc
Definition: ERF_IndexDefines.H:87
@ ymom
Definition: ERF_IndexDefines.H:176
@ cons
Definition: ERF_IndexDefines.H:174
@ zmom
Definition: ERF_IndexDefines.H:177
@ xmom
Definition: ERF_IndexDefines.H:175
@ ng
Definition: ERF_Morrison.H:48
@ xvel
Definition: ERF_IndexDefines.H:157
@ cons
Definition: ERF_IndexDefines.H:156
@ zvel
Definition: ERF_IndexDefines.H:159
@ yvel
Definition: ERF_IndexDefines.H:158
int qr
Definition: ERF_DataStruct.H:110
bool use_shoc
Definition: ERF_DataStruct.H:1175
bool moisture_tight_coupling
Definition: ERF_DataStruct.H:1213
bool custom_w_subsidence
Definition: ERF_DataStruct.H:1159
MoistureType moisture_type
Definition: ERF_DataStruct.H:1194
static TerrainType terrain_type
Definition: ERF_DataStruct.H:1056
PerturbationType pert_type
Definition: ERF_DataStruct.H:1184
WindFarmType windfarm_type
Definition: ERF_DataStruct.H:1195
MoistureComponentIndices moisture_indices
Definition: ERF_DataStruct.H:1211
bool time_avg_vel
Definition: ERF_DataStruct.H:1181
amrex::Vector< amrex::MultiFab > pb_cell
Definition: ERF_TurbPertStruct.H:640
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:223
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:324
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 
56 
57  MultiFab r_hse (base_state[level], make_alias, BaseState::r0_comp , 1);
58  MultiFab p_hse (base_state[level], make_alias, BaseState::p0_comp , 1);
59  MultiFab pi_hse(base_state[level], make_alias, BaseState::pi0_comp, 1);
60 
61  // These pointers are used in the MRI utility functions
62  MultiFab* r0 = &r_hse;
63  MultiFab* p0 = &p_hse;
64  MultiFab* pi0 = &pi_hse;
65 
66  MultiFab* rhotheta_src_ptr = solverChoice.custom_rhotheta_forcing ? rhotheta_src[level].get() : nullptr;
67  MultiFab* rhoqt_src_ptr = solverChoice.custom_moisture_forcing ? rhoqt_src[level].get() : nullptr;
68  Real* dptr_wbar_sub = solverChoice.custom_w_subsidence ? d_w_subsid[level].data() : nullptr;
69 
70  // Turbulent Perturbation Pointer
71  //Real* dptr_rhotheta_src = solverChoice.pert_type ? d_rhotheta_src[level].data() : nullptr;
72 
73  Vector<Real*> d_rayleigh_ptrs_at_lev;
74  d_rayleigh_ptrs_at_lev.resize(Rayleigh::nvars);
75  d_rayleigh_ptrs_at_lev[Rayleigh::ubar] = solverChoice.dampingChoice.rayleigh_damp_U ? d_rayleigh_ptrs[level][Rayleigh::ubar].data() : nullptr;
76  d_rayleigh_ptrs_at_lev[Rayleigh::vbar] = solverChoice.dampingChoice.rayleigh_damp_V ? d_rayleigh_ptrs[level][Rayleigh::vbar].data() : nullptr;
77  d_rayleigh_ptrs_at_lev[Rayleigh::wbar] = solverChoice.dampingChoice.rayleigh_damp_W ? d_rayleigh_ptrs[level][Rayleigh::wbar].data() : nullptr;
78  d_rayleigh_ptrs_at_lev[Rayleigh::thetabar] = solverChoice.dampingChoice.rayleigh_damp_T ? d_rayleigh_ptrs[level][Rayleigh::thetabar].data() : nullptr;
79 
80  bool use_rayleigh =
83  Real* d_sinesq_at_lev = (use_rayleigh) ? d_sinesq_ptrs[level].data() : nullptr;
84  Real* d_sinesq_stag_at_lev = (use_rayleigh) ? d_sinesq_stag_ptrs[level].data() : nullptr;
85 
86  Vector<Real*> d_sponge_ptrs_at_lev;
87  if(sc.sponge_type=="input_sponge")
88  {
89  d_sponge_ptrs_at_lev.resize(Sponge::nvars_sponge);
90  d_sponge_ptrs_at_lev[Sponge::ubar_sponge] = d_sponge_ptrs[level][Sponge::ubar_sponge].data();
91  d_sponge_ptrs_at_lev[Sponge::vbar_sponge] = d_sponge_ptrs[level][Sponge::vbar_sponge].data();
92  }
93 
94  bool l_use_terrain_fitted_coords = (solverChoice.mesh_type != MeshType::ConstantDz);
95  bool l_use_kturb = tc.use_kturb;
96  bool l_use_diff = ( (dc.molec_diff_type != MolecDiffType::None) ||
97  l_use_kturb );
98 
99  const bool use_SurfLayer = (m_SurfaceLayer != nullptr);
100  const MultiFab* z_0 = (use_SurfLayer) ? m_SurfaceLayer->get_z0(level) : nullptr;
101 
102  const BoxArray& ba = state_old[IntVars::cons].boxArray();
103  const BoxArray& ba_z = zvel_old.boxArray();
104  const DistributionMapping& dm = state_old[IntVars::cons].DistributionMap();
105 
106  int num_prim = state_old[IntVars::cons].nComp() - 1;
107 
108  MultiFab S_prim (ba , dm, num_prim, state_old[IntVars::cons].nGrowVect());
109  MultiFab pi_stage (ba , dm, 1, 1);
110  MultiFab fast_coeffs(ba_z, dm, 5, 0);
111 
112  MultiFab* eddyDiffs = eddyDiffs_lev[level].get();
113  MultiFab* SmnSmn = SmnSmn_lev[level].get();
114 
115  // **************************************************************************************
116  // Compute strain for use in slow RHS and Smagorinsky model
117  // **************************************************************************************
118  {
119  BL_PROFILE("erf_advance_strain");
120  if (l_use_diff) {
121 
122  const BCRec* bc_ptr_h = domain_bcs_type.data();
123  const GpuArray<Real, AMREX_SPACEDIM> dxInv = fine_geom.InvCellSizeArray();
124 
125 #ifdef _OPENMP
126 #pragma omp parallel if (Gpu::notInLaunchRegion())
127 #endif
128  for ( MFIter mfi(state_new[IntVars::cons],TileNoZ()); mfi.isValid(); ++mfi)
129  {
130  Box bxcc = mfi.growntilebox(IntVect(1,1,0));
131  Box tbxxy = mfi.tilebox(IntVect(1,1,0),IntVect(1,1,0));
132  Box tbxxz = mfi.tilebox(IntVect(1,0,1),IntVect(1,1,0));
133  Box tbxyz = mfi.tilebox(IntVect(0,1,1),IntVect(1,1,0));
134 
135  if (bxcc.smallEnd(2) != domain.smallEnd(2)) {
136  bxcc.growLo(2,1);
137  tbxxy.growLo(2,1);
138  tbxxz.growLo(2,1);
139  tbxyz.growLo(2,1);
140  }
141 
142  if (bxcc.bigEnd(2) != domain.bigEnd(2)) {
143  bxcc.growHi(2,1);
144  tbxxy.growHi(2,1);
145  tbxxz.growHi(2,1);
146  tbxyz.growHi(2,1);
147  }
148 
149  const Array4<const Real> & u = xvel_old.array(mfi);
150  const Array4<const Real> & v = yvel_old.array(mfi);
151  const Array4<const Real> & w = zvel_old.array(mfi);
152 
153  Array4<Real> tau11 = Tau[level][TauType::tau11].get()->array(mfi);
154  Array4<Real> tau22 = Tau[level][TauType::tau22].get()->array(mfi);
155  Array4<Real> tau33 = Tau[level][TauType::tau33].get()->array(mfi);
156  Array4<Real> tau12 = Tau[level][TauType::tau12].get()->array(mfi);
157  Array4<Real> tau13 = Tau[level][TauType::tau13].get()->array(mfi);
158  Array4<Real> tau23 = Tau[level][TauType::tau23].get()->array(mfi);
159 
160  Array4<Real> tau21 = l_use_terrain_fitted_coords ? Tau[level][TauType::tau21].get()->array(mfi) : Array4<Real>{};
161  Array4<Real> tau31 = l_use_terrain_fitted_coords ? Tau[level][TauType::tau31].get()->array(mfi) : Array4<Real>{};
162  Array4<Real> tau32 = l_use_terrain_fitted_coords ? Tau[level][TauType::tau32].get()->array(mfi) : Array4<Real>{};
163  const Array4<const Real>& z_nd = z_phys_nd[level]->const_array(mfi);
164 
165  const Array4<const Real> mf_mx = mapfac[level][MapFacType::m_x]->const_array(mfi);
166  const Array4<const Real> mf_ux = mapfac[level][MapFacType::u_x]->const_array(mfi);
167  const Array4<const Real> mf_vx = mapfac[level][MapFacType::v_x]->const_array(mfi);
168  const Array4<const Real> mf_my = mapfac[level][MapFacType::m_y]->const_array(mfi);
169  const Array4<const Real> mf_uy = mapfac[level][MapFacType::u_y]->const_array(mfi);
170  const Array4<const Real> mf_vy = mapfac[level][MapFacType::v_y]->const_array(mfi);
171 
172  // We update Tau_corr[level] in erf_make_tau_terms, not here
173  Array4<Real> no_tau_corr_update_here{};
174 
175  if (solverChoice.mesh_type == MeshType::StretchedDz) {
176  ComputeStrain_S(bxcc, tbxxy, tbxxz, tbxyz, domain,
177  u, v, w,
178  tau11, tau22, tau33,
179  tau12, tau21,
180  tau13, tau31,
181  tau23, tau32,
182  stretched_dz_d[level], dxInv,
183  mf_mx, mf_ux, mf_vx, mf_my, mf_uy, mf_vy, bc_ptr_h,
184  no_tau_corr_update_here, no_tau_corr_update_here);
185  } else if (l_use_terrain_fitted_coords) {
186  ComputeStrain_T(bxcc, tbxxy, tbxxz, tbxyz, domain,
187  u, v, w,
188  tau11, tau22, tau33,
189  tau12, tau21,
190  tau13, tau31,
191  tau23, tau32,
192  z_nd, detJ_cc[level]->const_array(mfi), dxInv,
193  mf_mx, mf_ux, mf_vx, mf_my, mf_uy, mf_vy, bc_ptr_h,
194  no_tau_corr_update_here, no_tau_corr_update_here);
195  } else {
196  if (solverChoice.terrain_type == TerrainType::EB) {
197  ComputeStrain_EB(mfi, bxcc, tbxxy, tbxxz, tbxyz, domain,
198  u, v, w,
199  tau11, tau22, tau33,
200  tau12, tau13, tau23,
201  dxInv,
202  bc_ptr_h,
203  get_eb(level),
204  no_tau_corr_update_here, no_tau_corr_update_here);
205  } else {
206  ComputeStrain_N(bxcc, tbxxy, tbxxz, tbxyz, domain,
207  u, v, w,
208  tau11, tau22, tau33,
209  tau12, tau13, tau23,
210  dxInv,
211  mf_mx, mf_ux, mf_vx, mf_my, mf_uy, mf_vy, bc_ptr_h,
212  no_tau_corr_update_here, no_tau_corr_update_here);
213  }
214  }
215  } // mfi
216  } // l_use_diff
217  } // profile
218 
219 #include "ERF_TI_utils.H"
220 
221  // Additional SFS quantities, calculated once per timestep
222  MultiFab* Hfx1 = SFS_hfx1_lev[level].get();
223  MultiFab* Hfx2 = SFS_hfx2_lev[level].get();
224  MultiFab* Hfx3 = SFS_hfx3_lev[level].get();
225  MultiFab* Q1fx1 = SFS_q1fx1_lev[level].get();
226  MultiFab* Q1fx2 = SFS_q1fx2_lev[level].get();
227  MultiFab* Q1fx3 = SFS_q1fx3_lev[level].get();
228  MultiFab* Q2fx3 = SFS_q2fx3_lev[level].get();
229  MultiFab* Diss = SFS_diss_lev[level].get();
230 
231  // *************************************************************************
232  // Calculate cell-centered eddy viscosity & diffusivities
233  //
234  // Notes -- we fill all the data in ghost cells before calling this so
235  // that we can fill the eddy viscosity in the ghost regions and
236  // not have to call a boundary filler on this data itself
237  //
238  // LES - updates both horizontal and vertical eddy viscosity components
239  // PBL - only updates vertical eddy viscosity components so horizontal
240  // components come from the LES model or are left as zero.
241  // *************************************************************************
242  if (l_use_kturb)
243  {
244  // NOTE: state_new transfers to state_old for PBL (due to ptr swap in advance)
245  bool l_use_moisture = ( solverChoice.moisture_type != MoistureType::None );
246  const BCRec* bc_ptr_h = domain_bcs_type.data();
247  ComputeTurbulentViscosity(dt_advance, xvel_old, yvel_old,Tau[level],
248  state_old[IntVars::cons],
249  *walldist[level].get(),
250  *eddyDiffs, *Hfx1, *Hfx2, *Hfx3, *Diss, // to be updated
251  fine_geom, mapfac[level],
252  z_phys_nd[level], solverChoice,
253  m_SurfaceLayer, z_0, l_use_terrain_fitted_coords,
254  l_use_moisture, level,
255  bc_ptr_h,
256  get_eb(level));
257  }
258 
259  // ***********************************************************************************************
260  // Update user-defined source terms -- these are defined once per time step (not per RK stage)
261  // ***********************************************************************************************
263  prob->update_rhotheta_sources(old_time,
264  rhotheta_src_ptr,
265  fine_geom, z_phys_cc[level]);
266  }
267 
269  prob->update_rhoqt_sources(old_time,
270  rhoqt_src_ptr,
271  fine_geom, z_phys_cc[level]);
272  }
273 
275  prob->update_geostrophic_profile(old_time,
276  h_u_geos[level], d_u_geos[level],
277  h_v_geos[level], d_v_geos[level],
278  fine_geom, z_phys_cc[level]);
279  }
280 
282  prob->update_w_subsidence(old_time,
283  h_w_subsid[level], d_w_subsid[level],base_state[level],
284  fine_geom, z_phys_nd[level]);
285  }
286 
287  // ***********************************************************************************************
288  // Convert old velocity available on faces to old momentum on faces to be used in time integration
289  // ***********************************************************************************************
290  MultiFab density(state_old[IntVars::cons], make_alias, Rho_comp, 1);
291 
292  //
293  // This is an optimization since we won't need more than one ghost
294  // cell of momentum in the integrator if not using numerical diffusion
295  //
296  IntVect ngu = (!solverChoice.use_num_diff) ? IntVect(1,1,1) : xvel_old.nGrowVect();
297  IntVect ngv = (!solverChoice.use_num_diff) ? IntVect(1,1,1) : yvel_old.nGrowVect();
298  IntVect ngw = (!solverChoice.use_num_diff) ? IntVect(1,1,0) : zvel_old.nGrowVect();
299 
300  const MultiFab* c_vfrac = nullptr;
301  if (solverChoice.terrain_type == TerrainType::EB) {
302  c_vfrac = &((get_eb(level).get_const_factory())->getVolFrac());
303  }
304 
305  VelocityToMomentum(xvel_old, ngu, yvel_old, ngv, zvel_old, ngw, density,
306  state_old[IntVars::xmom],
307  state_old[IntVars::ymom],
308  state_old[IntVars::zmom],
309  domain, domain_bcs_type, c_vfrac);
310 
311  MultiFab::Copy(xvel_new,xvel_old,0,0,1,xvel_old.nGrowVect());
312  MultiFab::Copy(yvel_new,yvel_old,0,0,1,yvel_old.nGrowVect());
313  MultiFab::Copy(zvel_new,zvel_old,0,0,1,zvel_old.nGrowVect());
314 
315  bool fast_only = false;
316  bool vel_and_mom_synced = true;
317 
318  apply_bcs(state_old, old_time,
319  state_old[IntVars::cons].nGrow(), state_old[IntVars::xmom].nGrow(),
320  fast_only, vel_and_mom_synced);
321  cons_to_prim(state_old[IntVars::cons], state_old[IntVars::cons].nGrow());
322 
323  // ***********************************************************************************************
324  // Define a new MultiFab that holds q_total and fill it by summing the moisture components --
325  // to be used in buoyancy calculation and as part of the inertial weighting in the
326  // ***********************************************************************************************
327 
328  const bool l_eb_terrain = (solverChoice.terrain_type == TerrainType::EB);
329  MultiFab qt(grids[level], dmap[level], 1, (l_eb_terrain) ? 2 : 1);
330  qt.setVal(0.0);
331 
332 #include "ERF_TI_no_substep_fun.H"
333 #include "ERF_TI_substep_fun.H"
334 #include "ERF_TI_slow_rhs_pre.H"
335 #include "ERF_TI_slow_rhs_post.H"
336 
337  // ***************************************************************************************
338  // Setup the integrator and integrate for a single timestep
339  // **************************************************************************************
340  MRISplitIntegrator<Vector<MultiFab> >& mri_integrator = *mri_integrator_mem[level];
341 
342  // Define rhs and 'post update' utility function that is called after calculating
343  // any state data (e.g. at RK stages or at the end of a timestep)
344  mri_integrator.set_slow_rhs_pre(slow_rhs_fun_pre);
345  mri_integrator.set_slow_rhs_post(slow_rhs_fun_post);
346 
349  mri_integrator.set_no_substep(no_substep_fun);
350 
351  mri_integrator.advance(state_old, state_new, old_time, dt_advance);
352 
353  if (verbose) Print() << "Done with advance_dycore at level " << level << std::endl;
354 }
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:788
@ 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:16
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 apply_bcs
Definition: ERF_TI_utils.H:73
auto cons_to_prim
Definition: ERF_TI_utils.H:4
Real z_0
Definition: ERF_UpdateWSubsidence_Bomex.H:10
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > mapfac
Definition: ERF.H:960
amrex::Vector< std::unique_ptr< MRISplitIntegrator< amrex::Vector< amrex::MultiFab > > > > mri_integrator_mem
Definition: ERF.H:828
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_sinesq_stag_ptrs
Definition: ERF.H:1322
amrex::Vector< amrex::Vector< amrex::Real > > h_w_subsid
Definition: ERF.H:1290
amrex::Vector< std::unique_ptr< amrex::MultiFab > > detJ_cc
Definition: ERF.H:936
amrex::Vector< amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > > d_sponge_ptrs
Definition: ERF.H:1318
amrex::Vector< long > dt_mri_ratio
Definition: ERF.H:813
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q2fx3_lev
Definition: ERF.H:927
std::unique_ptr< ProblemBase > prob
Definition: ERF.H:800
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > stretched_dz_d
Definition: ERF.H:966
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_diss_lev
Definition: ERF.H:925
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_sinesq_ptrs
Definition: ERF.H:1321
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_v_geos
Definition: ERF.H:1297
amrex::Vector< amrex::Vector< amrex::Real > > h_v_geos
Definition: ERF.H:1296
amrex::Vector< std::unique_ptr< amrex::MultiFab > > rhotheta_src
Definition: ERF.H:1287
amrex::Vector< amrex::Vector< amrex::Real > > h_u_geos
Definition: ERF.H:1293
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SmnSmn_lev
Definition: ERF.H:911
amrex::Vector< std::unique_ptr< amrex::MultiFab > > rhoqt_src
Definition: ERF.H:1288
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_u_geos
Definition: ERF.H:1294
static int fixed_mri_dt_ratio
Definition: ERF.H:1060
amrex::Vector< amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > > d_rayleigh_ptrs
Definition: ERF.H:1317
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:65
@ p0_comp
Definition: ERF_IndexDefines.H:64
@ r0_comp
Definition: ERF_IndexDefines.H:63
@ qt
Definition: ERF_Kessler.H:27
real(c_double), parameter p0
Definition: ERF_module_model_constants.F90:40
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:1068
DampingChoice dampingChoice
Definition: ERF_DataStruct.H:1078
DiffChoice diffChoice
Definition: ERF_DataStruct.H:1077
bool custom_rhotheta_forcing
Definition: ERF_DataStruct.H:1157
bool custom_geostrophic_profile
Definition: ERF_DataStruct.H:1162
bool use_num_diff
Definition: ERF_DataStruct.H:1187
bool custom_moisture_forcing
Definition: ERF_DataStruct.H:1158
amrex::Vector< TurbChoice > turbChoice
Definition: ERF_DataStruct.H:1080
SpongeChoice spongeChoice
Definition: ERF_DataStruct.H:1079
Definition: ERF_SpongeStruct.H:15
std::string sponge_type
Definition: ERF_SpongeStruct.H:58
Definition: ERF_TurbStruct.H:42
bool use_kturb
Definition: ERF_TurbStruct.H:424
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 dt_advance 
)
10 {
11  if (solverChoice.lsm_type != LandSurfaceType::None) {
12  if (solverChoice.lsm_type == LandSurfaceType::NOAHMP) {
13  lsm.Advance(lev, cons_in, xvel_in, yvel_in, SFS_hfx3_lev[lev].get(), SFS_q1fx3_lev[lev].get(), dt_advance, istep[0]);
14  } else {
15  lsm.Advance(lev, dt_advance);
16  }
17  }
18 }
LandSurface lsm
Definition: ERF.H:879
amrex::Vector< int > istep
Definition: ERF.H:806
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 &dt_advance, const int &nstep)
Definition: ERF_LandSurface.H:52
LandSurfaceType lsm_type
Definition: ERF_DataStruct.H:1197
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  micro->Set_RealWidth(lev, real_width);
13  micro->Update_Micro_Vars_Lev(lev, cons);
14  micro->Advance(lev, dt_advance, iteration, time, solverChoice, vars_new, z_phys_nd, phys_bc_type);
15  micro->Update_State_Vars_Lev(lev, cons);
16  }
17 }
std::unique_ptr< Microphysics > micro
Definition: ERF.H:863
int real_width
Definition: ERF.H:1237

◆ 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:916
amrex::Vector< std::unique_ptr< IRadiation > > rad
Definition: ERF.H:885
amrex::Vector< amrex::Real > t_old
Definition: ERF.H:811
amrex::Vector< std::unique_ptr< amrex::MultiFab > > lon_m
Definition: ERF.H:763
amrex::Vector< std::unique_ptr< amrex::MultiFab > > lat_m
Definition: ERF.H:763
amrex::Vector< std::unique_ptr< amrex::MultiFab > > qheating_rates
Definition: ERF.H:886
amrex::Vector< std::unique_ptr< amrex::MultiFab > > rad_fluxes
Definition: ERF.H:887
int Get_DataIdx(const int &lev, std::string &varname)
Definition: ERF_LandSurface.H:107
amrex::MultiFab * Get_Data_Ptr(const int &lev, const int &varIdx)
Definition: ERF_LandSurface.H:89
RadiationType rad_type
Definition: ERF_DataStruct.H:1198

◆ appendPlotVariables()

void ERF::appendPlotVariables ( const std::string &  pp_plot_var_names,
amrex::Vector< std::string > &  plot_var_names 
)
private
230 {
231  ParmParse pp(pp_prefix);
232 
233  Vector<std::string> plot_var_names(0);
234  if (pp.contains(pp_plot_var_names.c_str())) {
235  std::string nm;
236  int nPltVars = pp.countval(pp_plot_var_names.c_str());
237  for (int i = 0; i < nPltVars; i++) {
238  pp.get(pp_plot_var_names.c_str(), nm, i);
239  // Add the named variable to our list of plot variables
240  // if it is not already in the list
241  if (!containerHasElement(plot_var_names, nm)) {
242  plot_var_names.push_back(nm);
243  }
244  }
245  }
246 
247  Vector<std::string> tmp_plot_names(0);
248 #ifdef ERF_USE_PARTICLES
249  Vector<std::string> particle_mesh_plot_names;
250  particleData.GetMeshPlotVarNames( particle_mesh_plot_names );
251  if (particle_mesh_plot_names.size() > 0) {
252  static bool first_call = true;
253  if (first_call) {
254  Print() << "ParticleData: the following additional Eulerian variables are available to plot:\n";
255  for (int i = 0; i < particle_mesh_plot_names.size(); i++) {
256  Print() << " " << particle_mesh_plot_names[i] << "\n";
257  }
258  first_call = false;
259  }
260  for (int i = 0; i < particle_mesh_plot_names.size(); i++) {
261  std::string tmp(particle_mesh_plot_names[i]);
262  if (containerHasElement(plot_var_names, tmp) ) {
263  tmp_plot_names.push_back(tmp);
264  }
265  }
266  }
267 #endif
268 
269  {
270  Vector<std::string> microphysics_plot_names;
271  micro->GetPlotVarNames(microphysics_plot_names);
272  if (microphysics_plot_names.size() > 0) {
273  static bool first_call = true;
274  if (first_call) {
275  Print() << getEnumNameString(solverChoice.moisture_type)
276  << ": the following additional variables are available to plot:\n";
277  for (int i = 0; i < microphysics_plot_names.size(); i++) {
278  Print() << " " << microphysics_plot_names[i] << "\n";
279  }
280  first_call = false;
281  }
282  for (auto& plot_name : microphysics_plot_names) {
283  if (containerHasElement(plot_var_names, plot_name)) {
284  tmp_plot_names.push_back(plot_name);
285  }
286  }
287  }
288  }
289 
290  for (int i = 0; i < tmp_plot_names.size(); i++) {
291  a_plot_var_names.push_back( tmp_plot_names[i] );
292  }
293 
294  // Finally, check to see if we found all the requested variables
295  for (const auto& plot_name : plot_var_names) {
296  if (!containerHasElement(a_plot_var_names, plot_name)) {
297  if (amrex::ParallelDescriptor::IOProcessor()) {
298  Warning("\nWARNING: Requested to plot variable '" + plot_name + "' but it is not available");
299  }
300  }
301  }
302 }
bool containerHasElement(const V &iterable, const T &query)
Definition: ERF_Container.H:5
std::string pp_prefix
Definition: ERF.H:546
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 &  cons_pert,
amrex::MultiFab &  xvel_pert,
amrex::MultiFab &  yvel_pert,
amrex::MultiFab &  zvel_pert 
)
149 {
150  ignore_unused(cons_pert);
151  ignore_unused(yvel_pert);
152  ignore_unused(zvel_pert);
153 
154  const Geometry& gm = geom[lev];
155  const Real dx = gm.CellSize(0);
156  const Real dy = gm.CellSize(1);
157 
158  const Real dmesh = std::min(dx, dy);
159  // ---- User choices ----
160  const Real sigma = solverChoice.pert_correlated_radius; // e.g. 2 km correlation length
161  const int r = static_cast<int>(3.0 * sigma / dmesh); // stencil radius
162 
163  // ---- Precompute Gaussian weights on host ----
164  const int wsize = 2*r + 1;
165  Vector<Real> w_host(wsize * wsize);
166 
167  Real Z = 0.0;
168  for (int m = -r; m <= r; ++m) {
169  for (int n = -r; n <= r; ++n) {
170  Real val = std::exp(-(m*m*dx*dx + n*n*dy*dy)/(2.0*sigma*sigma));
171  w_host[(m+r)*wsize + (n+r)] = val;
172  Z += val;
173  }
174  }
175  for (auto& v : w_host) {
176  v = v/Z;
177  }
178 
179  Gpu::DeviceVector<Real> w_dev;
180  w_dev.resize(w_host.size());
181  Gpu::copy(Gpu::hostToDevice, w_host.begin(), w_host.end(), w_dev.begin());
182 
183  Real const* w = w_dev.data();
184 
185  // 1. Define ngrow_big using the actual dimension macro
186  IntVect ngrow_big(AMREX_D_DECL(r, r, 0));
187 
188  // 2. Create the copy
189  MultiFab xvel_pert_copy(xvel_pert.boxArray(),
190  xvel_pert.DistributionMap(),
191  1, ngrow_big);
192  //MultiFab::Copy(xvel_pert_copy, xvel_pert, 0, 0, 1, 0);
193 
194  // 3. Use the built-in copy that includes ghost cell logic
195  // Copy(dst, src, src_comp, dst_comp, num_comp, ngrow)
196  // Setting ngrow to 0 ensures we only take valid data from the original
197  xvel_pert_copy.ParallelCopy(xvel_pert, 0, 0, 1, IntVect(0), ngrow_big, gm.periodicity());
198 
199  for (MFIter mfi(xvel_pert, TileNoZ()); mfi.isValid(); ++mfi)
200  {
201  const Box& tbx = mfi.tilebox();
202 
203  auto const& in = xvel_pert_copy.array(mfi);
204  auto const& out = xvel_pert.array(mfi);
205 
206  ParallelFor(tbx,
207  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
208  {
209  Real sum = 0.0;
210  for (int m = -r; m <= r; ++m) {
211  for (int n = -r; n <= r; ++n) {
212  Real wij = w[(m+r)*wsize + (n+r)];
213  sum += wij * in(i+m, j+n, k);
214  }
215  }
216  out(i,j,k) = sum;
217  });
218  }
219 }
struct @21 in
struct @21 out
const Real dy
Definition: ERF_InitCustomPert_ABL.H:24
const Real dx
Definition: ERF_InitCustomPert_ABL.H:23
ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { const auto prob_lo=geomdata.ProbLo();const auto dx=geomdata.CellSize();const Real x=(prob_lo[0]+(i+0.5) *dx[0])/mf_m(i, j, 0);const Real z=z_cc(i, j, k);Real L=std::sqrt(std::pow((x - x_c)/x_r, 2)+std::pow((z - z_c)/z_r, 2));if(L<=1.0) { Real dT=T_pert *(std::cos(PI *L)+1.0)/2.0;Real Tbar_hse=p_hse(i, j, k)/(R_d *r_hse(i, j, k));Real theta_perturbed=(Tbar_hse+dT) *std::pow(p_0/p_hse(i, j, k), rdOcp);Real theta_0=(Tbar_hse) *std::pow(p_0/p_hse(i, j, k), rdOcp);if(const_rho) { state_pert(i, j, k, RhoTheta_comp)=r_hse(i, j, k) *(theta_perturbed - theta_0);} else { state_pert(i, j, k, Rho_comp)=getRhoThetagivenP(p_hse(i, j, k))/theta_perturbed - r_hse(i, j, k);} } })
amrex::Real sigma
Definition: ERF_InitCustomPert_IsentropicVortex.H:11
amrex::Real pert_correlated_radius
Definition: ERF_DataStruct.H:1249
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)
Definition: ERF_AverageDown.cpp:36
amrex::Vector< int > anelastic
Definition: ERF_DataStruct.H:1086
CouplingType coupling_type
Definition: ERF_DataStruct.H:1193
Here is the call graph for this function:

◆ AverageDownTo()

void ERF::AverageDownTo ( int  crse_lev,
int  scomp,
int  ncomp 
)
37 {
38  if (solverChoice.anelastic[crse_lev]) {
39  AMREX_ALWAYS_ASSERT(scomp == 1);
40  } else {
41  AMREX_ALWAYS_ASSERT(scomp == 0);
42  }
43 
44  AMREX_ALWAYS_ASSERT(ncomp == vars_new[crse_lev][Vars::cons].nComp() - scomp);
45  AMREX_ALWAYS_ASSERT(solverChoice.coupling_type == CouplingType::TwoWay);
46 
47  // ******************************************************************************************
48  // First do cell-centered quantities
49  // The quantity that is conserved is not (rho S), but rather (rho S / m^2) where
50  // m is the map scale factor at cell centers
51  // Here we multiply (rho S) by detJ and divide (rho S) by m^2 before average down
52  // ******************************************************************************************
53  for (int lev = crse_lev; lev <= crse_lev+1; lev++) {
54  for (MFIter mfi(vars_new[lev][Vars::cons], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
55  const Box& bx = mfi.tilebox();
56  const Array4< Real> cons_arr = vars_new[lev][Vars::cons].array(mfi);
57  const Array4<const Real> mfx_arr = mapfac[lev][MapFacType::m_x]->const_array(mfi);
58  const Array4<const Real> mfy_arr = mapfac[lev][MapFacType::m_y]->const_array(mfi);
59  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
60  const Array4<const Real> detJ_arr = detJ_cc[lev]->const_array(mfi);
61  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
62  {
63  cons_arr(i,j,k,scomp+n) *= detJ_arr(i,j,k) / (mfx_arr(i,j,0)*mfy_arr(i,j,0));
64  });
65  } else {
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) /= (mfx_arr(i,j,0)*mfy_arr(i,j,0));
69  });
70  }
71  } // mfi
72  } // lev
73 
74  int fine_lev = crse_lev+1;
75 
76  if (interpolation_type == StateInterpType::Perturbational) {
77  // Make the fine rho and (rho theta) be perturbational
78  MultiFab::Divide(vars_new[fine_lev][Vars::cons],vars_new[fine_lev][Vars::cons],
79  Rho_comp,RhoTheta_comp,1,IntVect{0});
80  MultiFab::Subtract(vars_new[fine_lev][Vars::cons],base_state[fine_lev],
81  BaseState::r0_comp,Rho_comp,1,IntVect{0});
82  MultiFab::Subtract(vars_new[fine_lev][Vars::cons],base_state[fine_lev],
83  BaseState::th0_comp,RhoTheta_comp,1,IntVect{0});
84 
85  // Make the crse rho and (rho theta) be perturbational
86  MultiFab::Divide(vars_new[crse_lev][Vars::cons],vars_new[crse_lev][Vars::cons],
87  Rho_comp,RhoTheta_comp,1,IntVect{0});
88  MultiFab::Subtract(vars_new[crse_lev][Vars::cons],base_state[crse_lev],
89  BaseState::r0_comp,Rho_comp,1,IntVect{0});
90  MultiFab::Subtract(vars_new[crse_lev][Vars::cons],base_state[crse_lev],
91  BaseState::th0_comp,RhoTheta_comp,1,IntVect{0});
92  }
93 
94  if (SolverChoice::terrain_type != TerrainType::EB) {
95  average_down(vars_new[crse_lev+1][Vars::cons],vars_new[crse_lev ][Vars::cons],
96  scomp, ncomp, refRatio(crse_lev));
97  } else {
98  // const auto dx = geom[fine_lev].CellSize();
99  // Setting cell_vol to the exact value may cause round-off errors in volume average.
100  // const Real cell_vol = dx[0]*dx[1]*dx[2];
101  constexpr Real cell_vol = 1.0;
102  const BoxArray& ba = vars_new[fine_lev][IntVars::cons].boxArray();
103  const DistributionMapping& dm = vars_new[fine_lev][IntVars::cons].DistributionMap();
104  MultiFab vol_fine(ba, dm, 1, 0);
105  vol_fine.setVal(cell_vol);
106  EB_average_down(vars_new[fine_lev][Vars::cons],vars_new[crse_lev][Vars::cons],
107  vol_fine, *detJ_cc[fine_lev],
108  scomp, ncomp, refRatio(crse_lev));
109  }
110 
111  if (interpolation_type == StateInterpType::Perturbational) {
112  // Restore the fine data to what it was
113  MultiFab::Add(vars_new[fine_lev][Vars::cons],base_state[fine_lev],
114  BaseState::r0_comp,Rho_comp,1,IntVect{0});
115  MultiFab::Add(vars_new[fine_lev][Vars::cons],base_state[fine_lev],
116  BaseState::th0_comp,RhoTheta_comp,1,IntVect{0});
117  MultiFab::Multiply(vars_new[fine_lev][Vars::cons],vars_new[fine_lev][Vars::cons],
118  Rho_comp,RhoTheta_comp,1,IntVect{0});
119 
120  // Make the crse data be full values not perturbational
121  MultiFab::Add(vars_new[crse_lev][Vars::cons],base_state[crse_lev],
122  BaseState::r0_comp,Rho_comp,1,IntVect{0});
123  MultiFab::Add(vars_new[crse_lev][Vars::cons],base_state[crse_lev],
124  BaseState::th0_comp,RhoTheta_comp,1,IntVect{0});
125  MultiFab::Multiply(vars_new[crse_lev][Vars::cons],vars_new[crse_lev][Vars::cons],
126  Rho_comp,RhoTheta_comp,1,IntVect{0});
127  }
128 
129  vars_new[crse_lev][Vars::cons].FillBoundary(geom[crse_lev].periodicity());
130 
131  // ******************************************************************************************
132  // Here we multiply (rho S) by m^2 and divide by detJ after average down
133  // ******************************************************************************************
134  for (int lev = crse_lev; lev <= crse_lev+1; lev++) {
135  for (MFIter mfi(vars_new[lev][Vars::cons], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
136  const Box& bx = mfi.tilebox();
137  const Array4< Real> cons_arr = vars_new[lev][Vars::cons].array(mfi);
138  const Array4<const Real> mfx_arr = mapfac[lev][MapFacType::m_x]->const_array(mfi);
139  const Array4<const Real> mfy_arr = mapfac[lev][MapFacType::m_y]->const_array(mfi);
140  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
141  const Array4<const Real> detJ_arr = detJ_cc[lev]->const_array(mfi);
142  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
143  {
144  cons_arr(i,j,k,scomp+n) *= (mfx_arr(i,j,0)*mfy_arr(i,j,0)) / detJ_arr(i,j,k);
145  });
146  } else { // MeshType::ConstantDz
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));
150  });
151  }
152  } // mfi
153  } // lev
154 
155  // Fill EB covered cells by old values
156  // (This won't be needed because EB_average_down copies the covered value.)
157  if (SolverChoice::terrain_type == TerrainType::EB) {
158  for (int lev = crse_lev; lev <= crse_lev+1; lev++) {
159  for (MFIter mfi(vars_new[lev][Vars::cons], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
160  const Box& bx = mfi.tilebox();
161  const Array4< Real> cons_new = vars_new[lev][Vars::cons].array(mfi);
162  const Array4<const Real> cons_old = vars_old[lev][Vars::cons].array(mfi);
163  const Array4<const Real> detJ_arr = detJ_cc[lev]->const_array(mfi);
164  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
165  {
166  if (detJ_arr(i,j,k) == 0.0) {
167  cons_new(i,j,k,scomp+n) = cons_old(i,j,k,scomp+n);
168  }
169  });
170  } // mfi
171  } // lev
172  }
173 
174  // ******************************************************************************************
175  // Now average down momenta.
176  // Note that vars_new holds velocities not momenta, but we want to do conservative
177  // averaging so we first convert to momentum, then average down, then convert
178  // back to velocities -- only on the valid region
179  // ******************************************************************************************
180  for (int lev = crse_lev; lev <= crse_lev+1; lev++)
181  {
182  // FillBoundary for density so we can go back and forth between velocity and momentum
183  vars_new[lev][Vars::cons].FillBoundary(geom[lev].periodicity());
184 
185  const MultiFab* c_vfrac = nullptr;
186  if (SolverChoice::terrain_type == TerrainType::EB) {
187  c_vfrac = &((get_eb(lev).get_const_factory())->getVolFrac());
188  }
189 
190  VelocityToMomentum(vars_new[lev][Vars::xvel], IntVect(0,0,0),
191  vars_new[lev][Vars::yvel], IntVect(0,0,0),
192  vars_new[lev][Vars::zvel], IntVect(0,0,0),
193  vars_new[lev][Vars::cons],
194  rU_new[lev],
195  rV_new[lev],
196  rW_new[lev],
197  Geom(lev).Domain(),
199  c_vfrac);
200  }
201 
202  if (SolverChoice::terrain_type != TerrainType::EB) {
203  average_down_faces(rU_new[crse_lev+1], rU_new[crse_lev], refRatio(crse_lev), geom[crse_lev]);
204  average_down_faces(rV_new[crse_lev+1], rV_new[crse_lev], refRatio(crse_lev), geom[crse_lev]);
205  average_down_faces(rW_new[crse_lev+1], rW_new[crse_lev], refRatio(crse_lev), geom[crse_lev]);
206  } else {
207  EB_average_down_faces({&rU_new[crse_lev+1], &rV_new[crse_lev+1], &rW_new[crse_lev+1]},
208  {&rU_new[crse_lev], &rV_new[crse_lev], &rW_new[crse_lev]},
209  refRatio(crse_lev), 0);
210  }
211 
212  for (int lev = crse_lev; lev <= crse_lev+1; lev++) {
213 
214  const MultiFab* c_vfrac = nullptr;
215  if (SolverChoice::terrain_type == TerrainType::EB) {
216  c_vfrac = &((get_eb(lev).get_const_factory())->getVolFrac());
217  }
218 
220  vars_new[lev][Vars::yvel],
221  vars_new[lev][Vars::zvel],
222  vars_new[lev][Vars::cons],
223  rU_new[lev],
224  rV_new[lev],
225  rW_new[lev],
226  Geom(lev).Domain(),
228  c_vfrac);
229  }
230 }
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:1226
@ th0_comp
Definition: ERF_IndexDefines.H:66
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)
3174 {
3175  // *****************************************************************************
3176  // Test for low temp (low is defined as beyond the microphysics range of validity)
3177  // *****************************************************************************
3178  //
3179  // This value is defined in erf_dtesati in Source/Utils/ERF_MicrophysicsUtils.H
3180  Real t_low = 273.16 - 85.;
3181  //
3182  for (MFIter mfi(S); mfi.isValid(); ++mfi)
3183  {
3184  Box bx = mfi.tilebox();
3185  const Array4<Real> &s_arr = S.array(mfi);
3186  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
3187  {
3188  const Real rho = s_arr(i, j, k, Rho_comp);
3189  const Real rhotheta = s_arr(i, j, k, RhoTheta_comp);
3190  const Real qv = s_arr(i, j, k, RhoQ1_comp) / rho;
3191 
3192  Real temp = getTgivenRandRTh(rho, rhotheta, qv);
3193 
3194  if (temp < t_low) {
3195 #ifdef AMREX_USE_GPU
3196  AMREX_DEVICE_PRINTF("Temperature too low in cell: %d %d %d %e \n", i,j,k,temp);
3197 #else
3198  printf("Temperature too low in cell: %d %d %d \n", i,j,k);
3199  printf("Based on temp / rhotheta / rho / qv %e %e %e %e \n", temp,rhotheta,rho,qv);
3200 #endif
3201  Abort();
3202  }
3203  });
3204  }
3205 }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getTgivenRandRTh(const amrex::Real rho, const amrex::Real rhotheta, const amrex::Real qv=0.0)
Definition: ERF_EOS.H:46
rho
Definition: ERF_InitCustomPert_Bubble.H:106
@ qv
Definition: ERF_Kessler.H:28
Here is the call graph for this function:

◆ check_for_negative_theta()

void ERF::check_for_negative_theta ( amrex::MultiFab &  S)
3209 {
3210  // *****************************************************************************
3211  // Test for negative (rho theta)
3212  // *****************************************************************************
3213  for (MFIter mfi(S); mfi.isValid(); ++mfi)
3214  {
3215  Box bx = mfi.tilebox();
3216  const Array4<Real> &s_arr = S.array(mfi);
3217  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
3218  {
3219  const Real rho = s_arr(i, j, k, Rho_comp);
3220  const Real rhotheta = s_arr(i, j, k, RhoTheta_comp);
3221 
3222  if (rho <= 0.) {
3223 #ifdef AMREX_USE_GPU
3224  AMREX_DEVICE_PRINTF("Rho is negative at %d %d %d %e \n", i,j,k,rho);
3225 #else
3226  printf("Rho is negative at %d %d %d %e \n", i,j,k,rho);
3227  Abort("Bad rho in check_for_negative_theta");
3228 #endif
3229  }
3230 
3231  if (rhotheta <= 0.) {
3232 #ifdef AMREX_USE_GPU
3233  AMREX_DEVICE_PRINTF("RhoTheta is negative at %d %d %d %e \n", i,j,k,rhotheta);
3234 #else
3235  printf("RhoTheta is negative at %d %d %d %e \n", i,j,k,rhotheta);
3236  Abort("Bad theta in check_for_negative_theta");
3237 #endif
3238  }
3239 
3240  });
3241  } // mfi
3242 }
Here is the call graph for this function:

◆ check_state_for_nans()

void ERF::check_state_for_nans ( amrex::MultiFab const &  S)
3128 {
3129  bool any_have_nans = false;
3130 
3131  for (int i = 0; i < S.nComp(); i++) {
3132 
3133  if (S.contains_nan(i,1,0))
3134  {
3135  amrex::Print() << "Component " << i << " of conserved variables contains NaNs" << '\n';
3136  any_have_nans = true;
3137  }
3138  }
3139 
3140  if (any_have_nans) {
3141  exit(0);
3142  }
3143 }

◆ check_vels_for_nans()

void ERF::check_vels_for_nans ( amrex::MultiFab const &  xvel,
amrex::MultiFab const &  yvel,
amrex::MultiFab const &  zvel 
)
3147 {
3148  //
3149  // Test at the end of every full timestep whether the solution data contains NaNs
3150  //
3151  bool any_have_nans = false;
3152  if (xvel.contains_nan(0,1,0))
3153  {
3154  amrex::Print() << "x-velocity contains NaNs " << '\n';
3155  any_have_nans = true;
3156  }
3157  if (yvel.contains_nan(0,1,0))
3158  {
3159  amrex::Print() << "y-velocity contains NaNs" << '\n';
3160  any_have_nans = true;
3161  }
3162  if (zvel.contains_nan(0,1,0))
3163  {
3164  amrex::Print() << "z-velocity contains NaNs" << '\n';
3165  any_have_nans = true;
3166  }
3167  if (any_have_nans) {
3168  exit(0);
3169  }
3170 }

◆ ClearLevel()

void ERF::ClearLevel ( int  lev)
override
821 {
822  for (int var_idx = 0; var_idx < Vars::NumTypes; ++var_idx) {
823  vars_new[lev][var_idx].clear();
824  vars_old[lev][var_idx].clear();
825  }
826 
827  base_state[lev].clear();
828 
829  rU_new[lev].clear();
830  rU_old[lev].clear();
831  rV_new[lev].clear();
832  rV_old[lev].clear();
833  rW_new[lev].clear();
834  rW_old[lev].clear();
835 
836  if (lev > 0) {
837  zmom_crse_rhs[lev].clear();
838  }
839 
840  if ( (solverChoice.anelastic[lev] == 1) || (solverChoice.project_initial_velocity[lev] == 1) ) {
841  pp_inc[lev].clear();
842  }
843  if (solverChoice.anelastic[lev] == 0) {
844  lagged_delta_rt[lev].clear();
845  }
846  avg_xmom[lev].clear();
847  avg_ymom[lev].clear();
848  avg_zmom[lev].clear();
849 
850  // Clears the integrator memory
851  mri_integrator_mem[lev].reset();
852 
853  // Clears the physical boundary condition routines
854  physbcs_cons[lev].reset();
855  physbcs_u[lev].reset();
856  physbcs_v[lev].reset();
857  physbcs_w[lev].reset();
858  physbcs_base[lev].reset();
859 
860  // Clears the flux register array
861  advflux_reg[lev]->reset();
862 
863  // Clears the 2D arrays
864  if (sst_lev[lev][0]) {
865  for (int n = 0; n < sst_lev[lev].size(); n++) {
866  sst_lev[lev][n].reset();
867  }
868  }
869  if (tsk_lev[lev][0]) {
870  for (int n = 0; n < tsk_lev[lev].size(); n++) {
871  tsk_lev[lev][n].reset();
872  }
873  }
874  if (lat_m[lev]) {
875  lat_m[lev].reset();
876  }
877  if (lon_m[lev]) {
878  lon_m[lev].reset();
879  }
880  if (sinPhi_m[lev]) {
881  sinPhi_m[lev].reset();
882  }
883  if (cosPhi_m[lev]) {
884  cosPhi_m[lev].reset();
885  }
886 }
amrex::Vector< amrex::MultiFab > avg_xmom
Definition: ERF.H:835
amrex::Vector< amrex::MultiFab > pp_inc
Definition: ERF.H:831
amrex::Vector< amrex::MultiFab > lagged_delta_rt
Definition: ERF.H:834
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > sst_lev
Definition: ERF.H:914
amrex::Vector< amrex::YAFluxRegister * > advflux_reg
Definition: ERF.H:979
amrex::Vector< std::unique_ptr< amrex::MultiFab > > sinPhi_m
Definition: ERF.H:765
amrex::Vector< std::unique_ptr< amrex::MultiFab > > cosPhi_m
Definition: ERF.H:765
amrex::Vector< amrex::MultiFab > avg_ymom
Definition: ERF.H:836
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_base > > physbcs_base
Definition: ERF.H:844
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > tsk_lev
Definition: ERF.H:915
amrex::Vector< amrex::MultiFab > avg_zmom
Definition: ERF.H:837
@ NumTypes
Definition: ERF_IndexDefines.H:160
amrex::Vector< int > project_initial_velocity
Definition: ERF_DataStruct.H:1088

◆ cloud_fraction()

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

◆ 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 0.

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 = 1.0/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:937
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ay
Definition: ERF.H:938
Here is the call graph for this function:

◆ ComputeDt()

void ERF::ComputeDt ( int  step = -1)
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 != 1.0) {
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 = 1.e-3*dt_0;
43  if (t_new[0] + dt_0 > (stop_time - start_time) - eps) {
44  dt_0 = (stop_time - start_time) - t_new[0];
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::Vector< amrex::Real > t_new
Definition: ERF.H:810
amrex::Real estTimeStep(int lev, long &dt_fast_ratio) const
Definition: ERF_ComputeTimestep.cpp:60
static amrex::Real stop_time
Definition: ERF.H:1041
amrex::Vector< int > nsubsteps
Definition: ERF.H:807
static amrex::Real init_shrink
Definition: ERF.H:1052
static amrex::Real change_max
Definition: ERF.H:1053

◆ ComputeGhostCells()

static AMREX_FORCE_INLINE int ERF::ComputeGhostCells ( const SolverChoice sc)
inlinestaticprivate
1355  {
1356  int ngrow = 0;
1357 
1358  if (sc.use_num_diff)
1359  {
1360  ngrow = 3;
1361  } else {
1362  if (
1369  { ngrow = 3; }
1370  else if (
1377  { ngrow = 3; }
1378  else if (
1387  { ngrow = 3; }
1388  else if (
1397  { ngrow = 4; }
1398  else
1399  {
1400  if (sc.terrain_type == TerrainType::EB){
1401  ngrow = 4;
1402  } else {
1403  ngrow = 2;
1404  }
1405  }
1406  }
1407 
1408  return ngrow;
1409  }
@ 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:1076

◆ Construct_ERFFillPatchers()

void ERF::Construct_ERFFillPatchers ( int  lev)
private
3030 {
3031  auto& fine_new = vars_new[lev];
3032  auto& crse_new = vars_new[lev-1];
3033  auto& ba_fine = fine_new[Vars::cons].boxArray();
3034  auto& ba_crse = crse_new[Vars::cons].boxArray();
3035  auto& dm_fine = fine_new[Vars::cons].DistributionMap();
3036  auto& dm_crse = crse_new[Vars::cons].DistributionMap();
3037 
3038  int ncomp = vars_new[lev][Vars::cons].nComp();
3039 
3040  FPr_c.emplace_back(ba_fine, dm_fine, geom[lev] ,
3041  ba_crse, dm_crse, geom[lev-1],
3042  -cf_width, -cf_set_width, ncomp, &cell_cons_interp);
3043  FPr_u.emplace_back(convert(ba_fine, IntVect(1,0,0)), dm_fine, geom[lev] ,
3044  convert(ba_crse, IntVect(1,0,0)), dm_crse, geom[lev-1],
3045  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
3046  FPr_v.emplace_back(convert(ba_fine, IntVect(0,1,0)), dm_fine, geom[lev] ,
3047  convert(ba_crse, IntVect(0,1,0)), dm_crse, geom[lev-1],
3048  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
3049  FPr_w.emplace_back(convert(ba_fine, IntVect(0,0,1)), dm_fine, geom[lev] ,
3050  convert(ba_crse, IntVect(0,0,1)), dm_crse, geom[lev-1],
3051  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
3052 }
int cf_set_width
Definition: ERF.H:901

◆ create_random_perturbations()

void ERF::create_random_perturbations ( const int  lev,
amrex::MultiFab &  cons_pert,
amrex::MultiFab &  xvel_pert,
amrex::MultiFab &  yvel_pert,
amrex::MultiFab &  zvel_pert 
)
127 {
128  ignore_unused(cons_pert);
129  ignore_unused(yvel_pert);
130  ignore_unused(zvel_pert);
131 
132  auto& lev_new = vars_new[lev];
133  for (MFIter mfi(lev_new[Vars::cons], TileNoZ()); mfi.isValid(); ++mfi) {
134  const auto &xvel_pert_arr = xvel_pert.array(mfi);
135  const Box &xbx = mfi.tilebox(IntVect(1,0,0));
136  ParallelForRNG(xbx, [=] AMREX_GPU_DEVICE(int i, int j, int k, const amrex::RandomEngine& engine) noexcept
137  {
138  xvel_pert_arr(i, j, k) = amrex::Random(engine);
139  });
140  }
141 }
ParallelForRNG(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k, const amrex::RandomEngine &engine) noexcept { const Real x=prob_lo_x+(i+0.5) *dx;const Real y=prob_lo_y+(j+0.5) *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 !=0.0)) { Real rand_double=amrex::Random(engine);state_pert(i, j, k, RhoTheta_comp)=(rand_double *2.0 - 1.0) *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 *exp(-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, 1.0), KE_decay_order), 1e-12);} } })
const Box xbx
Definition: ERF_SetupDiff.H:7
Here is the call graph for this function:

◆ DataLog()

AMREX_FORCE_INLINE std::ostream& ERF::DataLog ( int  i)
inlineprivate
1420  {
1421  return *datalog[i];
1422  }
amrex::Vector< std::unique_ptr< std::fstream > > datalog
Definition: ERF.H:1599

◆ DataLogName()

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

The filename of the ith datalog file.

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

◆ Define_ERFFillPatchers()

void ERF::Define_ERFFillPatchers ( int  lev)
private
3056 {
3057  auto& fine_new = vars_new[lev];
3058  auto& crse_new = vars_new[lev-1];
3059  auto& ba_fine = fine_new[Vars::cons].boxArray();
3060  auto& ba_crse = crse_new[Vars::cons].boxArray();
3061  auto& dm_fine = fine_new[Vars::cons].DistributionMap();
3062  auto& dm_crse = crse_new[Vars::cons].DistributionMap();
3063 
3064  int ncomp = fine_new[Vars::cons].nComp();
3065 
3066  FPr_c[lev-1].Define(ba_fine, dm_fine, geom[lev] ,
3067  ba_crse, dm_crse, geom[lev-1],
3068  -cf_width, -cf_set_width, ncomp, &cell_cons_interp);
3069  FPr_u[lev-1].Define(convert(ba_fine, IntVect(1,0,0)), dm_fine, geom[lev] ,
3070  convert(ba_crse, IntVect(1,0,0)), dm_crse, geom[lev-1],
3071  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
3072  FPr_v[lev-1].Define(convert(ba_fine, IntVect(0,1,0)), dm_fine, geom[lev] ,
3073  convert(ba_crse, IntVect(0,1,0)), dm_crse, geom[lev-1],
3074  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
3075  FPr_w[lev-1].Define(convert(ba_fine, IntVect(0,0,1)), dm_fine, geom[lev] ,
3076  convert(ba_crse, IntVect(0,0,1)), dm_crse, geom[lev-1],
3077  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
3078 }

◆ DerDataLog()

AMREX_FORCE_INLINE std::ostream& ERF::DerDataLog ( int  i)
inlineprivate
1427  {
1428  return *der_datalog[i];
1429  }
amrex::Vector< std::unique_ptr< std::fstream > > der_datalog
Definition: ERF.H:1600

◆ DerDataLogName()

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

◆ derive_diag_profiles()

void ERF::derive_diag_profiles ( amrex::Real  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, Real(0.0));
245  Gpu::DeviceVector<Real> d_avg_v(hu_size, Real(0.0));
246  Gpu::DeviceVector<Real> d_avg_w(hu_size, Real(0.0));
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 = 0.0;
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) = 0.0;
293  fab_arr(i, j, k, 4) = 0.0;
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) = 0.5 * (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) = 0.; // qv
328  fab_arr(i, j, k,23) = 0.; // qc
329  fab_arr(i, j, k,24) = 0.; // qr
330  fab_arr(i, j, k,25) = 0.; // w*qv
331  fab_arr(i, j, k,26) = 0.; // w*qc
332  fab_arr(i, j, k,27) = 0.; // w*qr
333  fab_arr(i, j, k,28) = 0.; // qi
334  fab_arr(i, j, k,29) = 0.; // qs
335  fab_arr(i, j, k,30) = 0.; // qg
336  fab_arr(i, j, k,31) = 0.; // 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  Real(0.0);
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) = 0.0; // qi
382  fab_arr(i, j, k,29) = 0.0; // qs
383  fab_arr(i, j, k,30) = 0.0; // 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 + 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 = 0.;
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 }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getPgivenRTh(const amrex::Real rhotheta, const amrex::Real qv=0.)
Definition: ERF_EOS.H:81
#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
const Real dz
Definition: ERF_InitCustomPert_Bubble.H:25
@ Theta_v
Definition: ERF_IndexDefines.H:192
@ Mom_v
Definition: ERF_IndexDefines.H:191
@ theta
Definition: ERF_MM5.H:20
Here is the call graph for this function:

◆ derive_diag_profiles_stag()

void ERF::derive_diag_profiles_stag ( amrex::Real  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) = 0.5 * (u_arr(i,j,k) + u_arr(i+1,j ,k));
365  v_cc_arr(i,j,k) = 0.5 * (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 = 0.0;
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) = 0.0;
380  fab_arr(i, j, k, 4) = 0.0;
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 = 0.5 * (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) = 0.; // qv
404  fab_arr(i, j, k,17) = 0.; // qc
405  fab_arr(i, j, k,18) = 0.; // qr
406  fab_arr(i, j, k,19) = 0.; // qi
407  fab_arr(i, j, k,20) = 0.; // qs
408  fab_arr(i, j, k,21) = 0.; // 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 = 0.25 * ( 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 = 0.25 * ( 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 = 0.5*(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 = 0.5 * (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) = 0.; // w*qv
435  fab_arr_stag(i,j,k,7) = 0.; // w*qc
436  fab_arr_stag(i,j,k,8) = 0.; // w*qr
437  fab_arr_stag(i,j,k,9) = 0.; // 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  Real(0.0);
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) = 0.0; // qi
481  fab_arr(i, j, k,20) = 0.0; // qs
482  fab_arr(i, j, k,21) = 0.0; // 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  Real(0.0);
495  Real qr1 = (rhoqr_comp > -1) ? cons_arr(i,j,k-1,RhoQ3_comp) / cons_arr(i,j,k-1,Rho_comp) :
496  Real(0.0);
497  Real qvface = 0.5 * (qv0 + qv1);
498  Real qcface = 0.5 * (qc0 + qc1);
499  Real qrface = 0.5 * (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 = 0.5 * (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 = 0.5*(theta0 + theta1);
508  Real ql = qcface + qrface;
509  Real thv = thface * (1 + 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 }
const Box zbx
Definition: ERF_SetupDiff.H:9
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) = 0.5 * ( 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) ? 0.5 * ( q1fx3_arr(i,j,k) + q1fx3_arr(i,j,k+1) ) / rho_arr(i,j,k) : 0.0;
536  fab_arr(i, j, k, 8) = (l_use_moist) ? 0.5 * ( q2fx3_arr(i,j,k) + q2fx3_arr(i,j,k+1) ) / rho_arr(i,j,k) : 0.0;
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 = 0.5 * (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) = 0.5*(tau13_arr(i,j,k) + tau13_arr(i+1,j ,k)) / rho_face;
669  fab_arr_stag(i,j,k,1) = 0.5*(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 : 0.0;
673  fab_arr_stag(i,j,k,4) = (l_use_moist) ? q2fx3_arr(i,j,k) / rho_face : 0.0;
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
1633  {
1634  return *(eb[lev]->get_const_factory());
1635  }
amrex::Vector< std::unique_ptr< eb_ > > eb
Definition: ERF.H:1625

◆ 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
207 {
208  Real l_gravity = solverChoice.gravity;
209  bool l_use_terrain = (solverChoice.mesh_type != MeshType::ConstantDz);
210 
211  const auto geomdata = geom[lev].data();
212  const Real dz = geomdata.CellSize(2);
213 
214  for ( MFIter mfi(dens, TileNoZ()); mfi.isValid(); ++mfi )
215  {
216  // Create a flat box with same horizontal extent but only one cell in vertical
217  const Box& tbz = mfi.nodaltilebox(2);
218  int klo = tbz.smallEnd(2);
219  int khi = tbz.bigEnd(2);
220 
221  // Note we only grow by 1 because that is how big z_cc is.
222  Box b2d = tbz; // Copy constructor
223  b2d.grow(0,1);
224  b2d.grow(1,1);
225  b2d.setRange(2,0);
226 
227  // Intersect this box with the domain
228  Box zdomain = convert(geom[lev].Domain(),tbz.ixType());
229  b2d &= zdomain;
230 
231  // We integrate to the first cell (and below) by using rho in this cell
232  // If gravity == 0 this is constant pressure
233  // If gravity != 0, hence this is a wall, this gives gp0 = dens[0] * gravity
234  // (dens_hse*gravity would also be dens[0]*gravity because we use foextrap for rho at k = -1)
235  // Note ng_pres_hse = 1
236 
237  // We start by assuming pressure on the ground is p_0 (in ERF_Constants.H)
238  // Note that gravity is positive
239 
240  Array4<Real> rho_arr = dens.array(mfi);
241  Array4<Real> pres_arr = pres.array(mfi);
242  Array4<Real> pi_arr = pi.array(mfi);
243  Array4<Real> th_arr = theta.array(mfi);
244  Array4<Real> zcc_arr;
245  if (l_use_terrain) {
246  zcc_arr = z_cc->array(mfi);
247  }
248 
249  const Real rdOcp = solverChoice.rdOcp;
250 
251  ParallelFor(b2d, [=] AMREX_GPU_DEVICE (int i, int j, int)
252  {
253  // Set value at surface from Newton iteration for rho
254  if (klo == 0)
255  {
256  // Physical height of the terrain at cell center
257  Real hz;
258  if (l_use_terrain) {
259  hz = zcc_arr(i,j,klo);
260  } else {
261  hz = 0.5*dz;
262  }
263 
264  pres_arr(i,j,klo) = p_0 - hz * rho_arr(i,j,klo) * l_gravity;
265  pi_arr(i,j,klo) = getExnergivenP(pres_arr(i,j,klo), rdOcp);
266  th_arr(i,j,klo) = getRhoThetagivenP(pres_arr(i,j,klo)) / rho_arr(i,j,klo);
267 
268  //
269  // Set ghost cell with dz and rho at boundary
270  // (We will set the rest of the ghost cells in the boundary condition routine)
271  //
272  pres_arr(i,j,klo-1) = p_0 + hz * rho_arr(i,j,klo) * l_gravity;
273  pi_arr(i,j,klo-1) = getExnergivenP(pres_arr(i,j,klo-1), rdOcp);
274  th_arr(i,j,klo-1) = getRhoThetagivenP(pres_arr(i,j,klo-1)) / rho_arr(i,j,klo-1);
275 
276  } else {
277 
278  // If level > 0 and klo > 0, we need to use the value of pres_arr(i,j,klo-1) which was
279  // filled from FillPatch-ing it.
280  Real dz_loc;
281  if (l_use_terrain) {
282  dz_loc = (zcc_arr(i,j,klo) - zcc_arr(i,j,klo-1));
283  } else {
284  dz_loc = dz;
285  }
286 
287  Real dens_interp = 0.5*(rho_arr(i,j,klo) + rho_arr(i,j,klo-1));
288  pres_arr(i,j,klo) = pres_arr(i,j,klo-1) - dz_loc * dens_interp * l_gravity;
289 
290  pi_arr(i,j,klo ) = getExnergivenP(pres_arr(i,j,klo ), rdOcp);
291  th_arr(i,j,klo ) = getRhoThetagivenP(pres_arr(i,j,klo )) / rho_arr(i,j,klo );
292 
293  pi_arr(i,j,klo-1) = getExnergivenP(pres_arr(i,j,klo-1), rdOcp);
294  th_arr(i,j,klo-1) = getRhoThetagivenP(pres_arr(i,j,klo-1)) / rho_arr(i,j,klo-1);
295  }
296 
297  Real dens_interp;
298  if (l_use_terrain) {
299  for (int k = klo+1; k <= khi; k++) {
300  Real dz_loc = (zcc_arr(i,j,k) - zcc_arr(i,j,k-1));
301  dens_interp = 0.5*(rho_arr(i,j,k) + rho_arr(i,j,k-1));
302  pres_arr(i,j,k) = pres_arr(i,j,k-1) - dz_loc * dens_interp * l_gravity;
303  pi_arr(i,j,k) = getExnergivenP(pres_arr(i,j,k), rdOcp);
304  th_arr(i,j,k) = getRhoThetagivenP(pres_arr(i,j,k)) / rho_arr(i,j,k);
305  }
306  } else {
307  for (int k = klo+1; k <= khi; k++) {
308  dens_interp = 0.5*(rho_arr(i,j,k) + rho_arr(i,j,k-1));
309  pres_arr(i,j,k) = pres_arr(i,j,k-1) - dz * dens_interp * l_gravity;
310  pi_arr(i,j,k) = getExnergivenP(pres_arr(i,j,k), rdOcp);
311  th_arr(i,j,k) = getRhoThetagivenP(pres_arr(i,j,k)) / rho_arr(i,j,k);
312  }
313  }
314  });
315 
316  } // mfi
317 
318  dens.FillBoundary(geom[lev].periodicity());
319  pres.FillBoundary(geom[lev].periodicity());
320  pi.FillBoundary(geom[lev].periodicity());
321  theta.FillBoundary(geom[lev].periodicity());
322  qv.FillBoundary(geom[lev].periodicity());
323 }
constexpr amrex::Real p_0
Definition: ERF_Constants.H:18
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getRhoThetagivenP(const amrex::Real p, const amrex::Real qv=0.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 int klo
Definition: ERF_InitCustomPertVels_ParticleTests.H:4
const Real rdOcp
Definition: ERF_InitCustomPert_Bomex.H:16
const int khi
Definition: ERF_InitCustomPert_Bubble.H:21
@ pres
Definition: ERF_Kessler.H:25
real(c_double), parameter, private pi
Definition: ERF_module_mp_morr_two_moment.F90:100
amrex::Real rdOcp
Definition: ERF_DataStruct.H:1144
amrex::Real gravity
Definition: ERF_DataStruct.H:1142
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 
231  const std::string& pv3d_1 = "plot_vars_1" ; setPlotVariables(pv3d_1,plot3d_var_names_1);
232  const std::string& pv3d_2 = "plot_vars_2" ; setPlotVariables(pv3d_2,plot3d_var_names_2);
233  const std::string& pv2d_1 = "plot2d_vars_1"; setPlotVariables2D(pv2d_1,plot2d_var_names_1);
234  const std::string& pv2d_2 = "plot2d_vars_2"; setPlotVariables2D(pv2d_2,plot2d_var_names_2);
235 
236  // This is only used when we have mesh_type == MeshType::StretchedDz
237  stretched_dz_h.resize(nlevs_max);
238  stretched_dz_d.resize(nlevs_max);
239 
240  // Initialize staggered vertical levels for grid stretching or terrain, and
241  // to simplify Rayleigh damping layer calculations.
242  zlevels_stag.resize(max_level+1);
246  geom,
247  refRatio(),
250  solverChoice.dz0);
251 
252  if (SolverChoice::mesh_type == MeshType::StretchedDz ||
253  SolverChoice::mesh_type == MeshType::VariableDz) {
254  int nz = geom[0].Domain().length(2) + 1; // staggered
255  if (std::fabs(zlevels_stag[0][nz-1]-geom[0].ProbHi(2)) > 1.0e-4) {
256  Print() << "Note: prob_hi[2]=" << geom[0].ProbHi(2)
257  << " does not match highest requested z level " << zlevels_stag[0][nz-1]
258  << std::endl;
259  }
260  if (std::fabs(zlevels_stag[0][0]-geom[0].ProbLo(2)) > 1.0e-4) {
261  Print() << "Note: prob_lo[2]=" << geom[0].ProbLo(2)
262  << " does not match lowest requested level " << zlevels_stag[0][0]
263  << std::endl;
264  }
265 
266  // Redefine the problem domain here?
267  }
268 
269  // Get lo/hi indices for massflux calc
271  if (solverChoice.mesh_type == MeshType::ConstantDz) {
272  const Real massflux_zlo = solverChoice.const_massflux_layer_lo - geom[0].ProbLo(2);
273  const Real massflux_zhi = solverChoice.const_massflux_layer_hi - geom[0].ProbLo(2);
274  const Real dz = geom[0].CellSize(2);
275  if (massflux_zlo == -1e34) {
276  solverChoice.massflux_klo = geom[0].Domain().smallEnd(2);
277  } else {
278  solverChoice.massflux_klo = static_cast<int>(std::ceil(massflux_zlo / dz - 0.5));
279  }
280  if (massflux_zhi == 1e34) {
281  solverChoice.massflux_khi = geom[0].Domain().bigEnd(2);
282  } else {
283  solverChoice.massflux_khi = static_cast<int>(std::floor(massflux_zhi / dz - 0.5));
284  }
285  } else if (solverChoice.mesh_type == MeshType::StretchedDz) {
286  const Real massflux_zlo = solverChoice.const_massflux_layer_lo;
287  const Real massflux_zhi = solverChoice.const_massflux_layer_hi;
288  solverChoice.massflux_klo = geom[0].Domain().smallEnd(2);
289  solverChoice.massflux_khi = geom[0].Domain().bigEnd(2) + 1;
290  for (int k=0; k <= geom[0].Domain().bigEnd(2)+1; ++k) {
291  if (zlevels_stag[0][k] <= massflux_zlo) solverChoice.massflux_klo = k;
292  if (zlevels_stag[0][k] <= massflux_zhi) solverChoice.massflux_khi = k;
293  }
294  } else { // solverChoice.mesh_type == MeshType::VariableDz
295  Error("Const massflux with variable dz not supported -- planar averages are on k rather than constant-z planes");
296  }
297 
298  Print() << "Constant mass flux based on k in ["
299  << solverChoice.massflux_klo << ", " << solverChoice.massflux_khi << "]" << std::endl;
300  }
301 
302  prob = amrex_probinit(geom[0].ProbLo(),geom[0].ProbHi());
303 
304  // Geometry on all levels has been defined already.
305 
306  // No valid BoxArray and DistributionMapping have been defined.
307  // But the arrays for them have been resized.
308 
309  t_new.resize(nlevs_max, 0.0);
310  t_old.resize(nlevs_max, -1.e100);
311  dt.resize(nlevs_max, std::min(1.e100,dt_max_initial));
312  dt_mri_ratio.resize(nlevs_max, 1);
313 
314  vars_new.resize(nlevs_max);
315  vars_old.resize(nlevs_max);
316  gradp.resize(nlevs_max);
317 
318  // We resize this regardless in order to pass it without error
319  pp_inc.resize(nlevs_max);
320 
321  // Used in the fast substepping only
322  lagged_delta_rt.resize(nlevs_max);
323  avg_xmom.resize(nlevs_max);
324  avg_ymom.resize(nlevs_max);
325  avg_zmom.resize(nlevs_max);
326 
327  rU_new.resize(nlevs_max);
328  rV_new.resize(nlevs_max);
329  rW_new.resize(nlevs_max);
330 
331  rU_old.resize(nlevs_max);
332  rV_old.resize(nlevs_max);
333  rW_old.resize(nlevs_max);
334 
335  // xmom_crse_rhs.resize(nlevs_max);
336  // ymom_crse_rhs.resize(nlevs_max);
337  zmom_crse_rhs.resize(nlevs_max);
338 
339  for (int lev = 0; lev < nlevs_max; ++lev) {
340  vars_new[lev].resize(Vars::NumTypes);
341  vars_old[lev].resize(Vars::NumTypes);
342  gradp[lev].resize(AMREX_SPACEDIM);
343  }
344 
345  // Time integrator
346  mri_integrator_mem.resize(nlevs_max);
347 
348  // Physical boundary conditions
349  physbcs_cons.resize(nlevs_max);
350  physbcs_u.resize(nlevs_max);
351  physbcs_v.resize(nlevs_max);
352  physbcs_w.resize(nlevs_max);
353  physbcs_base.resize(nlevs_max);
354 
355  // Planes to hold Dirichlet values at boundaries
356  xvel_bc_data.resize(nlevs_max);
357  yvel_bc_data.resize(nlevs_max);
358  zvel_bc_data.resize(nlevs_max);
359  th_bc_data.resize(nlevs_max);
360 
361  advflux_reg.resize(nlevs_max);
362 
363  // Stresses
364  Tau.resize(nlevs_max);
365  Tau_corr.resize(nlevs_max);
366  SFS_hfx1_lev.resize(nlevs_max); SFS_hfx2_lev.resize(nlevs_max); SFS_hfx3_lev.resize(nlevs_max);
367  SFS_diss_lev.resize(nlevs_max);
368  SFS_q1fx1_lev.resize(nlevs_max); SFS_q1fx2_lev.resize(nlevs_max); SFS_q1fx3_lev.resize(nlevs_max);
369  SFS_q2fx3_lev.resize(nlevs_max);
370  eddyDiffs_lev.resize(nlevs_max);
371  SmnSmn_lev.resize(nlevs_max);
372 
373  // Sea surface temps
374  sst_lev.resize(nlevs_max);
375  tsk_lev.resize(nlevs_max);
376  lmask_lev.resize(nlevs_max);
377 
378  // Land and soil grid type and urban fractions
379  land_type_lev.resize(nlevs_max);
380  soil_type_lev.resize(nlevs_max);
381  urb_frac_lev.resize(nlevs_max);
382 
383  // Metric terms
384  z_phys_nd.resize(nlevs_max);
385  z_phys_cc.resize(nlevs_max);
386  detJ_cc.resize(nlevs_max);
387  ax.resize(nlevs_max);
388  ay.resize(nlevs_max);
389  az.resize(nlevs_max);
390 
391  z_phys_nd_new.resize(nlevs_max);
392  detJ_cc_new.resize(nlevs_max);
393 
394  z_phys_nd_src.resize(nlevs_max);
395  z_phys_cc_src.resize(nlevs_max);
396  detJ_cc_src.resize(nlevs_max);
397  ax_src.resize(nlevs_max);
398  ay_src.resize(nlevs_max);
399  az_src.resize(nlevs_max);
400 
401  z_t_rk.resize(nlevs_max);
402 
403  terrain_blanking.resize(nlevs_max);
404 
405  // Wall distance
406  walldist.resize(nlevs_max);
407 
408  // BoxArrays to make MultiFabs needed to convert WRFBdy data
409  ba1d.resize(nlevs_max);
410  ba2d.resize(nlevs_max);
411 
412  // MultiFabs needed to convert WRFBdy data
413  mf_PSFC.resize(nlevs_max);
414 
415  // Map factors
416  mapfac.resize(nlevs_max);
417 
418  // Fine mask
419  fine_mask.resize(nlevs_max);
420 
421  // Thin immersed body
422  xflux_imask.resize(nlevs_max);
423  yflux_imask.resize(nlevs_max);
424  zflux_imask.resize(nlevs_max);
425  //overset_imask.resize(nlevs_max);
426  thin_xforce.resize(nlevs_max);
427  thin_yforce.resize(nlevs_max);
428  thin_zforce.resize(nlevs_max);
429 
430  // Base state
431  base_state.resize(nlevs_max);
432  base_state_new.resize(nlevs_max);
433 
434  // Wave coupling data
435  Hwave.resize(nlevs_max);
436  Lwave.resize(nlevs_max);
437  for (int lev = 0; lev < max_level; ++lev)
438  {
439  Hwave[lev] = nullptr;
440  Lwave[lev] = nullptr;
441  }
442  Hwave_onegrid.resize(nlevs_max);
443  Lwave_onegrid.resize(nlevs_max);
444  for (int lev = 0; lev < max_level; ++lev)
445  {
446  Hwave_onegrid[lev] = nullptr;
447  Lwave_onegrid[lev] = nullptr;
448  }
449 
450  // Theta prim for MOST
451  Theta_prim.resize(nlevs_max);
452 
453  // Qv prim for MOST
454  Qv_prim.resize(nlevs_max);
455 
456  // Qr prim for MOST
457  Qr_prim.resize(nlevs_max);
458 
459  // Time averaged velocity field
460  vel_t_avg.resize(nlevs_max);
461  t_avg_cnt.resize(nlevs_max);
462 
463  // Size lat long arrays and default to null pointers
464  lat_m.resize(nlevs_max);
465  lon_m.resize(nlevs_max);
466  for (int lev = 0; lev < max_level; ++lev) {
467  lat_m[lev] = nullptr;
468  lon_m[lev] = nullptr;
469  }
470 
471  // Variable coriolis
472  sinPhi_m.resize(nlevs_max);
473  cosPhi_m.resize(nlevs_max);
474  for (int lev = 0; lev < max_level; ++lev) {
475  sinPhi_m[lev] = nullptr;
476  cosPhi_m[lev] = nullptr;
477  }
478 
479  // Rayleigh damping
480  h_rayleigh_ptrs.resize(nlevs_max);
481  d_rayleigh_ptrs.resize(nlevs_max);
482  h_sinesq_ptrs.resize(nlevs_max);
483  d_sinesq_ptrs.resize(nlevs_max);
484  h_sinesq_stag_ptrs.resize(nlevs_max);
485  d_sinesq_stag_ptrs.resize(nlevs_max);
486 
487  // Initialize tagging criteria for mesh refinement
489 
490  for (int lev = 0; lev < max_level; ++lev)
491  {
492  Print() << "Refinement ratio at level " << lev+1 << " set to be " <<
493  ref_ratio[lev][0] << " " << ref_ratio[lev][1] << " " << ref_ratio[lev][2] << std::endl;
494  }
495 
496  // We will create each of these in MakeNewLevelFromScratch
497  eb.resize(max_level+1);
498  for (int lev = 0; lev < max_level + 1; lev++){
499  eb[lev] = std::make_unique<eb_>();
500  }
501 
502  //
503  // Construct the EB data structures and store in a separate class
504  //
505  // This is needed before initializing level MultiFabs
506  if ( solverChoice.terrain_type == TerrainType::EB ||
507  solverChoice.terrain_type == TerrainType::ImmersedForcing)
508  {
509  std::string geometry ="terrain";
510  ParmParse pp_eb2("eb2");
511  pp_eb2.queryAdd("geometry", geometry);
512 
513  constexpr int ngrow_for_eb = 4; // This is the default in amrex but we need to explicitly pass it here since
514  // we want to also pass the build_coarse_level_by_coarsening argument
515  const bool build_eb_for_multigrid = (solverChoice.terrain_type == TerrainType::EB &&
517  solverChoice.anelastic[0] == 1));
518  // Note this just needs to be an integer > number of V-cycles one might use
519  const int max_coarsening_level = (build_eb_for_multigrid) ? 100 : 0;
520  const bool build_coarse_level_by_coarsening(false);
521 
522  // Define GeometryShop using the implicit function
523  if (geometry == "terrain") {
524  Box terrain_bx(surroundingNodes(geom[max_level].Domain())); terrain_bx.grow(3);
525  FArrayBox terrain_fab(makeSlab(terrain_bx,2,0),1);
526  Real dummy_time = 0.0;
527  prob->init_terrain_surface(geom[max_level], terrain_fab, dummy_time);
528  TerrainIF implicit_fun(terrain_fab, geom[max_level], stretched_dz_d[max_level]);
529  auto gshop = EB2::makeShop(implicit_fun);
530  if (build_eb_for_multigrid) {
531  EB2::Build(gshop, geom[max_level], max_level, max_coarsening_level,
532  ngrow_for_eb, build_coarse_level_by_coarsening);
533  } else {
534  EB2::Build(gshop, this->Geom(), ngrow_for_eb);
535  }
536  } else if (geometry == "plane") {
537  RealArray plane_point{0.0, 0.0, 0.0};
538  RealArray plane_normal{0.0, 0.0, -1.0}; // pointing into the solid region
539  pp_eb2.query("plane_point", plane_point);
540  pp_eb2.query("plane_normal", plane_normal);
541  EB2::PlaneIF implicit_fun(plane_point, plane_normal, false);
542  auto gshop = EB2::makeShop(implicit_fun);
543  if (build_eb_for_multigrid) {
544  EB2::Build(gshop, geom[max_level], max_level, max_coarsening_level,
545  ngrow_for_eb, build_coarse_level_by_coarsening);
546  } else {
547  EB2::Build(gshop, this->Geom(), ngrow_for_eb);
548  }
549  } else if (geometry == "box") {
550  RealArray box_lo{0.0, 0.0, 0.0};
551  RealArray box_hi{0.0, 0.0, 0.0};
552  pp_eb2.query("box_lo", box_lo);
553  pp_eb2.query("box_hi", box_hi);
554  EB2::BoxIF implicit_fun(box_lo, box_hi, false);
555  auto gshop = EB2::makeShop(implicit_fun);
556  if (build_eb_for_multigrid) {
557  EB2::Build(gshop, geom[max_level], max_level, max_coarsening_level,
558  ngrow_for_eb, build_coarse_level_by_coarsening);
559  } else {
560  EB2::Build(gshop, this->Geom(), ngrow_for_eb);
561  }
562  } else if (geometry == "sphere") {
563  auto ProbLoArr = geom[max_level].ProbLoArray();
564  auto ProbHiArr = geom[max_level].ProbHiArray();
565  const Real xcen = 0.5 * (ProbLoArr[0] + ProbHiArr[0]);
566  const Real ycen = 0.5 * (ProbLoArr[1] + ProbHiArr[1]);
567  RealArray sphere_center = {xcen, ycen, 0.0};
568  EB2::SphereIF implicit_fun(0.5, sphere_center, false);
569  auto gshop = EB2::makeShop(implicit_fun);
570  if (build_eb_for_multigrid) {
571  EB2::Build(gshop, geom[max_level], max_level, max_coarsening_level,
572  ngrow_for_eb, build_coarse_level_by_coarsening);
573  } else {
574  EB2::Build(gshop, this->Geom(), ngrow_for_eb);
575  }
576  }
577  }
578 
579  if ( solverChoice.buildings_type == BuildingsType::ImmersedForcing) {
580  constexpr int ngrow_for_eb = 4;
581  Box buildings_bx(surroundingNodes(geom[max_level].Domain())); buildings_bx.grow(3);
582  FArrayBox buildings_fab(makeSlab(buildings_bx,2,0),1);
583  Real dummy_time = 0.0;
584  prob->init_buildings_surface(geom[max_level], buildings_fab, dummy_time);
585  TerrainIF implicit_fun(buildings_fab, geom[max_level], stretched_dz_d[max_level]);
586  auto gshop = EB2::makeShop(implicit_fun);
587  EB2::Build(gshop, this->Geom(), ngrow_for_eb);
588  }
589 
590  forecast_state_1.resize(nlevs_max);
591  forecast_state_2.resize(nlevs_max);
592  forecast_state_interp.resize(nlevs_max);
593 
594  surface_state_1.resize(nlevs_max);
595  surface_state_2.resize(nlevs_max);
596  surface_state_interp.resize(nlevs_max);
597 }
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:974
amrex::Vector< std::unique_ptr< amrex::MultiFab > > thin_yforce
Definition: ERF.H:1007
void setPlotVariables(const std::string &pp_plot_var_names, amrex::Vector< std::string > &plot_var_names)
Definition: ERF_Plotfile.cpp:25
amrex::Vector< amrex::BoxArray > ba2d
Definition: ERF.H:1259
amrex::Vector< amrex::Vector< amrex::MultiFab > > gradp
Definition: ERF.H:822
void ReadParameters()
Definition: ERF.cpp:2294
amrex::Vector< amrex::Vector< amrex::MultiFab > > forecast_state_interp
Definition: ERF.H:165
amrex::Vector< std::unique_ptr< amrex::MultiFab > > mf_PSFC
Definition: ERF.H:1264
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_nd_src
Definition: ERF.H:941
amrex::Vector< amrex::MultiFab > base_state_new
Definition: ERF.H:969
amrex::Vector< std::unique_ptr< amrex::MultiFab > > az
Definition: ERF.H:939
amrex::Vector< std::unique_ptr< amrex::MultiFab > > terrain_blanking
Definition: ERF.H:954
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_nd_new
Definition: ERF.H:948
amrex::Vector< std::unique_ptr< amrex::MultiFab > > thin_zforce
Definition: ERF.H:1008
amrex::Vector< std::string > plot3d_var_names_2
Definition: ERF.H:1105
amrex::Vector< std::string > plot2d_var_names_1
Definition: ERF.H:1106
amrex::Vector< std::unique_ptr< amrex::MultiFab > > thin_xforce
Definition: ERF.H:1006
void setPlotVariables2D(const std::string &pp_plot_var_names, amrex::Vector< std::string > &plot_var_names)
Definition: ERF_Plotfile.cpp:187
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > th_bc_data
Definition: ERF.H:777
amrex::Vector< amrex::MultiFab > surface_state_1
Definition: ERF.H:166
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_t_rk
Definition: ERF.H:951
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Lwave_onegrid
Definition: ERF.H:975
amrex::Vector< amrex::Vector< amrex::Real > > h_sinesq_ptrs
Definition: ERF.H:1313
amrex::Vector< std::unique_ptr< amrex::MultiFab > > fine_mask
Definition: ERF.H:963
amrex::Vector< std::unique_ptr< ForestDrag > > m_forest_drag
Definition: ERF.H:1341
amrex::Vector< amrex::BoxArray > ba1d
Definition: ERF.H:1258
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > xvel_bc_data
Definition: ERF.H:774
int rad_datalog_int
Definition: ERF.H:897
amrex::Vector< amrex::MultiFab > surface_state_2
Definition: ERF.H:167
amrex::Vector< std::unique_ptr< amrex::MultiFab > > detJ_cc_src
Definition: ERF.H:943
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ay_src
Definition: ERF.H:945
amrex::Vector< std::unique_ptr< amrex::iMultiFab > > yflux_imask
Definition: ERF.H:1001
amrex::Vector< amrex::Vector< amrex::MultiFab * > > lsm_flux
Definition: ERF.H:883
amrex::Vector< std::string > plot3d_var_names_1
Definition: ERF.H:1104
void refinement_criteria_setup()
Definition: ERF_Tagging.cpp:363
amrex::Vector< std::string > plot2d_var_names_2
Definition: ERF.H:1107
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > Tau_corr
Definition: ERF.H:909
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ax_src
Definition: ERF.H:944
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > urb_frac_lev
Definition: ERF.H:921
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_cc_src
Definition: ERF.H:942
amrex::Vector< amrex::Vector< amrex::MultiFab > > forecast_state_2
Definition: ERF.H:164
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::iMultiFab > > > soil_type_lev
Definition: ERF.H:920
amrex::Vector< amrex::Vector< amrex::Real > > zlevels_stag
Definition: ERF.H:930
amrex::Vector< amrex::Vector< amrex::MultiFab * > > lsm_data
Definition: ERF.H:881
amrex::Vector< amrex::Vector< amrex::Real > > stretched_dz_h
Definition: ERF.H:965
amrex::Vector< std::unique_ptr< amrex::MultiFab > > az_src
Definition: ERF.H:946
static amrex::Real dt_max_initial
Definition: ERF.H:1054
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Lwave
Definition: ERF.H:973
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::iMultiFab > > > land_type_lev
Definition: ERF.H:919
amrex::Vector< amrex::Vector< amrex::MultiFab > > forecast_state_1
Definition: ERF.H:163
amrex::Vector< std::unique_ptr< amrex::iMultiFab > > zflux_imask
Definition: ERF.H:1002
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > zvel_bc_data
Definition: ERF.H:776
amrex::Vector< amrex::Vector< amrex::Real > > h_sinesq_stag_ptrs
Definition: ERF.H:1314
amrex::Vector< std::unique_ptr< amrex::MultiFab > > detJ_cc_new
Definition: ERF.H:949
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > yvel_bc_data
Definition: ERF.H:775
amrex::Vector< amrex::MultiFab > surface_state_interp
Definition: ERF.H:168
amrex::Vector< amrex::Vector< amrex::Vector< amrex::Real > > > h_rayleigh_ptrs
Definition: ERF.H:1309
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Hwave
Definition: ERF.H:972
amrex::Vector< std::unique_ptr< amrex::iMultiFab > > xflux_imask
Definition: ERF.H:1000
void initializeMicrophysics(const int &)
Definition: ERF.cpp:2068
void ReSize(const int &nlev)
Definition: ERF_LandSurface.H:24
Definition: ERF_EBIFTerrain.H:14
const char * buildInfoGetGitHash(int i)
amrex::Real dz0
Definition: ERF_DataStruct.H:1149
amrex::Real const_massflux_layer_lo
Definition: ERF_DataStruct.H:1232
amrex::Real const_massflux_v
Definition: ERF_DataStruct.H:1230
int massflux_klo
Definition: ERF_DataStruct.H:1234
amrex::Real grid_stretching_ratio
Definition: ERF_DataStruct.H:1147
amrex::Real const_massflux_u
Definition: ERF_DataStruct.H:1229
amrex::Real zsurf
Definition: ERF_DataStruct.H:1148
static BuildingsType buildings_type
Definition: ERF_DataStruct.H:1059
amrex::Real const_massflux_layer_hi
Definition: ERF_DataStruct.H:1233
int massflux_khi
Definition: ERF_DataStruct.H:1235
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 j=0; j < ref_tags.size(); ++j)
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[j].Field() == "density")
185  {
186  MultiFab::Copy(*mf,vars_new[levc][Vars::cons],Rho_comp,0,1,1);
187 
188  // This allows dynamic refinement based on the value of qv
189  } else if ( ref_tags[j].Field() == "qv" ) {
190  MultiFab::Copy( *mf, vars_new[levc][Vars::cons], RhoQ1_comp, 0, 1, 1);
191  MultiFab::Divide(*mf, vars_new[levc][Vars::cons], Rho_comp, 0, 1, 1);
192 
193 
194  // This allows dynamic refinement based on the value of qc
195  } else if (ref_tags[j].Field() == "qc" ) {
196  MultiFab::Copy( *mf, vars_new[levc][Vars::cons], RhoQ2_comp, 0, 1, 1);
197  MultiFab::Divide(*mf, vars_new[levc][Vars::cons], Rho_comp, 0, 1, 1);
198 
199  // This allows dynamic refinement based on the value of the z-component of vorticity
200  } else if (ref_tags[j].Field() == "vorticity" ) {
201  Vector<MultiFab> mf_cc_vel(1);
202  mf_cc_vel[0].define(grids[levc], dmap[levc], AMREX_SPACEDIM, IntVect(1,1,1));
203  average_face_to_cellcenter(mf_cc_vel[0],0,Array<const MultiFab*,3>{&U_new, &V_new, &W_new});
204 
205  // Impose bc's at domain boundaries at all levels
206  FillBdyCCVels(mf_cc_vel,levc);
207 
208  mf->setVal(0.);
209 
210  for (MFIter mfi(*mf, TilingIfNotGPU()); mfi.isValid(); ++mfi)
211  {
212  const Box& bx = mfi.tilebox();
213  auto& dfab = (*mf)[mfi];
214  auto& sfab = mf_cc_vel[0][mfi];
215  derived::erf_dervortz(bx, dfab, 0, 1, sfab, Geom(levc), time, nullptr, levc);
216  }
217 
218  // This allows dynamic refinement based on the value of the scalar/theta
219  } else if ( (ref_tags[j].Field() == "scalar" ) ||
220  (ref_tags[j].Field() == "theta" ) )
221  {
222  for (MFIter mfi(*mf, TilingIfNotGPU()); mfi.isValid(); ++mfi)
223  {
224  const Box& bx = mfi.growntilebox();
225  auto& dfab = (*mf)[mfi];
226  auto& sfab = vars_new[levc][Vars::cons][mfi];
227  if (ref_tags[j].Field() == "scalar") {
228  derived::erf_derscalar(bx, dfab, 0, 1, sfab, Geom(levc), time, nullptr, levc);
229  } else if (ref_tags[j].Field() == "theta") {
230  derived::erf_dertheta(bx, dfab, 0, 1, sfab, Geom(levc), time, nullptr, levc);
231  }
232  } // mfi
233  // This allows dynamic refinement based on the value of the density
234  } else if ( (SolverChoice::terrain_type == TerrainType::ImmersedForcing) &&
235  (ref_tags[j].Field() == "terrain_blanking") )
236  {
237  MultiFab::Copy(*mf,*terrain_blanking[levc],0,0,1,1);
238  }
239  else if (ref_tags[j].Field() == "velmag")
240  {
241  ParmParse pp(pp_prefix);
242  Vector<std::string> refinement_indicators;
243  pp.queryarr("refinement_indicators",refinement_indicators,0,pp.countval("refinement_indicators"));
244  Real velmag_threshold;
245  bool is_hurricane_tracker = false;
246  for (int i=0; i<refinement_indicators.size(); ++i)
247  {
248  if (refinement_indicators[i]=="hurricane_tracker") {
249  is_hurricane_tracker = true;
250  std::string ref_prefix = pp_prefix + "." + refinement_indicators[i];
251  ParmParse ppr(ref_prefix);
252  ppr.get("value_greater", velmag_threshold);
253  break;
254  }
255  }
256 
257  Vector<MultiFab> mf_cc_vel(1);
258  mf_cc_vel[0].define(grids[levc], dmap[levc], AMREX_SPACEDIM, IntVect(0,0,0));
259  average_face_to_cellcenter(mf_cc_vel[0],0,Array<const MultiFab*,3>{&U_new, &V_new, &W_new});
260 
261  if (is_hurricane_tracker) {
262  HurricaneTracker(levc, time, mf_cc_vel[0], velmag_threshold, &tags);
263  } else {
264  for (MFIter mfi(*mf, TilingIfNotGPU()); mfi.isValid(); ++mfi)
265  {
266  const Box& bx = mfi.tilebox();
267  auto& dfab = (*mf)[mfi];
268  auto& sfab = mf_cc_vel[0][mfi];
269  derived::erf_dermagvel(bx, dfab, 0, 1, sfab, Geom(levc), time, nullptr, levc);
270  }
271  }
272 
273 #ifdef ERF_USE_PARTICLES
274  } else {
275  //
276  // This allows dynamic refinement based on the number of particles per cell
277  //
278  // Note that we must count all the particles in levels both at and above the current,
279  // since otherwise, e.g., if the particles are all at level 1, counting particles at
280  // level 0 will not trigger refinement when regridding so level 1 will disappear,
281  // then come back at the next regridding
282  //
283  const auto& particles_namelist( particleData.getNames() );
284  mf->setVal(0.0);
285  for (ParticlesNamesVector::size_type i = 0; i < particles_namelist.size(); i++)
286  {
287  std::string tmp_string(particles_namelist[i]+"_count");
288  IntVect rr = IntVect::TheUnitVector();
289  if (ref_tags[j].Field() == tmp_string) {
290  for (int lev = levc; lev <= finest_level; lev++)
291  {
292  MultiFab temp_dat(grids[lev], dmap[lev], 1, 0); temp_dat.setVal(0);
293  particleData[particles_namelist[i]]->IncrementWithTotal(temp_dat, lev);
294 
295  MultiFab temp_dat_crse(grids[levc], dmap[levc], 1, 0); temp_dat_crse.setVal(0);
296 
297  if (lev == levc) {
298  MultiFab::Copy(*mf, temp_dat, 0, 0, 1, 0);
299  } else {
300  for (int d = 0; d < AMREX_SPACEDIM; d++) {
301  rr[d] *= ref_ratio[levc][d];
302  }
303  average_down(temp_dat, temp_dat_crse, 0, 1, rr);
304  MultiFab::Add(*mf, temp_dat_crse, 0, 0, 1, 0);
305  }
306  }
307  }
308  }
309 #endif
310  }
311 
312  ref_tags[j](tags,mf.get(),clearval,tagval,time,levc,geom[levc]);
313  } // loop over j
314 
315  // ********************************************************************************************
316  // Refinement based on 2d distance from the "eye" which is defined here as the (x,y) location of
317  // the integrated qv
318  // ********************************************************************************************
319  ParmParse pp(pp_prefix);
320  Vector<std::string> refinement_indicators;
321  pp.queryarr("refinement_indicators",refinement_indicators,0,pp.countval("refinement_indicators"));
322  for (int i=0; i<refinement_indicators.size(); ++i)
323  {
324  if ( (refinement_indicators[i]=="storm_tracker") && (solverChoice.moisture_type != MoistureType::None) )
325  {
326  std::string ref_prefix = pp_prefix + "." + refinement_indicators[i];
327  ParmParse ppr(ref_prefix);
328 
329  Real ref_start_time = -1.0;
330  ppr.query("start_time",ref_start_time);
331 
332  if (time >= ref_start_time) {
333 
334  Real max_radius = -1.0;
335  ppr.get("max_radius", max_radius);
336 
337  // Create the volume-weighted sum of (rho qv) in each column
338  MultiFab mf_qv_int(ba2d[levc], dmap[levc], 1, 0); mf_qv_int.setVal(0.);
339 
340  // Define the 2D MultiFab holding the column-integrated (rho qv)
341  volWgtColumnSum(levc, S_new, RhoQ1_comp, mf_qv_int, *detJ_cc[levc]);
342 
343  // Find the max value in the domain
344  IntVect eye = mf_qv_int.maxIndex(0);
345 
346  const auto dx = geom[levc].CellSizeArray();
347  const auto prob_lo = geom[levc].ProbLoArray();
348 
349  Real eye_x = prob_lo[0] + (eye[0] + 0.5) * dx[0];
350  Real eye_y = prob_lo[1] + (eye[1] + 0.5) * dx[1];
351 
352  tag_on_distance_from_eye(geom[levc], &tags, eye_x, eye_y, max_radius);
353  }
354  }
355  }
356 }
const amrex::Real * prob_lo
Definition: ERF_InitCustomPert_IsentropicVortex.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:827
amrex::Vector< amrex::Vector< amrex::Box > > boxes_at_level
Definition: ERF.H:804
void FillBdyCCVels(amrex::Vector< amrex::MultiFab > &mf_cc_vel, int levc=0)
Definition: ERF_FillBdyCCVels.cpp:11
void volWgtColumnSum(int lev, const amrex::MultiFab &mf, int comp, amrex::MultiFab &mf_2d, const amrex::MultiFab &dJ)
Definition: ERF_VolWgtSum.cpp:82
void FillPatchCrseLevel(int lev, amrex::Real time, const amrex::Vector< amrex::MultiFab * > &mfs_vel, bool cons_only=false)
Definition: ERF_FillPatch.cpp:288
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:856
static amrex::Vector< amrex::Vector< std::string > > nc_init_file
Definition: ERF.H:1232
amrex::Vector< amrex::Vector< amrex::BoxArray > > subdomains
Definition: ERF.H:1348
static amrex::Vector< amrex::Vector< int > > have_read_nc_init_file
Definition: ERF.H:1233
static amrex::Vector< amrex::AMRErrorTag > ref_tags
Definition: ERF.H:1346
amrex::Vector< int > num_boxes_at_level
Definition: ERF.H:802
void erf_derscalar(const Box &bx, FArrayBox &derfab, int, int, const FArrayBox &datfab, const Geometry &, Real, const int *, const int)
Definition: ERF_Derive.cpp:165
void erf_dermagvel(const amrex::Box &bx, amrex::FArrayBox &derfab, int dcomp, int ncomp, const amrex::FArrayBox &datfab, const amrex::Geometry &, amrex::Real, const int *, const int)
Definition: ERF_Derive.cpp:319
void erf_dervortz(const amrex::Box &bx, amrex::FArrayBox &derfab, int dcomp, int ncomp, const amrex::FArrayBox &datfab, const amrex::Geometry &geomdata, amrex::Real, const int *, const int)
Definition: ERF_Derive.cpp:256
void erf_dertheta(const Box &bx, FArrayBox &derfab, int, int, const FArrayBox &datfab, const Geometry &, Real, const int *, const int)
Definition: ERF_Derive.cpp:144
real(c_double), private rr
Definition: ERF_module_mp_morr_two_moment.F90:224
integer, private isub
Definition: ERF_module_mp_morr_two_moment.F90:164
static InitType init_type
Definition: ERF_DataStruct.H:1050
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 = 1.e20;
65  Real estdt_lowM = 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 = 1.0 / 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 = -1.e100;
108  amrex::Loop(b, [=,&new_comp_dt] (int i, int j, int k) noexcept
109  {
110  if (vf(i,j,k) > 0.)
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  estdt_comp_inv = ReduceMax(S_new, ccvel, 0,
161  [=] AMREX_GPU_HOST_DEVICE (Box const& b,
162  Array4<Real const> const& s,
163  Array4<Real const> const& u) -> Real
164  {
165  Real new_comp_dt = -1.e100;
166  amrex::Loop(b, [=,&new_comp_dt] (int i, int j, int k) noexcept
167  {
168  {
169  const Real rho = s(i, j, k, Rho_comp);
170  const Real rhotheta = s(i, j, k, RhoTheta_comp);
171 
172  // NOTE: even when moisture is present,
173  // we only use the partial pressure of the dry air
174  // to compute the soundspeed
175  Real pressure = getPgivenRTh(rhotheta);
176  Real c = std::sqrt(Gamma * pressure / rho);
177 
178  // If we are doing implicit acoustic substepping, then the z-direction does not contribute
179  // to the computation of the time step
180  if (l_substepping) {
181  if ((nxc > 1) && (nyc==1)) {
182  // 2-D in x-z
183  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]), new_comp_dt);
184  } else if ((nyc > 1) && (nxc==1)) {
185  // 2-D in y-z
186  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,1))+c)*dxinv[1]), new_comp_dt);
187  } else {
188  // 3-D
189  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]),
190  ((amrex::Math::abs(u(i,j,k,1))+c)*dxinv[1]), new_comp_dt);
191  }
192 
193  // If we are not doing implicit acoustic substepping, then the z-direction contributes
194  // to the computation of the time step
195  } else {
196  if (nxc > 1 && nyc > 1) {
197  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]),
198  ((amrex::Math::abs(u(i,j,k,1))+c)*dxinv[1]),
199  ((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
200  } else if (nxc > 1) {
201  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]),
202  ((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
203  } else if (nyc > 1) {
204  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,1))+c)*dxinv[1]),
205  ((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
206  } else {
207  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
208  }
209 
210  }
211  }
212  });
213  return new_comp_dt;
214  });
215  } // not EB
216 
217  ParallelDescriptor::ReduceRealMax(estdt_comp_inv);
218  estdt_comp = cfl / estdt_comp_inv;
219 
220  Real estdt_lowM_inv = ReduceMax(ccvel, 0,
221  [=] AMREX_GPU_HOST_DEVICE (Box const& b,
222  Array4<Real const> const& u) -> Real
223  {
224  Real new_lm_dt = -1.e100;
225  Loop(b, [=,&new_lm_dt] (int i, int j, int k) noexcept
226  {
227  new_lm_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0)))*dxinv[0]),
228  ((amrex::Math::abs(u(i,j,k,1)))*dxinv[1]),
229  ((amrex::Math::abs(u(i,j,k,2)))*dxinv[2]), new_lm_dt);
230  });
231  return new_lm_dt;
232  });
233 
234  ParallelDescriptor::ReduceRealMax(estdt_lowM_inv);
235  if (estdt_lowM_inv > 0.0_rt)
236  estdt_lowM = cfl / estdt_lowM_inv;
237 
238  // Additional vertical diagnostics
239  if (l_comp_substepping_diag) {
240  estdt_vert_comp_inv = ReduceMax(S_new, ccvel, 0,
241  [=] AMREX_GPU_HOST_DEVICE (Box const& b,
242  Array4<Real const> const& s,
243  Array4<Real const> const& u) -> Real
244  {
245  Real new_comp_dt = -1.e100;
246  amrex::Loop(b, [=,&new_comp_dt] (int i, int j, int k) noexcept
247  {
248  {
249  const Real rho = s(i, j, k, Rho_comp);
250  const Real rhotheta = s(i, j, k, RhoTheta_comp);
251 
252  // NOTE: even when moisture is present,
253  // we only use the partial pressure of the dry air
254  // to compute the soundspeed
255  Real pressure = getPgivenRTh(rhotheta);
256  Real c = std::sqrt(Gamma * pressure / rho);
257 
258  // Look at z-direction only
259  new_comp_dt = amrex::max((amrex::Math::abs(u(i,j,k,2)) + c) * dzinv, new_comp_dt);
260  }
261  });
262  return new_comp_dt;
263  });
264 
265  estdt_vert_lowM_inv = ReduceMax(ccvel, 0,
266  [=] AMREX_GPU_HOST_DEVICE (Box const& b,
267  Array4<Real const> const& u) -> Real
268  {
269  Real new_lowM_dt = -1.e100;
270  amrex::Loop(b, [=,&new_lowM_dt] (int i, int j, int k) noexcept
271  {
272  new_lowM_dt = amrex::max((amrex::Math::abs(u(i,j,k,2))) * dzinv, new_lowM_dt);
273  });
274  return new_lowM_dt;
275  });
276 
277  ParallelDescriptor::ReduceRealMax(estdt_vert_comp_inv);
278  ParallelDescriptor::ReduceRealMax(estdt_vert_lowM_inv);
279  }
280 
281  if (verbose) {
282  if (fixed_dt[level] <= 0.0) {
283  Print() << "Using cfl = " << cfl << " and dx/dy/dz_min = " <<
284  1.0/dxinv[0] << " " << 1.0/dxinv[1] << " " << dz_min[level] << std::endl;
285  Print() << "Compressible dt at level " << level << ": " << estdt_comp << std::endl;
286  if (estdt_lowM_inv > 0.0_rt) {
287  Print() << "Anelastic dt at level " << level << ": " << estdt_lowM << std::endl;
288  } else {
289  Print() << "Anelastic dt at level " << level << ": undefined " << std::endl;
290  }
291  }
292 
293  if (fixed_dt[level] > 0.0) {
294  Print() << "Based on cfl of 1.0 " << std::endl;
295  Print() << "Compressible dt at level " << level << " would be: " << estdt_comp/cfl << std::endl;
296  if (estdt_lowM_inv > 0.0_rt) {
297  Print() << "Anelastic dt at level " << level << " would be: " << estdt_lowM/cfl << std::endl;
298  } else {
299  Print() << "Anelastic dt at level " << level << " would be undefined " << std::endl;
300  }
301  Print() << "Fixed dt at level " << level << " is: " << fixed_dt[level] << std::endl;
302  if (fixed_fast_dt[level] > 0.0) {
303  Print() << "Fixed fast dt at level " << level << " is: " << fixed_fast_dt[level] << std::endl;
304  }
305  }
306  }
307 
308  if (solverChoice.substepping_type[level] != SubsteppingType::None) {
309  if (fixed_dt[level] > 0. && fixed_fast_dt[level] > 0.) {
310  dt_fast_ratio = static_cast<long>( fixed_dt[level] / fixed_fast_dt[level] );
311  if (dt_fast_ratio < 1) {
312  Abort("Invalid fixed_fast_dt: must be <= fixed_dt so mri_dt_ratio >= 1");
313  }
314  } else if (fixed_dt[level] > 0.) {
315  // Max CFL_c = 1.0 for substeps by default, but we enforce a min of 4 substeps
316  auto dt_sub_max = (estdt_comp/cfl * sub_cfl);
317  dt_fast_ratio = static_cast<long>( std::max(fixed_dt[level]/dt_sub_max,4.) );
318  } else {
319  // auto dt_sub_max = (estdt_comp/cfl * sub_cfl);
320  // dt_fast_ratio = static_cast<long>( std::max(estdt_comp/dt_sub_max,4.) );
321  dt_fast_ratio = static_cast<long>( std::max(cfl / sub_cfl, 4.) );
322  }
323 
324  // Force time step ratio to be an even value
326  if ( dt_fast_ratio%2 != 0) dt_fast_ratio += 1;
327  } else {
328  if ( dt_fast_ratio%6 != 0) {
329  Print() << "mri_dt_ratio = " << dt_fast_ratio
330  << " not divisible by 6 for N/3 substeps in stage 1" << std::endl;
331  dt_fast_ratio = static_cast<int>(std::ceil(dt_fast_ratio/6.0) * 6);
332  }
333  }
334 
335  if (verbose) {
336  Print() << "smallest even ratio is: " << dt_fast_ratio << std::endl;
337  }
338  } // if substepping
339 
340  // Print out some extra diagnostics -- dt calcs are repeated so as to not
341  // disrupt the overall code flow...
342  if (l_comp_substepping_diag) {
343  Real dt_diag = (fixed_dt[level] > 0.0) ? fixed_dt[level] : estdt_comp;
344  int ns = (fixed_mri_dt_ratio > 0.0) ? fixed_mri_dt_ratio : dt_fast_ratio;
345 
346  // horizontal acoustic CFL must be < 1 (fully explicit)
347  // vertical acoustic CFL may be > 1
348  Print() << "effective horiz,vert acoustic CFL with " << ns << " substeps : "
349  << (dt_diag / ns) * estdt_comp_inv << " "
350  << (dt_diag / ns) * estdt_vert_comp_inv << std::endl;
351 
352  // vertical advective CFL should be < 1, otherwise w-damping may be needed
353  Print() << "effective vert advective CFL : "
354  << dt_diag * estdt_vert_lowM_inv << std::endl;
355  }
356 
357  if (fixed_dt[level] > 0.0) {
358  return fixed_dt[level];
359  } else {
360  // Anelastic (substepping is not allowed)
361  if (l_anelastic) {
362 
363  // Make sure that timestep is less than the dt_max
364  estdt_lowM = amrex::min(estdt_lowM, dt_max);
365 
366  // On the first timestep enforce dt_max_initial
367  if (istep[level] == 0) {
368  return amrex::min(dt_max_initial, estdt_lowM);
369  } else {
370  return estdt_lowM;
371  }
372 
373 
374  // Compressible with or without substepping
375  } else {
376  return estdt_comp;
377  }
378  }
379 }
constexpr amrex::Real Gamma
Definition: ERF_Constants.H:19
amrex::Vector< amrex::Real > dz_min
Definition: ERF.H:1350
amrex::Vector< amrex::Real > fixed_dt
Definition: ERF.H:1058
static amrex::Real dt_max
Definition: ERF.H:1055
amrex::Vector< amrex::Real > fixed_fast_dt
Definition: ERF.H:1059
static amrex::Real cfl
Definition: ERF.H:1050
static amrex::Real sub_cfl
Definition: ERF.H:1051
Definition: ERF_EB.H:13
@ ns
Definition: ERF_Morrison.H:47
int force_stage1_single_substep
Definition: ERF_DataStruct.H:1083
amrex::Vector< SubsteppingType > substepping_type
Definition: ERF_DataStruct.H:1085
bool substepping_diag
Definition: ERF_DataStruct.H:1092
Here is the call graph for this function:

◆ Evolve()

void ERF::Evolve ( )
604 {
605  BL_PROFILE_VAR("ERF::Evolve()", evolve);
606 
607  //
608  // cur_time = t_new is elapsed time, not total time
609  // stop_time is total time
610  //
611  Real cur_time = t_new[0];
612 
613  // Take one coarse timestep by calling timeStep -- which recursively calls timeStep
614  // for finer levels (with or without subcycling)
615  for (int step = istep[0]; (step < max_step) && (start_time+cur_time < stop_time); ++step)
616  {
617  if (use_datetime) {
618  Print() << "\n" << getTimestamp(start_time+cur_time, datetime_format)
619  << " (" << cur_time << " s elapsed)" << std::endl;
620  }
621  Print() << "\nCoarse STEP " << step+1 << " starts ..." << std::endl;
622 
623  ComputeDt(step);
624 
625  // Make sure we have read enough of the boundary plane data to make it through this timestep
626  if (input_bndry_planes)
627  {
628  m_r2d->read_input_files(cur_time+start_time,dt[0],m_bc_extdir_vals);
629  }
630 
631 #ifdef ERF_USE_PARTICLES
632  // We call this every time step with the knowledge that the particles may be
633  // initialized at a later time than the simulation start time.
634  // The ParticleContainer carries a "start time" so the initialization will happen
635  // only when a) time > start_time, and b) particles have not yet been initialized
636  initializeTracers((ParGDBBase*)GetParGDB(),z_phys_nd,cur_time);
637 #endif
638 
639  if(solverChoice.init_type == InitType::HindCast and
641  for(int lev=0;lev<finest_level+1;lev++){
642  WeatherDataInterpolation(lev,cur_time,z_phys_nd,false);
643  }
644  }
645 
646  if(solverChoice.init_type == InitType::HindCast and
648  for(int lev=0;lev<finest_level+1;lev++){
649  SurfaceDataInterpolation(lev,cur_time,z_phys_nd,false);
650  }
651  }
652 
653  auto dEvolveTime0 = amrex::second();
654 
655  int iteration = 1;
656  timeStep(0, cur_time, iteration);
657 
658  cur_time += dt[0];
659 
660  Print() << "Coarse STEP " << step+1 << " ends." << " TIME = " << cur_time
661  << " DT = " << dt[0] << std::endl;
662 
663  if (check_for_nans > 0) {
664  amrex::Print() << "Testing new state and vels for NaNs at end of timestep" << std::endl;
665  for (int lev = 0; lev <= finest_level; ++lev) {
668  }
669  }
670 
671  if (verbose > 0)
672  {
673  auto dEvolveTime = amrex::second() - dEvolveTime0;
674  ParallelDescriptor::ReduceRealMax(dEvolveTime,ParallelDescriptor::IOProcessorNumber());
675  amrex::Print() << "Timestep time = " << dEvolveTime << " seconds." << '\n';
676  }
677 
678  post_timestep(step, cur_time, dt[0]);
679 
680  if (writeNow(cur_time, step+1, m_plot3d_int_1, m_plot3d_per_1, dt[0], last_plot3d_file_time_1)) {
681  last_plot3d_file_step_1 = step+1;
683  for (int lev = 0; lev <= finest_level; ++lev) {lsm.Plot(lev, step+1);}
685  }
686  if (writeNow(cur_time, step+1, m_plot3d_int_2, m_plot3d_per_2, dt[0], last_plot3d_file_time_2)) {
687  last_plot3d_file_step_2 = step+1;
689  for (int lev = 0; lev <= finest_level; ++lev) {lsm.Plot(lev, step+1);}
691  }
692 
693  if (writeNow(cur_time, step+1, m_plot2d_int_1, m_plot2d_per_1, dt[0], last_plot2d_file_time_1)) {
694  last_plot2d_file_step_1 = step+1;
697  }
698 
699  if (writeNow(cur_time, step+1, m_plot2d_int_2, m_plot2d_per_2, dt[0], last_plot2d_file_time_2)) {
700  last_plot2d_file_step_2 = step+1;
703  }
704 
705  for (int i = 0; i < m_subvol_int.size(); i++) {
706  if (writeNow(cur_time, step+1, m_subvol_int[i], m_subvol_per[i], dt[0], last_subvol_time[i])) {
707  last_subvol_step[i] = step+1;
709  if (m_subvol_per[i] > 0.) {last_subvol_time[i] += m_subvol_per[i];}
710  }
711  }
712 
713  if (writeNow(cur_time, step+1, m_check_int, m_check_per, dt[0], last_check_file_time)) {
714  last_check_file_step = step+1;
717  }
718 
719 #ifdef AMREX_MEM_PROFILING
720  {
721  std::ostringstream ss;
722  ss << "[STEP " << step+1 << "]";
723  MemProfiler::report(ss.str());
724  }
725 #endif
726 
727  if (start_time+cur_time >= stop_time - 1.e-6*dt[0]) break;
728  }
729 
730  // Write plotfiles at final time
731  if ( (m_plot3d_int_1 > 0 || m_plot3d_per_1 > 0.) && istep[0] > last_plot3d_file_step_1 ) {
734  }
735  if ( (m_plot3d_int_2 > 0 || m_plot3d_per_2 > 0.) && istep[0] > last_plot3d_file_step_2) {
738  }
739  if ( (m_plot2d_int_1 > 0 || m_plot2d_per_1 > 0.) && istep[0] > last_plot2d_file_step_1 ) {
742  }
743  if ( (m_plot2d_int_2 > 0 || m_plot2d_per_2 > 0.) && istep[0] > last_plot2d_file_step_2) {
746  }
747 
748  for (int i = 0; i < m_subvol_int.size(); i++) {
749  if ( (m_subvol_int[i] > 0 || m_subvol_per[i] > 0.) && istep[0] > last_subvol_step[i]) {
751  if (m_subvol_per[i] > 0.) {last_subvol_time[i] += m_subvol_per[i];}
752  }
753  }
754 
755  if ( (m_check_int > 0 || m_check_per > 0.) && istep[0] > last_check_file_step) {
758  }
759 
760  BL_PROFILE_VAR_STOP(evolve);
761 }
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:72
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:1014
int max_step
Definition: ERF.H:1037
static amrex::Real last_plot2d_file_time_2
Definition: ERF.H:1019
amrex::Vector< std::string > subvol3d_var_names
Definition: ERF.H:1102
amrex::Real m_plot2d_per_1
Definition: ERF.H:1087
static amrex::Real last_plot2d_file_time_1
Definition: ERF.H:1018
static int last_plot2d_file_step_2
Definition: ERF.H:1013
amrex::Array< amrex::Array< amrex::Real, AMREX_SPACEDIM *2 >, AMREX_SPACEDIM+NBCVAR_max > m_bc_extdir_vals
Definition: ERF.H:991
static amrex::Real last_plot3d_file_time_2
Definition: ERF.H:1017
int m_plot2d_int_2
Definition: ERF.H:1080
int m_plot3d_int_1
Definition: ERF.H:1077
static int last_plot3d_file_step_2
Definition: ERF.H:1011
void post_timestep(int nstep, amrex::Real time, amrex::Real dt_lev)
Definition: ERF.cpp:765
amrex::Real m_plot2d_per_2
Definition: ERF.H:1088
amrex::Real m_check_per
Definition: ERF.H:1100
int m_check_int
Definition: ERF.H:1099
static int input_bndry_planes
Definition: ERF.H:1281
void Write2DPlotFile(int which, PlotFileType plotfile_type, amrex::Vector< std::string > plot_var_names)
Definition: ERF_Plotfile.cpp:1994
const std::string datetime_format
Definition: ERF.H:1044
bool use_datetime
Definition: ERF.H:1043
amrex::Vector< amrex::Real > m_subvol_per
Definition: ERF.H:1083
void ComputeDt(int step=-1)
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:1086
amrex::Vector< int > last_subvol_step
Definition: ERF.H:1022
static PlotFileType plotfile3d_type_2
Definition: ERF.H:1219
static PlotFileType plotfile2d_type_2
Definition: ERF.H:1221
bool writeNow(const amrex::Real 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:3106
int m_plot2d_int_1
Definition: ERF.H:1079
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:318
static int last_plot2d_file_step_1
Definition: ERF.H:1012
amrex::Real m_plot3d_per_1
Definition: ERF.H:1085
std::unique_ptr< ReadBndryPlanes > m_r2d
Definition: ERF.H:1339
amrex::Vector< amrex::Real > last_subvol_time
Definition: ERF.H:1023
static amrex::Real last_check_file_time
Definition: ERF.H:1020
static int last_plot3d_file_step_1
Definition: ERF.H:1010
static amrex::Real last_plot3d_file_time_1
Definition: ERF.H:1016
static PlotFileType plotfile2d_type_1
Definition: ERF.H:1220
static PlotFileType plotfile3d_type_1
Definition: ERF.H:1218
amrex::Vector< int > m_subvol_int
Definition: ERF.H:1082
int m_plot3d_int_2
Definition: ERF.H:1078
void timeStep(int lev, amrex::Real time, int iteration)
Definition: ERF_TimeStep.cpp:17
void Plot(const int &lev, const int &nstep)
Definition: ERF_LandSurface.H:71
bool hindcast_lateral_forcing
Definition: ERF_DataStruct.H:1239
bool hindcast_surface_bcs
Definition: ERF_DataStruct.H:1240

Referenced by main().

Here is the call graph for this function:
Here is the caller 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  if (var_idx == Vars::xvel) bx_xhi.setSmall(0,dom_hi.x);
75 
77  bx_xlo, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) {
78  int bc_comp = (icomp+n >= RhoScalar_comp && icomp+n < RhoScalar_comp+NSCALARS) ?
79  BCVars::RhoScalar_bc_comp : icomp+n;
80  if (bc_ptr[bc_comp].lo(0) == ERFBCType::ext_dir_ingested) {
81  int jb = std::min(std::max(j,dom_lo.y),dom_hi.y);
82  int kb = std::min(std::max(k,dom_lo.z),dom_hi.z);
83  dest_arr(i,j,k,icomp+n) = bdatxlo(dom_lo.x-1,jb,kb,bccomp+n);
84  }
85  },
86  bx_xhi, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) {
87  int bc_comp = (icomp+n >= RhoScalar_comp && icomp+n < RhoScalar_comp+NSCALARS) ?
88  BCVars::RhoScalar_bc_comp : icomp+n;
89  if (bc_ptr[bc_comp].hi(0) == ERFBCType::ext_dir_ingested) {
90  int jb = std::min(std::max(j,dom_lo.y),dom_hi.y);
91  int kb = std::min(std::max(k,dom_lo.z),dom_hi.z);
92  dest_arr(i,j,k,icomp+n) = bdatxhi(dom_hi.x+1,jb,kb,bccomp+n);
93  }
94  }
95  );
96  } // x-faces
97 
98  // y-faces
99  {
100  Box bx_ylo(bx); bx_ylo.setBig (1,dom_lo.y-1);
101  if (var_idx == Vars::yvel) bx_ylo.setBig(1,dom_lo.y);
102 
103  Box bx_yhi(bx); bx_yhi.setSmall(1,dom_hi.y+1);
104  if (var_idx == Vars::yvel) bx_yhi.setSmall(1,dom_hi.y);
105 
106  ParallelFor(
107  bx_ylo, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) {
108  int bc_comp = (icomp+n >= RhoScalar_comp && icomp+n < RhoScalar_comp+NSCALARS) ?
109  BCVars::RhoScalar_bc_comp : icomp+n;
110  if (bc_ptr[bc_comp].lo(1) == ERFBCType::ext_dir_ingested) {
111  int ib = std::min(std::max(i,dom_lo.x),dom_hi.x);
112  int kb = std::min(std::max(k,dom_lo.z),dom_hi.z);
113  dest_arr(i,j,k,icomp+n) = bdatylo(ib,dom_lo.y-1,kb,bccomp+n);
114  }
115  },
116  bx_yhi, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) {
117  int bc_comp = (icomp+n >= RhoScalar_comp && icomp+n < RhoScalar_comp+NSCALARS) ?
118  BCVars::RhoScalar_bc_comp : icomp+n;
119  if (bc_ptr[bc_comp].hi(1) == ERFBCType::ext_dir_ingested) {
120  int ib = std::min(std::max(i,dom_lo.x),dom_hi.x);
121  int kb = std::min(std::max(k,dom_lo.z),dom_hi.z);
122  dest_arr(i,j,k,icomp+n) = bdatyhi(ib,dom_hi.y+1,kb,bccomp+n);
123  }
124  }
125  );
126  } // y-faces
127  } // mf
128  } // var_idx
129 }
#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:985
@ RhoScalar_bc_comp
Definition: ERF_IndexDefines.H:80
@ ext_dir_ingested
Definition: ERF_IndexDefines.H:228
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::Vector< amrex::MultiFab > &  mf_cc_vel,
int  levc = 0 
)
12 {
13  // Impose bc's at domain boundaries
14  for (int ilev(0); ilev < mf_cc_vel.size(); ++ilev)
15  {
16  int lev = ilev + levc;
17  Box domain(Geom(lev).Domain());
18 
19  int ihi = domain.bigEnd(0);
20  int jhi = domain.bigEnd(1);
21  int khi = domain.bigEnd(2);
22 
23  // Impose periodicity first
24  mf_cc_vel[lev].FillBoundary(geom[lev].periodicity());
25 
26  int jper = (Geom(lev).isPeriodic(1));
27  int kper = (Geom(lev).isPeriodic(2));
28 
29  for (MFIter mfi(mf_cc_vel[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi)
30  {
31  const Box& bx = mfi.tilebox();
32  const Array4<Real>& vel_arr = mf_cc_vel[lev].array(mfi);
33 
34  if (!Geom(lev).isPeriodic(0)) {
35  // Low-x side
36  if (bx.smallEnd(0) <= domain.smallEnd(0)) {
37  Real multn = ( (phys_bc_type[0] == ERF_BC::slip_wall ) ||
39  (phys_bc_type[0] == ERF_BC::symmetry ) ) ? -1. : 1.;
40  Real multt = (phys_bc_type[0] == ERF_BC::no_slip_wall) ? -1. : 1.;
41  Box gbx(bx); gbx.grow(1,jper); gbx.grow(2,kper);
42  ParallelFor(makeSlab(gbx,0,0), [=] AMREX_GPU_DEVICE(int , int j, int k) noexcept
43  {
44  vel_arr(-1,j,k,0) = multn*vel_arr(0,j,k,0); // u
45  vel_arr(-1,j,k,1) = multt*vel_arr(0,j,k,1); // v
46  vel_arr(-1,j,k,2) = multt*vel_arr(0,j,k,2); // w
47  });
48  }
49 
50  // High-x side
51  if (bx.bigEnd(0) >= domain.bigEnd(0)) {
52  Real multn = ( (phys_bc_type[3] == ERF_BC::slip_wall ) ||
54  (phys_bc_type[3] == ERF_BC::symmetry ) ) ? -1. : 1.;
55  Real multt = (phys_bc_type[3] == ERF_BC::no_slip_wall) ? -1. : 1.;
56  Box gbx(bx); gbx.grow(1,jper); gbx.grow(2,kper);
57  ParallelFor(makeSlab(gbx,0,0), [=] AMREX_GPU_DEVICE(int , int j, int k) noexcept
58  {
59  vel_arr(ihi+1,j,k,0) = multn*vel_arr(ihi,j,k,0); // u
60  vel_arr(ihi+1,j,k,1) = multt*vel_arr(ihi,j,k,1); // v
61  vel_arr(ihi+1,j,k,2) = multt*vel_arr(ihi,j,k,2); // w
62  });
63  }
64  } // !periodic
65 
66  if (!Geom(lev).isPeriodic(1)) {
67  // Low-y side
68  if (bx.smallEnd(1) <= domain.smallEnd(1)) {
69  Real multn = ( (phys_bc_type[1] == ERF_BC::slip_wall ) ||
71  (phys_bc_type[1] == ERF_BC::symmetry ) ) ? -1. : 1.;
72  Real multt = (phys_bc_type[1] == ERF_BC::no_slip_wall) ? -1. : 1.;
73  Box gbx(bx); gbx.grow(0,1); gbx.grow(2,kper);
74  ParallelFor(makeSlab(gbx,1,0), [=] AMREX_GPU_DEVICE(int i, int , int k) noexcept
75  {
76  vel_arr(i,-1,k,0) = multt*vel_arr(i,0,k,0); // u
77  vel_arr(i,-1,k,1) = multn*vel_arr(i,0,k,1); // u
78  vel_arr(i,-1,k,2) = multt*vel_arr(i,0,k,2); // w
79  });
80  }
81 
82  // High-y side
83  if (bx.bigEnd(1) >= domain.bigEnd(1)) {
84  Real multn = ( (phys_bc_type[4] == ERF_BC::slip_wall ) ||
86  (phys_bc_type[4] == ERF_BC::symmetry ) ) ? -1. : 1.;
87  Real multt = (phys_bc_type[4] == ERF_BC::no_slip_wall) ? -1. : 1.;
88  Box gbx(bx); gbx.grow(0,1); gbx.grow(2,kper);
89  ParallelFor(makeSlab(gbx,1,0), [=] AMREX_GPU_DEVICE(int i, int , int k) noexcept
90  {
91  vel_arr(i,jhi+1,k,0) = multt*vel_arr(i,jhi,k,0); // u
92  vel_arr(i,jhi+1,k,1) = multn*vel_arr(i,jhi,k,1); // v
93  vel_arr(i,jhi+1,k,2) = multt*vel_arr(i,jhi,k,2); // w
94  });
95  }
96  } // !periodic
97 
98  if (!Geom(lev).isPeriodic(2)) {
99  // Low-z side
100  if (bx.smallEnd(2) <= domain.smallEnd(2)) {
101  Real multn = ( (phys_bc_type[2] == ERF_BC::slip_wall ) ||
103  (phys_bc_type[2] == ERF_BC::symmetry ) ) ? -1. : 1.;
104  Real multt = (phys_bc_type[2] == ERF_BC::no_slip_wall) ? -1. : 1.;
105  Box gbx(bx); gbx.grow(0,1); gbx.grow(1,1);
106  ParallelFor(makeSlab(gbx,2,0), [=] AMREX_GPU_DEVICE(int i, int j, int) noexcept
107  {
108  vel_arr(i,j,-1,0) = multt*vel_arr(i,j,0,0); // u
109  vel_arr(i,j,-1,1) = multt*vel_arr(i,j,0,1); // v
110  vel_arr(i,j,-1,2) = multn*vel_arr(i,j,0,2); // w
111  });
112  }
113 
114  // High-z side
115  if (bx.bigEnd(2) >= domain.bigEnd(2)) {
116  Real multn = ( (phys_bc_type[5] == ERF_BC::slip_wall ) ||
118  (phys_bc_type[5] == ERF_BC::symmetry ) ) ? -1. : 1.;
119  Real multt = (phys_bc_type[5] == ERF_BC::no_slip_wall) ? -1. : 1.;
120  Box gbx(bx); gbx.grow(0,1); gbx.grow(1,1);
121  ParallelFor(makeSlab(gbx,2,0), [=] AMREX_GPU_DEVICE(int i, int j, int) noexcept
122  {
123  vel_arr(i,j,khi+1,0) = multt*vel_arr(i,j,khi,0); // u
124  vel_arr(i,j,khi+1,1) = multt*vel_arr(i,j,khi,1); // v
125  vel_arr(i,j,khi+1,2) = multn*vel_arr(i,j,khi,2); // w
126  });
127  }
128  } // !periodic
129  } // MFIter
130 
131  // Impose periodicity again
132  mf_cc_vel[lev].FillBoundary(geom[lev].periodicity());
133  } // lev
134 }
@ 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).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).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 = xvec_h.size();
106  int ny = yvec_h.size();
107  int nz = 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 + 0.5) * dx[0];
184  const Real y = prob_lo[1] + (j + 0.5) * dx[1];
185  //const Real z = prob_lo[2] + (k + 0.5) * dx[2];
186  const Real z = (z_arr(i,j,k) + z_arr(i,j,k+1))/2.0;
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, 0.0,
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, 0.0,
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+0.5) * dx_erf[1];
242  //Real z = prob_lo_erf[2] + (k+0.5) * dx_erf[2];
243  const Real z = (z_arr(i,j,k) + z_arr(i,j,k+1))/2.0;
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+0.5) * dx_erf[0];
257  Real y = prob_lo_erf[1] + j * dx_erf[1];
258  //Real z = prob_lo_erf[2] + (k+0.5) * dx_erf[2];
259  const Real z = (z_arr(i,j,k) + z_arr(i,j,k+1))/2.0;
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+0.5) * dx_erf[0];
273  Real y = prob_lo_erf[1] + (j+0.5) * 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))/2.0;
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 = 0.0;
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))/2.0;
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))/2.0;
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))/2.0;
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:24
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:12
Gpu::DeviceVector< Real > rho_d(khi+1, 0.0)
Vector< Real > rho_h(khi+1, 0.0)
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(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(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  if (m_r2d && !solverChoice.use_real_bcs) fill_from_bndryregs(mfs_vel,time);
324 
325  // We call this even if use_real_bcs is true because these will fill the vertical bcs
326  (*physbcs_cons[lev])(*mfs_vel[Vars::cons],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
327  icomp_cons,ncomp_cons,ngvect_cons,time,BCVars::cons_bc, do_fb);
328  if (!cons_only) {
329  (*physbcs_u[lev])(*mfs_vel[Vars::xvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
330  ngvect_vels,time,BCVars::xvel_bc, do_fb);
331  (*physbcs_v[lev])(*mfs_vel[Vars::yvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
332  ngvect_vels,time,BCVars::yvel_bc, do_fb);
333  (*physbcs_w[lev])(*mfs_vel[Vars::zvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
334  ngvect_vels,time,BCVars::zvel_bc, do_fb);
335  }
336  // ***************************************************************************
337 
338  // We always come in to this call with momenta so we need to leave with momenta!
339  // We need to make sure we convert back on all ghost cells/faces because this is
340  // how velocity from fine-fine copies (as well as physical and interpolated bcs) will be filled
341  if (!cons_only)
342  {
343  IntVect ngu = (!solverChoice.use_num_diff) ? IntVect(1,1,1) : mfs_vel[Vars::xvel]->nGrowVect();
344  IntVect ngv = (!solverChoice.use_num_diff) ? IntVect(1,1,1) : mfs_vel[Vars::yvel]->nGrowVect();
345  IntVect ngw = (!solverChoice.use_num_diff) ? IntVect(1,1,0) : mfs_vel[Vars::zvel]->nGrowVect();
346 
347  const MultiFab* c_vfrac = nullptr;
348  if (solverChoice.terrain_type == TerrainType::EB) {
349  c_vfrac = &((get_eb(lev).get_const_factory())->getVolFrac());
350  }
351 
352  VelocityToMomentum(*mfs_vel[Vars::xvel], ngu,
353  *mfs_vel[Vars::yvel], ngv,
354  *mfs_vel[Vars::zvel], ngw,
355  *mfs_vel[Vars::cons],
356  *mfs_mom[IntVars::xmom], *mfs_mom[IntVars::ymom], *mfs_mom[IntVars::zmom],
357  Geom(lev).Domain(),
358  domain_bcs_type, c_vfrac);
359  }
360 
361  // NOTE: There are not FillBoundary calls here for the following reasons:
362  // Removal of the FillBoundary (FB) calls has bee completed for the following reasons:
363  //
364  // 1. physbc_cons is called before VelocityToMomentum and a FB is completed in that functor.
365  // Therefore, the conserved CC vars have their inter-rank ghost cells filled and then their
366  // domain ghost cells filled from the BC operations. We should not call FB on this MF again.
367  //
368  // 2. physbc_u/v/w is also called before VelocityToMomentum and a FB is completed those functors.
369  // Furthermore, VelocityToMomentum operates on a growntilebox so we exit that routine with momentum
370  // filled everywhere---i.e., physbc_u/v/w fills velocity ghost cells (inter-rank and domain)
371  // and then V2M does the conversion to momenta everywhere; so there is again no need to do a FB on momenta.
372 }
AMREX_GPU_HOST AMREX_FORCE_INLINE void ApplyMask(amrex::MultiFab &dst, const amrex::iMultiFab &imask, const int nghost=0)
Definition: ERF_Utils.H:316
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:178
static bool use_real_bcs
Definition: ERF_DataStruct.H:1062
Here is the call graph for this function:

◆ FillPatchCrseLevel()

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

◆ FillPatchFineLevel()

void ERF::FillPatchFineLevel ( int  lev,
amrex::Real  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  Interpolater* mapper = nullptr;
32 
33  PhysBCFunctNoOp null_bc;
34 
35  //
36  // ***************************************************************************
37  // The first thing we do is interpolate the momenta on the "valid" faces of
38  // the fine grids (where the interface is coarse/fine not fine/fine) -- this
39  // will not be over-written below because the FillPatch operators see these as
40  // valid faces.
41  //
42  // Note that we interpolate momentum not velocity, but all the other boundary
43  // conditions are imposed on velocity, so we convert to momentum here then
44  // convert back.
45  // ***************************************************************************
46  if (fillset) {
47  if (cf_set_width > 0) {
48  FPr_c[lev-1].FillSet(*mfs_vel[Vars::cons], time, null_bc, domain_bcs_type);
49  }
50  if (cf_set_width >= 0 && !cons_only) {
51 
52  const MultiFab* c_vfrac = nullptr;
53  if (solverChoice.terrain_type == TerrainType::EB) {
54  c_vfrac = &((get_eb(lev).get_const_factory())->getVolFrac());
55  }
56 
57  VelocityToMomentum(*mfs_vel[Vars::xvel], IntVect{0},
58  *mfs_vel[Vars::yvel], IntVect{0},
59  *mfs_vel[Vars::zvel], IntVect{0},
60  *mfs_vel[Vars::cons],
61  *mfs_mom[IntVars::xmom],
62  *mfs_mom[IntVars::ymom],
63  *mfs_mom[IntVars::zmom],
64  Geom(lev).Domain(),
65  domain_bcs_type, c_vfrac);
66 
67  FPr_u[lev-1].FillSet(*mfs_mom[IntVars::xmom], time, null_bc, domain_bcs_type);
68  FPr_v[lev-1].FillSet(*mfs_mom[IntVars::ymom], time, null_bc, domain_bcs_type);
69  FPr_w[lev-1].FillSet(*mfs_mom[IntVars::zmom], time, null_bc, domain_bcs_type);
70 
71  MomentumToVelocity(*mfs_vel[Vars::xvel], *mfs_vel[Vars::yvel], *mfs_vel[Vars::zvel],
72  *mfs_vel[Vars::cons],
73  *mfs_mom[IntVars::xmom],
74  *mfs_mom[IntVars::ymom],
75  *mfs_mom[IntVars::zmom],
76  Geom(lev).Domain(),
77  domain_bcs_type, c_vfrac);
78  }
79  }
80 
81  IntVect ngvect_cons = mfs_vel[Vars::cons]->nGrowVect();
82  IntVect ngvect_vels = mfs_vel[Vars::xvel]->nGrowVect();
83 
84  Vector<Real> ftime = {t_old[lev ], t_new[lev ]};
85  Vector<Real> ctime = {t_old[lev-1], t_new[lev-1]};
86 
87  amrex::Real small_dt = 1.e-8 * (ftime[1] - ftime[0]);
88 
89  Vector<MultiFab*> fmf;
90  if ( amrex::almostEqual(time,ftime[0]) || (time-ftime[0]) < small_dt ) {
91  fmf = {&vars_old[lev][Vars::cons], &vars_old[lev][Vars::cons]};
92  } else if (amrex::almostEqual(time,ftime[1])) {
93  fmf = {&vars_new[lev][Vars::cons], &vars_new[lev][Vars::cons]};
94  } else {
95  fmf = {&vars_old[lev][Vars::cons], &vars_new[lev][Vars::cons]};
96  }
97  Vector<MultiFab*> cmf = {&vars_old[lev-1][Vars::cons], &vars_new[lev-1][Vars::cons]};
98 
99  // We must fill a temporary then copy it back so we don't double add/subtract
100  MultiFab mf_c(mfs_vel[Vars::cons]->boxArray(),mfs_vel[Vars::cons]->DistributionMap(),
101  mfs_vel[Vars::cons]->nComp() ,mfs_vel[Vars::cons]->nGrowVect());
102 
103  mapper = &cell_cons_interp;
104 
105  if (interpolation_type == StateInterpType::Perturbational)
106  {
107  // Divide (rho theta) by rho to get theta (before we subtract rho0 from rho!)
108  if (!amrex::almostEqual(time,ctime[1])) {
109  MultiFab::Divide(vars_old[lev-1][Vars::cons],vars_old[lev-1][Vars::cons],
110  Rho_comp,RhoTheta_comp,1,ngvect_cons);
111  MultiFab::Subtract(vars_old[lev-1][Vars::cons],base_state[lev-1],
112  BaseState::r0_comp,Rho_comp,1,ngvect_cons);
113  MultiFab::Subtract(vars_old[lev-1][Vars::cons],base_state[lev-1],
114  BaseState::th0_comp,RhoTheta_comp,1,ngvect_cons);
115  }
116  if (!amrex::almostEqual(time,ctime[0])) {
117  MultiFab::Divide(vars_new[lev-1][Vars::cons],vars_new[lev-1][Vars::cons],
118  Rho_comp,RhoTheta_comp,1,ngvect_cons);
119  MultiFab::Subtract(vars_new[lev-1][Vars::cons],base_state[lev-1],
120  BaseState::r0_comp,Rho_comp,1,ngvect_cons);
121  MultiFab::Subtract(vars_new[lev-1][Vars::cons],base_state[lev-1],
122  BaseState::th0_comp,RhoTheta_comp,1,ngvect_cons);
123  }
124 
125  if (!amrex::almostEqual(time,ftime[1])) {
126  MultiFab::Divide(vars_old[lev ][Vars::cons],vars_old[lev ][Vars::cons],
127  Rho_comp,RhoTheta_comp,1,IntVect{0});
128  MultiFab::Subtract(vars_old[lev ][Vars::cons],old_base_state,
129  BaseState::r0_comp,Rho_comp,1,IntVect{0});
130  MultiFab::Subtract(vars_old[lev ][Vars::cons],old_base_state,
131  BaseState::th0_comp,RhoTheta_comp,1,IntVect{0});
132  }
133  if (!amrex::almostEqual(time,ftime[0])) {
134  MultiFab::Divide(vars_new[lev ][Vars::cons],vars_new[lev ][Vars::cons],
135  Rho_comp,RhoTheta_comp,1,IntVect{0});
136  MultiFab::Subtract(vars_new[lev ][Vars::cons],old_base_state,
137  BaseState::r0_comp,Rho_comp,1,IntVect{0});
138  MultiFab::Subtract(vars_new[lev ][Vars::cons],old_base_state,
139  BaseState::th0_comp,RhoTheta_comp,1,IntVect{0});
140  }
141  }
142 
143  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
144  FillPatchTwoLevels(mf_c, ngvect_cons, IntVect(0,0,0),
145  time, cmf, ctime, fmf, ftime,
146  0, 0, mf_c.nComp(), geom[lev-1], geom[lev],
147  refRatio(lev-1), mapper, domain_bcs_type,
149 
150  if (interpolation_type == StateInterpType::Perturbational)
151  {
152  // Restore the coarse values to what they were
153  if (!amrex::almostEqual(time,ctime[1])) {
154  MultiFab::Add(vars_old[lev-1][Vars::cons], base_state[lev-1],
155  BaseState::r0_comp,Rho_comp,1,ngvect_cons);
156  MultiFab::Add(vars_old[lev-1][Vars::cons], base_state[lev-1],
157  BaseState::th0_comp,RhoTheta_comp,1,ngvect_cons);
158  MultiFab::Multiply(vars_old[lev-1][Vars::cons], vars_old[lev-1][Vars::cons],
159  Rho_comp,RhoTheta_comp,1,ngvect_cons);
160  }
161  if (!amrex::almostEqual(time,ctime[0])) {
162  MultiFab::Add(vars_new[lev-1][Vars::cons], base_state[lev-1],
163  BaseState::r0_comp,Rho_comp,1,vars_new[lev-1][Vars::cons].nGrowVect());
164  MultiFab::Add(vars_new[lev-1][Vars::cons], base_state[lev-1],
165  BaseState::th0_comp,RhoTheta_comp,1,vars_new[lev-1][Vars::cons].nGrowVect());
166  MultiFab::Multiply(vars_new[lev-1][Vars::cons], vars_new[lev-1][Vars::cons],
167  Rho_comp,RhoTheta_comp,1,ngvect_cons);
168  }
169 
170  if (!amrex::almostEqual(time,ftime[1])) {
171  MultiFab::Add(vars_old[lev][Vars::cons],base_state[lev ],BaseState::r0_comp,Rho_comp,1,ngvect_cons);
172  MultiFab::Add(vars_old[lev][Vars::cons],base_state[lev ],BaseState::th0_comp,RhoTheta_comp,1,ngvect_cons);
173  MultiFab::Multiply(vars_old[lev][Vars::cons], vars_old[lev][Vars::cons],
174  Rho_comp,RhoTheta_comp,1,ngvect_cons);
175  }
176  if (!amrex::almostEqual(time,ftime[0])) {
177  MultiFab::Add(vars_new[lev][Vars::cons], base_state[lev],BaseState::r0_comp,Rho_comp,1,ngvect_cons);
178  MultiFab::Add(vars_new[lev][Vars::cons], base_state[lev],BaseState::th0_comp,RhoTheta_comp,1,ngvect_cons);
179  MultiFab::Multiply(vars_new[lev][Vars::cons], vars_new[lev][Vars::cons],
180  Rho_comp,RhoTheta_comp,1,ngvect_cons);
181  }
182 
183  // Set values in the cells outside the domain boundary so that we can do the Add
184  // without worrying about uninitialized values outside the domain -- these
185  // will be filled in the physbcs call
186  mf_c.setDomainBndry(1.234e20,0,2,geom[lev]); // Do both rho and (rho theta) together
187 
188  // Add rho_0 back to rho and theta_0 back to theta
189  MultiFab::Add(mf_c, new_base_state,BaseState::r0_comp,Rho_comp,1,ngvect_cons);
190  MultiFab::Add(mf_c, new_base_state,BaseState::th0_comp,RhoTheta_comp,1,ngvect_cons);
191 
192  // Multiply (theta) by rho to get (rho theta)
193  MultiFab::Multiply(mf_c,mf_c,Rho_comp,RhoTheta_comp,1,ngvect_cons);
194  }
195 
196  MultiFab::Copy(*mfs_vel[Vars::cons],mf_c,0,0,mf_c.nComp(),mf_c.nGrowVect());
197 
198  // ***************************************************************************************
199 
200  if (!cons_only)
201  {
202  mapper = &face_cons_linear_interp;
203 
204  MultiFab& mf_u = *mfs_vel[Vars::xvel];
205  MultiFab& mf_v = *mfs_vel[Vars::yvel];
206  MultiFab& mf_w = *mfs_vel[Vars::zvel];
207 
208  Vector<MultiFab*> fmf_u; Vector<MultiFab*> fmf_v; Vector<MultiFab*> fmf_w;
209  Vector<MultiFab*> cmf_u; Vector<MultiFab*> cmf_v; Vector<MultiFab*> cmf_w;
210 
211  // **********************************************************************
212 
213  if ( amrex::almostEqual(time,ftime[0]) || (time-ftime[0]) < small_dt ) {
214  fmf_u = {&vars_old[lev][Vars::xvel], &vars_old[lev][Vars::xvel]};
215  fmf_v = {&vars_old[lev][Vars::yvel], &vars_old[lev][Vars::yvel]};
216  fmf_w = {&vars_old[lev][Vars::zvel], &vars_old[lev][Vars::zvel]};
217  } else if ( amrex::almostEqual(time,ftime[1]) ) {
218  fmf_u = {&vars_new[lev][Vars::xvel], &vars_new[lev][Vars::xvel]};
219  fmf_v = {&vars_new[lev][Vars::yvel], &vars_new[lev][Vars::yvel]};
220  fmf_w = {&vars_new[lev][Vars::zvel], &vars_new[lev][Vars::zvel]};
221  } else {
222  fmf_u = {&vars_old[lev][Vars::xvel], &vars_new[lev][Vars::xvel]};
223  fmf_v = {&vars_old[lev][Vars::yvel], &vars_new[lev][Vars::yvel]};
224  fmf_w = {&vars_old[lev][Vars::zvel], &vars_new[lev][Vars::zvel]};
225  }
226  cmf_u = {&vars_old[lev-1][Vars::xvel], &vars_new[lev-1][Vars::xvel]};
227  cmf_v = {&vars_old[lev-1][Vars::yvel], &vars_new[lev-1][Vars::yvel]};
228  cmf_w = {&vars_old[lev-1][Vars::zvel], &vars_new[lev-1][Vars::zvel]};
229 
230  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
231  FillPatchTwoLevels(mf_u, ngvect_vels, IntVect(0,0,0),
232  time, cmf_u, ctime, fmf_u, ftime,
233  0, 0, 1, geom[lev-1], geom[lev],
234  refRatio(lev-1), mapper, domain_bcs_type,
236 
237  FillPatchTwoLevels(mf_v, ngvect_vels, IntVect(0,0,0),
238  time, cmf_v, ctime, fmf_v, ftime,
239  0, 0, 1, geom[lev-1], geom[lev],
240  refRatio(lev-1), mapper, domain_bcs_type,
242 
243  // We put these here because these may be used in constructing omega outside the
244  // domain when fillpatching w
245  bool do_fb = true;
246  (*physbcs_u[lev])(*mfs_vel[Vars::xvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
247  ngvect_vels,time,BCVars::xvel_bc, do_fb);
248  (*physbcs_v[lev])(*mfs_vel[Vars::yvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
249  ngvect_vels,time,BCVars::yvel_bc, do_fb);
250 
251  // **********************************************************************
252 
253  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
254  FillPatchTwoLevels(mf_w, ngvect_vels, IntVect(0,0,0),
255  time, cmf_w, ctime, fmf_w, ftime,
256  0, 0, 1, geom[lev-1], geom[lev],
257  refRatio(lev-1), mapper, domain_bcs_type,
259  } // !cons_only
260 
261  // ***************************************************************************
262  // Physical bc's at domain boundary
263  // ***************************************************************************
264  int icomp_cons = 0;
265  int ncomp_cons = mfs_vel[Vars::cons]->nComp();
266 
267  bool do_fb = true;
268 
269  if (m_r2d && !solverChoice.use_real_bcs) fill_from_bndryregs(mfs_vel,time);
270 
271  // We call this even if use_real_bcs is true because these will fill the vertical bcs
272  // Note that we call FillBoundary inside the physbcs call
273  (*physbcs_cons[lev])(*mfs_vel[Vars::cons],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
274  icomp_cons,ncomp_cons,ngvect_cons,time,BCVars::cons_bc, do_fb);
275  if (!cons_only) {
276  // Note that we need to fill u and v in the case of terrain because we will use
277  // these in the call of WFromOmega in lateral ghost cells of the fine grid
278  // (*physbcs_u[lev])(*mfs_vel[Vars::xvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
279  // ngvect_vels,time,BCVars::xvel_bc, do_fb);
280  // (*physbcs_v[lev])(*mfs_vel[Vars::yvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
281  // ngvect_vels,time,BCVars::yvel_bc, do_fb);
282  (*physbcs_w[lev])(*mfs_vel[Vars::zvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
283  ngvect_vels,time,BCVars::zvel_bc, do_fb);
284  }
285 }
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 + 0.5) * dx[0];
116  const Real y = prob_lo[1] + (j + 0.5) * 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, 1.0);
134  surf_arr(i, j, 1) = tmp_sst;
135  }
136  });
137  }
138 
139 }
amrex::Real value
Definition: ERF_HurricaneDiagnostics.H:20
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:130
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 
)
760 {
761  const auto dx = geom[levc].CellSizeArray();
762  const auto prob_lo = geom[levc].ProbLoArray();
763 
764  Gpu::DeviceVector<Real> d_coords(2, 0.0);
765  Gpu::DeviceVector<int> d_found(1,0);
766 
767  Real* d_coords_ptr = d_coords.data();
768  int* d_found_ptr = d_found.data();
769 
770  for (MFIter mfi(mf_cc_vel); mfi.isValid(); ++mfi)
771  {
772  const Box& box = mfi.validbox();
773  const Array4<const Real>& vel_arr = mf_cc_vel.const_array(mfi);
774 
775  ParallelFor(box, [=] AMREX_GPU_DEVICE(int i, int j, int k)
776  {
777  Real magnitude = std::sqrt(vel_arr(i,j,k,0) * vel_arr(i,j,k,0) +
778  vel_arr(i,j,k,1) * vel_arr(i,j,k,1) +
779  vel_arr(i,j,k,2) * vel_arr(i,j,k,2));
780 
781  magnitude *= 3.6;
782 
783  Real z = prob_lo[2] + (k + 0.5) * dx[2];
784 
785  // Check if magnitude exceeds threshold
786  if (z < 2000. && magnitude > velmag_threshold) {
787  // Use atomic operations to set found flag and store coordinates
788  Gpu::Atomic::Add(&d_found_ptr[0], 1); // Mark as found
789 
790  Real x = prob_lo[0] + (i + 0.5) * dx[0];
791  Real y = prob_lo[1] + (j + 0.5) * dx[1];
792 
793  // Store coordinates
794  Gpu::Atomic::Add(&d_coords_ptr[0],x); // Store x index
795  Gpu::Atomic::Add(&d_coords_ptr[1],y); // Store x index
796  }
797  });
798  }
799 
800  // Synchronize to ensure all threads complete their execution
801  amrex::Gpu::streamSynchronize(); // Wait for all GPU threads to finish
802 
803  Vector<int> h_found(1,0);
804  Gpu::copy(Gpu::deviceToHost, d_found.begin(), d_found.end(), h_found.begin());
805  ParallelAllReduce::Sum(h_found.data(), h_found.size(), ParallelContext::CommunicatorAll());
806 
807  // Broadcast coordinates if found
808  if (h_found[0] > 0) {
809  Vector<Real> h_coords(2,-1e10);
810  Gpu::copy(Gpu::deviceToHost, d_coords.begin(), d_coords.end(), h_coords.begin());
811 
812  ParallelAllReduce::Sum(h_coords.data(), h_coords.size(), ParallelContext::CommunicatorAll());
813 
814  eye_x = h_coords[0]/h_found[0];
815  eye_y = h_coords[1]/h_found[0];
816 
817  } else {
818  // Random large negative numbers so we don't trigger refinement in this case
819  eye_x = -1.e20;
820  eye_y = -1.e20;
821  }
822 
823  return (h_found[0] > 0);
824 }
Here is the call graph for this function:

◆ get_eb()

eb_ const& ERF::get_eb ( int  lev) const
inlineprivatenoexcept
1627  {
1628  AMREX_ASSERT(lev >= 0 && lev < eb.size() && eb[lev] != nullptr);
1629  return *eb[lev];
1630  }

◆ getAdvFluxReg()

AMREX_FORCE_INLINE amrex::YAFluxRegister* ERF::getAdvFluxReg ( int  lev)
inlineprivate
1413  {
1414  return advflux_reg[lev];
1415  }

◆ getCPUTime()

static amrex::Real ERF::getCPUTime ( )
inlinestaticprivate
1505  {
1506  int numCores = amrex::ParallelDescriptor::NProcs();
1507 #ifdef _OPENMP
1508  numCores = numCores * omp_get_max_threads();
1509 #endif
1510 
1511  amrex::Real T =
1512  numCores * (amrex::ParallelDescriptor::second() - startCPUTime) +
1514 
1515  return T;
1516  }
Real T
Definition: ERF_InitCustomPert_Bubble.H:105
static amrex::Real previousCPUTimeUsed
Definition: ERF.H:1501
static amrex::Real startCPUTime
Definition: ERF.H:1500

◆ 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 
)
861 {
862  bool is_found;
863 
864  Real eye_x, eye_y;
865 
866  if (time==0.0) {
867  is_found = FindInitialEye(levc, mf_cc_vel, velmag_threshold, eye_x, eye_y);
868  } else {
869  is_found = true;
870  const auto& last = hurricane_eye_track_xy.back();
871  eye_x = last[0];
872  eye_y = last[1];
873  }
874 
875  if (is_found) {
876  Real rad_tag = 4.e5 * std::pow(2, max_level-1-levc);
877  tag_on_distance_from_eye(geom[levc], tags, eye_x, eye_y, rad_tag);
878  }
879 }
amrex::Vector< std::array< amrex::Real, 2 > > hurricane_eye_track_xy
Definition: ERF.H:157
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:756
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(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:988
Here is the call graph for this function:

◆ init1DArrays()

void ERF::init1DArrays ( )
private

◆ init_bcs()

void ERF::init_bcs ( )
private
288 {
289  bool rho_read = false;
290  bool read_prim_theta = true;
291 
292  init_phys_bcs(rho_read, read_prim_theta);
293 
294  Vector<Real> cons_dir_init(NBCVAR_max,0.0);
295  cons_dir_init[BCVars::Rho_bc_comp] = 1.0;
296  cons_dir_init[BCVars::RhoTheta_bc_comp] = -1.0;
297 
298  bool keqn_dir = (solverChoice.turbChoice[max_level].rans_type == RANSType::kEqn &&
299  solverChoice.turbChoice[max_level].dirichlet_k == true);
300  if (keqn_dir) {
301  // Need to change wall BC type, assume for now that all levels are RANS
302  for (int lev = 0; lev < max_level; ++lev) {
303  if (solverChoice.turbChoice[lev].rans_type != RANSType::kEqn) {
304  Error("If using one-eqn RANS, all levels must be RANS for now");
305  }
306  }
307  Print() << "Using dirichlet BC for k equation" << std::endl;
308  }
309 
310  // *****************************************************************************
311  //
312  // Here we translate the physical boundary conditions -- one type per face --
313  // into logical boundary conditions for each velocity component
314  //
315  // *****************************************************************************
316  {
317  domain_bcs_type.resize(AMREX_SPACEDIM+NBCVAR_max);
318  domain_bcs_type_d.resize(AMREX_SPACEDIM+NBCVAR_max);
319 
320  for (OrientationIter oit; oit; ++oit) {
321  Orientation ori = oit();
322  int dir = ori.coordDir();
323  Orientation::Side side = ori.faceDir();
324  auto const bct = phys_bc_type[ori];
325  if ( bct == ERF_BC::symmetry )
326  {
327  if (side == Orientation::low) {
328  for (int i = 0; i < AMREX_SPACEDIM; i++) {
330  }
332  } else {
333  for (int i = 0; i < AMREX_SPACEDIM; i++) {
335  }
337  }
338  }
339  else if (bct == ERF_BC::outflow or bct == ERF_BC::ho_outflow )
340  {
341  if (side == Orientation::low) {
342  for (int i = 0; i < AMREX_SPACEDIM; i++) {
344  }
345  if (!solverChoice.anelastic[0]) {
347  }
348  } else {
349  for (int i = 0; i < AMREX_SPACEDIM; i++) {
351  }
352  if (!solverChoice.anelastic[0]) {
354  }
355  }
356  }
357  else if (bct == ERF_BC::open)
358  {
359  if (side == Orientation::low) {
360  for (int i = 0; i < AMREX_SPACEDIM; i++)
362  } else {
363  for (int i = 0; i < AMREX_SPACEDIM; i++)
365  }
366  }
367  else if (bct == ERF_BC::inflow)
368  {
369  if (side == Orientation::low) {
370  for (int i = 0; i < AMREX_SPACEDIM; i++) {
372  if (input_bndry_planes && dir < 2 && m_r2d->ingested_velocity()) {
374  }
375  }
376  } else {
377  for (int i = 0; i < AMREX_SPACEDIM; i++) {
379  if (input_bndry_planes && dir < 2 && m_r2d->ingested_velocity()) {
381  }
382  }
383  }
384  }
385  else if (bct == ERF_BC::inflow_outflow)
386  {
387  if (side == Orientation::low) {
388  for (int i = 0; i < AMREX_SPACEDIM; i++) {
390  }
391  } else {
392  for (int i = 0; i < AMREX_SPACEDIM; i++) {
394  }
395  }
396  }
397  else if (bct == ERF_BC::no_slip_wall)
398  {
399  if (side == Orientation::low) {
400  for (int i = 0; i < AMREX_SPACEDIM; i++) {
402  }
403  } else {
404  for (int i = 0; i < AMREX_SPACEDIM; i++) {
406  }
407  }
408  }
409  else if (bct == ERF_BC::slip_wall)
410  {
411  if (side == Orientation::low) {
412  for (int i = 0; i < AMREX_SPACEDIM; i++) {
414  }
415  // Only normal direction has ext_dir
417 
418  } else {
419  for (int i = 0; i < AMREX_SPACEDIM; i++) {
421  }
422  // Only normal direction has ext_dir
424  }
425  }
426  else if (bct == ERF_BC::periodic)
427  {
428  if (side == Orientation::low) {
429  for (int i = 0; i < AMREX_SPACEDIM; i++) {
431  }
432  } else {
433  for (int i = 0; i < AMREX_SPACEDIM; i++) {
435  }
436  }
437  }
438  else if ( bct == ERF_BC::surface_layer )
439  {
440  AMREX_ALWAYS_ASSERT(dir == 2 && side == Orientation::low);
444  }
445  }
446  }
447 
448  // *****************************************************************************
449  //
450  // Here we translate the physical boundary conditions -- one type per face --
451  // into logical boundary conditions for each cell-centered variable
452  // (including the base state variables)
453  // NOTE: all "scalars" share the same type of boundary condition
454  //
455  // *****************************************************************************
456  {
457  for (OrientationIter oit; oit; ++oit) {
458  Orientation ori = oit();
459  int dir = ori.coordDir();
460  Orientation::Side side = ori.faceDir();
461  auto const bct = phys_bc_type[ori];
462  if ( bct == ERF_BC::symmetry )
463  {
464  if (side == Orientation::low) {
465  for (int i = 0; i < NBCVAR_max; i++) {
467  }
468  } else {
469  for (int i = 0; i < NBCVAR_max; i++) {
471  }
472  }
473  }
474  else if ( bct == ERF_BC::outflow )
475  {
476  if (side == Orientation::low) {
477  for (int i = 0; i < NBCVAR_max; i++) {
479  }
480  } else {
481  for (int i = 0; i < NBCVAR_max; i++) {
483  }
484  }
485  }
486  else if ( bct == ERF_BC::ho_outflow )
487  {
488  if (side == Orientation::low) {
489  for (int i = 0; i < NBCVAR_max; i++) {
491  }
492  } else {
493  for (int i = 0; i < NBCVAR_max; i++) {
495  }
496  }
497  }
498  else if ( bct == ERF_BC::open )
499  {
500  if (side == Orientation::low) {
501  for (int i = 0; i < NBCVAR_max; i++)
503  } else {
504  for (int i = 0; i < NBCVAR_max; i++)
506  }
507  }
508  else if ( bct == ERF_BC::no_slip_wall )
509  {
510  if (side == Orientation::low) {
511  for (int i = 0; i < NBCVAR_max; i++) {
513  if (m_bc_extdir_vals[BCVars::cons_bc+i][ori] != cons_dir_init[BCVars::cons_bc+i]) {
514  if (rho_read) {
516  } else {
518  }
519  }
520  }
521  if (std::abs(m_bc_neumann_vals[BCVars::RhoTheta_bc_comp][ori]) > 0.) {
523  }
524  } else {
525  for (int i = 0; i < NBCVAR_max; i++) {
527  if (m_bc_extdir_vals[BCVars::cons_bc+i][ori] != cons_dir_init[BCVars::cons_bc+i]) {
528  if (rho_read) {
530  } else {
532  }
533  }
534  }
535  if (std::abs(m_bc_neumann_vals[BCVars::RhoTheta_bc_comp][ori]) > 0.) {
537  }
538  }
539  }
540  else if (bct == ERF_BC::slip_wall)
541  {
542  if (side == Orientation::low) {
543  for (int i = 0; i < NBCVAR_max; i++) {
545  if (m_bc_extdir_vals[BCVars::cons_bc+i][ori] != cons_dir_init[BCVars::cons_bc+i]) {
546  if (rho_read) {
548  } else {
550  }
551  }
552  }
553  if (std::abs(m_bc_neumann_vals[BCVars::RhoTheta_bc_comp][ori]) > 0.) {
555  }
556  if (std::abs(m_bc_neumann_vals[BCVars::Rho_bc_comp][ori]) > 0.) {
558  }
559  } else {
560  for (int i = 0; i < NBCVAR_max; i++) {
562  if (m_bc_extdir_vals[BCVars::cons_bc+i][ori] != cons_dir_init[BCVars::cons_bc+i]) {
563  if (rho_read) {
565  } else {
567  }
568  }
569  }
570  if (std::abs(m_bc_neumann_vals[BCVars::RhoTheta_bc_comp][ori]) > 0.) {
572  }
573  if (std::abs(m_bc_neumann_vals[BCVars::Rho_bc_comp][ori]) > 0.) {
575  }
576  }
577  }
578  else if (bct == ERF_BC::inflow)
579  {
580  if (side == Orientation::low) {
581  for (int i = 0; i < NBCVAR_max; i++) {
583  if ((BCVars::cons_bc+i == RhoTheta_comp) &&
584  (th_bc_data[0].data() != nullptr))
585  {
586  if (read_prim_theta) domain_bcs_type[BCVars::cons_bc+i].setLo(dir, ERFBCType::ext_dir_prim);
587  }
588  else if (input_bndry_planes && dir < 2 && (
589  ( (BCVars::cons_bc+i == BCVars::Rho_bc_comp) && m_r2d->ingested_density()) ||
590  ( (BCVars::cons_bc+i == BCVars::RhoTheta_bc_comp) && m_r2d->ingested_theta() ) ||
591  ( (BCVars::cons_bc+i == BCVars::RhoKE_bc_comp) && m_r2d->ingested_KE() ) ||
592  ( (BCVars::cons_bc+i == BCVars::RhoScalar_bc_comp) && m_r2d->ingested_scalar() ) ||
593  ( (BCVars::cons_bc+i == BCVars::RhoQ1_bc_comp) && m_r2d->ingested_q1() ) ||
594  ( (BCVars::cons_bc+i == BCVars::RhoQ2_bc_comp) && m_r2d->ingested_q2() )) )
595  {
597  }
598  else if (m_bc_extdir_vals[BCVars::Rho_bc_comp][ori] == 0) {
600  }
601  }
602  } else {
603  for (int i = 0; i < NBCVAR_max; i++) {
605  if ((BCVars::cons_bc+i == RhoTheta_comp) &&
606  (th_bc_data[0].data() != nullptr))
607  {
608  if (read_prim_theta) domain_bcs_type[BCVars::cons_bc+i].setHi(dir, ERFBCType::ext_dir_prim);
609  }
610  else if (input_bndry_planes && dir < 2 && (
611  ( (BCVars::cons_bc+i == BCVars::Rho_bc_comp) && m_r2d->ingested_density()) ||
612  ( (BCVars::cons_bc+i == BCVars::RhoTheta_bc_comp) && m_r2d->ingested_theta() ) ||
613  ( (BCVars::cons_bc+i == BCVars::RhoKE_bc_comp) && m_r2d->ingested_KE() ) ||
614  ( (BCVars::cons_bc+i == BCVars::RhoScalar_bc_comp) && m_r2d->ingested_scalar() ) ||
615  ( (BCVars::cons_bc+i == BCVars::RhoQ1_bc_comp) && m_r2d->ingested_q1() ) ||
616  ( (BCVars::cons_bc+i == BCVars::RhoQ2_bc_comp) && m_r2d->ingested_q2() )
617  ) )
618  {
620  }
621  else if (m_bc_extdir_vals[BCVars::Rho_bc_comp][ori] == 0) {
623  }
624  }
625  }
626  }
627  else if (bct == ERF_BC::inflow_outflow )
628  {
629  if (side == Orientation::low) {
630  for (int i = 0; i < NBCVAR_max; i++) {
632  if (m_bc_extdir_vals[BCVars::Rho_bc_comp][ori] == 0) {
634  }
635  }
636  } else {
637  for (int i = 0; i < NBCVAR_max; i++) {
639  if (m_bc_extdir_vals[BCVars::Rho_bc_comp][ori] == 0) {
641  }
642  }
643  }
644  }
645  else if (bct == ERF_BC::periodic)
646  {
647  if (side == Orientation::low) {
648  for (int i = 0; i < NBCVAR_max; i++) {
650  }
651  } else {
652  for (int i = 0; i < NBCVAR_max; i++) {
654  }
655  }
656  }
657  else if ( bct == ERF_BC::surface_layer )
658  {
659  AMREX_ALWAYS_ASSERT(dir == 2 && side == Orientation::low);
660  for (int i = 0; i < NBCVAR_max; i++) {
662  }
663  if (keqn_dir) {
664  Print() << "Setting surface layer logical BC to dirichlet for RANS with k model" << std::endl;
666  }
667  }
668  }
669  }
670 
671  // NOTE: Gpu:copy is a wrapper to htod_memcpy (GPU) or memcpy (CPU) and is a blocking comm
672  Gpu::copy(Gpu::hostToDevice, domain_bcs_type.begin(), domain_bcs_type.end(), domain_bcs_type_d.begin());
673 }
#define NBCVAR_max
Definition: ERF_IndexDefines.H:29
@ ho_outflow
@ inflow_outflow
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:994
@ RhoQ1_bc_comp
Definition: ERF_IndexDefines.H:81
@ RhoKE_bc_comp
Definition: ERF_IndexDefines.H:79
@ RhoTheta_bc_comp
Definition: ERF_IndexDefines.H:78
@ RhoQ2_bc_comp
Definition: ERF_IndexDefines.H:82
@ Rho_bc_comp
Definition: ERF_IndexDefines.H:77
@ neumann
Definition: ERF_IndexDefines.H:229
@ open
Definition: ERF_IndexDefines.H:231
@ reflect_odd
Definition: ERF_IndexDefines.H:221
@ hoextrap
Definition: ERF_IndexDefines.H:232
@ foextrap
Definition: ERF_IndexDefines.H:224
@ ext_dir
Definition: ERF_IndexDefines.H:225
@ ext_dir_prim
Definition: ERF_IndexDefines.H:227
@ ext_dir_upwind
Definition: ERF_IndexDefines.H:233
@ int_dir
Definition: ERF_IndexDefines.H:222
@ neumann_int
Definition: ERF_IndexDefines.H:230
@ reflect_even
Definition: ERF_IndexDefines.H:223
Here is the call graph for this function:

◆ init_custom()

void ERF::init_custom ( int  lev)
private

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  // If the initial condition needs to have spatially correlated perturbations superimposed onto
46  // the base state, then populate the "pert" multifabs with random perturbations,
47  // and then apply a Gaussian smoothing to make the perturbations spatially correlated
49  create_random_perturbations(lev, cons_pert, xvel_pert, yvel_pert, zvel_pert);
50  apply_gaussian_smoothing_to_perturbations(lev, cons_pert, xvel_pert, yvel_pert, zvel_pert);
51  }
52 
53 #ifdef _OPENMP
54 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
55 #endif
56  for (MFIter mfi(lev_new[Vars::cons], TileNoZ()); mfi.isValid(); ++mfi)
57  {
58  const Box &bx = mfi.tilebox();
59  const Box &xbx = mfi.tilebox(IntVect(1,0,0));
60  const Box &ybx = mfi.tilebox(IntVect(0,1,0));
61  const Box &zbx = mfi.tilebox(IntVect(0,0,1));
62 
63  const auto &cons_pert_arr = cons_pert.array(mfi);
64  const auto &xvel_pert_arr = xvel_pert.array(mfi);
65  const auto &yvel_pert_arr = yvel_pert.array(mfi);
66  const auto &zvel_pert_arr = zvel_pert.array(mfi);
67 
68  Array4<Real const> cons_arr = lev_new[Vars::cons].const_array(mfi);
69  Array4<Real const> z_nd_arr = (z_phys_nd[lev]) ? z_phys_nd[lev]->const_array(mfi) : Array4<Real const>{};
70  Array4<Real const> z_cc_arr = (z_phys_cc[lev]) ? z_phys_cc[lev]->const_array(mfi) : Array4<Real const>{};
71 
72  // Here we arbitrarily choose the x-oriented map factor -- this should be generalized
73  Array4<Real const> mf_m = mapfac[lev][MapFacType::m_x]->const_array(mfi);
74  Array4<Real const> mf_u = mapfac[lev][MapFacType::u_x]->const_array(mfi);
75  Array4<Real const> mf_v = mapfac[lev][MapFacType::v_y]->const_array(mfi);
76 
77  Array4<Real> r_hse_arr = r_hse.array(mfi);
78  Array4<Real> p_hse_arr = p_hse.array(mfi);
79 
80  prob->init_custom_pert(bx, cons_arr, cons_pert_arr,
81  r_hse_arr, p_hse_arr, z_nd_arr, z_cc_arr,
82  geom[lev].data(), mf_m, solverChoice, lev);
83  prob->init_custom_pert_vels(xbx, ybx, zbx,
84  xvel_pert_arr, yvel_pert_arr, zvel_pert_arr,
85  z_nd_arr, geom[lev].data(), mf_u, mf_v,
86  solverChoice, lev);
87  } //mfi
88 
89  // Add problem-specific perturbation to background flow if not doing anelastic with fixed-in-time density
90  if (!solverChoice.fixed_density[lev]) {
91  MultiFab::Add(lev_new[Vars::cons], cons_pert, Rho_comp, Rho_comp, 1, cons_pert.nGrow());
92  }
93  MultiFab::Add(lev_new[Vars::cons], cons_pert, RhoTheta_comp, RhoTheta_comp, 1, cons_pert.nGrow());
94  MultiFab::Add(lev_new[Vars::cons], cons_pert, RhoScalar_comp,RhoScalar_comp,NSCALARS, cons_pert.nGrow());
95 
96  // RhoKE is relevant if using Deardorff with LES, k-equation for RANS, or MYNN with PBL
97  if (solverChoice.turbChoice[lev].use_tke) {
98  MultiFab::Add(lev_new[Vars::cons], cons_pert, RhoKE_comp, RhoKE_comp, 1, cons_pert.nGrow());
99  }
100 
101  if (solverChoice.moisture_type != MoistureType::None) {
102  int qstate_size = micro->Get_Qstate_Size();
103  for (int q_offset(0); q_offset<qstate_size; ++q_offset) {
104  int q_idx = RhoQ1_comp+q_offset;
105  MultiFab::Add(lev_new[Vars::cons], cons_pert, q_idx, q_idx, 1, cons_pert.nGrow());
106  }
107  }
108 
109  // Should we initialize the velocities from a checkpoint file?
110  static std::string init_vels_from_checkpoint;
111  ParmParse pp("erf");
112  if (pp.query("init_vels_from_checkpoint",init_vels_from_checkpoint)) {
113  ReadVelsOnlyFromCheckpointFile(lev,init_vels_from_checkpoint);
114  } else {
115  MultiFab::Add(lev_new[Vars::xvel], xvel_pert, 0, 0, 1, xvel_pert.nGrowVect());
116  MultiFab::Add(lev_new[Vars::yvel], yvel_pert, 0, 0, 1, yvel_pert.nGrowVect());
117  MultiFab::Add(lev_new[Vars::zvel], zvel_pert, 0, 0, 1, zvel_pert.nGrowVect());
118  }
119 }
const Box ybx
Definition: ERF_SetupDiff.H:8
void ReadVelsOnlyFromCheckpointFile(int lev_to_fill, std::string &chkfile)
Definition: ERF_Checkpoint.cpp:1076
void apply_gaussian_smoothing_to_perturbations(const int lev, amrex::MultiFab &cons_pert, amrex::MultiFab &xvel_pert, amrex::MultiFab &yvel_pert, amrex::MultiFab &zvel_pert)
Definition: ERF_InitCustomPertState.cpp:144
void create_random_perturbations(const int lev, amrex::MultiFab &cons_pert, amrex::MultiFab &xvel_pert, amrex::MultiFab &yvel_pert, amrex::MultiFab &zvel_pert)
Definition: ERF_InitCustomPertState.cpp:122
bool is_init_with_correlated_pert
Definition: ERF_DataStruct.H:1248
amrex::Vector< int > fixed_density
Definition: ERF_DataStruct.H:1087
Here is the call graph for this function:

◆ init_Dirichlet_bc_data()

void ERF::init_Dirichlet_bc_data ( const std::string  input_file)
private
676 {
677  // Read the dirichlet_input file
678  Print() << "dirichlet_input file location : " << input_file << std::endl;
679  std::ifstream input_reader(input_file);
680  if (!input_reader.is_open()) {
681  amrex::Abort("Error opening the dirichlet_input file.\n");
682  }
683 
684  Print() << "Successfully opened the dirichlet_input file. Now reading... " << std::endl;
685  std::string line;
686 
687  // Size of Ninp (number of z points in input file)
688  Vector<Real> z_inp_tmp, u_inp_tmp, v_inp_tmp, w_inp_tmp, th_inp_tmp;
689 
690  // Top and bot for domain
691  const int klo = geom[0].Domain().smallEnd()[2];
692  const int khi = geom[0].Domain().bigEnd()[2];
693  const Real zbot = zlevels_stag[0][klo];
694  const Real ztop = zlevels_stag[0][khi+1];
695 
696  // Flag if theta input
697  Real th_init = -300.0;
698  bool th_read{false};
699 
700  // Add surface
701  z_inp_tmp.push_back(zbot); // height above sea level [m]
702  u_inp_tmp.push_back(0.);
703  v_inp_tmp.push_back(0.);
704  w_inp_tmp.push_back(0.);
705  th_inp_tmp.push_back(th_init);
706 
707  // Read the vertical profile at each given height
708  Real z, u, v, w, th;
709  while(std::getline(input_reader, line)) {
710  std::istringstream iss_z(line);
711 
712  Vector<Real> rval_v;
713  Real rval;
714  while (iss_z >> rval) {
715  rval_v.push_back(rval);
716  }
717  if ((rval_v.size() != 4) && (rval_v.size() != 5)) {
718  Abort("Unknown inflow file format!");
719  }
720  z = rval_v[0];
721  u = rval_v[1];
722  v = rval_v[2];
723  w = rval_v[3];
724 
725  // Format without theta
726  if (rval_v.size() == 4) {
727  if (z == zbot) {
728  u_inp_tmp[0] = u;
729  v_inp_tmp[0] = v;
730  w_inp_tmp[0] = w;
731  } else {
732  AMREX_ALWAYS_ASSERT(z > z_inp_tmp[z_inp_tmp.size()-1]); // sounding is increasing in height
733  z_inp_tmp.push_back(z);
734  u_inp_tmp.push_back(u);
735  v_inp_tmp.push_back(v);
736  w_inp_tmp.push_back(w);
737  if (z >= ztop) break;
738  }
739  } else if (rval_v.size() == 5) {
740  th_read = true;
741  th = rval_v[4];
742  if (z == zbot) {
743  u_inp_tmp[0] = u;
744  v_inp_tmp[0] = v;
745  w_inp_tmp[0] = w;
746  th_inp_tmp[0] = th;
747  } else {
748  AMREX_ALWAYS_ASSERT(z > z_inp_tmp[z_inp_tmp.size()-1]); // sounding is increasing in height
749  z_inp_tmp.push_back(z);
750  u_inp_tmp.push_back(u);
751  v_inp_tmp.push_back(v);
752  w_inp_tmp.push_back(w);
753  th_inp_tmp.push_back(th);
754  if (z >= ztop) break;
755  }
756  } else {
757  Abort("Unknown inflow file format!");
758  }
759  }
760 
761  // Ensure we set a reasonable theta surface
762  if (th_read) {
763  if (th_inp_tmp[0] == th_init) {
764  AMREX_ALWAYS_ASSERT_WITH_MESSAGE((th_inp_tmp.size() > 2) && (z_inp_tmp.size() > 2),
765  "Need at least 3 theta profile points to extrapolate surface theta");
766  Real slope = (th_inp_tmp[2] - th_inp_tmp[1]) / (z_inp_tmp[2] - z_inp_tmp[1]);
767  Real dz = z_inp_tmp[0] - z_inp_tmp[1];
768  th_inp_tmp[0] = slope * dz + th_inp_tmp[1];
769  }
770  }
771 
772  amrex::Print() << "Successfully read and interpolated the dirichlet_input file..." << std::endl;
773  input_reader.close();
774 
775  for (int lev = 0; lev <= max_level; lev++) {
776 
777  const int Nz = geom[lev].Domain().size()[2];
778 
779  // Size of Nz (domain grid)
780  Vector<Real> zcc_inp(Nz );
781  Vector<Real> znd_inp(Nz+1);
782  Vector<Real> u_inp(Nz ); xvel_bc_data[lev].resize(Nz ,0.0);
783  Vector<Real> v_inp(Nz ); yvel_bc_data[lev].resize(Nz ,0.0);
784  Vector<Real> w_inp(Nz+1); zvel_bc_data[lev].resize(Nz+1,0.0);
785  Vector<Real> th_inp;
786  if (th_read) {
787  th_inp.resize(Nz);
788  th_bc_data[lev].resize(Nz, 0.0);
789  }
790 
791  // At this point, we have an input from zbot up to
792  // z_inp_tmp[N-1] >= ztop. Now, interpolate to grid level 0 heights
793  const int Ninp = z_inp_tmp.size();
794  for (int k(0); k<Nz; ++k) {
795  zcc_inp[k] = 0.5 * (zlevels_stag[lev][k] + zlevels_stag[lev][k+1]);
796  znd_inp[k] = zlevels_stag[lev][k+1];
797  u_inp[k] = interpolate_1d(z_inp_tmp.dataPtr(), u_inp_tmp.dataPtr(), zcc_inp[k], Ninp);
798  v_inp[k] = interpolate_1d(z_inp_tmp.dataPtr(), v_inp_tmp.dataPtr(), zcc_inp[k], Ninp);
799  w_inp[k] = interpolate_1d(z_inp_tmp.dataPtr(), w_inp_tmp.dataPtr(), znd_inp[k], Ninp);
800  if (th_read) {
801  th_inp[k] = interpolate_1d(z_inp_tmp.dataPtr(), th_inp_tmp.dataPtr(), zcc_inp[k], Ninp);
802  }
803  }
804  znd_inp[Nz] = ztop;
805  w_inp[Nz] = interpolate_1d(z_inp_tmp.dataPtr(), w_inp_tmp.dataPtr(), ztop, Ninp);
806 
807  // Copy host data to the device
808  Gpu::copy(Gpu::hostToDevice, u_inp.begin(), u_inp.end(), xvel_bc_data[lev].begin());
809  Gpu::copy(Gpu::hostToDevice, v_inp.begin(), v_inp.end(), yvel_bc_data[lev].begin());
810  Gpu::copy(Gpu::hostToDevice, w_inp.begin(), w_inp.end(), zvel_bc_data[lev].begin());
811  if (th_read) {
812  Gpu::copy(Gpu::hostToDevice, th_inp.begin(), th_inp.end(), th_bc_data[lev].begin());
813  }
814 
815  // NOTE: These device vectors are passed to the PhysBC constructors when that
816  // class is instantiated in ERF_MakeNewArrays.cpp.
817  } // lev
818 }
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(...)
    • 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 = 1.0
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:768
@ rho0_bc_comp
Definition: ERF_IndexDefines.H:98
@ qv0_comp
Definition: ERF_IndexDefines.H:67
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:1053
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) ? 0.5 * (zlev_stag[k] + zlev_stag[k+1])
54  : zbot + (k + 0.5) * 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 = 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 = 0.5 * (t_blank_arr(i, j, k) + t_blank_arr(i-1, j, k));
40  if (t_blank == 1.0) { xvel_arr(i, j, k) = epsilon; }
41  },
42  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept {
43  const Real t_blank = 0.5 * (t_blank_arr(i, j, k) + t_blank_arr(i, j-1, k));
44  if (t_blank == 1.0) { yvel_arr(i, j, k) = epsilon; }
45  },
46  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept {
47  const Real t_blank = 0.5 * (t_blank_arr(i, j, k) + t_blank_arr(i, j, k-1));
48  if (t_blank == 1.0) { 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 
)
2165 {
2166  t_new[lev] = elapsed_time;
2167  t_old[lev] = elapsed_time - 1.e200;
2168 
2169  auto& lev_new = vars_new[lev];
2170  auto& lev_old = vars_old[lev];
2171 
2172  // Loop over grids at this level to initialize our grid data
2173  lev_new[Vars::cons].setVal(0.0); lev_old[Vars::cons].setVal(0.0);
2174  lev_new[Vars::xvel].setVal(0.0); lev_old[Vars::xvel].setVal(0.0);
2175  lev_new[Vars::yvel].setVal(0.0); lev_old[Vars::yvel].setVal(0.0);
2176  lev_new[Vars::zvel].setVal(0.0); lev_old[Vars::zvel].setVal(0.0);
2177 
2178  // Initialize background flow (optional)
2179  if (solverChoice.init_type == InitType::Input_Sounding) {
2180  // The physbc's need the terrain but are needed for initHSE
2181  // We have already made the terrain in the call to init_zphys
2182  // in MakeNewLevelFromScratch
2183  make_physbcs(lev);
2184 
2185  // Now init the base state and the data itself
2187 
2188  // The base state has been initialized by integrating vertically
2189  // through the sounding for ideal (like WRF) or isentropic approaches
2190  if (solverChoice.sounding_type == SoundingType::Ideal ||
2191  solverChoice.sounding_type == SoundingType::Isentropic ||
2192  solverChoice.sounding_type == SoundingType::DryIsentropic) {
2193  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(solverChoice.use_gravity,
2194  "Gravity should be on to be consistent with sounding initialization.");
2195  } else { // SoundingType::ConstantDensity
2196  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(!solverChoice.use_gravity || (solverChoice.anelastic[lev] == 1),
2197  "Constant density probably doesn't make sense for compressible flow with gravity");
2198  initHSE();
2199  }
2200 
2201 #ifdef ERF_USE_NETCDF
2202  }
2203  else if (solverChoice.init_type == InitType::WRFInput && !nc_init_file[lev].empty())
2204  {
2205  // The base state is initialized from WRF wrfinput data, output by
2206  // ideal.exe or real.exe
2207 
2208  init_from_wrfinput(lev, *mf_C1H, *mf_C2H, *mf_MUB, *mf_PSFC[lev]);
2209 
2210  // The physbc's need the terrain but are needed for initHSE
2211  if (!solverChoice.use_real_bcs) {
2212  make_physbcs(lev);
2213  }
2214  }
2215  else if (solverChoice.init_type == InitType::WRFInput && nc_init_file[lev].empty())
2216  {
2217  amrex::Abort("This pathway is not quite implemented yet");
2218  }
2219  else if (solverChoice.init_type == InitType::NCFile)
2220  {
2221  // The state is initialized by reading from a Netcdf file
2222  init_from_ncfile(lev);
2223 
2224  // The physbc's need the terrain but are needed for initHSE
2225  make_physbcs(lev);
2226  }
2227  else if (solverChoice.init_type == InitType::Metgrid)
2228  {
2229  // The base state is initialized from data output by WPS metgrid;
2230  // we will rebalance after interpolation
2231  init_from_metgrid(lev);
2232 #endif
2233  } else if ( (solverChoice.init_type == InitType::Uniform ) ||
2234  (solverChoice.init_type == InitType::ConstantDensity) ||
2235  (solverChoice.init_type == InitType::Isentropic ) ||
2236  (solverChoice.init_type == InitType::ConstantDensityLinearTheta ) ||
2237  (solverChoice.init_type == InitType::HindCast ) ||
2238  (solverChoice.init_type == InitType::MoistBaseState ) ) {
2239  // Initialize a uniform density/entropy background field and base state
2240  // based on the problem-specified reference density and temperature
2241 
2242  // The physbc's need the terrain but are needed for initHSE
2243  make_physbcs(lev);
2244 
2245  // We will initialize the state from the background state so must set that first
2246  // The choice between constant rho and constant theta will be made inside initHSE
2247  initHSE(lev);
2248 
2249  // Copy rho and rhotheta from rho_hse and p_hse
2250  init_from_hse(lev);
2251 
2252  } else {
2253  Abort("Unknown init_type!");
2254  }
2255 
2256  // Add problem-specific flow features
2257  //
2258  // Notes:
2259  // - This calls init_custom_pert that is defined for each problem
2260  // - This may modify the base state
2261  // - The fields set by init_custom_pert are **perturbations** to the
2262  // background flow set based on init_type
2263  if (solverChoice.init_type != InitType::NCFile) {
2264  init_custom(lev);
2265  }
2266 
2267  // Ensure that the face-based data are the same on both sides of a periodic domain.
2268  // The data associated with the lower grid ID is considered the correct value.
2269  lev_new[Vars::xvel].OverrideSync(geom[lev].periodicity());
2270  lev_new[Vars::yvel].OverrideSync(geom[lev].periodicity());
2271  lev_new[Vars::zvel].OverrideSync(geom[lev].periodicity());
2272 
2273  if(solverChoice.spongeChoice.sponge_type == "input_sponge"){
2274  input_sponge(lev);
2275  }
2276 
2277  // Initialize turbulent perturbation
2278  if (solverChoice.pert_type == PerturbationType::Source ||
2279  solverChoice.pert_type == PerturbationType::Direct ||
2280  solverChoice.pert_type == PerturbationType::CPM) {
2281  turbPert_update(lev, 0.);
2282  turbPert_amplitude(lev);
2283  }
2284 
2285  // Set initial velocity field for immersed cells to be close to 0
2286  if (solverChoice.terrain_type == TerrainType::ImmersedForcing ||
2287  solverChoice.buildings_type == BuildingsType::ImmersedForcing) {
2288  init_immersed_forcing(lev);
2289  }
2290 }
void init_from_input_sounding(int lev)
Definition: ERF_InitFromInputSounding.cpp:53
std::unique_ptr< amrex::MultiFab > mf_MUB
Definition: ERF.H:1262
std::unique_ptr< amrex::MultiFab > mf_C2H
Definition: ERF.H:1261
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:186
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:830
void init_immersed_forcing(int lev)
Definition: ERF_InitImmersedForcing.cpp:15
std::unique_ptr< amrex::MultiFab > mf_C1H
Definition: ERF.H:1260
void turbPert_amplitude(const int lev)
Definition: ERF_InitTurbPert.cpp:32
bool use_gravity
Definition: ERF_DataStruct.H:1117

◆ 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] = -1.0; // 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] = 0.0;
30  }
31 
32  m_bc_extdir_vals[BCVars::xvel_bc][ori] = 0.0; // 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 = 0.;
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 = 0.;
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  Real scalar_in = 0.;
145  if (input_bndry_planes && m_r2d->ingested_scalar()) {
147  } else {
148  if (pp.query("scalar", scalar_in))
149  m_bc_extdir_vals[BCVars::RhoScalar_bc_comp][ori] = rho_in*scalar_in;
150  }
151 
152  if (solverChoice.moisture_type != MoistureType::None) {
153  Real qv_in = 0.;
154  if (input_bndry_planes && m_r2d->ingested_q1()) {
156  } else {
157  if (pp.query("qv", qv_in))
158  m_bc_extdir_vals[BCVars::RhoQ1_bc_comp][ori] = rho_in*qv_in;
159  }
160  Real qc_in = 0.;
161  if (input_bndry_planes && m_r2d->ingested_q2()) {
163  } else {
164  if (pp.query("qc", qc_in))
165  m_bc_extdir_vals[BCVars::RhoQ2_bc_comp][ori] = rho_in*qc_in;
166  }
167  }
168 
169  Real KE_in = 0.;
170  if (input_bndry_planes && m_r2d->ingested_KE()) {
172  } else {
173  if (pp.query("KE", KE_in))
174  m_bc_extdir_vals[BCVars::RhoKE_bc_comp][ori] = rho_in*KE_in;
175  }
176  }
177  else if (bc_type == "noslipwall")
178  {
179  // Print() << bcid <<" set to no-slip wall.\n";
181  domain_bc_type[ori] = "NoSlipWall";
182 
183  std::vector<Real> v;
184 
185  // The values of m_bc_extdir_vals default to 0.
186  // But if we find "velocity" in the inputs file, use those values instead.
187  if (pp.queryarr("velocity", v, 0, AMREX_SPACEDIM))
188  {
189  v[ori.coordDir()] = 0.0;
190  m_bc_extdir_vals[BCVars::xvel_bc][ori] = v[0];
191  m_bc_extdir_vals[BCVars::yvel_bc][ori] = v[1];
192  m_bc_extdir_vals[BCVars::zvel_bc][ori] = v[2];
193  }
194 
195  Real rho_in;
196  rho_read = pp.query("density", rho_in);
197  if (rho_read)
198  {
199  m_bc_extdir_vals[BCVars::Rho_bc_comp][ori] = rho_in;
200  }
201 
202  Real theta_in;
203  if (pp.query("theta", theta_in))
204  {
206  }
207 
208  Real theta_grad_in;
209  if (pp.query("theta_grad", theta_grad_in))
210  {
211  m_bc_neumann_vals[BCVars::RhoTheta_bc_comp][ori] = theta_grad_in;
212  }
213 
214  Real qv_in;
215  if (pp.query("qv", qv_in))
216  {
218  }
219  }
220  else if (bc_type == "slipwall")
221  {
222  // Print() << bcid <<" set to slip wall.\n";
223 
225  domain_bc_type[ori] = "SlipWall";
226 
227  Real rho_in;
228  rho_read = pp.query("density", rho_in);
229  if (rho_read)
230  {
231  m_bc_extdir_vals[BCVars::Rho_bc_comp][ori] = rho_in;
232  }
233 
234  Real theta_in;
235  if (pp.query("theta", theta_in))
236  {
238  }
239 
240  Real rho_grad_in;
241  if (pp.query("density_grad", rho_grad_in))
242  {
243  m_bc_neumann_vals[BCVars::Rho_bc_comp][ori] = rho_grad_in;
244  }
245 
246  Real theta_grad_in;
247  if (pp.query("theta_grad", theta_grad_in))
248  {
249  m_bc_neumann_vals[BCVars::RhoTheta_bc_comp][ori] = theta_grad_in;
250  }
251  }
252  else if (bc_type == "surface_layer")
253  {
255  domain_bc_type[ori] = "surface_layer";
256  }
257  else
258  {
260  }
261 
262  if (geom[0].isPeriodic(ori.coordDir())) {
263  domain_bc_type[ori] = "Periodic";
264  if (phys_bc_type[ori] == ERF_BC::undefined)
265  {
267  } else {
268  Abort("Wrong BC type for periodic boundary");
269  }
270  }
271 
272  if (phys_bc_type[ori] == ERF_BC::undefined)
273  {
274  Print() << "BC Type specified for face " << bcid << " is " << bc_type_in << std::endl;
275  Abort("This BC type is unknown");
276  }
277  };
278 
279  f("xlo", Orientation(Direction::x,Orientation::low));
280  f("xhi", Orientation(Direction::x,Orientation::high));
281  f("ylo", Orientation(Direction::y,Orientation::low));
282  f("yhi", Orientation(Direction::y,Orientation::high));
283  f("zlo", Orientation(Direction::z,Orientation::low));
284  f("zhi", Orientation(Direction::z,Orientation::high));
285 }
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:675
@ RhoQ6_bc_comp
Definition: ERF_IndexDefines.H:86
@ RhoQ4_bc_comp
Definition: ERF_IndexDefines.H:84
@ RhoQ3_bc_comp
Definition: ERF_IndexDefines.H:83
@ RhoQ5_bc_comp
Definition: ERF_IndexDefines.H:85
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(0.);
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(0.);
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  z_phys_cc[lev] = std::make_unique<MultiFab>(ba,dm,1,2);
57  init_default_zphys(lev, geom[lev], *tmp_zphys_nd, *z_phys_cc[lev]);
58 
59  if (solverChoice.terrain_type == TerrainType::MovingFittedMesh)
60  {
61  detJ_cc_new[lev] = std::make_unique<MultiFab>(ba,dm,1,1);
62  detJ_cc_src[lev] = std::make_unique<MultiFab>(ba,dm,1,1);
63 
64  ax_src[lev] = std::make_unique<MultiFab>(convert(ba,IntVect(1,0,0)),dm,1,1);
65  ay_src[lev] = std::make_unique<MultiFab>(convert(ba,IntVect(0,1,0)),dm,1,1);
66  az_src[lev] = std::make_unique<MultiFab>(convert(ba,IntVect(0,0,1)),dm,1,1);
67 
68  z_t_rk[lev] = std::make_unique<MultiFab>( convert(ba, IntVect(0,0,1)), dm, 1, 1 );
69 
70  z_phys_nd_new[lev] = std::make_unique<MultiFab>(ba_nd,dm,1,IntVect(ngrow,ngrow,ngrow));
71  z_phys_nd_src[lev] = std::make_unique<MultiFab>(ba_nd,dm,1,IntVect(ngrow,ngrow,ngrow));
72  z_phys_cc_src[lev] = std::make_unique<MultiFab>(ba,dm,1,1);
73  }
74  else
75  {
76  z_phys_nd_new[lev] = nullptr;
77  detJ_cc_new[lev] = nullptr;
78 
79  z_phys_nd_src[lev] = nullptr;
80  z_phys_cc_src[lev] = nullptr;
81  detJ_cc_src[lev] = nullptr;
82 
83  z_t_rk[lev] = nullptr;
84  }
85 
86  if (solverChoice.terrain_type == TerrainType::ImmersedForcing ||
87  solverChoice.buildings_type == BuildingsType::ImmersedForcing)
88  {
89  terrain_blanking[lev] = std::make_unique<MultiFab>(ba,dm,1,ngrow);
90  terrain_blanking[lev]->setVal(1.0);
91  }
92 
93  // We use these area arrays regardless of terrain, EB or none of the above
94  detJ_cc[lev] = std::make_unique<MultiFab>(ba,dm,1,1);
95  ax[lev] = std::make_unique<MultiFab>(convert(ba,IntVect(1,0,0)),dm,1,1);
96  ay[lev] = std::make_unique<MultiFab>(convert(ba,IntVect(0,1,0)),dm,1,1);
97  az[lev] = std::make_unique<MultiFab>(convert(ba,IntVect(0,0,1)),dm,1,1);
98 
99  detJ_cc[lev]->setVal(1.0);
100  ax[lev]->setVal(1.0);
101  ay[lev]->setVal(1.0);
102  az[lev]->setVal(1.0);
103 
104  // ********************************************************************************************
105  // Create wall distance array for RANS modeling
106  // ********************************************************************************************
107  if (solverChoice.turbChoice[lev].rans_type != RANSType::None) {
108  walldist[lev] = std::make_unique<MultiFab>(ba,dm,1,1);
109  walldist[lev]->setVal(1e23);
110  } else {
111  walldist[lev] = nullptr;
112  }
113 
114  // ********************************************************************************************
115  // These are the persistent containers for the old and new data
116  // ********************************************************************************************
117  int ncomp;
118  if (lev > 0) {
119  ncomp = vars_new[lev-1][Vars::cons].nComp();
120  } else {
121  int n_qstate = micro->Get_Qstate_Size();
122  ncomp = NDRY + NSCALARS + n_qstate;
123  }
124 
125  // ********************************************************************************************
126  // The number of ghost cells for density must be 1 greater than that for velocity
127  // so that we can go back in forth between velocity and momentum on all faces
128  // ********************************************************************************************
129  int ngrow_state = ComputeGhostCells(solverChoice) + 1;
130  int ngrow_vels = ComputeGhostCells(solverChoice);
131 
132  // ********************************************************************************************
133  // New solution data containers
134  // ********************************************************************************************
135  if (solverChoice.terrain_type != TerrainType::EB) {
136  lev_new[Vars::cons].define(ba, dm, ncomp, ngrow_state);
137  lev_old[Vars::cons].define(ba, dm, ncomp, ngrow_state);
138  } else {
139  // EB: Define the MultiFabs with the EBFactory
140  lev_new[Vars::cons].define(ba, dm, ncomp, ngrow_state, MFInfo(), EBFactory(lev));
141  lev_old[Vars::cons].define(ba, dm, ncomp, ngrow_state, MFInfo(), EBFactory(lev));
142  }
143 
144  // Initialize all components to zero so we don't need to explicitly set
145  // scalars / moisture variables to zero in the initialization
146  lev_new[Vars::cons].setVal(0.0);
147  lev_old[Vars::cons].setVal(0.0);
148 
149  lev_new[Vars::xvel].define(convert(ba, IntVect(1,0,0)), dm, 1, ngrow_vels);
150  lev_old[Vars::xvel].define(convert(ba, IntVect(1,0,0)), dm, 1, ngrow_vels);
151 
152  lev_new[Vars::yvel].define(convert(ba, IntVect(0,1,0)), dm, 1, ngrow_vels);
153  lev_old[Vars::yvel].define(convert(ba, IntVect(0,1,0)), dm, 1, ngrow_vels);
154 
155  // Set these to avoid operations on uninitialized data
156  lev_new[Vars::xvel].setVal(1.234e20);
157  lev_old[Vars::xvel].setVal(1.234e20);
158  lev_new[Vars::yvel].setVal(1.234e20);
159  lev_old[Vars::yvel].setVal(1.234e20);
160 
161  // Note that we need the ghost cells in the z-direction if we are doing any
162  // kind of domain decomposition in the vertical (at level 0 or above)
163  lev_new[Vars::zvel].define(convert(ba, IntVect(0,0,1)), dm, 1, ngrow_vels);
164  lev_old[Vars::zvel].define(convert(ba, IntVect(0,0,1)), dm, 1, ngrow_vels);
165 
166  gradp[lev][GpVars::gpx].define(convert(ba, IntVect(1,0,0)), dm, 1, 1); gradp[lev][GpVars::gpx].setVal(0.);
167  gradp[lev][GpVars::gpy].define(convert(ba, IntVect(0,1,0)), dm, 1, 1); gradp[lev][GpVars::gpy].setVal(0.);
168  gradp[lev][GpVars::gpz].define(convert(ba, IntVect(0,0,1)), dm, 1, 1); gradp[lev][GpVars::gpz].setVal(0.);
169 
170  if ( (solverChoice.anelastic[lev] == 1) || (solverChoice.project_initial_velocity[lev] == 1) ) {
171  pp_inc[lev].define(ba, dm, 1, 1);
172  pp_inc[lev].setVal(0.0);
173  }
174 
175  // We use this in the fast substepping only
176  if (solverChoice.anelastic[lev] == 0) {
177  lagged_delta_rt[lev].define(ba, dm, 1, 1);
178  lagged_delta_rt[lev].setVal(0.0);
179  }
180 
181  // We use these for advecting the slow variables, whether anelastic or compressible
182  avg_xmom[lev].define(convert(ba, IntVect(1,0,0)), dm, 1, 1);
183  avg_ymom[lev].define(convert(ba, IntVect(0,1,0)), dm, 1, 1);
184  avg_zmom[lev].define(convert(ba, IntVect(0,0,1)), dm, 1, 1);
185  avg_xmom[lev].setVal(0.0); avg_ymom[lev].setVal(0.0); avg_zmom[lev].setVal(0.0);
186 
187  // ********************************************************************************************
188  // These are just used for scratch in the time integrator but we might as well define them here
189  // ********************************************************************************************
190  if (solverChoice.terrain_type != TerrainType::EB) {
191  rU_old[lev].define(convert(ba, IntVect(1,0,0)), dm, 1, ngrow_vels);
192  rU_new[lev].define(convert(ba, IntVect(1,0,0)), dm, 1, ngrow_vels);
193 
194  rV_old[lev].define(convert(ba, IntVect(0,1,0)), dm, 1, ngrow_vels);
195  rV_new[lev].define(convert(ba, IntVect(0,1,0)), dm, 1, ngrow_vels);
196 
197  rW_old[lev].define(convert(ba, IntVect(0,0,1)), dm, 1, ngrow_vels);
198  rW_new[lev].define(convert(ba, IntVect(0,0,1)), dm, 1, ngrow_vels);
199  } else {
200  // EB: Define the MultiFabs with the EBFactory
201  rU_old[lev].define(convert(ba, IntVect(1,0,0)), dm, 1, ngrow_vels, MFInfo(), EBFactory(lev));
202  rU_new[lev].define(convert(ba, IntVect(1,0,0)), dm, 1, ngrow_vels, MFInfo(), EBFactory(lev));
203 
204  rV_old[lev].define(convert(ba, IntVect(0,1,0)), dm, 1, ngrow_vels, MFInfo(), EBFactory(lev));
205  rV_new[lev].define(convert(ba, IntVect(0,1,0)), dm, 1, ngrow_vels, MFInfo(), EBFactory(lev));
206 
207  rW_old[lev].define(convert(ba, IntVect(0,0,1)), dm, 1, ngrow_vels, MFInfo(), EBFactory(lev));
208  rW_new[lev].define(convert(ba, IntVect(0,0,1)), dm, 1, ngrow_vels, MFInfo(), EBFactory(lev));
209  }
210 
211  if (lev > 0) {
212  //xmom_crse_rhs[lev].define(convert(ba, IntVect(1,0,0)), dm, 1, IntVect{0});
213  //ymom_crse_rhs[lev].define(convert(ba, IntVect(0,1,0)), dm, 1, IntVect{0});
214  zmom_crse_rhs[lev].define(convert(ba, IntVect(0,0,1)), dm, 1, IntVect{0});
215  }
216 
217  // We do this here just so they won't be undefined in the initial FillPatch
218  rU_old[lev].setVal(1.2e21);
219  rV_old[lev].setVal(3.4e22);
220  rW_old[lev].setVal(5.6e23);
221  rU_new[lev].setVal(1.2e21);
222  rV_new[lev].setVal(3.4e22);
223  rW_new[lev].setVal(5.6e23);
224 
225  // ********************************************************************************************
226  // These are just time averaged fields for diagnostics
227  // ********************************************************************************************
228 
229  // NOTE: We are not completing a fillpatch call on the time averaged data;
230  // which would copy on intersection and interpolate from coarse.
231  // Therefore, we are restarting the averaging when the ba changes,
232  // this may give poor statistics for dynamic mesh refinement.
233  vel_t_avg[lev] = nullptr;
235  vel_t_avg[lev] = std::make_unique<MultiFab>(ba, dm, 4, 0); // Each vel comp and the mag
236  vel_t_avg[lev]->setVal(0.0);
237  t_avg_cnt[lev] = 0.0;
238  }
239 
240  // ********************************************************************************************
241  // Initialize flux registers whenever we create/re-create a level
242  // ********************************************************************************************
243  if (solverChoice.coupling_type == CouplingType::TwoWay) {
244  if (lev == 0) {
245  advflux_reg[0] = nullptr;
246  } else {
247  int ncomp_reflux = vars_new[0][Vars::cons].nComp();
248  advflux_reg[lev] = new YAFluxRegister(ba , grids[lev-1],
249  dm , dmap[lev-1],
250  geom[lev], geom[lev-1],
251  ref_ratio[lev-1], lev, ncomp_reflux);
252  }
253  }
254 
255  // ********************************************************************************************
256  // Define Theta_prim storage if using surface_layer BC
257  // ********************************************************************************************
258  if (phys_bc_type[Orientation(Direction::z,Orientation::low)] == ERF_BC::surface_layer) {
259  Theta_prim[lev] = std::make_unique<MultiFab>(ba,dm,1,IntVect(ngrow_state,ngrow_state,1));
260  if (solverChoice.moisture_type != MoistureType::None) {
261  Qv_prim[lev] = std::make_unique<MultiFab>(ba,dm,1,IntVect(ngrow_state,ngrow_state,1));
262  Qr_prim[lev] = std::make_unique<MultiFab>(ba,dm,1,IntVect(ngrow_state,ngrow_state,1));
263  } else {
264  Qv_prim[lev] = nullptr;
265  Qr_prim[lev] = nullptr;
266  }
267  } else {
268  Theta_prim[lev] = nullptr;
269  Qv_prim[lev] = nullptr;
270  Qr_prim[lev] = nullptr;
271  }
272 
273  // ********************************************************************************************
274  // Build 1D BA and 2D BA
275  // ********************************************************************************************
276 
277  // NOTE: By design, the compressed BAs have their compressed indices set to 0
278  // MFIters that need more detailed box information should be done over 3D MFs
279 
280  // Build 2D BA
281  BoxList bl2d = ba.boxList();
282  for (auto& b : bl2d) {
283  b.setRange(2,0);
284  }
285  ba2d[lev] = BoxArray(std::move(bl2d));
286 
287  // Build 1D BA
288  BoxList bl1d = ba.boxList();
289  for (auto& b : bl1d) {
290  b.setRange(0,0);
291  b.setRange(1,0);
292  }
293  ba1d[lev] = BoxArray(std::move(bl1d));
294 
295  // ********************************************************************************************
296  // Map factors
297  // ********************************************************************************************
298  mapfac[lev].resize(MapFacType::num);
299  mapfac[lev][MapFacType::m_x] = std::make_unique<MultiFab>( ba2d[lev],dm,1,IntVect(3,3,0));
300  mapfac[lev][MapFacType::u_x] = std::make_unique<MultiFab>(convert(ba2d[lev],IntVect(1,0,0)),dm,1,IntVect(3,3,0));
301  mapfac[lev][MapFacType::v_x] = std::make_unique<MultiFab>(convert(ba2d[lev],IntVect(0,1,0)),dm,1,IntVect(3,3,0));
302 
303 #if 0
304  // For now we comment this out to avoid CI failures but we will need to re-enable
305  // this if using non-conformal mappings
307  mapfac[lev][MapFacType::m_y] = std::make_unique<MultiFab>(ba2d[lev],dm,1,IntVect(3,3,0));
308  }
310  mapfac[lev][MapFacType::u_y] = std::make_unique<MultiFab>(convert(ba2d[lev],IntVect(1,0,0)),dm,1,IntVect(3,3,0));
311  }
313  mapfac[lev][MapFacType::v_y] = std::make_unique<MultiFab>(convert(ba2d[lev],IntVect(0,1,0)),dm,1,IntVect(3,3,0));
314  }
315 #endif
316 
318  for (int i = 0; i < 3; i++) {
319  mapfac[lev][i]->setVal(0.5);
320  }
321  for (int i = 3; i < mapfac[lev].size(); i++) {
322  mapfac[lev][i]->setVal(0.25);
323  }
324  } else {
325  for (int i = 0; i < mapfac[lev].size(); i++) {
326  mapfac[lev][i]->setVal(1.0);
327  }
328  }
329 
330  // ********************************************************************************************
331  // Build WRF data structures
332  // ********************************************************************************************
333  IntVect ng = vars_new[lev][Vars::cons].nGrowVect();
334 
335  if (lev == 0) {
336  mf_C1H = std::make_unique<MultiFab>(ba1d[lev],dm,1,IntVect(ng[0],ng[1],ng[2]));
337  mf_C2H = std::make_unique<MultiFab>(ba1d[lev],dm,1,IntVect(ng[0],ng[1],ng[2]));
338  mf_MUB = std::make_unique<MultiFab>(ba2d[lev],dm,1,IntVect(ng[0],ng[1],ng[2]));
339  }
340 
341  mf_PSFC[lev] = std::make_unique<MultiFab>(ba2d[lev],dm,1,ng);
342 
343  //*********************************************************
344  // Variables for Fitch model for windfarm parametrization
345  //*********************************************************
346 #if defined(ERF_USE_WINDFARM)
347  if (solverChoice.windfarm_type == WindFarmType::Fitch){
348  vars_windfarm[lev].define(ba, dm, 5, ngrow_state); // V, dVabsdt, dudt, dvdt, dTKEdt
349  }
350  if (solverChoice.windfarm_type == WindFarmType::EWP){
351  vars_windfarm[lev].define(ba, dm, 3, ngrow_state); // dudt, dvdt, dTKEdt
352  }
353  if (solverChoice.windfarm_type == WindFarmType::SimpleAD) {
354  vars_windfarm[lev].define(ba, dm, 2, ngrow_state);// dudt, dvdt
355  }
356  if (solverChoice.windfarm_type == WindFarmType::GeneralAD) {
357  vars_windfarm[lev].define(ba, dm, 3, ngrow_state);// dudt, dvdt, dwdt
358  }
359  Nturb[lev].define(ba, dm, 1, ngrow_state); // Number of turbines in a cell
360  SMark[lev].define(ba, dm, 2, 1); // Free stream velocity/source term
361  // sampling marker in a cell - 2 components
362 #endif
363 
364  if(solverChoice.init_type == InitType::HindCast and
366 
367  int ncomp_extra = 2;
368  int nvars = vars_new[lev].size();
369 
370  // Resize all containers
371  forecast_state_1[lev].resize(nvars + 1);
372  forecast_state_2[lev].resize(nvars + 1);
373  forecast_state_interp[lev].resize(nvars + 1);
374 
375  // Define the "normal" components
376  for (int comp = 0; comp < nvars; ++comp) {
377  const MultiFab& src = vars_new[lev][comp];
378  ncomp = src.nComp();
379  ngrow = src.nGrow();
380 
381  forecast_state_1[lev][comp].define(ba, dm, ncomp, ng);
382  forecast_state_2[lev][comp].define(ba, dm, ncomp, ng);
383  forecast_state_interp[lev][comp].define(ba, dm, ncomp, ng);
384  }
385 
386  // Define the "extra" component (last slot)
387  {
388  const MultiFab& src0 = vars_new[lev][0];
389  ngrow = src0.nGrow();
390  int idx = nvars;
391 
392  forecast_state_1[lev][idx].define(ba, dm, ncomp_extra, ngrow);
393  forecast_state_2[lev][idx].define(ba, dm, ncomp_extra, ngrow);
394  forecast_state_interp[lev][idx].define(ba, dm, ncomp_extra, ngrow);
395  }
396  bool regrid_forces_file_read = true;
397  WeatherDataInterpolation(lev, t_new[0],z_phys_nd, regrid_forces_file_read);
398  }
399 
400 
401  if(solverChoice.init_type == InitType::HindCast and
403 
404  {
405  const MultiFab& src = vars_new[lev][0];
406  const amrex::DistributionMapping& dm_hc = src.DistributionMap();
407 
408  surface_state_1[lev].define(ba2d[lev], dm_hc, 2, src.nGrow());
409  surface_state_2[lev].define(ba2d[lev], dm_hc, 2, src.nGrow());
410  surface_state_interp[lev].define(ba2d[lev], dm_hc, 2, src.nGrow());
411 
412  bool regrid_forces_file_read = true;
413  SurfaceDataInterpolation(lev, t_new[0], z_phys_nd, regrid_forces_file_read);
414  }
415 
416 #ifdef ERF_USE_WW3_COUPLING
417  // create a new BoxArray and DistributionMapping for a MultiFab with 1 box
418  BoxArray ba_onegrid(geom[lev].Domain());
419  BoxList bl2d_onegrid = ba_onegrid.boxList();
420  for (auto& b : bl2d_onegrid) { b.setRange(2,b.smallEnd(2)); }
421  BoxArray ba2d_onegrid(std::move(bl2d_onegrid));
422  Vector<int> pmap;
423  pmap.resize(1);
424  pmap[0]=0;
425  DistributionMapping dm_onegrid(ba2d_onegrid);
426  dm_onegrid.define(pmap);
427 
428  Hwave_onegrid[lev] = std::make_unique<MultiFab>(ba2d_onegrid,dm_onegrid,1,IntVect(1,1,0));
429  Lwave_onegrid[lev] = std::make_unique<MultiFab>(ba2d_onegrid,dm_onegrid,1,IntVect(1,1,0));
430 
431  BoxList bl2d_wave = ba.boxList();
432  for (auto& b : bl2d_wave) { b.setRange(2,b.smallEnd(2)); }
433  BoxArray ba2d_wave(std::move(bl2d_wave));
434 
435  Hwave[lev] = std::make_unique<MultiFab>(ba2d_wave,dm,1,IntVect(3,3,0));
436  Lwave[lev] = std::make_unique<MultiFab>(ba2d_wave,dm,1,IntVect(3,3,0));
437 
438  std::cout<<ba_onegrid<<std::endl;
439  std::cout<<ba2d_onegrid<<std::endl;
440  std::cout<<dm_onegrid<<std::endl;
441 #endif
442 
443 
444  //*********************************************************
445  // Radiation heating source terms
446  //*********************************************************
447  if (solverChoice.rad_type != RadiationType::None)
448  {
449  qheating_rates[lev] = std::make_unique<MultiFab>(ba, dm, 2, 0);
450  rad_fluxes[lev] = std::make_unique<MultiFab>(ba, dm, 4, 0);
451  qheating_rates[lev]->setVal(0.);
452  rad_fluxes[lev]->setVal(0.);
453  }
454 
455  //*********************************************************
456  // Turbulent perturbation region initialization
457  //*********************************************************
458  if (solverChoice.pert_type == PerturbationType::Source ||
459  solverChoice.pert_type == PerturbationType::Direct ||
460  solverChoice.pert_type == PerturbationType::CPM)
461  {
462  amrex::Box bnd_bx = ba.minimalBox();
464  turbPert.init_tpi(lev, bnd_bx.smallEnd(), bnd_bx.bigEnd(), geom[lev].CellSizeArray(),
465  ba, dm, ngrow_state, pp_prefix, refRatio(), max_level);
466  }
467 
468  //
469  // Define the land mask here and set it to all land by default
470  // NOTE: the logic below will BREAK if we have any grids not touching the bottom boundary
471  //
472  {
473  lmask_lev[lev].resize(1);
474  auto ngv = lev_new[Vars::cons].nGrowVect(); ngv[2] = 0;
475  lmask_lev[lev][0] = std::make_unique<iMultiFab>(ba2d[lev],dm,1,ngv);
476  lmask_lev[lev][0]->setVal(1);
477  lmask_lev[lev][0]->FillBoundary(geom[lev].periodicity());
478 
479  land_type_lev[lev].resize(1);
480  land_type_lev[lev][0] = std::make_unique<iMultiFab>(ba2d[lev],dm,1,ngv);
481  land_type_lev[lev][0]->setVal(0);
482  land_type_lev[lev][0]->FillBoundary(geom[lev].periodicity());
483 
484  soil_type_lev[lev].resize(1);
485  soil_type_lev[lev][0] = std::make_unique<iMultiFab>(ba2d[lev],dm,1,ngv);
486  soil_type_lev[lev][0]->setVal(0);
487  soil_type_lev[lev][0]->FillBoundary(geom[lev].periodicity());
488 
489  urb_frac_lev[lev].resize(1);
490  urb_frac_lev[lev][0] = std::make_unique<MultiFab>(ba2d[lev],dm,1,ngv);
491  urb_frac_lev[lev][0]->setVal(1.0);
492  urb_frac_lev[lev][0]->FillBoundary(geom[lev].periodicity());
493  }
494 
495  // Read in tables needed for windfarm simulations
496  // fill in Nturb multifab - number of turbines in each mesh cell
497  // write out the vtk files for wind turbine location and/or
498  // actuator disks
499  #ifdef ERF_USE_WINDFARM
500  //init_windfarm(lev);
501  #endif
502 
503  if (lev > 0) {
504  fine_mask[lev] = std::make_unique<MultiFab>(grids[lev-1], dmap[lev-1], 1, 0);
505  build_fine_mask(lev, *fine_mask[lev].get());
506  }
507 }
@ 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)
Definition: ERF_TerrainMetrics.cpp:15
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:1354
amrex::EBFArrayBoxFactory const & EBFactory(int lev) const noexcept
Definition: ERF.H:1633
@ num_comps
Definition: ERF_IndexDefines.H:68
@ gpz
Definition: ERF_IndexDefines.H:168
@ gpy
Definition: ERF_IndexDefines.H:167
@ gpx
Definition: ERF_IndexDefines.H:166
bool test_mapfactor
Definition: ERF_DataStruct.H:1112
void init_tpi_type(const PerturbationType &pert_type)
Definition: ERF_TurbPertStruct.H:28
void init_tpi(const int lev, const amrex::IntVect &valid_box_lo, const amrex::IntVect &valid_box_hi, 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:45
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 
)
890 {
891  //********************************************************************************************
892  // Thin immersed body
893  // *******************************************************************************************
894 #if 0
895  if ((solverChoice.advChoice.zero_xflux.size() > 0) ||
896  (solverChoice.advChoice.zero_yflux.size() > 0) ||
897  (solverChoice.advChoice.zero_zflux.size() > 0))
898  {
899  overset_imask[lev] = std::make_unique<iMultiFab>(ba,dm,1,0);
900  overset_imask[lev]->setVal(1); // == value is unknown (to be solved)
901  }
902 #endif
903 
904  if (solverChoice.advChoice.zero_xflux.size() > 0) {
905  amrex::Print() << "Setting up thin immersed body for "
906  << solverChoice.advChoice.zero_xflux.size() << " xfaces" << std::endl;
907  BoxArray ba_xf(ba);
908  ba_xf.surroundingNodes(0);
909  thin_xforce[lev] = std::make_unique<MultiFab>(ba_xf,dm,1,0);
910  thin_xforce[lev]->setVal(0.0);
911  xflux_imask[lev] = std::make_unique<iMultiFab>(ba_xf,dm,1,0);
912  xflux_imask[lev]->setVal(1);
913  for ( MFIter mfi(*xflux_imask[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi )
914  {
915  Array4<int> const& imask_arr = xflux_imask[lev]->array(mfi);
916  //Array4<int> const& imask_cell_arr = overset_imask[lev]->array(mfi);
917  Box xbx = mfi.nodaltilebox(0);
918  for (int iv=0; iv < solverChoice.advChoice.zero_xflux.size(); ++iv) {
919  const auto& faceidx = solverChoice.advChoice.zero_xflux[iv];
920  if ((faceidx[0] >= xbx.smallEnd(0)) && (faceidx[0] <= xbx.bigEnd(0)) &&
921  (faceidx[1] >= xbx.smallEnd(1)) && (faceidx[1] <= xbx.bigEnd(1)) &&
922  (faceidx[2] >= xbx.smallEnd(2)) && (faceidx[2] <= xbx.bigEnd(2)))
923  {
924  imask_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
925  //imask_cell_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
926  //imask_cell_arr(faceidx[0]-1,faceidx[1],faceidx[2]) = 0;
927  amrex::AllPrint() << " mask xface at " << faceidx << std::endl;
928  }
929  }
930  }
931  } else {
932  thin_xforce[lev] = nullptr;
933  xflux_imask[lev] = nullptr;
934  }
935 
936  if (solverChoice.advChoice.zero_yflux.size() > 0) {
937  amrex::Print() << "Setting up thin immersed body for "
938  << solverChoice.advChoice.zero_yflux.size() << " yfaces" << std::endl;
939  BoxArray ba_yf(ba);
940  ba_yf.surroundingNodes(1);
941  thin_yforce[lev] = std::make_unique<MultiFab>(ba_yf,dm,1,0);
942  thin_yforce[lev]->setVal(0.0);
943  yflux_imask[lev] = std::make_unique<iMultiFab>(ba_yf,dm,1,0);
944  yflux_imask[lev]->setVal(1);
945  for ( MFIter mfi(*yflux_imask[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi )
946  {
947  Array4<int> const& imask_arr = yflux_imask[lev]->array(mfi);
948  //Array4<int> const& imask_cell_arr = overset_imask[lev]->array(mfi);
949  Box ybx = mfi.nodaltilebox(1);
950  for (int iv=0; iv < solverChoice.advChoice.zero_yflux.size(); ++iv) {
951  const auto& faceidx = solverChoice.advChoice.zero_yflux[iv];
952  if ((faceidx[0] >= ybx.smallEnd(0)) && (faceidx[0] <= ybx.bigEnd(0)) &&
953  (faceidx[1] >= ybx.smallEnd(1)) && (faceidx[1] <= ybx.bigEnd(1)) &&
954  (faceidx[2] >= ybx.smallEnd(2)) && (faceidx[2] <= ybx.bigEnd(2)))
955  {
956  imask_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
957  //imask_cell_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
958  //imask_cell_arr(faceidx[0],faceidx[1]-1,faceidx[2]) = 0;
959  amrex::AllPrint() << " mask yface at " << faceidx << std::endl;
960  }
961  }
962  }
963  } else {
964  thin_yforce[lev] = nullptr;
965  yflux_imask[lev] = nullptr;
966  }
967 
968  if (solverChoice.advChoice.zero_zflux.size() > 0) {
969  amrex::Print() << "Setting up thin immersed body for "
970  << solverChoice.advChoice.zero_zflux.size() << " zfaces" << std::endl;
971  BoxArray ba_zf(ba);
972  ba_zf.surroundingNodes(2);
973  thin_zforce[lev] = std::make_unique<MultiFab>(ba_zf,dm,1,0);
974  thin_zforce[lev]->setVal(0.0);
975  zflux_imask[lev] = std::make_unique<iMultiFab>(ba_zf,dm,1,0);
976  zflux_imask[lev]->setVal(1);
977  for ( MFIter mfi(*zflux_imask[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi )
978  {
979  Array4<int> const& imask_arr = zflux_imask[lev]->array(mfi);
980  //Array4<int> const& imask_cell_arr = overset_imask[lev]->array(mfi);
981  Box zbx = mfi.nodaltilebox(2);
982  for (int iv=0; iv < solverChoice.advChoice.zero_zflux.size(); ++iv) {
983  const auto& faceidx = solverChoice.advChoice.zero_zflux[iv];
984  if ((faceidx[0] >= zbx.smallEnd(0)) && (faceidx[0] <= zbx.bigEnd(0)) &&
985  (faceidx[1] >= zbx.smallEnd(1)) && (faceidx[1] <= zbx.bigEnd(1)) &&
986  (faceidx[2] >= zbx.smallEnd(2)) && (faceidx[2] <= zbx.bigEnd(2)))
987  {
988  imask_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
989  //imask_cell_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
990  //imask_cell_arr(faceidx[0],faceidx[1],faceidx[2]-1) = 0;
991  amrex::AllPrint() << " mask zface at " << faceidx << std::endl;
992  }
993  }
994  }
995  } else {
996  thin_zforce[lev] = nullptr;
997  zflux_imask[lev] = nullptr;
998  }
999 }
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 
)
636 {
637  if (solverChoice.init_type != InitType::WRFInput && solverChoice.init_type != InitType::Metgrid)
638  {
639  if (lev > 0) {
640  //
641  // First interpolate from coarser level if there is one
642  // NOTE: this interpolater assumes that ALL ghost cells of the coarse MultiFab
643  // have been pre-filled - this includes ghost cells both inside and outside
644  // the domain
645  //
646  InterpFromCoarseLevel(*z_phys_nd[lev], z_phys_nd[lev]->nGrowVect(),
647  IntVect(0,0,0), // do NOT fill ghost cells outside the domain
648  *z_phys_nd[lev-1], 0, 0, 1,
649  geom[lev-1], geom[lev],
650  refRatio(lev-1), &node_bilinear_interp,
652  }
653 
654  int ngrow = ComputeGhostCells(solverChoice) + 2;
655  Box bx(surroundingNodes(Geom(lev).Domain())); bx.grow(ngrow);
656  FArrayBox terrain_fab(makeSlab(bx,2,0),1);
657 
658  //
659  // If we are using fitted mesh then we use the surface as defined above
660  // If we are not using fitted mesh but are using z_levels, we still need z_phys (for now)
661  // but we need to use a flat terrain for the mesh itself (the EB data has already been made
662  // from the correct terrain)
663  //
664  if (solverChoice.terrain_type != TerrainType::StaticFittedMesh &&
665  solverChoice.terrain_type != TerrainType::MovingFittedMesh) {
666  terrain_fab.template setVal<RunOn::Device>(0.0);
667  } else {
668  //
669  // Fill the values of the terrain height at k=0 only
670  //
671  prob->init_terrain_surface(geom[lev],terrain_fab,elapsed_time);
672  }
673 
674  for (MFIter mfi(*z_phys_nd[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
675  {
676  Box isect = terrain_fab.box() & (*z_phys_nd[lev])[mfi].box();
677  if (!isect.isEmpty()) {
678  (*z_phys_nd[lev])[mfi].template copy<RunOn::Device>(terrain_fab,isect,0,isect,0,1);
679  }
680  }
681 
683 
684  z_phys_nd[lev]->FillBoundary(geom[lev].periodicity());
685 
686  if (lev == 0) {
687  Real zmax = z_phys_nd[0]->max(0,0,false);
688  Real rel_diff = (zmax - zlevels_stag[0][zlevels_stag[0].size()-1]) / zmax;
689  if (rel_diff < 1.e-8) {
690  amrex::Print() << "max of zphys_nd " << zmax << std::endl;
691  amrex::Print() << "max of zlevels " << zlevels_stag[0][zlevels_stag[0].size()-1] << std::endl;
692  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(rel_diff < 1.e-8, "Terrain is taller than domain top!");
693  }
694  } // lev == 0
695 
696  } else {
697  // NOTE: If a WRFInput file is NOT provided for a finer level,
698  // we simply interpolate from the coarse. This is necessary
699  // since we average_down the terrain (ERF_MakeNewLevel.cpp L351).
700  // If a WRFInput file IS present, it overwrites the terrain data.
701  if (lev > 0) {
702  //
703  // First interpolate from coarser level if there is one
704  // NOTE: this interpolater assumes that ALL ghost cells of the coarse MultiFab
705  // have been pre-filled - this includes ghost cells both inside and outside
706  // the domain
707  //
708  InterpFromCoarseLevel(*z_phys_nd[lev], z_phys_nd[lev]->nGrowVect(),
709  z_phys_nd[lev]->nGrowVect(), // DO fill ghost cells outside the domain
710  *z_phys_nd[lev-1], 0, 0, 1,
711  geom[lev-1], geom[lev],
712  refRatio(lev-1), &node_bilinear_interp,
714  }
715  } // init_type
716 
717  if (solverChoice.terrain_type == TerrainType::ImmersedForcing ||
718  solverChoice.buildings_type == BuildingsType::ImmersedForcing) {
719  terrain_blanking[lev]->setVal(1.0);
720  MultiFab::Subtract(*terrain_blanking[lev], EBFactory(lev).getVolFrac(), 0, 0, 1, ComputeGhostCells(solverChoice) + 2);
721  terrain_blanking[lev]->FillBoundary(geom[lev].periodicity());
722  init_immersed_forcing(lev); // needed for real cases
723  }
724 
725  // Compute the min dz and pass to the micro model
726  Real dzmin = get_dzmin_terrain(*z_phys_nd[lev]);
727  micro->Set_dzmin(lev, dzmin);
728 }
Real get_dzmin_terrain(MultiFab &z_phys_nd)
Definition: ERF_TerrainMetrics.cpp:652
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:46
Here is the call graph for this function:

◆ InitData()

void ERF::InitData ( )
979 {
980  BL_PROFILE_VAR("ERF::InitData()", InitData);
981  InitData_pre();
982  InitData_post();
983  BL_PROFILE_VAR_STOP(InitData);
984 }
void InitData_pre()
Definition: ERF.cpp:987
void InitData_post()
Definition: ERF.cpp:1011
void InitData()
Definition: ERF.cpp:978

Referenced by main().

Here is the caller graph for this function:

◆ InitData_post()

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

◆ InitData_pre()

void ERF::InitData_pre ( )
988 {
989  // Initialize the start time for our CPU-time tracker
990  startCPUTime = ParallelDescriptor::second();
991 
992  // Create the ReadBndryPlanes object so we can read boundary plane data
993  // m_r2d is used by init_bcs so we must instantiate this class before
994  if (input_bndry_planes) {
995  Print() << "Defining r2d for the first time " << std::endl;
996  m_r2d = std::make_unique<ReadBndryPlanes>(geom[0], solverChoice.rdOcp);
997  }
998 
999  if (restart_chkfile.empty()) {
1000  // Start simulation from the beginning
1001  InitFromScratch(0.0);
1002  } else {
1003  // For initialization this is done in init_only; it is done here for restart
1004  init_bcs();
1005  }
1006 
1007  solverChoice.check_params(max_level,geom,phys_bc_type);
1008 }
void init_bcs()
Definition: ERF_InitBCs.cpp:287
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:767

◆ initHSE() [1/2]

void ERF::initHSE ( )
private

Initialize HSE.

187 {
188  for (int lev = 0; lev <= finest_level; lev++)
189  {
190  initHSE(lev);
191  }
192 }

◆ 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  if (all_boxes_touch_bottom || lev > 0) {
69 
70  // Initial r_hse may or may not be in HSE -- defined in ERF_Prob.cpp
71  if ( (solverChoice.init_type == InitType::MoistBaseState) ||
72  (solverChoice.init_type == InitType::HindCast) )
73  {
74  prob->erf_init_dens_hse_moist(r_hse, z_phys_nd[lev], geom[lev]);
75 
76  }
77  else if (solverChoice.init_type == InitType::ConstantDensity)
78  {
79  // In this case we set rho from user-specified values, then integrate
80  // to define p from HSE (even if gravity = 0), then compute theta from (p,rho)
81  prob->erf_init_const_dens_hse(r_hse);
82  }
83  else if (solverChoice.init_type == InitType::Uniform)
84  {
85  // In this case we set both rho and theta from user-specified values
87  prob->erf_init_const_dens_and_th_hse(r_hse,p_hse,pi_hse,th_hse,qv_hse,solverChoice.rdOcp);
88  }
89  else if (solverChoice.init_type == InitType::ConstantDensityLinearTheta)
90  {
91  // In this case we set both rho and theta from user-specified values
93  prob->erf_init_const_dens_and_linear_th_hse(r_hse,p_hse,pi_hse,th_hse,qv_hse,
95  }
96  else
97  {
98  // In this case we set rho from user-specified values, then integrate
99  // to define p from HSE (even if gravity = 0), then compute theta from (p,rho)
100  prob->erf_init_dens_hse(r_hse, z_phys_nd[lev], z_phys_cc[lev], geom[lev]);
101  }
102 
103  if (solverChoice.init_type != InitType::Uniform && solverChoice.init_type !=InitType::ConstantDensityLinearTheta) {
104  erf_enforce_hse(lev, r_hse, p_hse, pi_hse, th_hse, qv_hse, z_phys_cc[lev]);
105  }
106 
107  //
108  // Impose physical bc's on the base state
109  //
110  (*physbcs_base[lev])(base_state[lev],0,base_state[lev].nComp(),base_state[lev].nGrowVect());
111 
112  } else {
113 
114  BoxArray ba_new(domain);
115 
116  ChopGrids2D(ba_new, domain, ParallelDescriptor::NProcs());
117 
118  DistributionMapping dm_new(ba_new);
119 
120  MultiFab new_base_state(ba_new, dm_new, BaseState::num_comps, base_state[lev].nGrowVect());
121  new_base_state.ParallelCopy(base_state[lev],0,0,base_state[lev].nComp(),
122  base_state[lev].nGrowVect(),base_state[lev].nGrowVect());
123 
124  MultiFab new_r_hse (new_base_state, make_alias, BaseState::r0_comp, 1);
125  MultiFab new_p_hse (new_base_state, make_alias, BaseState::p0_comp, 1);
126  MultiFab new_pi_hse(new_base_state, make_alias, BaseState::pi0_comp, 1);
127  MultiFab new_th_hse(new_base_state, make_alias, BaseState::th0_comp, 1);
128  MultiFab new_qv_hse(new_base_state, make_alias, BaseState::qv0_comp, 1);
129 
130  std::unique_ptr<MultiFab> new_z_phys_cc;
131  std::unique_ptr<MultiFab> new_z_phys_nd;
132  if (solverChoice.mesh_type != MeshType::ConstantDz) {
133  new_z_phys_cc = std::make_unique<MultiFab>(ba_new,dm_new,1,1);
134  new_z_phys_cc->ParallelCopy(*z_phys_cc[lev],0,0,1,1,1);
135 
136  BoxArray ba_new_nd(ba_new);
137  ba_new_nd.surroundingNodes();
138  new_z_phys_nd = std::make_unique<MultiFab>(ba_new_nd,dm_new,1,1);
139  new_z_phys_nd->ParallelCopy(*z_phys_nd[lev],0,0,1,1,1);
140  }
141 
142  // Initial r_hse may or may not be in HSE -- defined in ERF_Prob.cpp
143  if (solverChoice.init_type == InitType::MoistBaseState) {
144  prob->erf_init_dens_hse_moist(new_r_hse, new_z_phys_nd, geom[lev]);
145 
146  } else if (solverChoice.init_type == InitType::ConstantDensity) {
147 
148  // In this case we set rho from user-specified values, then integrate
149  // to define p from HSE (even if gravity = 0), then compute theta from (p,rho)
150  prob->erf_init_const_dens_hse(new_r_hse);
151 
152  } else if (solverChoice.init_type == InitType::Uniform) {
153 
154  // In this case we set both rho and theta from user-specified values
156  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);
157 
158  } else {
159  prob->erf_init_dens_hse(new_r_hse, new_z_phys_nd, new_z_phys_cc, geom[lev]);
160  }
161 
162  erf_enforce_hse(lev, new_r_hse, new_p_hse, new_pi_hse, new_th_hse, new_qv_hse, new_z_phys_cc);
163 
164  //
165  // Impose physical bc's on the base state (we must make new, temporary bcs object because the z_phys_nd is different)
166  //
167  ERFPhysBCFunct_base* temp_physbcs_base =
168  new ERFPhysBCFunct_base(lev, geom[lev], domain_bcs_type, domain_bcs_type_d, new_z_phys_nd,
169  (solverChoice.terrain_type == TerrainType::MovingFittedMesh));
170  (*temp_physbcs_base)(new_base_state,0,new_base_state.nComp(),new_base_state.nGrowVect());
171  delete temp_physbcs_base;
172 
173  // Now copy back into the original arrays
174  base_state[lev].ParallelCopy(new_base_state,0,0,base_state[lev].nComp(),
175  base_state[lev].nGrowVect(),base_state[lev].nGrowVect());
176  }
177 
178  //
179  // Impose physical bc's on the base state -- the values outside the fine region
180  // but inside the domain have already been filled in the call above to InterpFromCoarseLevel
181  //
182  (*physbcs_base[lev])(base_state[lev],0,base_state[lev].nComp(),base_state[lev].nGrowVect());
183 }
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:204
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
809 {
810  const BoxArray& ba(cons_mf.boxArray());
811  const DistributionMapping& dm(cons_mf.DistributionMap());
812 
813  int ncomp_cons = cons_mf.nComp();
814 
815  // Initialize the integrator memory
816  Vector<MultiFab> int_state; // integration state data structure example
817  int_state.push_back(MultiFab(cons_mf, make_alias, 0, ncomp_cons)); // cons
818  int_state.push_back(MultiFab(convert(ba,IntVect(1,0,0)), dm, 1, vel_mf.nGrow())); // xmom
819  int_state.push_back(MultiFab(convert(ba,IntVect(0,1,0)), dm, 1, vel_mf.nGrow())); // ymom
820  int_state.push_back(MultiFab(convert(ba,IntVect(0,0,1)), dm, 1, vel_mf.nGrow())); // zmom
821 
822  mri_integrator_mem[lev] = std::make_unique<MRISplitIntegrator<Vector<MultiFab> > >(int_state);
823  mri_integrator_mem[lev]->setNoSubstepping((solverChoice.substepping_type[lev] == SubsteppingType::None));
824  mri_integrator_mem[lev]->setAnelastic(solverChoice.anelastic[lev]);
825  mri_integrator_mem[lev]->setNcompCons(ncomp_cons);
826  mri_integrator_mem[lev]->setForceFirstStageSingleSubstep(solverChoice.force_stage1_single_substep);
827 }

◆ 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
2069 {
2070  if (Microphysics::modelType(solverChoice.moisture_type) == MoistureModelType::Eulerian) {
2071 
2072  micro = std::make_unique<EulerianMicrophysics>(a_nlevsmax, solverChoice.moisture_type);
2073 
2074  } else if (Microphysics::modelType(solverChoice.moisture_type) == MoistureModelType::Lagrangian) {
2075 #ifdef ERF_USE_PARTICLES
2076  micro = std::make_unique<LagrangianMicrophysics>(a_nlevsmax, solverChoice.moisture_type);
2077  /* Lagrangian microphysics models will have a particle container; it needs to be added
2078  to ERF::particleData */
2079  const auto& pc_name( dynamic_cast<LagrangianMicrophysics&>(*micro).getName() );
2080  /* The particle container has not yet been constructed and initialized, so just add
2081  its name here for now (so that functions to set plotting variables can see it). */
2082  particleData.addName( pc_name );
2083 
2084 #else
2085  Abort("Lagrangian microphysics can be used when compiled with ERF_USE_PARTICLES");
2086 #endif
2087  }
2088 
2089  qmoist.resize(a_nlevsmax);
2090  return;
2091 }
amrex::Vector< amrex::Vector< amrex::MultiFab * > > qmoist
Definition: ERF.H:864
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 = 0.5 * (zlevels_stag[lev][k] + zlevels_stag[lev][k+1]);
42  if (z > (ztop - zdamp)) {
43  Real zfrac = 1.0 - (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] = 0.0;
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 = 1.0 - (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] = 0.0;
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:7
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:1310

◆ 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:771
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 
)
1873 {
1874  if (lon_m[lev-1] && !lon_m[lev]) {
1875  auto ngv = lon_m[lev-1]->nGrowVect(); ngv[2] = 0;
1876  lon_m[lev] = std::make_unique<MultiFab>(my_ba2d,my_dm,1,ngv);
1877  InterpFromCoarseLevel(*lon_m[lev], ngv, IntVect(0,0,0), // do not fill ghost cells outside the domain
1878  *lon_m[lev-1], 0, 0, 1,
1879  geom[lev-1], geom[lev],
1880  refRatio(lev-1), &cell_cons_interp,
1882  }
1883  if (lat_m[lev-1] && !lat_m[lev]) {
1884  auto ngv = lat_m[lev-1]->nGrowVect(); ngv[2] = 0;
1885  lat_m[lev] = std::make_unique<MultiFab>(my_ba2d,my_dm,1,ngv);
1886  InterpFromCoarseLevel(*lat_m[lev], ngv, IntVect(0,0,0), // do not fill ghost cells outside the domain
1887  *lat_m[lev-1], 0, 0, 1,
1888  geom[lev-1], geom[lev],
1889  refRatio(lev-1), &cell_cons_interp,
1891  }
1892  if (sinPhi_m[lev-1] && !sinPhi_m[lev]) {
1893  auto ngv = sinPhi_m[lev-1]->nGrowVect(); ngv[2] = 0;
1894  sinPhi_m[lev] = std::make_unique<MultiFab>(my_ba2d,my_dm,1,ngv);
1895  InterpFromCoarseLevel(*sinPhi_m[lev], ngv, IntVect(0,0,0), // do not fill ghost cells outside the domain
1896  *sinPhi_m[lev-1], 0, 0, 1,
1897  geom[lev-1], geom[lev],
1898  refRatio(lev-1), &cell_cons_interp,
1900  }
1901  if (cosPhi_m[lev-1] && !cosPhi_m[lev]) {
1902  auto ngv = cosPhi_m[lev-1]->nGrowVect(); ngv[2] = 0;
1903  cosPhi_m[lev] = std::make_unique<MultiFab>(my_ba2d,my_dm,1,ngv);
1904  InterpFromCoarseLevel(*cosPhi_m[lev], ngv, IntVect(0,0,0), // do not fill ghost cells outside the domain
1905  *cosPhi_m[lev-1], 0, 0, 1,
1906  geom[lev-1], geom[lev],
1907  refRatio(lev-1), &cell_cons_interp,
1909  }
1910  if (sst_lev[lev-1][0]) {
1911  if (sst_lev[lev].size() < sst_lev[lev-1].size()) {
1912  sst_lev[lev].resize(sst_lev[lev-1].size());
1913  }
1914 #ifdef ERF_USE_NETCDF
1915  Real time_since_start_low = t_new[0] + start_time - start_low_time;
1916  int n_time_old = static_cast<int>(time_since_start_low / low_time_interval);
1917  int ntimes_to_interp = std::min(n_time_old+3, static_cast<int>(sst_lev[lev-1].size()));
1918 #else
1919  // TODO: Fix if SST is provided without NETCDF
1920  int n_time_old = 0;
1921  int ntimes_to_interp = 1;
1922 #endif
1923  auto ngv = sst_lev[lev-1][0]->nGrowVect(); ngv[2] = 0;
1924 
1925  for (int n = n_time_old; n < ntimes_to_interp; n++) {
1926  if (!sst_lev[lev-1][n]) { continue; }
1927  if (!sst_lev[lev][n]) {
1928  sst_lev[lev][n] = std::make_unique<MultiFab>(my_ba2d,my_dm,1,ngv);
1929  InterpFromCoarseLevel(*sst_lev[lev][n], ngv, IntVect(0,0,0), // do not fill ghost cells outside the domain
1930  *sst_lev[lev-1][n], 0, 0, 1,
1931  geom[lev-1], geom[lev],
1932  refRatio(lev-1), &cell_cons_interp,
1934  }
1935  }
1936  }
1937  if (tsk_lev[lev-1][0]) {
1938  if (tsk_lev[lev].size() < tsk_lev[lev-1].size()) {
1939  tsk_lev[lev].resize(tsk_lev[lev-1].size());
1940  }
1941 #ifdef ERF_USE_NETCDF
1942  Real time_since_start_low = t_new[0] + start_time - start_low_time;
1943  int n_time_old = static_cast<int>(time_since_start_low / low_time_interval);
1944  int ntimes_to_interp = std::min(n_time_old+3, static_cast<int>(tsk_lev[lev-1].size()));
1945 #else
1946  // TODO: Fix if TSK is provided without NETCDF
1947  int n_time_old = 0;
1948  int ntimes_to_interp = 1;
1949 #endif
1950  auto ngv = tsk_lev[lev-1][0]->nGrowVect(); ngv[2] = 0;
1951 
1952  for (int n = n_time_old; n < ntimes_to_interp; n++) {
1953  if (!tsk_lev[lev-1][n]) { continue; }
1954  if (!tsk_lev[lev][n]) {
1955  tsk_lev[lev][n] = std::make_unique<MultiFab>(my_ba2d,my_dm,1,ngv);
1956  InterpFromCoarseLevel(*tsk_lev[lev][n], ngv, IntVect(0,0,0), // do not fill ghost cells outside the domain
1957  *tsk_lev[lev-1][n], 0, 0, 1,
1958  geom[lev-1], geom[lev],
1959  refRatio(lev-1), &cell_cons_interp,
1961  }
1962  }
1963  }
1964 
1965  Real time_for_fp = 0.; // This is not actually used
1966  Vector<Real> ftime = {time_for_fp, time_for_fp};
1967  Vector<Real> ctime = {time_for_fp, time_for_fp};
1968  if (lat_m[lev]) {
1969  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
1970  Vector<MultiFab*> fmf = {lat_m[lev ].get(), lat_m[lev ].get()};
1971  Vector<MultiFab*> cmf = {lat_m[lev-1].get(), lat_m[lev-1].get()};
1972  IntVect ngv = lat_m[lev]->nGrowVect(); ngv[2] = 0;
1973  Interpolater* mapper = &cell_cons_interp;
1974  FillPatchTwoLevels(*lat_m[lev].get(), ngv, IntVect(0,0,0),
1975  time_for_fp, cmf, ctime, fmf, ftime,
1976  0, 0, 1, geom[lev-1], geom[lev],
1977  refRatio(lev-1), mapper, domain_bcs_type,
1978  BCVars::cons_bc);
1979  }
1980  if (lon_m[lev]) {
1981  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
1982  Vector<MultiFab*> fmf = {lon_m[lev ].get(), lon_m[lev ].get()};
1983  Vector<MultiFab*> cmf = {lon_m[lev-1].get(), lon_m[lev-1].get()};
1984  IntVect ngv = lon_m[lev]->nGrowVect(); ngv[2] = 0;
1985  Interpolater* mapper = &cell_cons_interp;
1986  FillPatchTwoLevels(*lon_m[lev].get(), ngv, IntVect(0,0,0),
1987  time_for_fp, cmf, ctime, fmf, ftime,
1988  0, 0, 1, geom[lev-1], geom[lev],
1989  refRatio(lev-1), mapper, domain_bcs_type,
1990  BCVars::cons_bc);
1991  } // lon_m
1992  if (sinPhi_m[lev]) {
1993  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
1994  Vector<MultiFab*> fmf = {sinPhi_m[lev ].get(), sinPhi_m[lev ].get()};
1995  Vector<MultiFab*> cmf = {sinPhi_m[lev-1].get(), sinPhi_m[lev-1].get()};
1996  IntVect ngv = sinPhi_m[lev]->nGrowVect(); ngv[2] = 0;
1997  Interpolater* mapper = &cell_cons_interp;
1998  FillPatchTwoLevels(*sinPhi_m[lev].get(), ngv, IntVect(0,0,0),
1999  time_for_fp, cmf, ctime, fmf, ftime,
2000  0, 0, 1, geom[lev-1], geom[lev],
2001  refRatio(lev-1), mapper, domain_bcs_type,
2002  BCVars::cons_bc);
2003  } // sinPhi
2004  if (cosPhi_m[lev]) {
2005  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
2006  Vector<MultiFab*> fmf = {cosPhi_m[lev ].get(), cosPhi_m[lev ].get()};
2007  Vector<MultiFab*> cmf = {cosPhi_m[lev-1].get(), cosPhi_m[lev-1].get()};
2008  IntVect ngv = cosPhi_m[lev]->nGrowVect(); ngv[2] = 0;
2009  Interpolater* mapper = &cell_cons_interp;
2010  FillPatchTwoLevels(*cosPhi_m[lev].get(), ngv, IntVect(0,0,0),
2011  time_for_fp, cmf, ctime, fmf, ftime,
2012  0, 0, 1, geom[lev-1], geom[lev],
2013  refRatio(lev-1), mapper, domain_bcs_type,
2014  BCVars::cons_bc);
2015  } // cosPhi
2016  if (sst_lev[lev][0]) {
2017  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
2018 #ifdef ERF_USE_NETCDF
2019  Real time_since_start_low = t_new[0] + start_time - start_low_time;
2020  int n_time_old = static_cast<int>(time_since_start_low / low_time_interval);
2021  int ntimes_to_interp = std::min(n_time_old+3, static_cast<int>(sst_lev[lev-1].size()));
2022 #else
2023  // TODO: Fix if SST is provided without NETCDF
2024  int n_time_old = 0;
2025  int ntimes_to_interp = 1;
2026 #endif
2027  for (int n = n_time_old; n < ntimes_to_interp; n++) {
2028  if (!sst_lev[lev][n] || !sst_lev[lev-1][n]) { continue; }
2029  Vector<MultiFab*> fmf = {sst_lev[lev ][n].get(), sst_lev[lev ][n].get()};
2030  Vector<MultiFab*> cmf = {sst_lev[lev-1][n].get(), sst_lev[lev-1][n].get()};
2031  IntVect ngv = sst_lev[lev][n]->nGrowVect(); ngv[2] = 0;
2032  Interpolater* mapper = &cell_cons_interp;
2033  FillPatchTwoLevels(*sst_lev[lev][n].get(), ngv, IntVect(0,0,0),
2034  time_for_fp, cmf, ctime, fmf, ftime,
2035  0, 0, 1, geom[lev-1], geom[lev],
2036  refRatio(lev-1), mapper, domain_bcs_type,
2037  BCVars::cons_bc);
2038  } // ntimes
2039  } // sst_lev
2040  if (tsk_lev[lev][0]) {
2041  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
2042 #ifdef ERF_USE_NETCDF
2043  Real time_since_start_low = t_new[0] + start_time - start_low_time;
2044  int n_time_old = static_cast<int>(time_since_start_low / low_time_interval);
2045  int ntimes_to_interp = std::min(n_time_old+3, static_cast<int>(tsk_lev[lev-1].size()));
2046 #else
2047  // TODO: Fix if TSK is provided without NETCDF
2048  int n_time_old = 0;
2049  int ntimes_to_interp = 1;
2050 #endif
2051  for (int n = n_time_old; n < ntimes_to_interp; n++) {
2052  if (!tsk_lev[lev][n] || !tsk_lev[lev-1][n]) { continue; }
2053  Vector<MultiFab*> fmf = {tsk_lev[lev ][n].get(), tsk_lev[lev ][n].get()};
2054  Vector<MultiFab*> cmf = {tsk_lev[lev-1][n].get(), tsk_lev[lev-1][n].get()};
2055  IntVect ngv = tsk_lev[lev][n]->nGrowVect(); ngv[2] = 0;
2056  Interpolater* mapper = &cell_cons_interp;
2057  FillPatchTwoLevels(*tsk_lev[lev][n].get(), ngv, IntVect(0,0,0),
2058  time_for_fp, cmf, ctime, fmf, ftime,
2059  0, 0, 1, geom[lev-1], geom[lev],
2060  refRatio(lev-1), mapper, domain_bcs_type,
2061  BCVars::cons_bc);
2062  } // ntimes
2063  } // tsk_lev
2064 }
Here is the call graph for this function:

◆ is_it_time_for_action()

bool ERF::is_it_time_for_action ( int  nstep,
amrex::Real  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
654 {
655  bool int_test = (action_interval > 0 && nstep % action_interval == 0);
656 
657  bool per_test = false;
658  if (action_per > 0.0) {
659  const int num_per_old = static_cast<int>(amrex::Math::floor((time - dtlev) / action_per));
660  const int num_per_new = static_cast<int>(amrex::Math::floor((time) / action_per));
661 
662  if (num_per_old != num_per_new) {
663  per_test = true;
664  }
665  }
666 
667  return int_test || per_test;
668 }

◆ 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
831 {
832  if (SolverChoice::mesh_type == MeshType::VariableDz) {
833  AMREX_ALWAYS_ASSERT(z_phys_nd[lev] != nullptr);
834  }
835 
836  physbcs_cons[lev] = std::make_unique<ERFPhysBCFunct_cons> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
838  z_phys_nd[lev], solverChoice.use_real_bcs, th_bc_data[lev].data());
839  physbcs_u[lev] = std::make_unique<ERFPhysBCFunct_u> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
841  z_phys_nd[lev], solverChoice.use_real_bcs, xvel_bc_data[lev].data());
842  physbcs_v[lev] = std::make_unique<ERFPhysBCFunct_v> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
844  z_phys_nd[lev], solverChoice.use_real_bcs, yvel_bc_data[lev].data());
845  physbcs_w[lev] = std::make_unique<ERFPhysBCFunct_w> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
848  solverChoice.use_real_bcs, zvel_bc_data[lev].data());
849  physbcs_base[lev] = std::make_unique<ERFPhysBCFunct_base> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d, z_phys_nd[lev],
850  (solverChoice.terrain_type == TerrainType::MovingFittedMesh));
851 }
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 
)
2984 {
2985  // Get the number of cells in z at level 0
2986  int dir_z = AMREX_SPACEDIM-1;
2987  auto domain = geom[0].Domain();
2988  int size_z = domain.length(dir_z);
2989  int start_z = domain.smallEnd()[dir_z];
2990  Real area_z = static_cast<Real>(domain.length(0)*domain.length(1));
2991 
2992  // resize the level 0 horizontal average vectors
2993  h_havg.resize(size_z, 0.0_rt);
2994 
2995  // Get the cell centered data and construct sums
2996 #ifdef _OPENMP
2997 #pragma omp parallel if (Gpu::notInLaunchRegion())
2998 #endif
2999  for (MFIter mfi(S); mfi.isValid(); ++mfi) {
3000  const Box& box = mfi.validbox();
3001  const IntVect& se = box.smallEnd();
3002  const IntVect& be = box.bigEnd();
3003 
3004  auto fab_arr = S[mfi].array();
3005 
3006  FArrayBox fab_reduce(box, 1, The_Async_Arena());
3007  auto arr_reduce = fab_reduce.array();
3008 
3009  ParallelFor(box, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
3010  arr_reduce(i, j, k, 0) = fab_arr(i,j,k,n);
3011  });
3012 
3013  for (int k=se[dir_z]; k <= be[dir_z]; ++k) {
3014  Box kbox(box); kbox.setSmall(dir_z,k); kbox.setBig(dir_z,k);
3015  h_havg[k-start_z] += fab_reduce.sum<RunOn::Device>(kbox,0);
3016  }
3017  }
3018 
3019  // combine sums from different MPI ranks
3020  ParallelDescriptor::ReduceRealSum(h_havg.dataPtr(), h_havg.size());
3021 
3022  // divide by the total number of cells we are averaging over
3023  for (int k = 0; k < size_z; ++k) {
3024  h_havg[k] /= area_z;
3025  }
3026 }
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 ( )
2878 {
2879  int lev = 0;
2880 
2881  // First, average down all levels (if doing two-way coupling)
2882  if (solverChoice.coupling_type == CouplingType::TwoWay) {
2883  AverageDown();
2884  }
2885 
2886  MultiFab mf(grids[lev], dmap[lev], 5, 0);
2887 
2888  int zdir = 2;
2889  auto domain = geom[0].Domain();
2890 
2891  bool use_moisture = (solverChoice.moisture_type != MoistureType::None);
2892  bool is_anelastic = (solverChoice.anelastic[lev] == 1);
2893 
2894  for (MFIter mfi(mf); mfi.isValid(); ++mfi) {
2895  const Box& bx = mfi.validbox();
2896  auto fab_arr = mf.array(mfi);
2897  auto const hse_arr = base_state[lev].const_array(mfi);
2898  auto const cons_arr = vars_new[lev][Vars::cons].const_array(mfi);
2899  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
2900  Real dens = cons_arr(i, j, k, Rho_comp);
2901  fab_arr(i, j, k, 0) = dens;
2902  fab_arr(i, j, k, 1) = cons_arr(i, j, k, RhoTheta_comp) / dens;
2903  if (!use_moisture) {
2904  if (is_anelastic) {
2905  fab_arr(i,j,k,2) = hse_arr(i,j,k,BaseState::p0_comp);
2906  } else {
2907  fab_arr(i,j,k,2) = getPgivenRTh(cons_arr(i,j,k,RhoTheta_comp));
2908  }
2909  }
2910  });
2911  }
2912 
2913  if (use_moisture)
2914  {
2915  for (MFIter mfi(mf); mfi.isValid(); ++mfi) {
2916  const Box& bx = mfi.validbox();
2917  auto fab_arr = mf.array(mfi);
2918  auto const hse_arr = base_state[lev].const_array(mfi);
2919  auto const cons_arr = vars_new[lev][Vars::cons].const_array(mfi);
2920  int ncomp = vars_new[lev][Vars::cons].nComp();
2921 
2922  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
2923  Real dens = cons_arr(i, j, k, Rho_comp);
2924  if (is_anelastic) {
2925  fab_arr(i,j,k,2) = hse_arr(i,j,k,BaseState::p0_comp);
2926  } else {
2927  Real qv = cons_arr(i, j, k, RhoQ1_comp) / dens;
2928  fab_arr(i, j, k, 2) = getPgivenRTh(cons_arr(i, j, k, RhoTheta_comp), qv);
2929  }
2930  fab_arr(i, j, k, 3) = (ncomp > RhoQ1_comp ? cons_arr(i, j, k, RhoQ1_comp) / dens : 0.0);
2931  fab_arr(i, j, k, 4) = (ncomp > RhoQ2_comp ? cons_arr(i, j, k, RhoQ2_comp) / dens : 0.0);
2932  });
2933  }
2934 
2935  Gpu::HostVector<Real> h_avg_qv = sumToLine(mf,3,1,domain,zdir);
2936  Gpu::HostVector<Real> h_avg_qc = sumToLine(mf,4,1,domain,zdir);
2937  }
2938 
2939  // Sum in the horizontal plane
2940  Gpu::HostVector<Real> h_avg_density = sumToLine(mf,0,1,domain,zdir);
2941  Gpu::HostVector<Real> h_avg_temperature = sumToLine(mf,1,1,domain,zdir);
2942  Gpu::HostVector<Real> h_avg_pressure = sumToLine(mf,2,1,domain,zdir);
2943 
2944  // Divide by the total number of cells we are averaging over
2945  int size_z = domain.length(zdir);
2946  Real area_z = static_cast<Real>(domain.length(0)*domain.length(1));
2947  int klen = static_cast<int>(h_avg_density.size());
2948 
2949  for (int k = 0; k < klen; ++k) {
2950  h_havg_density[k] /= area_z;
2951  h_havg_temperature[k] /= area_z;
2952  h_havg_pressure[k] /= area_z;
2953  if (solverChoice.moisture_type != MoistureType::None)
2954  {
2955  h_havg_qc[k] /= area_z;
2956  h_havg_qv[k] /= area_z;
2957  }
2958  } // k
2959 
2960  // resize device vectors
2961  d_havg_density.resize(size_z, 0.0_rt);
2962  d_havg_temperature.resize(size_z, 0.0_rt);
2963  d_havg_pressure.resize(size_z, 0.0_rt);
2964 
2965  // copy host vectors to device vectors
2966  Gpu::copy(Gpu::hostToDevice, h_havg_density.begin(), h_havg_density.end(), d_havg_density.begin());
2967  Gpu::copy(Gpu::hostToDevice, h_havg_temperature.begin(), h_havg_temperature.end(), d_havg_temperature.begin());
2968  Gpu::copy(Gpu::hostToDevice, h_havg_pressure.begin(), h_havg_pressure.end(), d_havg_pressure.begin());
2969 
2970  if (solverChoice.moisture_type != MoistureType::None)
2971  {
2972  d_havg_qv.resize(size_z, 0.0_rt);
2973  d_havg_qc.resize(size_z, 0.0_rt);
2974  Gpu::copy(Gpu::hostToDevice, h_havg_qv.begin(), h_havg_qv.end(), d_havg_qv.begin());
2975  Gpu::copy(Gpu::hostToDevice, h_havg_qc.begin(), h_havg_qc.end(), d_havg_qc.begin());
2976  }
2977 }
amrex::Gpu::DeviceVector< amrex::Real > d_havg_temperature
Definition: ERF.H:1331
amrex::Gpu::DeviceVector< amrex::Real > d_havg_qv
Definition: ERF.H:1333
amrex::Vector< amrex::Real > h_havg_pressure
Definition: ERF.H:1326
amrex::Vector< amrex::Real > h_havg_qc
Definition: ERF.H:1328
amrex::Vector< amrex::Real > h_havg_density
Definition: ERF.H:1324
amrex::Gpu::DeviceVector< amrex::Real > d_havg_qc
Definition: ERF.H:1334
amrex::Gpu::DeviceVector< amrex::Real > d_havg_density
Definition: ERF.H:1330
amrex::Vector< amrex::Real > h_havg_temperature
Definition: ERF.H:1325
amrex::Gpu::DeviceVector< amrex::Real > d_havg_pressure
Definition: ERF.H:1332
amrex::Vector< amrex::Real > h_havg_qv
Definition: ERF.H:1327
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
283 {
284  //
285  // Note that "time" here is elapsed time
286  //
287  AMREX_ALWAYS_ASSERT(lev > 0);
288 
289  if (verbose) {
290  amrex::Print() <<" NEW BA FROM COARSE AT LEVEL " << lev << " " << ba << std::endl;
291  }
292 
293  //
294  // Grow the subdomains vector and build the subdomains vector at this level
295  //
296  subdomains.resize(lev+1);
297  //
298  // Create subdomains at each level within the domain such that
299  // 1) all boxes in a given subdomain are "connected"
300  // 2) no boxes in a subdomain touch any boxes in any other subdomain
301  //
302  if ( (solverChoice.anelastic[lev] == 0) && (solverChoice.project_initial_velocity[lev] == 0) ) {
303  BoxArray dom(geom[lev].Domain());
304  subdomains[lev].push_back(dom);
305  } else {
306  make_subdomains(ba.simplified_list(), subdomains[lev]);
307  }
308 
309  if (lev == 0) init_bcs();
310 
311  //********************************************************************************************
312  // This allocates all kinds of things, including but not limited to: solution arrays,
313  // terrain arrays, ba2d, metric terms and base state.
314  // *******************************************************************************************
315  init_stuff(lev, ba, dm, vars_new[lev], vars_old[lev], base_state[lev], z_phys_nd[lev]);
316 
317  //
318  // Note that t_new = time here is elapsed time
319  //
320  t_new[lev] = time;
321  t_old[lev] = time - 1.e200;
322 
323  // ********************************************************************************************
324  // Build the data structures for metric quantities used with terrain-fitted coordinates
325  // ********************************************************************************************
326  if ( solverChoice.terrain_type == TerrainType::EB ||
327  solverChoice.terrain_type == TerrainType::ImmersedForcing ||
328  solverChoice.buildings_type == BuildingsType::ImmersedForcing)
329  {
330  const amrex::EB2::IndexSpace& ebis = amrex::EB2::IndexSpace::top();
331  const EB2::Level& eb_level = ebis.getLevel(geom[lev]);
332  if (solverChoice.terrain_type == TerrainType::EB) {
333  eb[lev]->make_all_factories(lev, geom[lev], ba, dm, eb_level);
334  } else if (solverChoice.terrain_type == TerrainType::ImmersedForcing ||
335  solverChoice.buildings_type == BuildingsType::ImmersedForcing) {
336  eb[lev]->make_cc_factory(lev, geom[lev], ba, dm, eb_level);
337  }
338  }
339  init_zphys(lev, time);
341 
342  //
343  // Make sure that detJ and z_phys_cc are the average of the data on a finer level if there is one
344  // *and* if there is two-way coupling
345  //
346  if ( (SolverChoice::mesh_type != MeshType::ConstantDz) && (solverChoice.coupling_type == CouplingType::TwoWay) ) {
347  for (int crse_lev = lev-1; crse_lev >= 0; crse_lev--) {
348  average_down( *detJ_cc[crse_lev+1], *detJ_cc[crse_lev], 0, 1, refRatio(crse_lev));
349  average_down(*z_phys_cc[crse_lev+1], *z_phys_cc[crse_lev], 0, 1, refRatio(crse_lev));
350  }
351  }
352 
353  // ********************************************************************************************
354  // Build the data structures for canopy model (depends upon z_phys)
355  // ********************************************************************************************
357  m_forest_drag[lev]->define_drag_field(ba, dm, geom[lev], z_phys_cc[lev].get(), z_phys_nd[lev].get());
358  }
359 
360  //********************************************************************************************
361  // Radiation
362  // *******************************************************************************************
363  if (solverChoice.rad_type != RadiationType::None)
364  {
365  rad[lev]->Init(geom[lev], ba, &vars_new[lev][Vars::cons]);
366  }
367 
368  // *****************************************************************************************************
369  // Initialize the boundary conditions (after initializing the terrain but before calling
370  // initHSE or FillCoarsePatch)
371  // *****************************************************************************************************
372  make_physbcs(lev);
373 
374  // ********************************************************************************************
375  // Update the base state at this level by interpolation from coarser level
376  // ********************************************************************************************
377  InterpFromCoarseLevel(base_state[lev], base_state[lev].nGrowVect(),
378  IntVect(0,0,0), // do not fill ghost cells outside the domain
379  base_state[lev-1], 0, 0, base_state[lev].nComp(),
380  geom[lev-1], geom[lev],
381  refRatio(lev-1), &cell_cons_interp,
383 
384  // Impose bc's outside the domain
385  (*physbcs_base[lev])(base_state[lev],0,base_state[lev].nComp(),base_state[lev].nGrowVect());
386 
387  //********************************************************************************************
388  // Microphysics
389  // *******************************************************************************************
390  int q_size = micro->Get_Qmoist_Size(lev);
391  qmoist[lev].resize(q_size);
392  micro->Define(lev, solverChoice);
393  if (solverChoice.moisture_type != MoistureType::None)
394  {
395  micro->Init(lev, vars_new[lev][Vars::cons],
396  grids[lev], Geom(lev), 0.0,
397  z_phys_nd[lev], detJ_cc[lev]); // dummy dt value
398  }
399  for (int mvar(0); mvar<qmoist[lev].size(); ++mvar) {
400  qmoist[lev][mvar] = micro->Get_Qmoist_Ptr(lev,mvar);
401  }
402 
403  // ********************************************************************************************
404  // Build the data structures for calculating diffusive/turbulent terms
405  // ********************************************************************************************
406  update_diffusive_arrays(lev, ba, dm);
407 
408  // ********************************************************************************************
409  // Build the data structures for holding sea surface temps and skin temps
410  // ********************************************************************************************
411  sst_lev[lev].resize(1); sst_lev[lev][0] = nullptr;
412  tsk_lev[lev].resize(1); tsk_lev[lev][0] = nullptr;
413 
414  // ********************************************************************************************
415  // Fill data at the new level by interpolation from the coarser level
416  // Note that internal to FillCoarsePatch we will convert velocity to momentum,
417  // then interpolate momentum, then convert momentum back to velocity
418  // Also note that FillCoarsePatch is hard-wired to act only on lev_new at coarse and fine
419  // ********************************************************************************************
420 
421 #ifdef ERF_USE_NETCDF
422  if ( ( (solverChoice.init_type == InitType::WRFInput) || (solverChoice.init_type == InitType::Metgrid) ) &&
423  !nc_init_file[lev].empty() )
424  {
425  // Just making sure that ghost cells aren't uninitialized...
426  vars_new[lev][Vars::cons].setVal(0.0); vars_old[lev][Vars::cons].setVal(0.0);
427  vars_new[lev][Vars::xvel].setVal(0.0); vars_old[lev][Vars::xvel].setVal(0.0);
428  vars_new[lev][Vars::yvel].setVal(0.0); vars_old[lev][Vars::yvel].setVal(0.0);
429  vars_new[lev][Vars::zvel].setVal(0.0); vars_old[lev][Vars::zvel].setVal(0.0);
430 
431  AMREX_ALWAYS_ASSERT(solverChoice.terrain_type == TerrainType::StaticFittedMesh);
432  if (solverChoice.init_type == InitType::Metgrid) {
433  init_from_metgrid(lev);
434  } else if (solverChoice.init_type == InitType::WRFInput) {
435  init_from_wrfinput(lev, *mf_C1H, *mf_C2H, *mf_MUB, *mf_PSFC[lev]);
436  }
437  init_zphys(lev, time);
439  make_physbcs(lev);
440 
441  dz_min[lev] = (*detJ_cc[lev]).min(0) * geom[lev].CellSize(2);
442 
443  } else {
444 #endif
445  //
446  // Interpolate the solution data
447  //
448  FillCoarsePatch(lev, time);
449 
450  //
451  // Interpolate the 2D arrays at the lower boundary
452  // Note that ba2d is constructed already in init_stuff, but we have not yet defined dmap[lev]
453  // so we must explicitly pass dm.
454  Interp2DArrays(lev,ba2d[lev],dm);
455 #ifdef ERF_USE_NETCDF
456  }
457 #endif
458 
459  // ********************************************************************************************
460  // Initialize the integrator class
461  // ********************************************************************************************
462  dt_mri_ratio[lev] = dt_mri_ratio[lev-1];
464 
465  // ********************************************************************************************
466  // If we are making a new level then the FillPatcher for this level hasn't been allocated yet
467  // ********************************************************************************************
468  if (lev > 0 && cf_width >= 0) {
471  }
472 
473  // ********************************************************************************************
474  // For anelastic levels created from coarse (either on restart or during a run), project the
475  // interpolated velocity to enforce the divergence-free constraint. This Initializes gradp[lev]
476  // via the pressure projection, handling both the pure-anelastic case and the hybrid case
477  // (compressible lev-1, anelastic lev) where there is no coarse gradp to interpolate.
478  // FillPatchers must be constructed above before this call. pp_inc is scratch; zero afterward.
479  // ********************************************************************************************
480  if (solverChoice.anelastic[lev]) {
481  Real dummy_dt = 1.0;
482  project_initial_velocity(lev, time, dummy_dt);
483  pp_inc[lev].setVal(0.0);
484  }
485 
486  //********************************************************************************************
487  // Land Surface Model
488  // *******************************************************************************************
489  int lsm_data_size = lsm.Get_Data_Size();
490  int lsm_flux_size = lsm.Get_Flux_Size();
491  lsm_data[lev].resize(lsm_data_size);
492  lsm_data_name.resize(lsm_data_size);
493  lsm_flux[lev].resize(lsm_flux_size);
494  lsm_flux_name.resize(lsm_flux_size);
495  lsm.Define(lev, solverChoice);
496  if (solverChoice.lsm_type != LandSurfaceType::None)
497  {
498  lsm.Init(lev, vars_new[lev][Vars::cons], Geom(lev), 0.0); // dummy dt value
499  }
500  for (int mvar(0); mvar<lsm_data[lev].size(); ++mvar) {
501  lsm_data[lev][mvar] = lsm.Get_Data_Ptr(lev,mvar);
502  lsm_data_name[mvar] = lsm.Get_DataName(mvar);
503  }
504  for (int mvar(0); mvar<lsm_flux[lev].size(); ++mvar) {
505  lsm_flux[lev][mvar] = lsm.Get_Flux_Ptr(lev,mvar);
506  lsm_flux_name[mvar] = lsm.Get_FluxName(mvar);
507  }
508 
509  // ********************************************************************************************
510  // Create the SurfaceLayer arrays at this (new) level
511  // ********************************************************************************************
512  if (phys_bc_type[Orientation(Direction::z,Orientation::low)] == ERF_BC::surface_layer) {
513  Vector<MultiFab*> mfv_old = {&vars_old[lev][Vars::cons], &vars_old[lev][Vars::xvel],
514  &vars_old[lev][Vars::yvel], &vars_old[lev][Vars::zvel]};
515  m_SurfaceLayer->make_SurfaceLayer_at_level(lev,lev+1,
516  mfv_old, Theta_prim[lev], Qv_prim[lev],
517  Qr_prim[lev], z_phys_nd[lev],
518  Hwave[lev].get(), Lwave[lev].get(), eddyDiffs_lev[lev].get(),
520  sst_lev[lev], tsk_lev[lev], lmask_lev[lev]);
521  }
522 
523  // ********************************************************************************************
524  // Set up the Rayleigh damping vectors at this (new) level
525  // ********************************************************************************************
528  {
530  }
531 
532 #ifdef ERF_USE_PARTICLES
533  // particleData.Redistribute();
534 #endif
535 }
void update_diffusive_arrays(int lev, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm)
Definition: ERF_MakeNewArrays.cpp:510
void initialize_integrator(int lev, amrex::MultiFab &cons_mf, amrex::MultiFab &vel_mf)
Definition: ERF_MakeNewArrays.cpp:808
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:791
void init_zphys(int lev, amrex::Real elapsed_time)
Definition: ERF_MakeNewArrays.cpp:635
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:3055
int Get_Data_Size()
Definition: ERF_LandSurface.H:98
std::string Get_DataName(const int &varIdx)
Definition: ERF_LandSurface.H:104
std::string Get_FluxName(const int &varIdx)
Definition: ERF_LandSurface.H:110
amrex::MultiFab * Get_Flux_Ptr(const int &lev, const int &varIdx)
Definition: ERF_LandSurface.H:92
void Init(const int &lev, const amrex::MultiFab &cons_in, const amrex::Geometry &geom, const amrex::Real &dt_advance)
Definition: ERF_LandSurface.H:43
void Define(const int &lev, SolverChoice &sc)
Definition: ERF_LandSurface.H:36
int Get_Flux_Size()
Definition: ERF_LandSurface.H:101
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  if ( (lev == 0) || (
66  (solverChoice.anelastic[lev] == 0) && (solverChoice.project_initial_velocity[lev] == 0) &&
67  (solverChoice.init_type != InitType::WRFInput) && (solverChoice.init_type != InitType::Metgrid) ) ) {
68  BoxArray dom(geom[lev].Domain());
69  subdomains[lev].push_back(dom);
70  } else {
71  //
72  // Create subdomains at each level within the domain such that
73  // 1) all boxes in a given subdomain are "connected"
74  // 2) no boxes in a subdomain touch any boxes in any other subdomain
75  //
76  make_subdomains(ba.simplified_list(), subdomains[lev]);
77  }
78 
79  if (lev == 0) init_bcs();
80 
81  if ( solverChoice.terrain_type == TerrainType::EB ||
82  solverChoice.terrain_type == TerrainType::ImmersedForcing ||
83  solverChoice.buildings_type == BuildingsType::ImmersedForcing)
84  {
85  const amrex::EB2::IndexSpace& ebis = amrex::EB2::IndexSpace::top();
86  const EB2::Level& eb_level = ebis.getLevel(geom[lev]);
87  if (solverChoice.terrain_type == TerrainType::EB) {
88  eb[lev]->make_all_factories(lev, geom[lev], grids[lev], dmap[lev], eb_level);
89  } else if (solverChoice.terrain_type == TerrainType::ImmersedForcing ||
90  solverChoice.buildings_type == BuildingsType::ImmersedForcing) {
91  eb[lev]->make_cc_factory(lev, geom[lev], grids[lev], dmap[lev], eb_level);
92  }
93  }
94 
95  auto& lev_new = vars_new[lev];
96  auto& lev_old = vars_old[lev];
97 
98  //********************************************************************************************
99  // This allocates all kinds of things, including but not limited to: solution arrays,
100  // terrain arrays, metric terms and base state.
101  // *******************************************************************************************
102  init_stuff(lev, ba, dm, lev_new, lev_old, base_state[lev], z_phys_nd[lev]);
103 
104  //********************************************************************************************
105  // Land Surface Model
106  // *******************************************************************************************
107  int lsm_data_size = lsm.Get_Data_Size();
108  int lsm_flux_size = lsm.Get_Flux_Size();
109  lsm_data[lev].resize(lsm_data_size);
110  lsm_data_name.resize(lsm_data_size);
111  lsm_flux[lev].resize(lsm_flux_size);
112  lsm_flux_name.resize(lsm_flux_size);
113  lsm.Define(lev, solverChoice);
114  if (solverChoice.lsm_type != LandSurfaceType::None)
115  {
116  lsm.Init(lev, vars_new[lev][Vars::cons], Geom(lev), 0.0); // dummy dt value
117  }
118  for (int mvar(0); mvar<lsm_data[lev].size(); ++mvar) {
119  lsm_data[lev][mvar] = lsm.Get_Data_Ptr(lev,mvar);
120  lsm_data_name[mvar] = lsm.Get_DataName(mvar);
121  }
122  for (int mvar(0); mvar<lsm_flux[lev].size(); ++mvar) {
123  lsm_flux[lev][mvar] = lsm.Get_Flux_Ptr(lev,mvar);
124  lsm_flux_name[mvar] = lsm.Get_FluxName(mvar);
125  }
126 
127 
128 
129  // ********************************************************************************************
130  // Build the data structures for calculating diffusive/turbulent terms
131  // ********************************************************************************************
132  update_diffusive_arrays(lev, ba, dm);
133 
134  // ********************************************************************************************
135  // Build the data structures for holding sea surface temps and skin temps
136  // ********************************************************************************************
137  sst_lev[lev].resize(1); sst_lev[lev][0] = nullptr;
138  tsk_lev[lev].resize(1); tsk_lev[lev][0] = nullptr;
139 
140  // ********************************************************************************************
141  // Thin immersed body
142  // *******************************************************************************************
143  init_thin_body(lev, ba, dm);
144 
145  // ********************************************************************************************
146  // Initialize the integrator class
147  // ********************************************************************************************
148  initialize_integrator(lev, lev_new[Vars::cons],lev_new[Vars::xvel]);
149 
150  // ********************************************************************************************
151  // Initialize the data itself
152  // If (init_type == InitType::WRFInput) then we are initializing terrain and the initial data in
153  // the same call so we must call init_only before update_terrain_arrays
154  // If (init_type != InitType::WRFInput) then we want to initialize the terrain before the initial data
155  // since we may need to use the grid information before constructing
156  // initial idealized data
157  // ********************************************************************************************
158  if (restart_chkfile.empty()) {
159  if ( (solverChoice.init_type == InitType::WRFInput) || (solverChoice.init_type == InitType::Metgrid) )
160  {
161  AMREX_ALWAYS_ASSERT(solverChoice.terrain_type == TerrainType::StaticFittedMesh);
162  //
163  // Note that "time" here is elapsed time, and start_time is the start_time from wrfinput/metgrid files
164  //
165  init_only(lev, time);
166  init_zphys(lev, time);
168  make_physbcs(lev);
169  } else {
170  //
171  // Note that "time" here is elapsed time, and start_time = 0 when not using wrfinput/metgrid
172  //
173  init_zphys(lev, time);
175  // Note that for init_type != InitType::WRFInput and != InitType::Metgrid,
176  // make_physbcs is called inside init_only
177  init_only(lev, time);
178  }
179  } else {
180  // if restarting and nudging from input sounding, load the input sounding files
181  if (lev == 0 && solverChoice.init_type == InitType::Input_Sounding && solverChoice.nudging_from_input_sounding)
182  {
184  Error("input_sounding file name must be provided via input");
185  }
186 
188 
189  // this will interpolate the input profiles to the nominal height levels
190  // (ranging from 0 to the domain top)
191  for (int n = 0; n < input_sounding_data.n_sounding_files; n++) {
192  input_sounding_data.read_from_file(geom[lev], zlevels_stag[lev], n);
193  }
194 
195  // this will calculate the hydrostatically balanced density and pressure
196  // profiles following WRF ideal.exe
197  if (solverChoice.sounding_type == SoundingType::Ideal) {
199  } else if (solverChoice.sounding_type == SoundingType::Isentropic ||
200  solverChoice.sounding_type == SoundingType::DryIsentropic) {
201  input_sounding_data.assume_dry = (solverChoice.sounding_type == SoundingType::DryIsentropic);
203  }
204  }
205 
206  // We re-create terrain_blanking on restart rather than storing it in the checkpoint
207  if (solverChoice.terrain_type == TerrainType::ImmersedForcing ||
208  solverChoice.buildings_type == BuildingsType::ImmersedForcing) {
209  int ngrow = ComputeGhostCells(solverChoice) + 2;
210  terrain_blanking[lev]->setVal(1.0);
211  MultiFab::Subtract(*terrain_blanking[lev], EBFactory(lev).getVolFrac(), 0, 0, 1, ngrow);
212  terrain_blanking[lev]->FillBoundary(geom[lev].periodicity());
213  }
214  }
215 
216  // Read in tables needed for windfarm simulations
217  // fill in Nturb multifab - number of turbines in each mesh cell
218  // write out the vtk files for wind turbine location and/or
219  // actuator disks
220  #ifdef ERF_USE_WINDFARM
221  init_windfarm(lev);
222  #endif
223 
224  // ********************************************************************************************
225  // Build the data structures for canopy model (depends upon z_phys)
226  // ********************************************************************************************
227  if (restart_chkfile.empty()) {
229  m_forest_drag[lev]->define_drag_field(ba, dm, geom[lev], z_phys_cc[lev].get(), z_phys_nd[lev].get());
230  }
231  }
232 
233  //********************************************************************************************
234  // Microphysics
235  // *******************************************************************************************
236  int q_size = micro->Get_Qmoist_Size(lev);
237  qmoist[lev].resize(q_size);
238  micro->Define(lev, solverChoice);
239  if (solverChoice.moisture_type != MoistureType::None)
240  {
241  micro->Init(lev, vars_new[lev][Vars::cons],
242  grids[lev], Geom(lev), 0.0,
243  z_phys_nd[lev], detJ_cc[lev]); // dummy dt value
244  }
245  for (int mvar(0); mvar<qmoist[lev].size(); ++mvar) {
246  qmoist[lev][mvar] = micro->Get_Qmoist_Ptr(lev,mvar);
247  }
248 
249  //********************************************************************************************
250  // Radiation
251  // *******************************************************************************************
252  if (solverChoice.rad_type != RadiationType::None)
253  {
254  rad[lev]->Init(geom[lev], ba, &vars_new[lev][Vars::cons]);
255  }
256 
257  // ********************************************************************************************
258  // If we are making a new level then the FillPatcher for this level hasn't been allocated yet
259  // ********************************************************************************************
260  if (lev > 0 && cf_width >= 0) {
263  }
264 
265 #ifdef ERF_USE_PARTICLES
266  if (restart_chkfile.empty()) {
267  if (lev == 0) {
268  initializeTracers((ParGDBBase*)GetParGDB(),z_phys_nd,time);
269  } else {
270  particleData.Redistribute();
271  }
272  }
273 #endif
274 }
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:2164
void init_thin_body(int lev, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm)
Definition: ERF_MakeNewLevel.cpp:889
bool nudging_from_input_sounding
Definition: ERF_DataStruct.H:1169
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
1638  { return 5; }

◆ nghost_eb_full()

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

◆ nghost_eb_volume()

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

◆ NumDataLogs()

AMREX_FORCE_INLINE int ERF::NumDataLogs ( )
inlineprivatenoexcept
1434  {
1435  return datalog.size();
1436  }

◆ NumDerDataLogs()

AMREX_FORCE_INLINE int ERF::NumDerDataLogs ( )
inlineprivatenoexcept
1441  {
1442  return der_datalog.size();
1443  }

◆ NumSampleLineLogs()

AMREX_FORCE_INLINE int ERF::NumSampleLineLogs ( )
inlineprivatenoexcept
1470  {
1471  return samplelinelog.size();
1472  }

◆ NumSampleLines()

AMREX_FORCE_INLINE int ERF::NumSampleLines ( )
inlineprivatenoexcept
1496  {
1497  return sampleline.size();
1498  }

◆ NumSamplePointLogs()

AMREX_FORCE_INLINE int ERF::NumSamplePointLogs ( )
inlineprivatenoexcept
1456  {
1457  return sampleptlog.size();
1458  }

◆ NumSamplePoints()

AMREX_FORCE_INLINE int ERF::NumSamplePoints ( )
inlineprivatenoexcept
1483  {
1484  return samplepoint.size();
1485  }

◆ operator=() [1/2]

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

◆ operator=() [2/2]

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

◆ ParameterSanityChecks()

void ERF::ParameterSanityChecks ( )
private
2813 {
2814  AMREX_ALWAYS_ASSERT(cfl > 0. || fixed_dt[0] > 0.);
2815 
2816  // We don't allow use_real_bcs to be true if init_type is not either InitType::WRFInput or InitType::Metgrid
2818  ((solverChoice.init_type == InitType::WRFInput) || (solverChoice.init_type == InitType::Metgrid)) );
2819 
2821 
2822  if (cf_width < 0 || cf_set_width < 0 || cf_width < cf_set_width) {
2823  Abort("You must set cf_width >= cf_set_width >= 0");
2824  }
2825  if (max_level > 0 && cf_set_width > 0) {
2826  for (int lev = 1; lev <= max_level; lev++) {
2827  if (cf_set_width%ref_ratio[lev-1][0] != 0 ||
2828  cf_set_width%ref_ratio[lev-1][1] != 0 ||
2829  cf_set_width%ref_ratio[lev-1][2] != 0 ) {
2830  Abort("You must set cf_width to be a multiple of ref_ratio");
2831  }
2832  }
2833  }
2834 
2835  // If fixed_mri_dt_ratio is set, it must be even
2836  if (fixed_mri_dt_ratio > 0 && (fixed_mri_dt_ratio%2 != 0) )
2837  {
2838  Abort("If you specify fixed_mri_dt_ratio, it must be even");
2839  }
2840 
2841  for (int lev = 0; lev <= max_level; lev++)
2842  {
2843  // We ignore fixed_fast_dt if not substepping
2844  if (solverChoice.substepping_type[lev] == SubsteppingType::None) {
2845  fixed_fast_dt[lev] = -1.0;
2846  }
2847 
2848  // If both fixed_dt and fast_dt are specified, their ratio must be an even integer
2849  if (fixed_dt[lev] > 0. && fixed_fast_dt[lev] > 0. && fixed_mri_dt_ratio <= 0)
2850  {
2851  Real eps = 1.e-12;
2852  int ratio = static_cast<int>( ( (1.0+eps) * fixed_dt[lev] ) / fixed_fast_dt[lev] );
2853  if (fixed_dt[lev] / fixed_fast_dt[lev] != ratio)
2854  {
2855  Abort("Ratio of fixed_dt to fixed_fast_dt must be an even integer");
2856  }
2857  }
2858 
2859  // If all three are specified, they must be consistent
2860  if (fixed_dt[lev] > 0. && fixed_fast_dt[lev] > 0. && fixed_mri_dt_ratio > 0)
2861  {
2862  if (fixed_dt[lev] / fixed_fast_dt[lev] != fixed_mri_dt_ratio)
2863  {
2864  Abort("Dt is over-specfied");
2865  }
2866  }
2867  } // lev
2868 
2869  if (solverChoice.coupling_type == CouplingType::TwoWay && cf_width > 0) {
2870  Abort("For two-way coupling you must set cf_width = 0");
2871  }
2872 }
Here is the call graph for this function:

◆ PlotFileName()

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

◆ PlotFileVarNames()

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

◆ 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–248. https://doi.org/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 + 0.5) * 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 = 0.0;
266  constexpr Real constB = -1.0;
267 
268  MLABecLaplacian mlabec(geom_tmp, ba_tmp, dm_tmp, info);
269 
270  mlabec.setScalars(constA, constB);
271  mlabec.setACoeffs(0, 0.0);
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 = 1.0 / 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, 1.0);
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 = 0.25 * 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 = 0.25 * 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 = 0.25 * 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 = 0.25 * 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 = 0.25 * 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 = 0.25 * 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 = 0.25 * 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 = 0.25 * 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_IsentropicVortex.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:115
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:53
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:182
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:102
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:196
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:142
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:168
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:209
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:8
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:162
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:83
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:46
static int mg_verbose
Definition: ERF.H:1207
amrex::Real poisson_reltol
Definition: ERF_DataStruct.H:1110
int ncorr
Definition: ERF_DataStruct.H:1108
amrex::Real poisson_abstol
Definition: ERF_DataStruct.H:1109
Here is the call graph for this function:

◆ post_timestep()

void ERF::post_timestep ( int  nstep,
amrex::Real  time,
amrex::Real  dt_lev 
)
766 {
767  BL_PROFILE("ERF::post_timestep()");
768 
769 #ifdef ERF_USE_PARTICLES
770  particleData.Redistribute();
771 #endif
772 
773  if (solverChoice.coupling_type == CouplingType::TwoWay)
774  {
775  int ncomp = vars_new[0][Vars::cons].nComp();
776  for (int lev = finest_level-1; lev >= 0; lev--)
777  {
778  // The quantity that is conserved is not (rho S), but rather (rho S / m^2) where
779  // m is the map scale factor at cell centers
780  // Here we pre-divide (rho S) by m^2 before refluxing
781  for (MFIter mfi(vars_new[lev][Vars::cons], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
782  const Box& bx = mfi.tilebox();
783  const Array4< Real> cons_arr = vars_new[lev][Vars::cons].array(mfi);
784  const Array4<const Real> mfx_arr = mapfac[lev][MapFacType::m_x]->const_array(mfi);
785  const Array4<const Real> mfy_arr = mapfac[lev][MapFacType::m_y]->const_array(mfi);
786  if (SolverChoice::mesh_type == MeshType::ConstantDz) {
787  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
788  {
789  cons_arr(i,j,k,n) /= (mfx_arr(i,j,0)*mfy_arr(i,j,0));
790  });
791  } else {
792  const Array4<const Real> detJ_arr = detJ_cc[lev]->const_array(mfi);
793  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
794  {
795  cons_arr(i,j,k,n) *= detJ_arr(i,j,k) / (mfx_arr(i,j,0)*mfy_arr(i,j,0));
796  });
797  }
798  } // mfi
799 
800  // This call refluxes all "slow" cell-centered variables
801  // (i.e. not density or (rho theta) or velocities) from the lev/lev+1 interface onto lev
802  getAdvFluxReg(lev+1)->Reflux(vars_new[lev][Vars::cons], 2, 2, ncomp-2);
803 
804  // Here we multiply (rho S) by m^2 after refluxing
805  for (MFIter mfi(vars_new[lev][Vars::cons], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
806  const Box& bx = mfi.tilebox();
807  const Array4< Real> cons_arr = vars_new[lev][Vars::cons].array(mfi);
808  const Array4<const Real> mfx_arr = mapfac[lev][MapFacType::m_x]->const_array(mfi);
809  const Array4<const Real> mfy_arr = mapfac[lev][MapFacType::m_y]->const_array(mfi);
810  if (SolverChoice::mesh_type == MeshType::ConstantDz) {
811  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
812  {
813  cons_arr(i,j,k,n) *= (mfx_arr(i,j,0)*mfy_arr(i,j,0));
814  });
815  } else {
816  const Array4<const Real> detJ_arr = detJ_cc[lev]->const_array(mfi);
817  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
818  {
819  cons_arr(i,j,k,n) *= (mfx_arr(i,j,0)*mfy_arr(i,j,0)) / detJ_arr(i,j,k);
820  });
821  }
822  } // mfi
823 
824  // We need to do this before anything else because refluxing changes the
825  // values of coarse cells underneath fine grids with the assumption they'll
826  // be over-written by averaging down
827  int src_comp;
828  if (solverChoice.anelastic[lev]) {
829  src_comp = 1;
830  } else {
831  src_comp = 0;
832  }
833  int num_comp = ncomp - src_comp;
834  AverageDownTo(lev,src_comp,num_comp);
835  }
836  }
837 
838  if (is_it_time_for_action(nstep, time, dt_lev0, sum_interval, sum_per)) {
841  sum_energy_quantities(time);
842  }
843 
844  if (solverChoice.pert_type == PerturbationType::Source ||
845  solverChoice.pert_type == PerturbationType::Direct ||
846  solverChoice.pert_type == PerturbationType::CPM) {
847  if (is_it_time_for_action(nstep, time, dt_lev0, pert_interval, -1.)) {
848  turbPert.debug(time);
849  }
850  }
851 
852  if (profile_int > 0 && (nstep+1) % profile_int == 0) {
853  if (destag_profiles) {
854  // all variables cell-centered
855  write_1D_profiles(time);
856  } else {
857  // some variables staggered
859  }
860  }
861 
862  if (solverChoice.rad_type != RadiationType::None)
863  {
864  if ( rad_datalog_int > 0 &&
865  (((nstep+1) % rad_datalog_int == 0) || (nstep==0)) ) {
866  if (rad[0]->hasDatalog()) {
867  rad[0]->WriteDataLog(time+start_time);
868  }
869  }
870  }
871 
872  if (output_1d_column) {
873 #ifdef ERF_USE_NETCDF
874  if (is_it_time_for_action(nstep, time, dt_lev0, column_interval, column_per))
875  {
876  int lev_column = 0;
877  for (int lev = finest_level; lev >= 0; lev--)
878  {
879  Real dx_lev = geom[lev].CellSize(0);
880  Real dy_lev = geom[lev].CellSize(1);
881  int i_lev = static_cast<int>(std::floor(column_loc_x / dx_lev));
882  int j_lev = static_cast<int>(std::floor(column_loc_y / dy_lev));
883  if (grids[lev].contains(IntVect(i_lev,j_lev,0))) lev_column = lev;
884  }
885  writeToNCColumnFile(lev_column, column_file_name, column_loc_x, column_loc_y, time);
886  }
887 #else
888  Abort("To output 1D column files ERF must be compiled with NetCDF");
889 #endif
890  }
891 
893  {
896  {
897  bool is_moist = (micro->Get_Qstate_Moist_Size() > 0);
898  m_w2d->write_planes(istep[0], time+start_time, vars_new, is_moist);
899  }
900  }
901 
902  // Write plane/line sampler data
904  line_sampler->get_sample_data(geom, vars_new);
905  line_sampler->write_sample_data(t_new, istep, ref_ratio, geom);
906  }
908  plane_sampler->get_sample_data(geom, vars_new);
909  plane_sampler->write_sample_data(t_new, istep, ref_ratio, geom);
910  }
911 
912  // Moving terrain
913  if ( solverChoice.terrain_type == TerrainType::MovingFittedMesh )
914  {
915  for (int lev = finest_level; lev >= 0; lev--)
916  {
917  // Copy z_phs_nd and detJ_cc at end of timestep
918  MultiFab::Copy(*z_phys_nd[lev], *z_phys_nd_new[lev], 0, 0, 1, z_phys_nd[lev]->nGrowVect());
919  MultiFab::Copy( *detJ_cc[lev], *detJ_cc_new[lev], 0, 0, 1, detJ_cc[lev]->nGrowVect());
920  MultiFab::Copy(base_state[lev],base_state_new[lev],0,0,BaseState::num_comps,base_state[lev].nGrowVect());
921 
922  make_zcc(geom[lev],*z_phys_nd[lev],*z_phys_cc[lev]);
923  }
924  }
925 
926  if ( solverChoice.io_hurricane_eye_tracker and (nstep == 0 or (nstep+1)%m_plot3d_int_1 == 0) )
927  {
928  int levc=finest_level;
929 
930  HurricaneEyeTracker(geom[levc],
931  vars_new[levc],
939 
940  MultiFab& U_new = vars_new[levc][Vars::xvel];
941  MultiFab& V_new = vars_new[levc][Vars::yvel];
942  MultiFab& W_new = vars_new[levc][Vars::zvel];
943 
944  MultiFab mf_cc_vel(grids[levc], dmap[levc], AMREX_SPACEDIM, IntVect(0,0,0));
945  average_face_to_cellcenter(mf_cc_vel,0,{AMREX_D_DECL(&U_new,&V_new,&W_new)},0);
946 
947  HurricaneMaxVelTracker(geom[levc],
948  mf_cc_vel,
949  t_new[0],
952 
954  geom[levc],
955  vars_new[levc][Vars::cons],
956  t_new[0],
959 
960  std::string filename_tracker = MakeVTKFilename_TrackerCircle(nstep);
961  std::string filename_xy = MakeVTKFilename_EyeTracker_xy(nstep);
962  std::string filename_latlon = MakeFilename_EyeTracker_latlon(nstep);
963  std::string filename_maxvel = MakeFilename_EyeTracker_maxvel(nstep);
964  std::string filename_minpressure = MakeFilename_EyeTracker_minpressure(nstep);
965 
966  if (ParallelDescriptor::IOProcessor()) {
967  WriteVTKPolyline(filename_tracker, hurricane_tracker_circle);
969  WriteLinePlot(filename_latlon, hurricane_eye_track_latlon);
970  WriteLinePlot(filename_maxvel, hurricane_maxvel_vs_time);
971  WriteLinePlot(filename_minpressure, hurricane_minpressure_vs_time);
972  }
973  }
974 } // 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:627
std::string MakeFilename_EyeTracker_maxvel(int nstep)
Definition: ERF_TrackerOutput.cpp:66
static amrex::Real column_loc_y
Definition: ERF.H:1271
amrex::Vector< std::array< amrex::Real, 2 > > hurricane_tracker_circle
Definition: ERF.H:161
amrex::Vector< std::array< amrex::Real, 2 > > hurricane_maxvel_vs_time
Definition: ERF.H:159
static std::string column_file_name
Definition: ERF.H:1272
AMREX_FORCE_INLINE amrex::YAFluxRegister * getAdvFluxReg(int lev)
Definition: ERF.H:1412
amrex::Vector< std::array< amrex::Real, 2 > > hurricane_minpressure_vs_time
Definition: ERF.H:160
static amrex::Real bndry_output_planes_per
Definition: ERF.H:1277
static amrex::Real column_per
Definition: ERF.H:1269
static amrex::Real column_loc_x
Definition: ERF.H:1270
amrex::Vector< std::array< amrex::Real, 2 > > hurricane_eye_track_latlon
Definition: ERF.H:158
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:1276
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:1267
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:1268
amrex::Real hurricane_eye_latitude
Definition: ERF_DataStruct.H:1246
amrex::Real hurricane_eye_longitude
Definition: ERF_DataStruct.H:1246
bool io_hurricane_eye_tracker
Definition: ERF_DataStruct.H:1245
Here is the call 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 0.

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 0.

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) = Real(0.0);
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, 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, 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],-1.0/l_dt,fluxes[0][0],0,0,1,0);
732  MultiFab::Saxpy(gradp[lev][GpVars::gpy],-1.0/l_dt,fluxes[0][1],0,0,1,0);
733  MultiFab::Saxpy(gradp[lev][GpVars::gpz],-1.0/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)) > 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], 1.0/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:412
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:462
static bool use_fft
Definition: ERF.H:1208
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], 1.0, phi[0],0,0,1,0);
194 
195  // Subtract grad(phi) from the velocity components
196  Real beta = 1.0;
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],-1.0/l_dt,fluxes[0][0],0,0,1,0);
215  MultiFab::Saxpy(gradp[lev][GpVars::gpy],-1.0/l_dt,fluxes[0][1],0,0,1,0);
216  MultiFab::Saxpy(gradp[lev][GpVars::gpz],-1.0/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 = 1.0;
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:338
Here is the call graph for this function:

◆ ReadCheckpointFile()

void ERF::ReadCheckpointFile ( )

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

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

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

◆ ReadParameters()

void ERF::ReadParameters ( )
private
2295 {
2296  std::string prob_name = "Unknown";
2297  ParmParse pp_pn("erf"); pp_pn.queryAdd("prob_name", prob_name);
2298  Print() << "Problem name (from inputs file) is " << prob_name << std::endl;
2299 
2300  ParmParse pp(pp_prefix);
2301  ParmParse pp_amr("amr");
2302  {
2303  pp.query("regrid_level_0_on_restart", regrid_level_0_on_restart);
2304  pp.query("regrid_int", regrid_int);
2305  pp.query("check_file", check_file);
2306 
2307  // The regression tests use "amr.restart" and "amr.m_check_int" so we allow
2308  // for those or "erf.restart" / "erf.m_check_int" with the former taking
2309  // precedence if both are specified
2310  pp.query("check_int", m_check_int);
2311  pp.query("check_per", m_check_per);
2312  pp_amr.query("check_int", m_check_int);
2313  pp_amr.query("check_per", m_check_per);
2314 
2315  pp.query("restart", restart_chkfile);
2316  pp_amr.query("restart", restart_chkfile);
2317 
2318  // Verbosity
2319  pp.query("v", verbose);
2320  pp.query("mg_v", mg_verbose);
2321  pp.query("use_fft", use_fft);
2322 #ifndef ERF_USE_FFT
2323  if (use_fft) {
2324  Abort("You must build with USE_FFT in order to set use_fft = true in your inputs file");
2325  }
2326 #endif
2327 
2328  // Check for NaNs?
2329  pp.query("check_for_nans", check_for_nans);
2330 
2331  // Frequency of diagnostic output
2332  pp.query("sum_interval", sum_interval);
2333  pp.query("sum_period" , sum_per);
2334 
2335  pp.query("pert_interval", pert_interval);
2336 
2337  // Time step controls
2338  pp.query("cfl", cfl);
2339  pp.query("substepping_cfl", sub_cfl);
2340  pp.query("init_shrink", init_shrink);
2341  pp.query("change_max", change_max);
2342  pp.query("dt_max_initial", dt_max_initial);
2343  pp.query("dt_max", dt_max);
2344 
2345  fixed_dt.resize(max_level+1,-1.);
2346  fixed_fast_dt.resize(max_level+1,-1.);
2347 
2348  pp.query("fixed_dt", fixed_dt[0]);
2349  pp.query("fixed_fast_dt", fixed_fast_dt[0]);
2350 
2351  int nlevs_max = max_level + 1;
2352  istep.resize(nlevs_max, 0);
2353  nsubsteps.resize(nlevs_max, 1);
2354  // This is the default
2355  for (int lev = 1; lev <= max_level; ++lev) {
2356  nsubsteps[lev] = MaxRefRatio(lev-1);
2357  }
2358 
2359  if (max_level > 0) {
2360  ParmParse pp_erf("erf");
2361  int count = pp_erf.countval("dt_ref_ratio");
2362  if (count > 0) {
2363  Vector<int> nsub;
2364  nsub.resize(nlevs_max, 0);
2365  if (count == 1) {
2366  pp_erf.queryarr("dt_ref_ratio", nsub, 0, 1);
2367  for (int lev = 1; lev <= max_level; ++lev) {
2368  nsubsteps[lev] = nsub[0];
2369  }
2370  } else {
2371  pp_erf.queryarr("dt_ref_ratio", nsub, 0, max_level);
2372  for (int lev = 1; lev <= max_level; ++lev) {
2373  nsubsteps[lev] = nsub[lev-1];
2374  }
2375  }
2376  }
2377  }
2378 
2379  // Make sure we do this after we have defined nsubsteps above
2380  for (int lev = 1; lev <= max_level; lev++)
2381  {
2382  fixed_dt[lev] = fixed_dt[lev-1] / static_cast<Real>(nsubsteps[lev]);
2383  fixed_fast_dt[lev] = fixed_fast_dt[lev-1] / static_cast<Real>(nsubsteps[lev]);
2384  }
2385 
2386  pp.query("fixed_mri_dt_ratio", fixed_mri_dt_ratio);
2387 
2388  // We use this to keep track of how many boxes we read in from WRF initialization
2389  num_files_at_level.resize(max_level+1,0);
2390 
2391  // We use this to keep track of how many boxes are specified thru the refinement indicators
2392  num_boxes_at_level.resize(max_level+1,0);
2393  boxes_at_level.resize(max_level+1);
2394 
2395  // We always have exactly one file at level 0
2396  num_boxes_at_level[0] = 1;
2397  boxes_at_level[0].resize(1);
2398  boxes_at_level[0][0] = geom[0].Domain();
2399 
2400 #ifdef ERF_USE_NETCDF
2401  nc_init_file.resize(max_level+1);
2402  have_read_nc_init_file.resize(max_level+1);
2403 
2404  // NetCDF wrfinput initialization files -- possibly multiple files at each of multiple levels
2405  // but we always have exactly one file at level 0
2406  for (int lev = 0; lev <= max_level; lev++) {
2407  const std::string nc_file_names = Concatenate("nc_init_file_",lev,1);
2408  if (pp.contains(nc_file_names.c_str())) {
2409  int num_files = pp.countval(nc_file_names.c_str());
2410  num_files_at_level[lev] = num_files;
2411  nc_init_file[lev].resize(num_files);
2412  have_read_nc_init_file[lev].resize(num_files);
2413  pp.queryarr(nc_file_names.c_str(), nc_init_file[lev],0,num_files);
2414  for (int j = 0; j < num_files; j++) {
2415  Print() << "Reading NC init file names at level " << lev << " and index " << j << " : " << nc_init_file[lev][j] << std::endl;
2416  have_read_nc_init_file[lev][j] = 0;
2417  } // j
2418  } // if pp.contains
2419  } // lev
2420 
2421  // NetCDF wrfbdy lateral boundary file
2422  if (pp.query("nc_bdy_file", nc_bdy_file)) {
2423  Print() << "Reading NC bdy file name " << nc_bdy_file << std::endl;
2424  }
2425 
2426  // NetCDF wrflow lateral boundary file
2427  if (pp.query("nc_low_file", nc_low_file)) {
2428  Print() << "Reading NC low file name " << nc_low_file << std::endl;
2429  }
2430 
2431 #endif
2432 
2433  // Options for vertical interpolation of met_em*.nc data.
2434  pp.query("metgrid_debug_quiescent", metgrid_debug_quiescent);
2435  pp.query("metgrid_debug_isothermal", metgrid_debug_isothermal);
2436  pp.query("metgrid_debug_dry", metgrid_debug_dry);
2437  pp.query("metgrid_debug_psfc", metgrid_debug_psfc);
2438  pp.query("metgrid_debug_msf", metgrid_debug_msf);
2439  pp.query("metgrid_interp_theta", metgrid_interp_theta);
2440  pp.query("metgrid_basic_linear", metgrid_basic_linear);
2441  pp.query("metgrid_use_below_sfc", metgrid_use_below_sfc);
2442  pp.query("metgrid_use_sfc", metgrid_use_sfc);
2443  pp.query("metgrid_retain_sfc", metgrid_retain_sfc);
2444  pp.query("metgrid_proximity", metgrid_proximity);
2445  pp.query("metgrid_order", metgrid_order);
2446  pp.query("metgrid_force_sfc_k", metgrid_force_sfc_k);
2447 
2448  // Set default to FullState for now ... later we will try Perturbation
2449  interpolation_type = StateInterpType::FullState;
2450  pp.query_enum_case_insensitive("interpolation_type" ,interpolation_type);
2451 
2452  PlotFileType plotfile3d_type_temp = PlotFileType::None;
2453  pp.query_enum_case_insensitive("plotfile_type" ,plotfile3d_type_temp);
2454  pp.query_enum_case_insensitive("plotfile_type_1",plotfile3d_type_1);
2455  pp.query_enum_case_insensitive("plotfile_type_2",plotfile3d_type_2);
2456 
2457  PlotFileType plotfile2d_type_temp = PlotFileType::None;
2458  pp.query_enum_case_insensitive("plotfile2d_type" ,plotfile2d_type_temp);
2459  pp.query_enum_case_insensitive("plotfile2d_type_1",plotfile2d_type_1);
2460  pp.query_enum_case_insensitive("plotfile2d_type_2",plotfile2d_type_2);
2461  //
2462  // This option is for backward consistency -- if only plotfile_type is set,
2463  // then it will be used for both 1 and 2 if and only if they are not set
2464  //
2465  // Default is native amrex if no type is specified
2466  //
2467  if (plotfile3d_type_temp == PlotFileType::None) {
2468  if (plotfile3d_type_1 == PlotFileType::None) {
2469  plotfile3d_type_1 = PlotFileType::Amrex;
2470  }
2471  if (plotfile3d_type_2 == PlotFileType::None) {
2472  plotfile3d_type_2 = PlotFileType::Amrex;
2473  }
2474  } else {
2475  if (plotfile3d_type_1 == PlotFileType::None) {
2476  plotfile3d_type_1 = plotfile3d_type_temp;
2477  } else {
2478  Abort("You must set either plotfile_type or plotfile_type_1, not both");
2479  }
2480  if (plotfile3d_type_2 == PlotFileType::None) {
2481  plotfile3d_type_2 = plotfile3d_type_temp;
2482  } else {
2483  Abort("You must set either plotfile_type or plotfile_type_2, not both");
2484  }
2485  }
2486  if (plotfile2d_type_temp == PlotFileType::None) {
2487  if (plotfile2d_type_1 == PlotFileType::None) {
2488  plotfile2d_type_1 = PlotFileType::Amrex;
2489  }
2490  if (plotfile2d_type_2 == PlotFileType::None) {
2491  plotfile2d_type_2 = PlotFileType::Amrex;
2492  }
2493  } else {
2494  if (plotfile2d_type_1 == PlotFileType::None) {
2495  plotfile2d_type_1 = plotfile2d_type_temp;
2496  } else {
2497  Abort("You must set either plotfile2d_type or plotfile2d_type_1, not both");
2498  }
2499  if (plotfile2d_type_2 == PlotFileType::None) {
2500  plotfile2d_type_2 = plotfile2d_type_temp;
2501  } else {
2502  Abort("You must set either plotfile2d_type or plotfile2d_type_2, not both");
2503  }
2504  }
2505 #ifndef ERF_USE_NETCDF
2506  if (plotfile3d_type_1 == PlotFileType::Netcdf ||
2507  plotfile3d_type_2 == PlotFileType::Netcdf ||
2508  plotfile2d_type_1 == PlotFileType::Netcdf ||
2509  plotfile2d_type_2 == PlotFileType::Netcdf) {
2510  Abort("Plotfile type = Netcdf is not allowed without USE_NETCDF = TRUE");
2511  }
2512 #endif
2513 
2514  pp.query("plot_file_1" , plot3d_file_1);
2515  pp.query("plot_file_2" , plot3d_file_2);
2516  pp.query("plot2d_file_1", plot2d_file_1);
2517  pp.query("plot2d_file_2", plot2d_file_2);
2518 
2519  pp.query("plot_int_1" , m_plot3d_int_1);
2520  pp.query("plot_int_2" , m_plot3d_int_2);
2521  pp.query("plot_per_1" , m_plot3d_per_1);
2522  pp.query("plot_per_2" , m_plot3d_per_2);
2523 
2524  pp.query("plot2d_int_1" , m_plot2d_int_1);
2525  pp.query("plot2d_int_2" , m_plot2d_int_2);
2526  pp.query("plot2d_per_1", m_plot2d_per_1);
2527  pp.query("plot2d_per_2", m_plot2d_per_2);
2528 
2529  pp.query("subvol_file", subvol_file);
2530 
2531  // Should we use format like plt1970-01-01_00:00:00.000000 (if true) or plt00001 (if false)
2532  pp.query("use_real_time_in_pltname", use_real_time_in_pltname);
2533 
2534  // If use_real_time_in_pltname is false, how many digits should we use for the timestep?
2535  pp.query("file_name_digits", file_name_digits);
2536 
2537  // Default if subvol_int not specified
2538  m_subvol_int.resize(1); m_subvol_int[0] = -1;
2539  m_subvol_per.resize(1); m_subvol_per[0] = -1.0;
2540  last_subvol_step.resize(1);
2541  last_subvol_time.resize(1);
2542 
2543  int nsi = pp.countval("subvol_int");
2544  int nsr = pp.countval("subvol_per");
2545 
2546  // We must specify only subvol_int OR subvol_per
2547  AMREX_ALWAYS_ASSERT (!(nsi > 0 && nsr > 0));
2548 
2549  int nsub = -1;
2550  if (nsi > 0 || nsr > 0) {
2551  ParmParse pp_sv("erf.subvol");
2552  int n1 = pp_sv.countval("origin"); int n2 = pp_sv.countval("nxnynz"); int n3 = pp_sv.countval("dxdydz");
2553  if (n1 != n2 || n1 != n3 || n2 != n3) {
2554  Abort("WriteSubvolume: must have same number of entries in origin, nxnynz, and dxdydz.");
2555  }
2556  if ( n1%AMREX_SPACEDIM != 0) {
2557  Abort("WriteSubvolume: origin, nxnynz, and dxdydz must have multiples of AMReX_SPACEDIM");
2558  }
2559  nsub = n1/AMREX_SPACEDIM;
2560  m_subvol_int.resize(nsub);
2561  last_subvol_step.resize(nsub);
2562  last_subvol_time.resize(nsub);
2563  m_subvol_int.resize(nsub);
2564  m_subvol_per.resize(nsub);
2565  }
2566 
2567  if (nsi > 0) {
2568  for (int i = 1; i < nsub; i++) m_subvol_per[i] = -1.0;
2569  if ( nsi == 1) {
2570  m_subvol_int[0] = -1;
2571  pp.get("subvol_int" , m_subvol_int[0]);
2572  } else if ( nsi == nsub) {
2573  pp.getarr("subvol_int" , m_subvol_int);
2574  } else {
2575  Abort("There must either be a single value of subvol_int or one for every subdomain");
2576  }
2577  }
2578 
2579  if (nsr > 0) {
2580  for (int i = 1; i < nsub; i++) m_subvol_int[i] = -1.0;
2581  if ( nsr == 1) {
2582  m_subvol_per[0] = -1.0;
2583  pp.get("subvol_per" , m_subvol_per[0]);
2584  } else if ( nsr == nsub) {
2585  pp.getarr("subvol_per" , m_subvol_per);
2586  } else {
2587  Abort("There must either be a single value of subvol_per or one for every subdomain");
2588  }
2589  }
2590 
2591  setSubVolVariables("subvol_sampling_vars",subvol3d_var_names);
2592 
2593  pp.query("expand_plotvars_to_unif_rr",m_expand_plotvars_to_unif_rr);
2594 
2595  pp.query("plot_face_vels",m_plot_face_vels);
2596 
2597  if ( (m_plot3d_int_1 > 0 && m_plot3d_per_1 > 0) ||
2598  (m_plot3d_int_2 > 0 && m_plot3d_per_2 > 0.) ) {
2599  Abort("Must choose only one of plot_int or plot_per");
2600  }
2601  if ( (m_plot2d_int_1 > 0 && m_plot2d_per_1 > 0) ||
2602  (m_plot2d_int_2 > 0 && m_plot2d_per_2 > 0.) ) {
2603  Abort("Must choose only one of plot_int or plot_per");
2604  }
2605 
2606  pp.query("profile_int", profile_int);
2607  pp.query("destag_profiles", destag_profiles);
2608 
2609  pp.query("plot_lsm", plot_lsm);
2610 #ifdef ERF_USE_RRTMGP
2611  pp.query("plot_rad", plot_rad);
2612 #endif
2613  pp.query("profile_rad_int", rad_datalog_int);
2614 
2615  pp.query("output_1d_column", output_1d_column);
2616  pp.query("column_per", column_per);
2617  pp.query("column_interval", column_interval);
2618  pp.query("column_loc_x", column_loc_x);
2619  pp.query("column_loc_y", column_loc_y);
2620  pp.query("column_file_name", column_file_name);
2621 
2622  // Sampler output frequency
2623  pp.query("line_sampling_per", line_sampling_per);
2624  pp.query("line_sampling_interval", line_sampling_interval);
2625  pp.query("plane_sampling_per", plane_sampling_per);
2626  pp.query("plane_sampling_interval", plane_sampling_interval);
2627 
2628  // Specify information about outputting planes of data
2629  pp.query("output_bndry_planes", output_bndry_planes);
2630  pp.query("bndry_output_planes_interval", bndry_output_planes_interval);
2631  pp.query("bndry_output_planes_per", bndry_output_planes_per);
2632  pp.query("bndry_output_start_time", bndry_output_planes_start_time);
2633 
2634  // Specify whether ingest boundary planes of data
2635  pp.query("input_bndry_planes", input_bndry_planes);
2636 
2637  // Query the total width for wrfbdy interior ghost cells
2638  pp.query("real_width", real_width);
2639 
2640  // If using real boundaries, do we extrapolate w (or set to 0)
2641  pp.query("real_extrap_w", real_extrap_w);
2642 
2643  // Query the set and total widths for crse-fine interior ghost cells
2644  pp.query("cf_width", cf_width);
2645  pp.query("cf_set_width", cf_set_width);
2646 
2647  // AmrMesh iterate on grids?
2648  bool iterate(true);
2649  pp_amr.query("iterate_grids",iterate);
2650  if (!iterate) SetIterateToFalse();
2651  }
2652 
2653 #ifdef ERF_USE_PARTICLES
2654  readTracersParams();
2655 #endif
2656 
2657  solverChoice.init_params(max_level,pp_prefix);
2658 
2659  {
2660  ParmParse pp_no_prefix; // Traditionally, max_step and stop_time do not have prefix.
2661  pp_no_prefix.query("max_step", max_step);
2662  if (max_step < 0) {
2663  max_step = std::numeric_limits<int>::max();
2664  }
2665 
2666  std::string start_datetime, stop_datetime;
2667  if (pp_no_prefix.query("start_datetime", start_datetime)) {
2668  if (start_datetime.length() == 16) { // YYYY-MM-DD HH:MM
2669  start_datetime += ":00"; // add seconds
2670  }
2671  if (start_datetime.length() != 19) {
2672  Print() << "Got start_datetime = \"" << start_datetime
2673  << "\", format should be " << datetime_format << std::endl;
2674  exit(0);
2675  }
2676  start_time = getEpochTime(start_datetime, datetime_format);
2677 
2678 #ifdef ERF_USE_NETCDF
2679  if (solverChoice.init_type == InitType::WRFInput) {
2680  // This is the start time as written in the wrfinput file
2681  Real start_time_from_wrfinput = read_start_time_from_wrfinput(0, nc_init_file[0][0]);
2682  if (start_time != start_time_from_wrfinput) {
2683  amrex::Print() << "start_datetime from inputs file = " << start_time <<
2684  " does not match SIMULATION START DATE from wrfinput = " <<
2685  start_time_from_wrfinput << std::endl;
2686  amrex::Abort();
2687  }
2688  } else if (solverChoice.init_type == InitType::Metgrid) {
2689  // This is the start time as written in the metgrid file
2690  Real start_time_from_metgrid = read_start_time_from_metgrid(0, nc_init_file[0][0]);
2691  if (start_time != start_time_from_metgrid) {
2692  amrex::Print() << "start_datetime from inputs file = " << start_time <<
2693  " does not match SIMULATION START DATE from metgrid = " <<
2694  start_time_from_metgrid << std::endl;
2695  amrex::Abort();
2696  }
2697  }
2698 #endif
2699  Print() << "Start datetime : " << start_datetime << std::endl;
2700 
2701  use_datetime = true;
2702 
2703  } else {
2704 
2705 #ifdef ERF_USE_NETCDF
2706  if (solverChoice.init_type == InitType::WRFInput) {
2707  // This is the start time as written in the wrfinput file
2708  Real start_time_from_wrfinput = read_start_time_from_wrfinput(0, nc_init_file[0][0]);
2709  start_time = start_time_from_wrfinput;
2710 
2711  use_datetime = true;
2712 
2713  if (pp_no_prefix.query("start_time", start_time)) {
2714  amrex::Print() << "start_time should not be set from inputs file; we are reading SIMULATION START DATE from wrfinput" << std::endl;
2715  amrex::Abort();
2716  }
2717  } else if (solverChoice.init_type == InitType::Metgrid) {
2718  // This is the start time as written in the metgrid file
2719  Real start_time_from_metgrid = read_start_time_from_metgrid(0, nc_init_file[0][0]);
2720  start_time = start_time_from_metgrid;
2721 
2722  use_datetime = true;
2723 
2724  if (pp_no_prefix.query("start_time", start_time)) {
2725  amrex::Print() << "start_time should not be set from inputs file; we are reading SIMULATION START DATE from metgrid" << std::endl;
2726  amrex::Abort();
2727  }
2728  }
2729 #endif
2730  }
2731 
2732  if (pp_no_prefix.query("stop_datetime", stop_datetime)) {
2733  if (stop_datetime.length() == 16) { // YYYY-MM-DD HH:MM
2734  stop_datetime += ":00"; // add seconds
2735  }
2736  if (stop_datetime.length() != 19) {
2737  Print() << "Got stop_datetime = \"" << stop_datetime
2738  << "\", format should be " << datetime_format << std::endl;
2739  exit(0);
2740  }
2741 
2742  stop_time = getEpochTime(stop_datetime, datetime_format);
2743  Print() << "Stop datetime : " << start_datetime << std::endl;
2744 
2745  } else {
2746 
2747  if (pp_no_prefix.query("stop_time", stop_time)) {
2748  Print() << "Maximum simulation length based on stop_time: " << stop_time << " s (elapsed) " << std::endl;
2749  amrex::Print() <<" Adding stop time " << stop_time << " to start_time " << start_time << std::endl;
2750  stop_time += start_time;
2751  }
2752  }
2753  }
2754 
2755 #ifndef ERF_USE_NETCDF
2756  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(( (solverChoice.init_type != InitType::WRFInput) &&
2757  (solverChoice.init_type != InitType::Metgrid ) &&
2758  (solverChoice.init_type != InitType::NCFile ) ),
2759  "init_type cannot be 'WRFInput', 'Metgrid' or 'NCFile' if we don't build with netcdf!");
2760 #endif
2761 
2762  // Query the canopy model file name
2763  std::string forestfile;
2764  solverChoice.do_forest_drag = pp.query("forest_file", forestfile);
2766  for (int lev = 0; lev <= max_level; ++lev) {
2767  m_forest_drag[lev] = std::make_unique<ForestDrag>(forestfile);
2768  }
2769  }
2770 
2771  // If init from WRFInput or Metgrid make sure a valid file name is present at level 0.
2772  // We allow for the possibility that finer levels may use native refinement rather than reading from a file
2773  if ((solverChoice.init_type == InitType::WRFInput) ||
2774  (solverChoice.init_type == InitType::Metgrid) ||
2775  (solverChoice.init_type == InitType::NCFile) ) {
2776  int num_files = nc_init_file[0].size();
2777  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(num_files>0, "A file name must be present at level 0 for init type WRFInput, Metgrid or NCFile.");
2778  for (int j = 0; j < num_files; j++) {
2779  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.");
2780  } //j
2781  } // InitType
2782 
2783  // What type of land surface model to use
2784  // NOTE: Must be checked after init_params
2785  if (solverChoice.lsm_type == LandSurfaceType::SLM) {
2786  lsm.SetModel<SLM>();
2787  Print() << "SLM land surface model!\n";
2788  } else if (solverChoice.lsm_type == LandSurfaceType::MM5) {
2789  lsm.SetModel<MM5>();
2790  Print() << "MM5 land surface model!\n";
2791 #ifdef ERF_USE_NOAHMP
2792  } else if (solverChoice.lsm_type == LandSurfaceType::NOAHMP) {
2793  lsm.SetModel<NOAHMP>();
2794  Print() << "Noah-MP land surface model!\n";
2795 #endif
2796  } else if (solverChoice.lsm_type == LandSurfaceType::None) {
2797  lsm.SetModel<NullSurf>();
2798  Print() << "Null land surface model!\n";
2799  } else {
2800  Abort("Dont know this LandSurfaceType!") ;
2801  }
2802 
2803  if (verbose > 0) {
2804  solverChoice.display(max_level,pp_prefix);
2805  }
2806 
2808 }
AMREX_GPU_HOST AMREX_FORCE_INLINE std::time_t getEpochTime(const std::string &dateTime, const std::string &dateTimeFormat)
Definition: ERF_EpochTime.H:15
bool metgrid_basic_linear
Definition: ERF.H:1250
bool metgrid_debug_msf
Definition: ERF.H:1248
std::string plot2d_file_2
Definition: ERF.H:1074
std::string plot3d_file_1
Definition: ERF.H:1071
bool plot_rad
Definition: ERF.H:896
bool m_plot_face_vels
Definition: ERF.H:1089
std::string plot3d_file_2
Definition: ERF.H:1072
int regrid_int
Definition: ERF.H:1064
bool metgrid_retain_sfc
Definition: ERF.H:1253
int file_name_digits
Definition: ERF.H:1223
bool metgrid_use_sfc
Definition: ERF.H:1252
amrex::Vector< int > num_files_at_level
Definition: ERF.H:803
bool metgrid_debug_quiescent
Definition: ERF.H:1244
bool metgrid_interp_theta
Definition: ERF.H:1249
bool regrid_level_0_on_restart
Definition: ERF.H:1068
int metgrid_force_sfc_k
Definition: ERF.H:1256
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:1238
bool metgrid_use_below_sfc
Definition: ERF.H:1251
std::string subvol_file
Definition: ERF.H:1075
amrex::Real metgrid_proximity
Definition: ERF.H:1254
std::string plot2d_file_1
Definition: ERF.H:1073
bool metgrid_debug_dry
Definition: ERF.H:1246
bool metgrid_debug_isothermal
Definition: ERF.H:1245
bool use_real_time_in_pltname
Definition: ERF.H:1224
bool metgrid_debug_psfc
Definition: ERF.H:1247
void ParameterSanityChecks()
Definition: ERF.cpp:2812
bool m_expand_plotvars_to_unif_rr
Definition: ERF.H:1076
std::string check_file
Definition: ERF.H:1098
int metgrid_order
Definition: ERF.H:1255
bool plot_lsm
Definition: ERF.H:1091
void SetModel()
Definition: ERF_LandSurface.H:28
Definition: ERF_MM5.H:26
Definition: ERF_NOAHMP.H:53
Definition: ERF_NullSurf.H:8
Definition: ERF_SLM.H:26
void display(int max_level, std::string pp_prefix)
Definition: ERF_DataStruct.H:855
void init_params(int max_level, std::string pp_prefix)
Definition: ERF_DataStruct.H:132
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.

1077 {
1078  Print() << "Reading vels only from native checkpoint " << chkfile_for_vels << " at level " << lev_to_fill << "\n";
1079 
1080  // Header
1081  std::string File(chkfile_for_vels + "/Header");
1082 
1083  VisMF::IO_Buffer io_buffer(VisMF::GetIOBufferSize());
1084 
1085  Vector<char> fileCharPtr;
1086  ParallelDescriptor::ReadAndBcastFile(File, fileCharPtr);
1087  std::string fileCharPtrString(fileCharPtr.dataPtr());
1088  std::istringstream is(fileCharPtrString, std::istringstream::in);
1089 
1090  AMREX_ALWAYS_ASSERT(lev_to_fill >= 0 && lev_to_fill <= finest_level);
1091 
1092  int lev = lev_to_fill;
1093 
1094  MultiFab xvel(convert(grids[lev],IntVect(1,0,0)),dmap[lev],1,0);
1095  VisMF::Read(xvel, MultiFabFileFullPrefix(lev, chkfile_for_vels, "Level_", "XFace"));
1096  MultiFab::Copy(vars_new[lev][Vars::xvel],xvel,0,0,1,0);
1097  vars_new[lev][Vars::xvel].setBndry(1.0e34);
1098 
1099  MultiFab yvel(convert(grids[lev],IntVect(0,1,0)),dmap[lev],1,0);
1100  VisMF::Read(yvel, MultiFabFileFullPrefix(lev, chkfile_for_vels, "Level_", "YFace"));
1101  MultiFab::Copy(vars_new[lev][Vars::yvel],yvel,0,0,1,0);
1102  vars_new[lev][Vars::yvel].setBndry(1.0e34);
1103 
1104  MultiFab zvel(convert(grids[lev],IntVect(0,0,1)),dmap[lev],1,0);
1105  VisMF::Read(zvel, MultiFabFileFullPrefix(lev, chkfile_for_vels, "Level_", "ZFace"));
1106  MultiFab::Copy(vars_new[lev][Vars::zvel],zvel,0,0,1,0);
1107  vars_new[lev][Vars::zvel].setBndry(1.0e34);
1108 }
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

364 {
365  if (max_level > 0)
366  {
367  ParmParse pp(pp_prefix);
368  Vector<std::string> refinement_indicators;
369  pp.queryarr("refinement_indicators",refinement_indicators,0,pp.countval("refinement_indicators"));
370 
371  for (int i=0; i<refinement_indicators.size(); ++i)
372  {
373  std::string ref_prefix = pp_prefix + "." + refinement_indicators[i];
374 
375  ParmParse ppr(ref_prefix);
376  RealBox realbox;
377  int lev_for_box;
378 
379  int num_real_lo = ppr.countval("in_box_lo");
380  int num_indx_lo = ppr.countval("in_box_lo_indices");
381  int num_indx_lo_crse = ppr.countval("in_box_lo_indices_crse");
382 
383  int num_real_hi = ppr.countval("in_box_hi");
384  int num_indx_hi = ppr.countval("in_box_hi_indices");
385  int num_indx_hi_crse = ppr.countval("in_box_hi_indices_crse");
386 
387  AMREX_ALWAYS_ASSERT( (num_real_lo == num_real_hi) && (num_real_lo == 0 || num_real_lo >= 2) );
388  AMREX_ALWAYS_ASSERT( (num_indx_lo == num_indx_hi) && (num_indx_lo == 0 || num_indx_lo >= 2) );
389  AMREX_ALWAYS_ASSERT( (num_indx_lo_crse == num_indx_hi_crse) && (num_indx_lo_crse == 0 || num_indx_lo_crse >= 2) );
390 
391  // Problem low and high (in real not index space) are the same at all levels
392  const Real* plo = geom[0].ProbLo();
393  const Real* phi = geom[0].ProbHi();
394  if ( !((num_real_lo >= AMREX_SPACEDIM-1 && num_indx_lo == 0 && num_indx_lo_crse == 0) ||
395  (num_indx_lo >= AMREX_SPACEDIM-1 && num_real_lo == 0 && num_indx_lo_crse == 0) ||
396  (num_indx_lo == 0 && num_real_lo == 0 && num_indx_lo_crse == 0) ||
397  (num_indx_lo_crse >= AMREX_SPACEDIM-1 && num_real_lo == 0 && num_indx_lo == 0)
398  ) )
399  {
400  amrex::Abort("Must only specify box for refinement using real OR index space with fine/coarse grid indices");
401  }
402 
403  if (num_real_lo > 0) {
404  std::vector<Real> rbox_lo(3), rbox_hi(3);
405  lev_for_box = max_level;
406  ppr.query("max_level",lev_for_box);
407  if (lev_for_box > 0 && lev_for_box <= max_level)
408  {
409  if (n_error_buf[0] != IntVect::TheZeroVector()) {
410  amrex::Abort("Don't use n_error_buf > 0 when setting the box explicitly");
411  }
412 
413  ppr.getarr("in_box_lo",rbox_lo,0,num_real_lo);
414  ppr.getarr("in_box_hi",rbox_hi,0,num_real_hi);
415 
416  if (rbox_lo[0] < plo[0]) rbox_lo[0] = plo[0];
417  if (rbox_lo[1] < plo[1]) rbox_lo[1] = plo[1];
418  if (rbox_hi[0] > phi[0]) rbox_hi[0] = phi[0];
419  if (rbox_hi[1] > phi[1]) rbox_hi[1] = phi[1];
420  if (num_real_lo < AMREX_SPACEDIM) {
421  rbox_lo[2] = plo[2];
422  rbox_hi[2] = phi[2];
423  }
424 
425  const Box& domain = geom[lev_for_box].Domain();
426 
427  realbox = RealBox(&(rbox_lo[0]),&(rbox_hi[0]));
428 
429  Print() << "Realbox read in and intersected laterally with domain is " << realbox << std::endl;
430 
431  num_boxes_at_level[lev_for_box] += 1;
432 
433  int ilo, jlo, klo;
434  int ihi, jhi, khi;
435  const auto* dx = geom[lev_for_box].CellSize();
436  ilo = static_cast<int>((rbox_lo[0] - plo[0])/dx[0]);
437  jlo = static_cast<int>((rbox_lo[1] - plo[1])/dx[1]);
438  ihi = static_cast<int>((rbox_hi[0] - plo[0])/dx[0]-1);
439  jhi = static_cast<int>((rbox_hi[1] - plo[1])/dx[1]-1);
440  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
441  // Search for k indices corresponding to nominal grid
442  // AGL heights
443  klo = domain.smallEnd(2) - 1;
444  khi = domain.smallEnd(2) - 1;
445 
446  if (rbox_lo[2] <= zlevels_stag[lev_for_box][domain.smallEnd(2)])
447  {
448  klo = domain.smallEnd(2);
449  }
450  else
451  {
452  for (int k=domain.smallEnd(2); k<=domain.bigEnd(2)+1; ++k) {
453  if (zlevels_stag[lev_for_box][k] > rbox_lo[2]) {
454  klo = k-1;
455  break;
456  }
457  }
458  }
459  AMREX_ASSERT(klo >= domain.smallEnd(2));
460 
461  if (rbox_hi[2] >= zlevels_stag[lev_for_box][domain.bigEnd(2)+1])
462  {
463  khi = domain.bigEnd(2);
464  }
465  else
466  {
467  for (int k=klo+1; k<=domain.bigEnd(2)+1; ++k) {
468  if (zlevels_stag[lev_for_box][k] > rbox_hi[2]) {
469  khi = k-1;
470  break;
471  }
472  }
473  }
474  AMREX_ASSERT((khi <= domain.bigEnd(2)) && (khi > klo));
475 
476  // Need to update realbox because tagging is based on
477  // the initial _un_deformed grid
478  realbox = RealBox(plo[0]+ ilo *dx[0], plo[1]+ jlo *dx[1], plo[2]+ klo *dx[2],
479  plo[0]+(ihi+1)*dx[0], plo[1]+(jhi+1)*dx[1], plo[2]+(khi+1)*dx[2]);
480  } else {
481  klo = static_cast<int>((rbox_lo[2] - plo[2])/dx[2]);
482  khi = static_cast<int>((rbox_hi[2] - plo[2])/dx[2]-1);
483  }
484 
485  Box bx(IntVect(ilo,jlo,klo),IntVect(ihi,jhi,khi));
486  // Error check for each index
487  if(ilo%ref_ratio[lev_for_box-1][0] != 0){
488  amrex::Print()<< "Requested in_box_lo in x direction = " << rbox_lo[0] << " corresponds to ilo = " << ilo << std::endl;
489  amrex::Print() << "ilo = " << ilo << " is not divisible by ref_ratio in x direction = " << ref_ratio[lev_for_box-1][0] << std::endl;
490  amrex::Error("Adjust in_box_lo in x-direction to be divisible by ref_ratio and try again");
491  }
492  if((ihi+1)%ref_ratio[lev_for_box-1][0] != 0){
493  amrex::Print()<< "Requested in_box_hi in x direction = " << rbox_hi[0] << " corresponds to ihi+1 = " << ihi+1 << std::endl;
494  amrex::Print() << "ihi+1 = " << ihi+1 << " is not divisible by ref_ratio in x direction = " << ref_ratio[lev_for_box-1][0] << std::endl;
495  amrex::Error("Adjust in_box_hi in x-direction to be divisible by ref_ratio and try again");
496  }
497  if(jlo%ref_ratio[lev_for_box-1][1] != 0){
498  amrex::Print()<< "Requested in_box_lo in y direction = " << rbox_lo[1] << " corresponds to jlo = " << jlo << std::endl;
499  amrex::Print() << "jlo = " << jlo << " is not divisible by ref_ratio in y direction = " << ref_ratio[lev_for_box-1][1] << std::endl;
500  amrex::Error("Adjust in_box_lo in y-direction to be divisible by ref_ratio and try again");
501  }
502  if((jhi+1)%ref_ratio[lev_for_box-1][1] != 0){
503  amrex::Print()<< "Requested in_box_hi in y direction = " << rbox_hi[1] << " corresponds to jhi+1 = " << jhi+1 << std::endl;
504  amrex::Print() << "jhi+1 = " << jhi+1 << " is not divisible by ref_ratio in y direction = " << ref_ratio[lev_for_box-1][1] << std::endl;
505  amrex::Error("Adjust in_box_hi in y-direction to be divisible by ref_ratio and try again");
506  }
507  if(klo%ref_ratio[lev_for_box-1][2] != 0){
508  amrex::Print()<< "Requested in_box_lo in z direction = " << rbox_lo[2] << " corresponds to klo = " << klo << std::endl;
509  amrex::Print() << "klo = " << klo << " is not divisible by ref_ratio in z direction = " << ref_ratio[lev_for_box-1][2] << std::endl;
510  amrex::Error("Adjust in_box_lo in z-direction to be divisible by ref_ratio and try again");
511  }
512  if((khi+1)%ref_ratio[lev_for_box-1][2] != 0){
513  amrex::Print()<< "Requested in_box_hi in z direction = " << rbox_hi[2] << " corresponds to khi+1 = " << khi+1 << std::endl;
514  amrex::Print() << "khi+1 = " << khi+1 << " is not divisible by ref_ratio in z direction = " << ref_ratio[lev_for_box-1][2] << std::endl;
515  amrex::Error("Adjust in_box_hi in z-direction to be divisible by ref_ratio and try again");
516  }
517 
518  bool using_pbl = (solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::MYJ ||
519  solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::MYNN25 ||
520  solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::MYNNEDMF ||
521  solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::YSU ||
522  solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::MRF);
523 
524  if ( using_pbl && ( (rbox_lo[2] > plo[2]) || (rbox_hi[2] < phi[2]) ) ) {
525  amrex::Print() << "PBL models need refinement boxes that go from the bottom to the top of the domain for calculation of PBLH" << std::endl;
526  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;
527  amrex::Abort();
528  }
529 
530  boxes_at_level[lev_for_box].push_back(bx);
531  Print() << "Saving in 'boxes at level' as " << bx << std::endl;
532  } // lev
533 
534  if (solverChoice.init_type == InitType::WRFInput) {
535  if ( (num_files_at_level[lev_for_box] > 0) &&
536  (num_boxes_at_level[lev_for_box] != num_files_at_level[lev_for_box]) ) {
537  amrex::Error("Number of boxes doesn't match number of input files");
538 
539  }
540  }
541 
542  } else if (num_indx_lo > 0) {
543 
544  std::vector<int> box_lo(3), box_hi(3);
545  ppr.get("max_level",lev_for_box);
546  if (lev_for_box > 0 && lev_for_box <= max_level)
547  {
548  if (n_error_buf[0] != IntVect::TheZeroVector()) {
549  amrex::Abort("Don't use n_error_buf > 0 when setting the box explicitly");
550  }
551 
552  ppr.getarr("in_box_lo_indices",box_lo,0,num_indx_lo);
553  ppr.getarr("in_box_hi_indices",box_hi,0,num_indx_hi);
554 
555  if (num_indx_lo < AMREX_SPACEDIM) {
556  box_lo[2] = geom[lev_for_box].Domain().smallEnd(2);
557  box_hi[2] = geom[lev_for_box].Domain().bigEnd(2);
558  }
559 
560  Box bx(IntVect(box_lo[0],box_lo[1],box_lo[2]),IntVect(box_hi[0],box_hi[1],box_hi[2]));
561  const Box& domain = geom[lev_for_box].Domain();
562 
563  if (!domain.contains(bx)) {
564  amrex::Print() << "\n";
565  amrex::Print() << "Box specified is " << bx << std::endl;
566  amrex::Print() << "But domain at level is " << domain << std::endl;
567  amrex::Error("Specified box doesn't fit in the domain");
568  }
569 
570  const auto* dx = geom[lev_for_box].CellSize();
571  realbox = RealBox(plo[0]+ box_lo[0] *dx[0], plo[1]+ box_lo[1] *dx[1], plo[2]+ box_lo[2] *dx[2],
572  plo[0]+(box_hi[0]+1)*dx[0], plo[1]+(box_hi[1]+1)*dx[1], plo[2]+(box_hi[2]+1)*dx[2]);
573 
574  Print() << "Reading " << bx << " at level " << lev_for_box << std::endl;
575  num_boxes_at_level[lev_for_box] += 1;
576 
577  if(box_lo[0]%ref_ratio[lev_for_box-1][0] != 0){
578  amrex::Print()<< "Requested ilo in x-direction : " << box_lo[0] << std::endl;
579  amrex::Print() << "ilo = " << box_lo[0] << " is not divisible by ref_ratio in x direction = " <<
580  ref_ratio[lev_for_box-1][0] << std::endl;
581  amrex::Error("Adjust in_box_lo_indices in x-direction to be divisible by ref_ratio and try again");
582  }
583  if((box_hi[0]+1)%ref_ratio[lev_for_box-1][0] != 0){
584  amrex::Print()<< "Requested ihi in x-direction : " << box_hi[0] << std::endl;
585  amrex::Print() << "ihi+1 = " << box_hi[0]+1 << " is not divisible by ref_ratio in x direction = " <<
586  ref_ratio[lev_for_box-1][0] << std::endl;
587  amrex::Error("Adjust in_box_hi_indices in x-direction to be divisible by ref_ratio and try again");
588  }
589  if(box_lo[1]%ref_ratio[lev_for_box-1][1] != 0){
590  amrex::Print()<< "Requested jlo in y-direction : " << box_lo[1] << std::endl;
591  amrex::Print() << "jlo = " << box_lo[1] << " is not divisible by ref_ratio in y direction = " <<
592  ref_ratio[lev_for_box-1][1] << std::endl;
593  amrex::Error("Adjust in_box_lo_indices in y-direction to be divisible by ref_ratio and try again");
594  }
595  if((box_hi[1]+1)%ref_ratio[lev_for_box-1][1] != 0){
596  amrex::Print()<< "Requested jhi in y-direction : " << box_hi[1] << std::endl;
597  amrex::Print() << "jhi+1 = " << box_hi[1]+1 << " is not divisible by ref_ratio in y direction = " <<
598  ref_ratio[lev_for_box-1][1] << std::endl;
599  amrex::Error("Adjust in_box_hi_indices in y-direction to be divisible by ref_ratio and try again");
600  }
601  if(box_lo[2]%ref_ratio[lev_for_box-1][2] != 0){
602  amrex::Print()<< "Requested klo in z-direction : " << box_lo[2] << std::endl;
603  amrex::Print() << "klo = " << box_lo[2] << " is not divisible by ref_ratio in z direction = " <<
604  ref_ratio[lev_for_box-1][2] << std::endl;
605  amrex::Error("Adjust in_box_lo_indices in z-direction to be divisible by ref_ratio and try again");
606  }
607  if((box_hi[2]+1)%ref_ratio[lev_for_box-1][2] != 0){
608  amrex::Print()<< "Requested khi in z-direction : " << box_hi[2] << std::endl;
609  amrex::Print() << "khi+1 = " << box_hi[2]+1 << " is not divisible by ref_ratio in z direction = " <<
610  ref_ratio[lev_for_box-1][2] << std::endl;
611  amrex::Error("Adjust in_box_hi_indices in z-direction to be divisible by ref_ratio and try again");
612  }
613 
614  bool using_pbl = (solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::MYJ ||
615  solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::MYNN25 ||
616  solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::MYNNEDMF ||
617  solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::YSU ||
618  solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::MRF);
619 
620  if ( using_pbl && ( (box_lo[2] > 0) || (box_hi[2] < domain.bigEnd(2)) ) ) {
621  amrex::Print() << "PBL models need refinement boxes that go from the bottom to the top of the domain for calculation of PBLH" << std::endl;
622  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;
623  amrex::Abort();
624  }
625 
626  boxes_at_level[lev_for_box].push_back(bx);
627  Print() << "Saving in 'boxes at level' as " << bx << std::endl;
628  } // lev
629 
630  if (solverChoice.init_type == InitType::WRFInput) {
631  if ( (num_files_at_level[lev_for_box] > 0) &&
632  (num_boxes_at_level[lev_for_box] != num_files_at_level[lev_for_box]) ) {
633  amrex::Error("Number of boxes doesn't match number of input files");
634 
635  }
636  }
637  }
638  else if (num_indx_lo_crse > 0) {
639 
640  std::vector<int> box_lo(3), box_hi(3);
641  ppr.get("max_level",lev_for_box);
642  if (lev_for_box > 0 && lev_for_box <= max_level)
643  {
644  if (n_error_buf[0] != IntVect::TheZeroVector()) {
645  amrex::Abort("Don't use n_error_buf > 0 when setting the box explicitly");
646  }
647 
648  ppr.getarr("in_box_lo_indices_crse",box_lo,0,num_indx_lo_crse);
649  ppr.getarr("in_box_hi_indices_crse",box_hi,0,num_indx_hi_crse);
650 
651  if (num_indx_lo_crse < AMREX_SPACEDIM) {
652  box_lo[2] = geom[lev_for_box-1].Domain().smallEnd(2);
653  box_hi[2] = geom[lev_for_box-1].Domain().bigEnd(2);
654  }
655 
656  Box bx(IntVect(box_lo[0],box_lo[1],box_lo[2]),IntVect(box_hi[0],box_hi[1],box_hi[2]));
657 
658  if (!geom[lev_for_box-1].Domain().contains(bx)) {
659  amrex::Print() << "\n";
660  amrex::Print() << "(Coarse) Box specified is " << bx << std::endl;
661  amrex::Print() << "But (coarse) domain at level is " << geom[lev_for_box-1].Domain() << std::endl;
662  amrex::Error("Specified box doesn't fit in the domain");
663  }
664 
665  bx.refine(ref_ratio[lev_for_box-1]);
666 
667  const auto* dx = geom[lev_for_box-1].CellSize();
668 
669  realbox = RealBox(plo[0]+ box_lo[0] *dx[0], plo[1]+ box_lo[1] *dx[1], plo[2]+ box_lo[2] *dx[2],
670  plo[0]+(box_hi[0]+1)*dx[0], plo[1]+(box_hi[1]+1)*dx[1], plo[2]+(box_hi[2]+1)*dx[2]);
671 
672  Print() << "Reading " << bx << " at level " << lev_for_box << std::endl;
673  num_boxes_at_level[lev_for_box] += 1;
674  bool using_pbl = (solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::MYJ ||
675  solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::MYNN25 ||
676  solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::MYNNEDMF ||
677  solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::YSU ||
678  solverChoice.turbChoice[lev_for_box].pbl_type == PBLType::MRF);
679 
680  const Box& domain = geom[lev_for_box].Domain();
681  if ( using_pbl && ( (box_lo[2] > 0) || (box_hi[2] < domain.bigEnd(2)) ) ) {
682  amrex::Print() << "PBL models need refinement boxes that go from the bottom to the top of the domain for calculation of PBLH" << std::endl;
683  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;
684  amrex::Abort();
685  }
686 
687  boxes_at_level[lev_for_box].push_back(bx);
688  Print() << "Saving in 'boxes at level' as " << bx << std::endl;
689  } // lev
690 
691  if (solverChoice.init_type == InitType::WRFInput) {
692  if ( (num_files_at_level[lev_for_box] > 0) &&
693  (num_boxes_at_level[lev_for_box] != num_files_at_level[lev_for_box]) ) {
694  amrex::Error("Number of boxes doesn't match number of input files");
695 
696  }
697  }
698  }
699  AMRErrorTagInfo info;
700 
701  if (realbox.ok()) {
702  info.SetRealBox(realbox);
703  }
704 
705  if (ppr.countval("start_time") > 0) {
706  Real ref_min_time; ppr.get("start_time",ref_min_time);
707  info.SetMinTime(ref_min_time);
708  }
709 
710  if (ppr.countval("end_time") > 0) {
711  Real ref_max_time; ppr.get("end_time",ref_max_time);
712  info.SetMaxTime(ref_max_time);
713  }
714 
715  if (ppr.countval("max_level") > 0) {
716  int ref_max_level; ppr.get("max_level",ref_max_level);
717  info.SetMaxLevel(ref_max_level);
718  }
719 
720  if (ppr.countval("value_greater")) {
721  int num_val = ppr.countval("value_greater");
722  Vector<Real> value(num_val);
723  ppr.getarr("value_greater",value,0,num_val);
724  std::string field; ppr.get("field_name",field);
725  ref_tags.push_back(AMRErrorTag(value,AMRErrorTag::GREATER,field,info));
726  }
727  else if (ppr.countval("value_less"))
728  {
729  int num_val = ppr.countval("value_less");
730  Vector<Real> value(num_val);
731  ppr.getarr("value_less",value,0,num_val);
732  std::string field; ppr.get("field_name",field);
733  ref_tags.push_back(AMRErrorTag(value,AMRErrorTag::LESS,field,info));
734  }
735  else if (ppr.countval("adjacent_difference_greater"))
736  {
737  int num_val = ppr.countval("adjacent_difference_greater");
738  Vector<Real> value(num_val);
739  ppr.getarr("adjacent_difference_greater",value,0,num_val);
740  std::string field; ppr.get("field_name",field);
741  ref_tags.push_back(AMRErrorTag(value,AMRErrorTag::GRAD,field,info));
742  }
743  else if (realbox.ok())
744  {
745  ref_tags.push_back(AMRErrorTag(info));
746  }
747  else if ( (lev_for_box > 0) && (refinement_indicators[i] != "storm_tracker") )
748  {
749  Abort(std::string("Unrecognized refinement indicator for " + refinement_indicators[i]).c_str());
750  }
751  } // loop over criteria
752  } // if max_level > 0
753 }
Here is the call graph for this function:

◆ remake_zphys()

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

◆ restart()

void ERF::restart ( )
2103 {
2104  auto dRestartTime0 = amrex::second();
2105 
2107 
2109  //
2110  // Coarsening before we split the grids ensures that each resulting
2111  // grid will have an even number of cells in each direction.
2112  //
2113  BoxArray new_ba(amrex::coarsen(Geom(0).Domain(),2));
2114  //
2115  // Now split up into list of grids within max_grid_size[0] limit.
2116  //
2117  new_ba.maxSize(max_grid_size[0]/2);
2118  //
2119  // Now refine these boxes back to level 0.
2120  //
2121  new_ba.refine(2);
2122 
2123  if (refine_grid_layout) {
2124  ChopGrids(0, new_ba, ParallelDescriptor::NProcs());
2125  }
2126 
2127  if (new_ba != grids[0]) {
2128  DistributionMapping new_dm(new_ba);
2129  RemakeLevel(0,t_new[0],new_ba,new_dm);
2130  }
2131  }
2132 
2133 #ifdef ERF_USE_PARTICLES
2134  // We call this here without knowing whether the particles have already been initialized or not
2135  initializeTracers((ParGDBBase*)GetParGDB(),z_phys_nd,t_new[0]);
2136 #endif
2137 
2138  Real cur_time = t_new[0];
2139  if (m_check_per > 0.) {last_check_file_time = cur_time;}
2140  if (m_plot2d_per_1 > 0.) {last_plot2d_file_time_1 = std::floor(cur_time/m_plot2d_per_1) * m_plot2d_per_1;}
2141  if (m_plot2d_per_2 > 0.) {last_plot2d_file_time_2 = std::floor(cur_time/m_plot2d_per_2) * m_plot2d_per_2;}
2142  if (m_plot3d_per_1 > 0.) {last_plot3d_file_time_1 = std::floor(cur_time/m_plot3d_per_1) * m_plot3d_per_1;}
2143  if (m_plot3d_per_2 > 0.) {last_plot3d_file_time_2 = std::floor(cur_time/m_plot3d_per_2) * m_plot3d_per_2;}
2144 
2145  if (m_check_int > 0.) {last_check_file_step = istep[0];}
2146  if (m_plot2d_int_1 > 0.) {last_plot2d_file_step_1 = istep[0];}
2147  if (m_plot2d_int_2 > 0.) {last_plot2d_file_step_2 = istep[0];}
2148  if (m_plot3d_int_1 > 0.) {last_plot3d_file_step_1 = istep[0];}
2149  if (m_plot3d_int_2 > 0.) {last_plot3d_file_step_2 = istep[0];}
2150 
2151  if (verbose > 0)
2152  {
2153  auto dRestartTime = amrex::second() - dRestartTime0;
2154  ParallelDescriptor::ReduceRealMax(dRestartTime,ParallelDescriptor::IOProcessorNumber());
2155  amrex::Print() << "Restart time = " << dRestartTime << " seconds." << '\n';
2156  }
2157 }
void RemakeLevel(int lev, amrex::Real time, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm) override
Definition: ERF_MakeNewLevel.cpp:542
void ReadCheckpointFile()
Definition: ERF_Checkpoint.cpp:466

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

◆ 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
528 {
529  int ifile = 0;
530 
531  //
532  // Sample the data at a single point in space
533  //
534  int ncomp = mf.nComp();
535  Vector<Real> my_point = get_cell_data(mf, cell);
536 
537  if (!my_point.empty()) {
538 
539  // HERE DO WHATEVER YOU WANT TO THE DATA BEFORE WRITING
540 
541  std::ostream& sample_log = SamplePointLog(ifile);
542  if (sample_log.good()) {
543  sample_log << std::setw(datwidth) << time;
544  for (int i = 0; i < ncomp; ++i)
545  {
546  sample_log << std::setw(datwidth) << my_point[i];
547  }
548  sample_log << std::endl;
549  } // if good
550  } // only write from processor that holds the cell
551 }
AMREX_FORCE_INLINE std::ostream & SamplePointLog(int i)
Definition: ERF.H:1448

◆ SampleLine()

amrex::IntVect& ERF::SampleLine ( int  i)
inlineprivate
1489  {
1490  return sampleline[i];
1491  }

◆ SampleLineLog()

AMREX_FORCE_INLINE std::ostream& ERF::SampleLineLog ( int  i)
inlineprivate
1463  {
1464  return *samplelinelog[i];
1465  }

◆ SampleLineLogName()

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

The filename of the ith samplelinelog file.

1622 { return samplelinelogname[i]; }

◆ SamplePoint()

amrex::IntVect& ERF::SamplePoint ( int  i)
inlineprivate
1476  {
1477  return samplepoint[i];
1478  }

◆ SamplePointLog()

AMREX_FORCE_INLINE std::ostream& ERF::SamplePointLog ( int  i)
inlineprivate
1449  {
1450  return *sampleptlog[i];
1451  }

◆ SamplePointLogName()

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

The filename of the ith sampleptlog file.

1619 { return sampleptlogname[i]; }

◆ setPlotVariables()

void ERF::setPlotVariables ( const std::string &  pp_plot_var_names,
amrex::Vector< std::string > &  plot_var_names 
)
private
26 {
27  ParmParse pp(pp_prefix);
28 
29  if (pp.contains(pp_plot_var_names.c_str()))
30  {
31  std::string nm;
32 
33  int nPltVars = pp.countval(pp_plot_var_names.c_str());
34 
35  for (int i = 0; i < nPltVars; i++)
36  {
37  pp.get(pp_plot_var_names.c_str(), nm, i);
38 
39  // Add the named variable to our list of plot variables
40  // if it is not already in the list
41  if (!containerHasElement(plot_var_names, nm)) {
42  plot_var_names.push_back(nm);
43  }
44  }
45  } else {
46  //
47  // The default is to add none of the variables to the list
48  //
49  plot_var_names.clear();
50  }
51 
52  // Get state variables in the same order as we define them,
53  // since they may be in any order in the input list
54  Vector<std::string> tmp_plot_names;
55 
56  for (int i = 0; i < cons_names.size(); ++i) {
57  if ( containerHasElement(plot_var_names, cons_names[i]) ) {
58  if (solverChoice.moisture_type == MoistureType::None) {
59  if (cons_names[i] != "rhoQ1" && cons_names[i] != "rhoQ2" && cons_names[i] != "rhoQ3" &&
60  cons_names[i] != "rhoQ4" && 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::Kessler) { // allow rhoQ1, rhoQ2, rhoQ3
65  if (cons_names[i] != "rhoQ4" && cons_names[i] != "rhoQ5" && cons_names[i] != "rhoQ6")
66  {
67  tmp_plot_names.push_back(cons_names[i]);
68  }
69  } else if ( (solverChoice.moisture_type == MoistureType::SatAdj) ||
70  (solverChoice.moisture_type == MoistureType::SAM_NoPrecip_NoIce) ||
71  (solverChoice.moisture_type == MoistureType::Kessler_NoRain) ) { // allow rhoQ1, rhoQ2
72  if (cons_names[i] != "rhoQ3" && cons_names[i] != "rhoQ4" &&
73  cons_names[i] != "rhoQ5" && cons_names[i] != "rhoQ6")
74  {
75  tmp_plot_names.push_back(cons_names[i]);
76  }
77  } else if ( (solverChoice.moisture_type == MoistureType::Morrison_NoIce) ||
78  (solverChoice.moisture_type == MoistureType::SAM_NoIce ) ) { // allow rhoQ1, rhoQ2, rhoQ4
79  if (cons_names[i] != "rhoQ3" && cons_names[i] != "rhoQ5" && cons_names[i] != "rhoQ6")
80  {
81  tmp_plot_names.push_back(cons_names[i]);
82  }
83  } else
84  {
85  // For moisture_type SAM and Morrison we have all six variables
86  tmp_plot_names.push_back(cons_names[i]);
87  }
88  }
89  }
90 
91  // check for velocity since it's not in cons_names
92  // if we are asked for any velocity component, we will need them all
93  if (containerHasElement(plot_var_names, "x_velocity") ||
94  containerHasElement(plot_var_names, "y_velocity") ||
95  containerHasElement(plot_var_names, "z_velocity")) {
96  tmp_plot_names.push_back("x_velocity");
97  tmp_plot_names.push_back("y_velocity");
98  tmp_plot_names.push_back("z_velocity");
99  }
100 
101  //
102  // If the model we are running doesn't have the variable listed in the inputs file,
103  // just ignore it rather than aborting
104  //
105  for (int i = 0; i < derived_names.size(); ++i) {
106  if ( containerHasElement(plot_var_names, derived_names[i]) ) {
107  bool ok_to_add = ( (solverChoice.terrain_type == TerrainType::ImmersedForcing || solverChoice.buildings_type == BuildingsType::ImmersedForcing ) ||
108  (derived_names[i] != "terrain_IB_mask") );
109  ok_to_add &= ( (SolverChoice::terrain_type == TerrainType::StaticFittedMesh) ||
110  (SolverChoice::terrain_type == TerrainType::MovingFittedMesh) ||
111  (derived_names[i] != "detJ") );
112  ok_to_add &= ( (SolverChoice::terrain_type == TerrainType::StaticFittedMesh) ||
113  (SolverChoice::terrain_type == TerrainType::MovingFittedMesh) ||
114  (derived_names[i] != "z_phys") );
115 #ifndef ERF_USE_WINDFARM
116  ok_to_add &= (derived_names[i] != "SMark0" && derived_names[i] != "SMark1");
117 #endif
118  if (ok_to_add)
119  {
120  if (solverChoice.moisture_type == MoistureType::None) { // no moist quantities allowed
121  if (derived_names[i] != "qv" && derived_names[i] != "qc" && derived_names[i] != "qrain" &&
122  derived_names[i] != "qi" && derived_names[i] != "qsnow" && derived_names[i] != "qgraup" &&
123  derived_names[i] != "qt" && derived_names[i] != "qn" && derived_names[i] != "qp" &&
124  derived_names[i] != "rain_accum" && derived_names[i] != "snow_accum" && derived_names[i] != "graup_accum")
125  {
126  tmp_plot_names.push_back(derived_names[i]);
127  }
128  } else if ( (solverChoice.moisture_type == MoistureType::Kessler ) ||
129  (solverChoice.moisture_type == MoistureType::Morrison_NoIce) ||
130  (solverChoice.moisture_type == MoistureType::SAM_NoIce ) ) { // allow qv, qc, qrain
131  if (derived_names[i] != "qi" && derived_names[i] != "qsnow" && derived_names[i] != "qgraup" &&
132  derived_names[i] != "snow_accum" && derived_names[i] != "graup_accum")
133  {
134  tmp_plot_names.push_back(derived_names[i]);
135  }
136  } else if ( (solverChoice.moisture_type == MoistureType::SatAdj) ||
137  (solverChoice.moisture_type == MoistureType::SAM_NoPrecip_NoIce) ||
138  (solverChoice.moisture_type == MoistureType::Kessler_NoRain) ) { // allow qv, qc
139  if (derived_names[i] != "qrain" &&
140  derived_names[i] != "qi" && derived_names[i] != "qsnow" && derived_names[i] != "qgraup" &&
141  derived_names[i] != "qp" &&
142  derived_names[i] != "rain_accum" && derived_names[i] != "snow_accum" && derived_names[i] != "graup_accum")
143  {
144  tmp_plot_names.push_back(derived_names[i]);
145  }
146  } else
147  {
148  // For moisture_type SAM and Morrison we have all moist quantities
149  tmp_plot_names.push_back(derived_names[i]);
150  }
151  } // use_terrain?
152  } // hasElement
153  }
154 
155 #ifdef ERF_USE_WINDFARM
156  for (int i = 0; i < derived_names.size(); ++i) {
157  if ( containerHasElement(plot_var_names, derived_names[i]) ) {
158  if(solverChoice.windfarm_type == WindFarmType::Fitch or solverChoice.windfarm_type == WindFarmType::EWP) {
159  if(derived_names[i] == "num_turb" or derived_names[i] == "SMark0") {
160  tmp_plot_names.push_back(derived_names[i]);
161  }
162  }
163  if( solverChoice.windfarm_type == WindFarmType::SimpleAD or
164  solverChoice.windfarm_type == WindFarmType::GeneralAD ) {
165  if(derived_names[i] == "num_turb" or derived_names[i] == "SMark0" or derived_names[i] == "SMark1") {
166  tmp_plot_names.push_back(derived_names[i]);
167  }
168  }
169  }
170  }
171 #endif
172 
173 #ifdef ERF_USE_PARTICLES
174  const auto& particles_namelist( particleData.getNamesUnalloc() );
175  for (auto it = particles_namelist.cbegin(); it != particles_namelist.cend(); ++it) {
176  std::string tmp( (*it)+"_count" );
177  if (containerHasElement(plot_var_names, tmp) ) {
178  tmp_plot_names.push_back(tmp);
179  }
180  }
181 #endif
182 
183  plot_var_names = tmp_plot_names;
184 }
const amrex::Vector< std::string > derived_names
Definition: ERF.H:1115
const amrex::Vector< std::string > cons_names
Definition: ERF.H:1108
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
188 {
189  ParmParse pp(pp_prefix);
190 
191  if (pp.contains(pp_plot_var_names.c_str()))
192  {
193  std::string nm;
194 
195  int nPltVars = pp.countval(pp_plot_var_names.c_str());
196 
197  for (int i = 0; i < nPltVars; i++)
198  {
199  pp.get(pp_plot_var_names.c_str(), nm, i);
200 
201  // Add the named variable to our list of plot variables
202  // if it is not already in the list
203  if (!containerHasElement(plot_var_names, nm)) {
204  plot_var_names.push_back(nm);
205  }
206  }
207  } else {
208  //
209  // The default is to add none of the variables to the list
210  //
211  plot_var_names.clear();
212  }
213 
214  // Get state variables in the same order as we define them,
215  // since they may be in any order in the input list
216  Vector<std::string> tmp_plot_names;
217 
218  // 2D plot variables
219  for (int i = 0; i < derived_names_2d.size(); ++i) {
220  if (containerHasElement(plot_var_names, derived_names_2d[i]) ) {
221  tmp_plot_names.push_back(derived_names_2d[i]);
222  }
223  }
224 
225  plot_var_names = tmp_plot_names;
226 }
const amrex::Vector< std::string > derived_names_2d
Definition: ERF.H:1158
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);
124  h_rayleigh_ptrs[lev][Rayleigh::wbar][k] = Real(0.0);
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
1519  {
1520  if (amrex::ParallelDescriptor::IOProcessor())
1521  {
1522  datalog[i] = std::make_unique<std::fstream>();
1523  datalog[i]->open(filename.c_str(),std::ios::out|std::ios::app);
1524  if (!datalog[i]->good()) {
1525  amrex::FileOpenFailed(filename);
1526  }
1527  }
1528  amrex::ParallelDescriptor::Barrier("ERF::setRecordDataInfo");
1529  }

◆ setRecordDerDataInfo()

void ERF::setRecordDerDataInfo ( int  i,
const std::string &  filename 
)
inlineprivate
1532  {
1533  if (amrex::ParallelDescriptor::IOProcessor())
1534  {
1535  der_datalog[i] = std::make_unique<std::fstream>();
1536  der_datalog[i]->open(filename.c_str(),std::ios::out|std::ios::app);
1537  if (!der_datalog[i]->good()) {
1538  amrex::FileOpenFailed(filename);
1539  }
1540  }
1541  amrex::ParallelDescriptor::Barrier("ERF::setRecordDerDataInfo");
1542  }

◆ setRecordEnergyDataInfo()

void ERF::setRecordEnergyDataInfo ( int  i,
const std::string &  filename 
)
inlineprivate
1545  {
1546  if (amrex::ParallelDescriptor::IOProcessor())
1547  {
1548  tot_e_datalog[i] = std::make_unique<std::fstream>();
1549  tot_e_datalog[i]->open(filename.c_str(),std::ios::out|std::ios::app);
1550  if (!tot_e_datalog[i]->good()) {
1551  amrex::FileOpenFailed(filename);
1552  }
1553  }
1554  amrex::ParallelDescriptor::Barrier("ERF::setRecordEnergyDataInfo");
1555  }

◆ setRecordSampleLineInfo()

void ERF::setRecordSampleLineInfo ( int  i,
int  lev,
amrex::IntVect &  cell,
const std::string &  filename 
)
inlineprivate
1575  {
1576  amrex::MultiFab dummy(grids[lev],dmap[lev],1,0);
1577  for (amrex::MFIter mfi(dummy); mfi.isValid(); ++mfi)
1578  {
1579  const amrex::Box& bx = mfi.validbox();
1580  if (bx.contains(cell)) {
1581  samplelinelog[i] = std::make_unique<std::fstream>();
1582  samplelinelog[i]->open(filename.c_str(),std::ios::out|std::ios::app);
1583  if (!samplelinelog[i]->good()) {
1584  amrex::FileOpenFailed(filename);
1585  }
1586  }
1587  }
1588  amrex::ParallelDescriptor::Barrier("ERF::setRecordSampleLineInfo");
1589  }

◆ setRecordSamplePointInfo()

void ERF::setRecordSamplePointInfo ( int  i,
int  lev,
amrex::IntVect &  cell,
const std::string &  filename 
)
inlineprivate
1558  {
1559  amrex::MultiFab dummy(grids[lev],dmap[lev],1,0);
1560  for (amrex::MFIter mfi(dummy); mfi.isValid(); ++mfi)
1561  {
1562  const amrex::Box& bx = mfi.validbox();
1563  if (bx.contains(cell)) {
1564  sampleptlog[i] = std::make_unique<std::fstream>();
1565  sampleptlog[i]->open(filename.c_str(),std::ios::out|std::ios::app);
1566  if (!sampleptlog[i]->good()) {
1567  amrex::FileOpenFailed(filename);
1568  }
1569  }
1570  }
1571  amrex::ParallelDescriptor::Barrier("ERF::setRecordSamplePointInfo");
1572  }

◆ 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+0.5) * 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:1168
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 ( amrex::Real  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  derived::erf_dermagvelsq(bx, dest1_fab, 0, 1, src_fab, Geom(lev), t_new[0], nullptr, lev);
222 
223  auto& dest2_fab = enstrophysq[mfi];
224  derived::erf_derenstrophysq(bx, dest2_fab, 0, 1, src_fab, Geom(lev), t_new[0], nullptr, lev);
225  }
226 
227  // 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
228  MultiFab::Copy(r_wted_magvelsq, unwted_magvelsq, 0, 0, 1, 0);
229 
230  // 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)
231  MultiFab::Multiply(r_wted_magvelsq, vars_new[lev][Vars::cons], 0, 0, 1, 0);
232 
233  // Copy the MF holding (rho theta) into "theta_mf"
234  MultiFab::Copy(theta_mf, vars_new[lev][Vars::cons], RhoTheta_comp, 0, 1, 0);
235 
236  // Divide (rho theta) by rho to get theta in the MF "theta_mf"
237  MultiFab::Divide(theta_mf, vars_new[lev][Vars::cons], Rho_comp, 0, 1, 0);
238 
239  Real unwted_avg = volWgtSumMF(lev, unwted_magvelsq, 0, dJ0, mfx0, mfy0, false);
240  Real r_wted_avg = volWgtSumMF(lev, r_wted_magvelsq, 0, dJ0, mfx0, mfy0, false);
241  Real enstrsq_avg = volWgtSumMF(lev, enstrophysq, 0, dJ0, mfx0, mfy0, false);
242  Real theta_avg = volWgtSumMF(lev, theta_mf, 0, dJ0, mfx0, mfy0, false);
243 
244  // Get volume including terrain (consistent with volWgtSumMF routine)
245  MultiFab volume(grids[lev], dmap[lev], 1, 0);
246  auto const& dx = geom[lev].CellSizeArray();
247  Real cell_vol = dx[0]*dx[1]*dx[2];
248  volume.setVal(cell_vol);
249  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
250  MultiFab::Multiply(volume, *detJ_cc[lev], 0, 0, 1, 0);
251  }
252 #ifdef _OPENMP
253 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
254 #endif
255  for (MFIter mfi(volume, TilingIfNotGPU()); mfi.isValid(); ++mfi)
256  {
257  const Box& tbx = mfi.tilebox();
258  auto dst = volume.array(mfi);
259  const auto& mfx = mapfac[lev][MapFacType::m_x]->const_array(mfi);
260  const auto& mfy = mapfac[lev][MapFacType::m_y]->const_array(mfi);
261  ParallelFor(tbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
262  {
263  dst(i,j,k) /= (mfx(i,j,0)*mfy(i,j,0));
264  });
265  }
266  Real vol = volume.sum();
267 
268  unwted_avg /= vol;
269  r_wted_avg /= vol;
270  enstrsq_avg /= vol;
271  theta_avg /= vol;
272 
273  const int nfoo = 4;
274  Real foo[nfoo] = {unwted_avg,r_wted_avg,enstrsq_avg,theta_avg};
275 #ifdef AMREX_LAZY
276  Lazy::QueueReduction([=]() mutable {
277 #endif
278  ParallelDescriptor::ReduceRealSum(
279  foo, nfoo, ParallelDescriptor::IOProcessorNumber());
280 
281  if (ParallelDescriptor::IOProcessor()) {
282  int i = 0;
283  unwted_avg = foo[i++];
284  r_wted_avg = foo[i++];
285  enstrsq_avg = foo[i++];
286  theta_avg = foo[i++];
287 
288  std::ostream& data_log_der = DerDataLog(0);
289 
290  if (time == 0.0) {
291  data_log_der << std::setw(datwidth) << " time";
292  data_log_der << std::setw(datwidth) << " ke_den";
293  data_log_der << std::setw(datwidth) << " velsq";
294  data_log_der << std::setw(datwidth) << " enstrophy";
295  data_log_der << std::setw(datwidth) << " int_energy";
296  data_log_der << std::endl;
297  }
298  data_log_der << std::setw(datwidth) << std::setprecision(timeprecision) << time;
299  data_log_der << std::setw(datwidth) << std::setprecision(datprecision) << unwted_avg;
300  data_log_der << std::setw(datwidth) << std::setprecision(datprecision) << r_wted_avg;
301  data_log_der << std::setw(datwidth) << std::setprecision(datprecision) << enstrsq_avg;
302  data_log_der << std::setw(datwidth) << std::setprecision(datprecision) << theta_avg;
303  data_log_der << std::endl;
304 
305  } // if IOProcessor
306 #ifdef AMREX_LAZY
307  }
308 #endif
309 }
AMREX_FORCE_INLINE std::ostream & DerDataLog(int i)
Definition: ERF.H:1426
const int timeprecision
Definition: ERF.H:1030
AMREX_FORCE_INLINE int NumDerDataLogs() noexcept
Definition: ERF.H:1440
void erf_dermagvelsq(const amrex::Box &bx, amrex::FArrayBox &derfab, int dcomp, int ncomp, const amrex::FArrayBox &datfab, const amrex::Geometry &, amrex::Real, const int *, const int)
Definition: ERF_Derive.cpp:346
void erf_derenstrophysq(const amrex::Box &bx, amrex::FArrayBox &derfab, int dcomp, int ncomp, const amrex::FArrayBox &datfab, const amrex::Geometry &geomdata, amrex::Real, const int *, const int)
Definition: ERF_Derive.cpp:284
Here is the call graph for this function:

◆ sum_energy_quantities()

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

◆ sum_integrated_quantities()

void ERF::sum_integrated_quantities ( amrex::Real  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 = 0.0;
27  Real rhth_ml = 0.0;
28  Real scal_ml = 0.0;
29  Real mois_ml = 0.0;
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 = 0.0;
49  if (solverChoice.moisture_type != MoistureType::None) {
50  int n_qstate_moist = micro->Get_Qstate_Moist_Size();
51  for (int qoff(0); qoff<n_qstate_moist; ++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_moist = micro->Get_Qstate_Moist_Size();
64  for (int qoff(0); qoff<n_qstate_moist; ++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] = 0.;
88  h_avg_tstar[0] = 0.;
89  h_avg_olen[0] = 0.;
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 == 0.0) {
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:1469
AMREX_FORCE_INLINE int NumSamplePointLogs() noexcept
Definition: ERF.H:1455
amrex::IntVect & SampleLine(int i)
Definition: ERF.H:1488
AMREX_FORCE_INLINE int NumSamplePoints() noexcept
Definition: ERF.H:1482
AMREX_FORCE_INLINE int NumSampleLines() noexcept
Definition: ERF.H:1495
amrex::IntVect & SamplePoint(int i)
Definition: ERF.H:1475
void sample_points(int lev, amrex::Real time, amrex::IntVect cell, amrex::MultiFab &mf)
Definition: ERF_WriteScalarProfiles.cpp:527
AMREX_FORCE_INLINE std::ostream & DataLog(int i)
Definition: ERF.H:1419
AMREX_FORCE_INLINE int NumDataLogs() noexcept
Definition: ERF.H:1433
void sample_lines(int lev, amrex::Real time, amrex::IntVect cell, amrex::MultiFab &mf)
Definition: ERF_WriteScalarProfiles.cpp:563
bool transport_scalar
Definition: ERF_DataStruct.H:1178

◆ 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*3600.0;
154 
155  // Initialize static vectors once
156  if (next_read_forecast_time.empty()) {
157  next_read_forecast_time.resize(nlevs, -1.0);
158  last_read_forecast_time.resize(nlevs, -1.0);
159  Print() << "Initializing the time vector values here by " << lev << std::endl;
160  }
161 
162  if (next_read_forecast_time[lev] < 0.0) {
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 = 1.0 - (time - prev_read_time)/hindcast_data_interval;
223  Real alpha2 = 1.0 - alpha1;
224 
225  amrex::Print()<< "The values of alpha1 and alpha2 are " << alpha1 << " "<< alpha2 <<std::endl;
226 
227  if (alpha1 < 0.0 || alpha1 > 1.0 ||
228  alpha2 < 0.0 || alpha2 > 1.0)
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:1237
amrex::Real hindcast_data_interval_in_hrs
Definition: ERF_DataStruct.H:1238

◆ timeStep()

void ERF::timeStep ( int  lev,
amrex::Real  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  int ntimes = bdy_data_xlo.size();
37  Real time_since_start_bdy = time + start_time - start_bdy_time;
38  int n_time_old = std::min(static_cast<int>( (time_since_start_bdy ) / bdy_time_interval), ntimes-1);
39  int n_time_new = std::min(static_cast<int>( (time_since_start_bdy+dt[lev]) / bdy_time_interval), ntimes-1);
40 
41  for (int itime = 0; itime < ntimes; itime++)
42  {
43  /*
44  if (bdy_data_xlo[itime].size() > 0) {
45  amrex::Print() << "HAVE BDY DATA AT TIME " << itime << std::endl;
46  } else {
47  amrex::Print() << " NO BDY DATA AT TIME " << itime << std::endl;
48  }
49  */
50 
51  bool clear_itime = (itime < n_time_old);
52 
53  if (clear_itime && bdy_data_xlo[itime].size() > 0) {
54  bdy_data_xlo[itime].clear();
55  bdy_data_xhi[itime].clear();
56  bdy_data_ylo[itime].clear();
57  bdy_data_yhi[itime].clear();
58  //amrex::Print() << "CLEAR BDY DATA AT TIME " << itime << std::endl;
59  }
60 
61  bool need_itime = (itime >= n_time_old && itime <= n_time_new+1);
62  //if (need_itime) { amrex::Print() << "NEED BDY DATA AT TIME " << itime << std::endl; }
63 
64  if (bdy_data_xlo[itime].size() == 0 && need_itime) {
65  read_from_wrfbdy(itime,nc_bdy_file,geom[0].Domain(),
66  bdy_data_xlo,bdy_data_xhi,bdy_data_ylo,bdy_data_yhi,
67  real_width);
68 
69  convert_all_wrfbdy_data(itime, geom[0].Domain(), bdy_data_xlo, bdy_data_xhi, bdy_data_ylo, bdy_data_yhi,
70  *mf_MUB, *mf_C1H, *mf_C2H,
72  geom[lev], use_moist);
73  }
74  } // itime
75  } // use_real_bcs && lev == 0
76 
77  if (!nc_low_file.empty() && (lev==0))
78  {
79  int ntimes = low_data_zlo.size();
80  Real time_since_start_low = time + start_time - start_low_time;
81  int n_time_old = std::min(static_cast<int>( (time_since_start_low ) / low_time_interval), ntimes-1);
82  int n_time_new = std::min(static_cast<int>( (time_since_start_low+dt[lev]) / low_time_interval), ntimes-1);
83 
84  for (int itime = 0; itime < ntimes; itime++)
85  {
86  /*
87  if (low_data_zlo[itime].size() > 0) {
88  amrex::Print() << "HAVE LOW DATA AT TIME " << itime << std::endl;
89  } else {
90  amrex::Print() << " NO LOW DATA AT TIME " << itime << std::endl;
91  }
92  */
93 
94  bool clear_itime = (itime < n_time_old);
95 
96  if (clear_itime && low_data_zlo[itime].size() > 0) {
97  low_data_zlo[itime].clear();
98  //amrex::Print() << "CLEAR LOW DATA AT TIME " << itime << std::endl;
99  }
100 
101  bool need_itime = (itime >= n_time_old && itime <= n_time_new+1);
102  //if (need_itime) { amrex::Print() << "NEED LOW DATA AT TIME " << itime << std::endl; }
103 
104  if (low_data_zlo[itime].size() == 0 && need_itime) {
105  read_from_wrflow(itime, nc_low_file, geom[lev].Domain(), low_data_zlo);
106 
107  update_sst_tsk(itime, geom[lev], ba2d[lev],
108  sst_lev[lev], tsk_lev[lev],
109  m_SurfaceLayer, low_data_zlo,
110  S_new, *mf_PSFC[lev],
111  solverChoice.rdOcp, lmask_lev[lev][0], use_moist);
112  }
113  } // itime
114  } // have nc_low_file && lev == 0
115 #endif
116 
117  //
118  // NOTE: the momenta here are not fillpatched (they are only used as scratch space)
119  //
120  if (lev == 0) {
121  FillPatchCrseLevel(lev, time, {&S_new, &U_new, &V_new, &W_new});
122  } else if (lev < finest_level) {
123  FillPatchFineLevel(lev, time, {&S_new, &U_new, &V_new, &W_new},
124  {&S_new, &rU_new[lev], &rV_new[lev], &rW_new[lev]},
125  base_state[lev], base_state[lev]);
126  }
127 
128  if (regrid_int > 0) // We may need to regrid
129  {
130  // help keep track of whether a level was already regridded
131  // from a coarser level call to regrid
132  static Vector<int> last_regrid_step(max_level+1, 0);
133 
134  // regrid changes level "lev+1" so we don't regrid on max_level
135  // also make sure we don't regrid fine levels again if
136  // it was taken care of during a coarser regrid
137  if (lev < max_level)
138  {
139  if ( (istep[lev] % regrid_int == 0) && (istep[lev] > last_regrid_step[lev]) )
140  {
141  // regrid could add newly refine levels (if finest_level < max_level)
142  // so we save the previous finest level index
143  int old_finest = finest_level;
144 
145  regrid(lev, time);
146 
147 #ifdef ERF_USE_PARTICLES
148  if (finest_level != old_finest) {
149  particleData.Redistribute();
150  }
151 #endif
152 
153  // mark that we have regridded this level already
154  for (int k = lev; k <= finest_level; ++k) {
155  last_regrid_step[k] = istep[k];
156  }
157 
158  // if there are newly created levels, set the time step
159  for (int k = old_finest+1; k <= finest_level; ++k) {
160  dt[k] = dt[k-1] / static_cast<Real>(nsubsteps[k]);
161  }
162  } // if
163  } // lev
164  }
165 
166  // Update what we call "old" and "new" time
167  t_old[lev] = t_new[lev];
168  t_new[lev] += dt[lev];
169 
170  if (Verbose()) {
171  amrex::Print() << "[Level " << lev << " step " << istep[lev]+1 << "] ";
172  amrex::Print() << std::setprecision(timeprecision)
173  << "ADVANCE from elapsed time = " << t_old[lev] << " to " << t_new[lev]
174  << " with dt = " << dt[lev] << std::endl;
175  }
176 
177 #ifdef ERF_USE_WW3_COUPLING
178  amrex::Print() << " About to call send_to_ww3 from ERF_Timestep" << std::endl;
179  send_to_ww3(lev);
180  amrex::Print() << " About to call read_waves from ERF_Timestep" << std::endl;
181  read_waves(lev);
182  //send_to_ww3(lev);
183  //read_waves(lev);
184  //send_to_ww3(lev);
185 #endif
186 
187  // Advance a single level for a single time step
188  Advance(lev, time, dt[lev], istep[lev], nsubsteps[lev]);
189 
190  ++istep[lev];
191 
192  if (Verbose()) {
193  amrex::Print() << "[Level " << lev << " step " << istep[lev] << "] ";
194  amrex::Print() << "Advanced " << CountCells(lev) << " cells" << std::endl;
195  }
196 
197  if (lev < finest_level)
198  {
199  // recursive call for next-finer level
200  for (int i = 1; i <= nsubsteps[lev+1]; ++i)
201  {
202  Real strt_time_for_fine = time + (i-1)*dt[lev+1];
203  timeStep(lev+1, strt_time_for_fine, i);
204  }
205  }
206 
207  if (verbose && lev == 0 && solverChoice.moisture_type != MoistureType::None) {
208  amrex::Print() << "Cloud fraction " << time << " " << cloud_fraction(time) << std::endl;
209  }
210 }
amrex::Real cloud_fraction(amrex::Real time)
Definition: ERF_WriteScalarProfiles.cpp:451
void Advance(int lev, amrex::Real time, amrex::Real dt_lev, int iteration, int ncycle)
Definition: ERF_Advance.cpp:20

◆ turbPert_amplitude()

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

◆ update_diffusive_arrays()

void ERF::update_diffusive_arrays ( int  lev,
const amrex::BoxArray &  ba,
const amrex::DistributionMapping &  dm 
)
private
511 {
512  // ********************************************************************************************
513  // Diffusive terms
514  // ********************************************************************************************
515  bool l_use_terrain = (SolverChoice::terrain_type != TerrainType::None);
516  bool l_use_kturb = solverChoice.turbChoice[lev].use_kturb;
517  bool l_use_diff = ( (solverChoice.diffChoice.molec_diff_type != MolecDiffType::None) ||
518  l_use_kturb );
519  bool l_need_SmnSmn = solverChoice.turbChoice[lev].use_keqn;
520  bool l_use_moist = ( solverChoice.moisture_type != MoistureType::None );
521  bool l_rotate = ( solverChoice.use_rotate_surface_flux );
522 
523  bool l_implicit_diff = (solverChoice.vert_implicit_fac[0] > 0 ||
526 
527  BoxArray ba12 = convert(ba, IntVect(1,1,0));
528  BoxArray ba13 = convert(ba, IntVect(1,0,1));
529  BoxArray ba23 = convert(ba, IntVect(0,1,1));
530 
531  Tau[lev].resize(9);
532  Tau_corr[lev].resize(3);
533 
534  if (l_use_diff) {
535  //
536  // NOTE: We require ghost cells in the vertical when allowing grids that don't
537  // cover the entire vertical extent of the domain at this level
538  //
539  for (int i = 0; i < 3; i++) {
540  Tau[lev][i] = std::make_unique<MultiFab>( ba , dm, 1, IntVect(1,1,1) );
541  }
542  Tau[lev][TauType::tau12] = std::make_unique<MultiFab>( ba12, dm, 1, IntVect(1,1,1) );
543  Tau[lev][TauType::tau13] = std::make_unique<MultiFab>( ba13, dm, 1, IntVect(1,1,1) );
544  Tau[lev][TauType::tau23] = std::make_unique<MultiFab>( ba23, dm, 1, IntVect(1,1,1) );
545  Tau[lev][TauType::tau12]->setVal(0.);
546  Tau[lev][TauType::tau13]->setVal(0.);
547  Tau[lev][TauType::tau23]->setVal(0.);
548  if (l_use_terrain) {
549  Tau[lev][TauType::tau21] = std::make_unique<MultiFab>( ba12, dm, 1, IntVect(1,1,1) );
550  Tau[lev][TauType::tau31] = std::make_unique<MultiFab>( ba13, dm, 1, IntVect(1,1,1) );
551  Tau[lev][TauType::tau32] = std::make_unique<MultiFab>( ba23, dm, 1, IntVect(1,1,1) );
552  Tau[lev][TauType::tau21]->setVal(0.);
553  Tau[lev][TauType::tau31]->setVal(0.);
554  Tau[lev][TauType::tau32]->setVal(0.);
555  } else if (l_implicit_diff) {
556  Tau[lev][TauType::tau31] = std::make_unique<MultiFab>( ba13, dm, 1, IntVect(1,1,1) );
557  Tau[lev][TauType::tau32] = std::make_unique<MultiFab>( ba23, dm, 1, IntVect(1,1,1) );
558  Tau[lev][TauType::tau31]->setVal(0.);
559  Tau[lev][TauType::tau32]->setVal(0.);
560  } else {
561  Tau[lev][TauType::tau21] = nullptr;
562  Tau[lev][TauType::tau31] = nullptr;
563  Tau[lev][TauType::tau32] = nullptr;
564  }
565 
566  if (l_implicit_diff && solverChoice.implicit_momentum_diffusion)
567  {
568  Tau_corr[lev][0] = std::make_unique<MultiFab>( ba13, dm, 1, IntVect(1,1,1) ); // Tau31
569  Tau_corr[lev][1] = std::make_unique<MultiFab>( ba23, dm, 1, IntVect(1,1,1) ); // Tau32
570  Tau_corr[lev][0]->setVal(0.);
571  Tau_corr[lev][1]->setVal(0.);
572 #ifdef ERF_IMPLICIT_W
573  Tau_corr[lev][2] = std::make_unique<MultiFab>( ba , dm, 1, IntVect(1,1,1) ); // Tau33
574  Tau_corr[lev][2]->setVal(0.);
575 #else
576  Tau_corr[lev][2] = nullptr;
577 #endif
578  } else {
579  Tau_corr[lev][0] = nullptr;
580  Tau_corr[lev][1] = nullptr;
581  Tau_corr[lev][2] = nullptr;
582  }
583 
584  SFS_hfx1_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(1,0,0)), dm, 1, IntVect(1,1,1) );
585  SFS_hfx2_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(0,1,0)), dm, 1, IntVect(1,1,1) );
586  SFS_hfx3_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(0,0,1)), dm, 1, IntVect(1,1,1) );
587  SFS_diss_lev[lev] = std::make_unique<MultiFab>( ba , dm, 1, IntVect(1,1,1) );
588  SFS_hfx1_lev[lev]->setVal(0.);
589  SFS_hfx2_lev[lev]->setVal(0.);
590  SFS_hfx3_lev[lev]->setVal(0.);
591  SFS_diss_lev[lev]->setVal(0.);
592  if (l_use_moist) {
593  SFS_q1fx3_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(0,0,1)), dm, 1, IntVect(1,1,1) );
594  SFS_q2fx3_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(0,0,1)), dm, 1, IntVect(1,1,1) );
595  SFS_q1fx3_lev[lev]->setVal(0.0);
596  SFS_q2fx3_lev[lev]->setVal(0.0);
597  if (l_rotate) {
598  SFS_q1fx1_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(1,0,0)), dm, 1, IntVect(1,1,1) );
599  SFS_q1fx2_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(0,1,0)), dm, 1, IntVect(1,1,1) );
600  SFS_q1fx1_lev[lev]->setVal(0.0);
601  SFS_q1fx2_lev[lev]->setVal(0.0);
602  } else {
603  SFS_q1fx1_lev[lev] = nullptr;
604  SFS_q1fx2_lev[lev] = nullptr;
605  }
606  } else {
607  SFS_q1fx1_lev[lev] = nullptr;
608  SFS_q1fx2_lev[lev] = nullptr;
609  SFS_q1fx3_lev[lev] = nullptr;
610  SFS_q2fx3_lev[lev] = nullptr;
611  }
612  } else {
613  for (int i = 0; i < 9; i++) {
614  Tau[lev][i] = nullptr;
615  }
616  SFS_hfx1_lev[lev] = nullptr; SFS_hfx2_lev[lev] = nullptr; SFS_hfx3_lev[lev] = nullptr;
617  SFS_diss_lev[lev] = nullptr;
618  }
619 
620  if (l_use_kturb) {
621  eddyDiffs_lev[lev] = std::make_unique<MultiFab>(ba, dm, EddyDiff::NumDiffs, 2);
622  eddyDiffs_lev[lev]->setVal(0.0);
623  if(l_need_SmnSmn) {
624  SmnSmn_lev[lev] = std::make_unique<MultiFab>( ba, dm, 1, 0 );
625  } else {
626  SmnSmn_lev[lev] = nullptr;
627  }
628  } else {
629  eddyDiffs_lev[lev] = nullptr;
630  SmnSmn_lev[lev] = nullptr;
631  }
632 }
@ NumDiffs
Definition: ERF_IndexDefines.H:197

◆ update_terrain_arrays()

void ERF::update_terrain_arrays ( int  lev)
792 {
793  if (SolverChoice::mesh_type == MeshType::StretchedDz ||
794  SolverChoice::mesh_type == MeshType::VariableDz) {
795  make_J(geom[lev],*z_phys_nd[lev],*detJ_cc[lev]);
796  make_areas(geom[lev],*z_phys_nd[lev],*ax[lev],*ay[lev],*az[lev]);
797  make_zcc(geom[lev],*z_phys_nd[lev],*z_phys_cc[lev]);
798  } else { // MeshType::ConstantDz
799  if (SolverChoice::terrain_type == TerrainType::EB) {
800  const auto& ebfact = *eb[lev]->get_const_factory();
801  const MultiFab& volfrac = ebfact.getVolFrac();
802  detJ_cc[lev] = std::make_unique<MultiFab>(volfrac, amrex::make_alias, 0, volfrac.nComp());
803  }
804  }
805 }
void make_areas(const Geometry &geom, MultiFab &z_phys_nd, MultiFab &ax, MultiFab &ay, MultiFab &az)
Definition: ERF_TerrainMetrics.cpp:560
void make_J(const Geometry &geom, MultiFab &z_phys_nd, MultiFab &detJ_cc)
Definition: ERF_TerrainMetrics.cpp:522
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 = 0.0;
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 = a_z_phys_nd.size();
357 
358  Real hindcast_data_interval = solverChoice.hindcast_data_interval_in_hrs*3600.0;
359 
360  // Initialize static vectors once
361  if (next_read_forecast_time.empty()) {
362  next_read_forecast_time.resize(nlevs, -1.0);
363  last_read_forecast_time.resize(nlevs, -1.0);
364  Print() << "Initializing the time vector values here by " << lev << std::endl;
365  }
366 
367  if (next_read_forecast_time[lev] < 0.0) {
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 = 1.0 - (time - prev_read_time)/hindcast_data_interval;
428  Real alpha2 = 1.0 - alpha1;
429 
430  amrex::Print()<< "The values of alpha1 and alpha2 are " << alpha1 << " "<< alpha2 <<std::endl;
431 
432  if (alpha1 < 0.0 || alpha1 > 1.0 ||
433  alpha2 < 0.0 || alpha2 > 1.0)
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))/2.0;
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))/2.0;
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))/2.0;
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:1237

◆ Write2DPlotFile()

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

◆ Write3DPlotFile()

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

◆ write_1D_profiles()

void ERF::write_1D_profiles ( amrex::Real  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 > 0.) {
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 = 0.5 * (zlevels_stag[0][k] + zlevels_stag[0][k+1]);
69  } else {
70  z = (k + 0.5)* 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 = 0.5 * (zlevels_stag[0][k] + zlevels_stag[0][k+1]);
92  } else {
93  z = (k + 0.5)* dx[2];
94  }
95  Real thv = h_avg_th[k] * (1 + 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 > 0.) {
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 = 0.5 * (zlevels_stag[0][k] + zlevels_stag[0][k+1]);
147  } else {
148  z = (k + 0.5)* 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(amrex::Real 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 ( amrex::Real  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+1.

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 > 0.) {
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 = 0.5*(h_avg_u[k] + h_avg_u[k-1]);
142  Real vface = 0.5*(h_avg_v[k] + h_avg_v[k-1]);
143  Real thface = 0.5*(h_avg_th[k] + h_avg_th[k-1]);
144  Real pface = 0.5*(h_avg_p[k] + h_avg_p[k-1]);
145  Real qvface = 0.5*(h_avg_qv[k] + h_avg_qv[k-1]);
146  Real qcface = 0.5*(h_avg_qc[k] + h_avg_qc[k-1]);
147  Real qrface = 0.5*(h_avg_qr[k] + h_avg_qr[k-1]);
148  Real uuface = 0.5*(h_avg_uu[k] + h_avg_uu[k-1]);
149  Real vvface = 0.5*(h_avg_vv[k] + h_avg_vv[k-1]);
150  Real thvface = thface * (1 + 0.61*qvface - qcface - qrface);
151  w_cc = 0.5*(h_avg_w[k-1] + h_avg_w[k]);
152  uw_cc = 0.5*(h_avg_uw[k-1] + h_avg_uw[k]);
153  vw_cc = 0.5*(h_avg_vw[k-1] + h_avg_vw[k]);
154  ww_cc = 0.5*(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 = 1.5*h_avg_u[k-1] - 0.5*h_avg_u[k-2];
199  Real vface = 1.5*h_avg_v[k-1] - 0.5*h_avg_v[k-2];
200  Real thface = 1.5*h_avg_th[k-1] - 0.5*h_avg_th[k-2];
201  Real pface = 1.5*h_avg_p[k-1] - 0.5*h_avg_p[k-2];
202  Real qvface = 1.5*h_avg_qv[k-1] - 0.5*h_avg_qv[k-2];
203  Real qcface = 1.5*h_avg_qc[k-1] - 0.5*h_avg_qc[k-2];
204  Real qrface = 1.5*h_avg_qr[k-1] - 0.5*h_avg_qr[k-2];
205  Real uuface = 1.5*h_avg_uu[k-1] - 0.5*h_avg_uu[k-2];
206  Real vvface = 1.5*h_avg_vv[k-1] - 0.5*h_avg_vv[k-2];
207  Real thvface = thface * (1 + 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 > 0.) {
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 = 0.0;
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(amrex::Real 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
145 {
146  std::string PrettyLine = std::string(78, '=') + "\n";
147  std::string OtherLine = std::string(78, '-') + "\n";
148  std::string SkipSpace = std::string(8, ' ');
149 
150  // build information
151  os << PrettyLine;
152  os << " ERF Build Information\n";
153  os << PrettyLine;
154 
155  os << "build date: " << buildInfoGetBuildDate() << "\n";
156  os << "build machine: " << buildInfoGetBuildMachine() << "\n";
157  os << "build dir: " << buildInfoGetBuildDir() << "\n";
158  os << "AMReX dir: " << buildInfoGetAMReXDir() << "\n";
159 
160  os << "\n";
161 
162  os << "COMP: " << buildInfoGetComp() << "\n";
163  os << "COMP version: " << buildInfoGetCompVersion() << "\n";
164 
165  os << "C++ compiler: " << buildInfoGetCXXName() << "\n";
166  os << "C++ flags: " << buildInfoGetCXXFlags() << "\n";
167 
168  os << "\n";
169 
170  os << "Link flags: " << buildInfoGetLinkFlags() << "\n";
171  os << "Libraries: " << buildInfoGetLibraries() << "\n";
172 
173  os << "\n";
174 
175  for (int n = 1; n <= buildInfoGetNumModules(); n++) {
176  os << buildInfoGetModuleName(n) << ": "
177  << buildInfoGetModuleVal(n) << "\n";
178  }
179 
180  os << "\n";
181  const char* githash1 = buildInfoGetGitHash(1);
182  const char* githash2 = buildInfoGetGitHash(2);
183  if (strlen(githash1) > 0) {
184  os << "ERF git hash: " << githash1 << "\n";
185  }
186  if (strlen(githash2) > 0) {
187  os << "AMReX git hash: " << githash2 << "\n";
188  }
189 
190  const char* buildgithash = buildInfoGetBuildGitHash();
191  const char* buildgitname = buildInfoGetBuildGitName();
192  if (strlen(buildgithash) > 0) {
193  os << buildgitname << " git hash: " << buildgithash << "\n";
194  }
195 
196  os << "\n";
197  os << " ERF Compile time variables: \n";
198 
199  os << "\n";
200  os << " ERF Defines: \n";
201 #ifdef _OPENMP
202  os << std::setw(35) << std::left << "_OPENMP " << std::setw(6) << "ON"
203  << std::endl;
204 #else
205  os << std::setw(35) << std::left << "_OPENMP " << std::setw(6) << "OFF"
206  << std::endl;
207 #endif
208 
209 #ifdef MPI_VERSION
210  os << std::setw(35) << std::left << "MPI_VERSION " << std::setw(6)
211  << MPI_VERSION << std::endl;
212 #else
213  os << std::setw(35) << std::left << "MPI_VERSION " << std::setw(6)
214  << "UNDEFINED" << std::endl;
215 #endif
216 
217 #ifdef MPI_SUBVERSION
218  os << std::setw(35) << std::left << "MPI_SUBVERSION " << std::setw(6)
219  << MPI_SUBVERSION << std::endl;
220 #else
221  os << std::setw(35) << std::left << "MPI_SUBVERSION " << std::setw(6)
222  << "UNDEFINED" << std::endl;
223 #endif
224 
225  os << "\n\n";
226 }

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 = 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 variables at level " << lev << std::endl;
391  MultiFab tmp1d(ba1d[0],dmap[0],1,0);
392 
393  MultiFab::Copy(tmp1d,*mf_C1H,0,0,1,0);
394  VisMF::Write(tmp1d, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "C1H"));
395 
396  MultiFab::Copy(tmp1d,*mf_C2H,0,0,1,0);
397  VisMF::Write(tmp1d, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "C2H"));
398 
399  MultiFab tmp2d(ba2d[0],dmap[0],1,mf_MUB->nGrowVect());
400 
401  MultiFab::Copy(tmp2d,*mf_MUB,0,0,1,mf_MUB->nGrowVect());
402  VisMF::Write(tmp2d, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "MUB"));
403  }
404  }
405 #endif
406  } // for lev
407 
408 #ifdef ERF_USE_PARTICLES
409  particleData.Checkpoint(checkpointname);
410 #endif
411 
412 #if 0
413 #ifdef ERF_USE_NETCDF
414  // Write bdy_data files
415  if ( ParallelDescriptor::IOProcessor() &&
416  ((solverChoice.init_type==InitType::WRFInput) || (solverChoice.init_type==InitType::Metgrid)) &&
418  {
419  // Vector dimensions
420  int num_time = bdy_data_xlo.size();
421  int num_var = bdy_data_xlo[0].size();
422 
423  // Open header file and write to it
424  std::ofstream bdy_h_file(MultiFabFileFullPrefix(0, checkpointname, "Level_", "bdy_H"));
425  bdy_h_file << std::setprecision(1) << std::fixed;
426  bdy_h_file << num_time << "\n";
427  bdy_h_file << num_var << "\n";
428  bdy_h_file << start_bdy_time << "\n";
429  bdy_h_file << bdy_time_interval << "\n";
430  bdy_h_file << real_width << "\n";
431  for (int ivar(0); ivar<num_var; ++ivar) {
432  bdy_h_file << bdy_data_xlo[0][ivar].box() << "\n";
433  bdy_h_file << bdy_data_xhi[0][ivar].box() << "\n";
434  bdy_h_file << bdy_data_ylo[0][ivar].box() << "\n";
435  bdy_h_file << bdy_data_yhi[0][ivar].box() << "\n";
436  }
437 
438  // Open data file and write to it
439  std::ofstream bdy_d_file(MultiFabFileFullPrefix(0, checkpointname, "Level_", "bdy_D"));
440  for (int itime(0); itime<num_time; ++itime) {
441  if (bdy_data_xlo[itime].size() > 0) {
442  for (int ivar(0); ivar<num_var; ++ivar) {
443  bdy_data_xlo[itime][ivar].writeOn(bdy_d_file,0,1);
444  bdy_data_xhi[itime][ivar].writeOn(bdy_d_file,0,1);
445  bdy_data_ylo[itime][ivar].writeOn(bdy_d_file,0,1);
446  bdy_data_yhi[itime][ivar].writeOn(bdy_d_file,0,1);
447  }
448  }
449  }
450  }
451 #endif
452 #endif
453 
454  if (verbose > 0)
455  {
456  auto dCheckTime = amrex::second() - dCheckTime0;
457  ParallelDescriptor::ReduceRealMax(dCheckTime,ParallelDescriptor::IOProcessorNumber());
458  amrex::Print() << "Checkpoint write time = " << dCheckTime << " seconds." << '\n';
459  }
460 }
bool variable_coriolis
Definition: ERF_DataStruct.H:1206
Here is the call 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
1916 {
1917  AMREX_ALWAYS_ASSERT(nlevels <= bArray.size());
1918  AMREX_ALWAYS_ASSERT(nlevels <= my_ref_ratio.size()+1);
1919  AMREX_ALWAYS_ASSERT(nlevels <= level_steps.size());
1920 
1921  HeaderFile.precision(17);
1922 
1923  // ---- this is the generic plot file type name
1924  HeaderFile << versionName << '\n';
1925 
1926  HeaderFile << varnames.size() << '\n';
1927 
1928  for (int ivar = 0; ivar < varnames.size(); ++ivar) {
1929  HeaderFile << varnames[ivar] << "\n";
1930  }
1931  HeaderFile << AMREX_SPACEDIM << '\n';
1932  HeaderFile << my_time << '\n';
1933  HeaderFile << finest_level << '\n';
1934  for (int i = 0; i < AMREX_SPACEDIM; ++i) {
1935  HeaderFile << my_geom[0].ProbLo(i) << ' ';
1936  }
1937  HeaderFile << '\n';
1938  for (int i = 0; i < AMREX_SPACEDIM; ++i) {
1939  HeaderFile << my_geom[0].ProbHi(i) << ' ';
1940  }
1941  HeaderFile << '\n';
1942  for (int i = 0; i < finest_level; ++i) {
1943  HeaderFile << my_ref_ratio[i][0] << ' ';
1944  }
1945  HeaderFile << '\n';
1946  for (int i = 0; i <= finest_level; ++i) {
1947  HeaderFile << my_geom[i].Domain() << ' ';
1948  }
1949  HeaderFile << '\n';
1950  for (int i = 0; i <= finest_level; ++i) {
1951  HeaderFile << level_steps[i] << ' ';
1952  }
1953  HeaderFile << '\n';
1954  for (int i = 0; i <= finest_level; ++i) {
1955  for (int k = 0; k < AMREX_SPACEDIM; ++k) {
1956  HeaderFile << my_geom[i].CellSize()[k] << ' ';
1957  }
1958  HeaderFile << '\n';
1959  }
1960  HeaderFile << (int) my_geom[0].Coord() << '\n';
1961  HeaderFile << "0\n";
1962 
1963  for (int level = 0; level <= finest_level; ++level) {
1964  HeaderFile << level << ' ' << bArray[level].size() << ' ' << my_time << '\n';
1965  HeaderFile << level_steps[level] << '\n';
1966 
1967  const IntVect& domain_lo = my_geom[level].Domain().smallEnd();
1968  for (int i = 0; i < bArray[level].size(); ++i)
1969  {
1970  // Need to shift because the RealBox ctor we call takes the
1971  // physical location of index (0,0,0). This does not affect
1972  // the usual cases where the domain index starts with 0.
1973  const Box& b = shift(bArray[level][i], -domain_lo);
1974  RealBox loc = RealBox(b, my_geom[level].CellSize(), my_geom[level].ProbLo());
1975  for (int n = 0; n < AMREX_SPACEDIM; ++n) {
1976  HeaderFile << loc.lo(n) << ' ' << loc.hi(n) << '\n';
1977  }
1978  }
1979 
1980  HeaderFile << MultiFabHeaderPath(level, levelPrefix, mfPrefix) << '\n';
1981  }
1982  HeaderFile << "1" << "\n";
1983  HeaderFile << "3" << "\n";
1984  HeaderFile << "amrexvec_nu_x" << "\n";
1985  HeaderFile << "amrexvec_nu_y" << "\n";
1986  HeaderFile << "amrexvec_nu_z" << "\n";
1987  std::string mf_nodal_prefix = "Nu_nd";
1988  for (int level = 0; level <= finest_level; ++level) {
1989  HeaderFile << MultiFabHeaderPath(level, levelPrefix, mf_nodal_prefix) << '\n';
1990  }
1991 }
Coord
Definition: ERF_DataStruct.H:92
Here is the call graph for this function:

◆ writeJobInfo()

void ERF::writeJobInfo ( const std::string &  dir) const
11 {
12  // job_info file with details about the run
13  std::ofstream jobInfoFile;
14  std::string FullPathJobInfoFile = dir;
15  FullPathJobInfoFile += "/job_info";
16  jobInfoFile.open(FullPathJobInfoFile.c_str(), std::ios::out);
17 
18  std::string PrettyLine = "==================================================="
19  "============================\n";
20  std::string OtherLine = "----------------------------------------------------"
21  "----------------------------\n";
22  std::string SkipSpace = " ";
23 
24  // job information
25  jobInfoFile << PrettyLine;
26  jobInfoFile << " ERF Job Information\n";
27  jobInfoFile << PrettyLine;
28 
29  jobInfoFile << "inputs file: " << inputs_name << "\n\n";
30 
31  jobInfoFile << "number of MPI processes: "
32  << ParallelDescriptor::NProcs() << "\n";
33 #ifdef _OPENMP
34  jobInfoFile << "number of threads: " << omp_get_max_threads() << "\n";
35 #endif
36 
37  jobInfoFile << "\n";
38  jobInfoFile << "CPU time used since start of simulation (CPU-hours): "
39  << getCPUTime() / 3600.0;
40 
41  jobInfoFile << "\n\n";
42 
43  if (use_datetime) {
44  const std::string dt_format = "%Y-%m-%d %H:%M:%S"; // ISO 8601 standard
45  jobInfoFile << "Simulation time: " << getTimestamp(start_time+t_new[0], dt_format) << "\n";
46  jobInfoFile << "\n\n";
47  }
48 
49  // plotfile information
50  jobInfoFile << PrettyLine;
51  jobInfoFile << " Plotfile Information\n";
52  jobInfoFile << PrettyLine;
53 
54  time_t now = time(nullptr);
55 
56  // Convert now to tm struct for local timezone
57  tm* localtm = localtime(&now);
58  jobInfoFile << "output data / time: " << asctime(localtm);
59 
60  std::string currentDir = FileSystem::CurrentPath();
61  jobInfoFile << "output dir: " << currentDir << "\n";
62 
63  jobInfoFile << "\n\n";
64 
65  // build information
66  jobInfoFile << PrettyLine;
67  jobInfoFile << " Build Information\n";
68  jobInfoFile << PrettyLine;
69 
70  jobInfoFile << "build date: " << buildInfoGetBuildDate() << "\n";
71  jobInfoFile << "build machine: " << buildInfoGetBuildMachine() << "\n";
72  jobInfoFile << "build dir: " << buildInfoGetBuildDir() << "\n";
73  jobInfoFile << "AMReX dir: " << buildInfoGetAMReXDir() << "\n";
74 
75  jobInfoFile << "\n";
76 
77  jobInfoFile << "COMP: " << buildInfoGetComp() << "\n";
78  jobInfoFile << "COMP version: " << buildInfoGetCompVersion() << "\n";
79 
80  jobInfoFile << "\n";
81 
82  for (int n = 1; n <= buildInfoGetNumModules(); n++) {
83  jobInfoFile << buildInfoGetModuleName(n) << ": "
84  << buildInfoGetModuleVal(n) << "\n";
85  }
86 
87  jobInfoFile << "\n";
88 
89  const char* githash1 = buildInfoGetGitHash(1);
90  const char* githash2 = buildInfoGetGitHash(2);
91  if (strlen(githash1) > 0) {
92  jobInfoFile << "ERF git hash: " << githash1 << "\n";
93  }
94  if (strlen(githash2) > 0) {
95  jobInfoFile << "AMReX git hash: " << githash2 << "\n";
96  }
97 
98  const char* buildgithash = buildInfoGetBuildGitHash();
99  const char* buildgitname = buildInfoGetBuildGitName();
100  if (strlen(buildgithash) > 0) {
101  jobInfoFile << buildgitname << " git hash: " << buildgithash << "\n";
102  }
103 
104  jobInfoFile << "\n\n";
105 
106  // grid information
107  jobInfoFile << PrettyLine;
108  jobInfoFile << " Grid Information\n";
109  jobInfoFile << PrettyLine;
110 
111  int f_lev = finest_level;
112 
113  for (int i = 0; i <= f_lev; i++) {
114  jobInfoFile << " level: " << i << "\n";
115  jobInfoFile << " number of boxes = " << grids[i].size() << "\n";
116  jobInfoFile << " maximum zones = ";
117  for (int n = 0; n < AMREX_SPACEDIM; n++) {
118  jobInfoFile << geom[i].Domain().length(n) << " ";
119  }
120  jobInfoFile << "\n\n";
121  }
122 
123  jobInfoFile << " Boundary conditions\n";
124 
125  jobInfoFile << " -x: " << domain_bc_type[0] << "\n";
126  jobInfoFile << " +x: " << domain_bc_type[3] << "\n";
127  jobInfoFile << " -y: " << domain_bc_type[1] << "\n";
128  jobInfoFile << " +y: " << domain_bc_type[4] << "\n";
129  jobInfoFile << " -z: " << domain_bc_type[2] << "\n";
130  jobInfoFile << " +z: " << domain_bc_type[5] << "\n";
131 
132  jobInfoFile << "\n\n";
133 
134  // runtime parameters
135  jobInfoFile << PrettyLine;
136  jobInfoFile << " Inputs File Parameters\n";
137  jobInfoFile << PrettyLine;
138 
139  ParmParse::dumpTable(jobInfoFile, true);
140  jobInfoFile.close();
141 }
std::string inputs_name
Definition: main.cpp:14
static amrex::Real getCPUTime()
Definition: ERF.H:1504
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
1830 {
1831  BL_PROFILE("WriteMultiLevelPlotfileWithTerrain()");
1832 
1833  AMREX_ALWAYS_ASSERT(nlevels <= mf.size());
1834  AMREX_ALWAYS_ASSERT(nlevels <= rr.size()+1);
1835  AMREX_ALWAYS_ASSERT(nlevels <= level_steps.size());
1836  AMREX_ALWAYS_ASSERT(mf[0]->nComp() == varnames.size());
1837 
1838  bool callBarrier(false);
1839  PreBuildDirectorHierarchy(plotfilename, levelPrefix, nlevels, callBarrier);
1840  if (!extra_dirs.empty()) {
1841  for (const auto& d : extra_dirs) {
1842  const std::string ed = plotfilename+"/"+d;
1843  PreBuildDirectorHierarchy(ed, levelPrefix, nlevels, callBarrier);
1844  }
1845  }
1846  ParallelDescriptor::Barrier();
1847 
1848  if (ParallelDescriptor::MyProc() == ParallelDescriptor::NProcs()-1) {
1849  Vector<BoxArray> boxArrays(nlevels);
1850  for(int level(0); level < boxArrays.size(); ++level) {
1851  boxArrays[level] = mf[level]->boxArray();
1852  }
1853 
1854  auto f = [=]() {
1855  VisMF::IO_Buffer io_buffer(VisMF::IO_Buffer_Size);
1856  std::string HeaderFileName(plotfilename + "/Header");
1857  std::ofstream HeaderFile;
1858  HeaderFile.rdbuf()->pubsetbuf(io_buffer.dataPtr(), io_buffer.size());
1859  HeaderFile.open(HeaderFileName.c_str(), std::ofstream::out |
1860  std::ofstream::trunc |
1861  std::ofstream::binary);
1862  if( ! HeaderFile.good()) FileOpenFailed(HeaderFileName);
1863  WriteGenericPlotfileHeaderWithTerrain(HeaderFile, nlevels, boxArrays, varnames,
1864  my_geom, time, level_steps, rr, versionName,
1865  levelPrefix, mfPrefix);
1866  };
1867 
1868  if (AsyncOut::UseAsyncOut()) {
1869  AsyncOut::Submit(std::move(f));
1870  } else {
1871  f();
1872  }
1873  }
1874 
1875  std::string mf_nodal_prefix = "Nu_nd";
1876  for (int level = 0; level <= finest_level; ++level)
1877  {
1878  if (AsyncOut::UseAsyncOut()) {
1879  VisMF::AsyncWrite(*mf[level],
1880  MultiFabFileFullPrefix(level, plotfilename, levelPrefix, mfPrefix),
1881  true);
1882  VisMF::AsyncWrite(*mf_nd[level],
1883  MultiFabFileFullPrefix(level, plotfilename, levelPrefix, mf_nodal_prefix),
1884  true);
1885  } else {
1886  const MultiFab* data;
1887  std::unique_ptr<MultiFab> mf_tmp;
1888  if (mf[level]->nGrowVect() != 0) {
1889  mf_tmp = std::make_unique<MultiFab>(mf[level]->boxArray(),
1890  mf[level]->DistributionMap(),
1891  mf[level]->nComp(), 0, MFInfo(),
1892  mf[level]->Factory());
1893  MultiFab::Copy(*mf_tmp, *mf[level], 0, 0, mf[level]->nComp(), 0);
1894  data = mf_tmp.get();
1895  } else {
1896  data = mf[level];
1897  }
1898  VisMF::Write(*data , MultiFabFileFullPrefix(level, plotfilename, levelPrefix, mfPrefix));
1899  VisMF::Write(*mf_nd[level], MultiFabFileFullPrefix(level, plotfilename, levelPrefix, mf_nodal_prefix));
1900  }
1901  }
1902 }
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:1905
Here is the call graph for this function:

◆ WriteMyEBSurface()

void ERF::WriteMyEBSurface ( )

◆ writeNow()

bool ERF::writeNow ( const amrex::Real  cur_time,
const int  nstep,
const int  plot_int,
const amrex::Real  plot_per,
const amrex::Real  dt_0,
amrex::Real last_file_time 
)
3108 {
3109  bool write_now = false;
3110 
3111  if ( plot_int > 0) {
3112 
3113  write_now = (nstep % plot_int == 0);
3114 
3115  } else if (plot_per > 0.0) {
3116 
3117  amrex::Print() << "CUR NEXT PER " << cur_time << " " << next_file_time << " " << plot_per << std::endl;
3118 
3119  // Only write now if nstep newly matches the number of elapsed periods
3120  write_now = (cur_time > (next_file_time - Real(0.1)*dt_0));
3121  }
3122 
3123  return write_now;
3124 }

◆ 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 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)) * 1.0001 / delta[offset+0]);
188  int j0 = static_cast<int>((origin[offset+1] - geom[lev_for_sub].ProbLo(1)) * 1.0001 / delta[offset+1]);
189  int k0 = static_cast<int>((origin[offset+2] - geom[lev_for_sub].ProbLo(2)) * 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  der_function(tbx, dfab, 0, 1, sfab, Geom(lev_for_sub), t_new[0], nullptr, lev_for_sub);
295  }
296  mf.ParallelCopy(dmf,0,mf_comp,1,0,0);
297  mf_comp++;
298  }
299  };
300 
301  // *****************************************************************************************
302  // NOTE: All derived variables computed below **MUST MATCH THE ORDER** of "derived_names"
303  // defined in ERF.H
304  // *****************************************************************************************
305 
306  calculate_derived("soundspeed", vars_new[lev_for_sub][Vars::cons], derived::erf_dersoundspeed);
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 
316  // *****************************************************************************************
317 
318  Real time = t_new[lev_for_sub];
319 
320  std::string sf = subvol_file + "_" + std::to_string(isub);
321  std::string subvol_filename;
322 
324  const std::string dt_format = "%Y-%m-%d_%H:%M:%S"; // ISO 8601 standard
325  subvol_filename = sf + getTimestamp(start_time+time, dt_format);
326  } else {
327  subvol_filename = Concatenate(sf + "_", istep[0], file_name_digits);
328  }
329 
330  amrex::Print() <<"Writing subvolume into " << subvol_filename << std::endl;
331  WriteSingleLevelPlotfile(subvol_filename,mf,varnames,geom[lev_for_sub],time,istep[0]);
332 
333 }
real(c_double), private cs
Definition: ERF_module_mp_morr_two_moment.F90:203
Here is the call 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 3.0\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 3.0\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] << " 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

◆ base_state

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

◆ base_state_new

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

◆ bndry_output_planes_interval

int ERF::bndry_output_planes_interval = -1
staticprivate

◆ bndry_output_planes_per

Real ERF::bndry_output_planes_per = -1.0
staticprivate

◆ bndry_output_planes_start_time

Real ERF::bndry_output_planes_start_time = 0.0
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 = 0.8
staticprivate

◆ change_max

Real ERF::change_max = 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 = 0.0
staticprivate

◆ column_loc_y

Real ERF::column_loc_y = 0.0
staticprivate

◆ column_per

Real ERF::column_per = -1.0
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"}

◆ 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

◆ dt_max

Real ERF::dt_max = 1.0e9
staticprivate

◆ dt_max_initial

Real ERF::dt_max_initial = 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

◆ 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 = 1.0
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

◆ 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

◆ last_check_file_time

Real ERF::last_check_file_time = 0.0
staticprivate

◆ last_plot2d_file_step_1

int ERF::last_plot2d_file_step_1 = -1
staticprivate

◆ last_plot2d_file_step_2

int ERF::last_plot2d_file_step_2 = -1
staticprivate

◆ last_plot2d_file_time_1

Real ERF::last_plot2d_file_time_1 = 0.0
staticprivate

◆ last_plot2d_file_time_2

Real ERF::last_plot2d_file_time_2 = 0.0
staticprivate

◆ last_plot3d_file_step_1

int ERF::last_plot3d_file_step_1 = -1
staticprivate

◆ last_plot3d_file_step_2

int ERF::last_plot3d_file_step_2 = -1
staticprivate

◆ last_plot3d_file_time_1

Real ERF::last_plot3d_file_time_1 = 0.0
staticprivate

◆ last_plot3d_file_time_2

Real ERF::last_plot3d_file_time_2 = 0.0
staticprivate

◆ last_subvol_step

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

◆ last_subvol_time

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

◆ 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 = -1.0
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_check_int

int ERF::m_check_int = -1
private

◆ m_check_per

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

◆ 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

◆ m_plot2d_int_2

int ERF::m_plot2d_int_2 = -1
private

◆ m_plot2d_per_1

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

◆ m_plot2d_per_2

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

◆ m_plot3d_int_1

int ERF::m_plot3d_int_1 = -1
private

◆ m_plot3d_int_2

int ERF::m_plot3d_int_2 = -1
private

◆ m_plot3d_per_1

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

◆ m_plot3d_per_2

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

◆ 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

◆ m_subvol_per

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

◆ 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 {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_C1H

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

◆ mf_C2H

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

◆ mf_MUB

std::unique_ptr<amrex::MultiFab> ERF::mf_MUB
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 = -1.0
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

◆ plot2d_var_names_2

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

◆ 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

◆ plot3d_var_names_2

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

◆ 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

◆ plotfile2d_type_2

PlotFileType ERF::plotfile2d_type_2 = PlotFileType::None
staticprivate

◆ plotfile3d_type_1

PlotFileType ERF::plotfile3d_type_1 = PlotFileType::None
staticprivate

◆ plotfile3d_type_2

PlotFileType ERF::plotfile3d_type_2 = PlotFileType::None
staticprivate

◆ pp_inc

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

◆ pp_prefix

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

◆ previousCPUTimeUsed

Real ERF::previousCPUTimeUsed = 0.0
staticprivate

Referenced by getCPUTime().

◆ prob

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

◆ profile_int

int ERF::profile_int = -1
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

◆ 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

◆ sponge_type

std::string ERF::sponge_type
staticprivate

◆ sst_lev

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

◆ start_time

Real ERF::start_time = 0.0
staticprivate

◆ startCPUTime

Real ERF::startCPUTime = 0.0
staticprivate

Referenced by getCPUTime().

◆ stop_time

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

◆ 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 = 1.0
staticprivate

◆ subdomains

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

◆ subvol3d_var_names

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

◆ subvol_file

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

◆ sum_interval

int ERF::sum_interval = -1
staticprivate

◆ sum_per

Real ERF::sum_per = -1.0
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

◆ 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

◆ 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

◆ 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

◆ 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: