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 ReadCheckpointFileSurfaceLayer ()
 
void init_zphys (int lev, amrex::Real time)
 
void remake_zphys (int lev, amrex::Real time, 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_uniform (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 ()
 Initialize Rayleigh damping profiles. 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
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > sw_lw_fluxes
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > solar_zenith
 
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}
 
int real_set_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 ( )
135 {
136  int fix_random_seed = 0;
137  ParmParse pp("erf"); pp.query("fix_random_seed", fix_random_seed);
138  // Note that the value of 1024UL is not significant -- the point here is just to set the
139  // same seed for all MPI processes for the purpose of regression testing
140  if (fix_random_seed) {
141  Print() << "Fixing the random seed" << std::endl;
142  InitRandom(1024UL, ParallelDescriptor::NProcs(), 1024UL);
143  }
144 
145  ERF_shared();
146 }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real pp(amrex::Real y)
Definition: ERF_MicrophysicsUtils.H:233
void ERF_shared()
Definition: ERF.cpp:149
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  FillPatchFineLevel(lev, time, {&S_old, &U_old, &V_old, &W_old},
50  {&S_old, &rU_old[lev], &rV_old[lev], &rW_old[lev]},
51  base_state[lev], base_state[lev]);
52  }
53 
54  //
55  // So we must convert the fillpatched to momenta, including the ghost values
56  //
57  const MultiFab* c_vfrac = nullptr;
58  if (solverChoice.terrain_type == TerrainType::EB) {
59  c_vfrac = &((get_eb(lev).get_const_factory())->getVolFrac());
60  }
61 
62  VelocityToMomentum(U_old, rU_old[lev].nGrowVect(),
63  V_old, rV_old[lev].nGrowVect(),
64  W_old, rW_old[lev].nGrowVect(),
65  S_old, rU_old[lev], rV_old[lev], rW_old[lev],
66  Geom(lev).Domain(),
67  domain_bcs_type, c_vfrac);
68 
69  // Update the inflow perturbation update time and amplitude
70  if (solverChoice.pert_type == PerturbationType::Source ||
71  solverChoice.pert_type == PerturbationType::Direct ||
72  solverChoice.pert_type == PerturbationType::CPM)
73  {
74  turbPert.calc_tpi_update(lev, dt_lev, U_old, V_old, S_old);
75  }
76 
77  // If PerturbationType::Direct or CPM is selected, directly add the computed perturbation
78  // on the conserved field
79  if (solverChoice.pert_type == PerturbationType::Direct ||
80  solverChoice.pert_type == PerturbationType::CPM)
81  {
82  auto m_ixtype = S_old.boxArray().ixType(); // Conserved term
83  for (MFIter mfi(S_old,TileNoZ()); mfi.isValid(); ++mfi) {
84  Box bx = mfi.tilebox();
85  const Array4<Real> &cell_data = S_old.array(mfi);
86  const Array4<const Real> &pert_cell = turbPert.pb_cell[lev].array(mfi);
87  turbPert.apply_tpi(lev, bx, RhoTheta_comp, m_ixtype, cell_data, pert_cell);
88  }
89  }
90 
91  // configure SurfaceLayer params if needed
92  if (phys_bc_type[Orientation(Direction::z,Orientation::low)] == ERF_BC::surface_layer) {
93  if (m_SurfaceLayer) {
94  IntVect ng = Theta_prim[lev]->nGrowVect();
95  MultiFab::Copy( *Theta_prim[lev], S_old, RhoTheta_comp, 0, 1, ng);
96  MultiFab::Divide(*Theta_prim[lev], S_old, Rho_comp , 0, 1, ng);
97  if (solverChoice.moisture_type != MoistureType::None) {
98  ng = Qv_prim[lev]->nGrowVect();
99 
100  MultiFab::Copy( *Qv_prim[lev], S_old, RhoQ1_comp, 0, 1, ng);
101  MultiFab::Divide(*Qv_prim[lev], S_old, Rho_comp , 0, 1, ng);
102 
103  if (solverChoice.moisture_indices.qr > -1) {
104  MultiFab::Copy( *Qr_prim[lev], S_old, solverChoice.moisture_indices.qr, 0, 1, ng);
105  MultiFab::Divide(*Qr_prim[lev], S_old, Rho_comp , 0, 1, ng);
106  } else {
107  Qr_prim[lev]->setVal(0.0);
108  }
109  }
110  // NOTE: std::swap above causes the field ptrs to be out of date.
111  // Reassign the field ptrs for MAC avg computation.
112  m_SurfaceLayer->update_mac_ptrs(lev, vars_old, Theta_prim, Qv_prim, Qr_prim);
113  m_SurfaceLayer->update_pblh(lev, vars_old, z_phys_cc[lev].get(),
115  m_SurfaceLayer->update_fluxes(lev, time, S_old, z_phys_nd[lev], walldist[lev]);
116  }
117  }
118 
119 #if defined(ERF_USE_WINDFARM)
120  // **************************************************************************************
121  // Update the windfarm sources
122  // **************************************************************************************
123  if (solverChoice.windfarm_type != WindFarmType::None) {
124  advance_windfarm(Geom(lev), dt_lev, S_old,
125  U_old, V_old, W_old, vars_windfarm[lev],
126  Nturb[lev], SMark[lev], time);
127  }
128 
129 #endif
130 
131  // **************************************************************************************
132  // Update the radiation sources with the "old" state
133  // **************************************************************************************
134  advance_radiation(lev, S_old, dt_lev);
135 
136 #ifdef ERF_USE_SHOC
137  // **************************************************************************************
138  // Update the "old" state using SHOC
139  // **************************************************************************************
140  if (solverChoice.use_shoc) {
141  // Get SFC fluxes from SurfaceLayer
142  if (m_SurfaceLayer) {
143  Vector<const MultiFab*> mfs = {&S_old, &U_old, &V_old, &W_old};
144  m_SurfaceLayer->impose_SurfaceLayer_bcs(lev, mfs, Tau[lev],
145  SFS_hfx1_lev[lev].get() , SFS_hfx2_lev[lev].get() , SFS_hfx3_lev[lev].get(),
146  SFS_q1fx1_lev[lev].get(), SFS_q1fx2_lev[lev].get(), SFS_q1fx3_lev[lev].get(),
147  z_phys_nd[lev].get());
148  }
149 
150  // Get Shoc tendencies and update the state
151  Real* w_sub = (solverChoice.custom_w_subsidence) ? d_w_subsid[lev].data() : nullptr;
152  compute_shoc_tendencies(lev, &S_old, &U_old, &V_old, &W_old, w_sub,
153  Tau[lev][TauType::tau13].get(), Tau[lev][TauType::tau23].get(),
154  SFS_hfx3_lev[lev].get() , SFS_q1fx3_lev[lev].get() ,
155  eddyDiffs_lev[lev].get() , z_phys_nd[lev].get() ,
156  dt_lev);
157  }
158 #endif
159 
160  const BoxArray& ba = S_old.boxArray();
161  const DistributionMapping& dm = S_old.DistributionMap();
162 
163  int nvars = S_old.nComp();
164 
165  // Source array for conserved cell-centered quantities -- this will be filled
166  // in the call to make_sources in ERF_TI_slow_rhs_pre.H
167  MultiFab cc_source(ba,dm,nvars,1); cc_source.setVal(0.0);
168 
169  // Source arrays for momenta -- these will be filled
170  // in the call to make_mom_sources in ERF_TI_slow_rhs_pre.H
171  BoxArray ba_x(ba); ba_x.surroundingNodes(0);
172  MultiFab xmom_source(ba_x,dm,1,1); xmom_source.setVal(0.0);
173 
174  BoxArray ba_y(ba); ba_y.surroundingNodes(1);
175  MultiFab ymom_source(ba_y,dm,1,1); ymom_source.setVal(0.0);
176 
177  BoxArray ba_z(ba); ba_z.surroundingNodes(2);
178  MultiFab zmom_source(ba_z,dm,1,1); zmom_source.setVal(0.0);
179  MultiFab buoyancy(ba_z,dm,1,1); buoyancy.setVal(0.0);
180 
181  amrex::Vector<MultiFab> state_old;
182  amrex::Vector<MultiFab> state_new;
183 
184  // **************************************************************************************
185  // Here we define state_old and state_new which are to be advanced
186  // **************************************************************************************
187  // Initial solution
188  // Note that "old" and "new" here are relative to each RK stage.
189  state_old.push_back(MultiFab(S_old , amrex::make_alias, 0, nvars)); // cons
190  state_old.push_back(MultiFab(rU_old[lev], amrex::make_alias, 0, 1)); // xmom
191  state_old.push_back(MultiFab(rV_old[lev], amrex::make_alias, 0, 1)); // ymom
192  state_old.push_back(MultiFab(rW_old[lev], amrex::make_alias, 0, 1)); // zmom
193 
194  // Final solution
195  // state_new at the end of the last RK stage holds the t^{n+1} data
196  state_new.push_back(MultiFab(S_new , amrex::make_alias, 0, nvars)); // cons
197  state_new.push_back(MultiFab(rU_new[lev], amrex::make_alias, 0, 1)); // xmom
198  state_new.push_back(MultiFab(rV_new[lev], amrex::make_alias, 0, 1)); // ymom
199  state_new.push_back(MultiFab(rW_new[lev], amrex::make_alias, 0, 1)); // zmom
200 
201  // **************************************************************************************
202  // Tests on the reasonableness of the solution before the dycore
203  // **************************************************************************************
204  // Test for NaNs after dycore
205  if (check_for_nans > 1) {
206  if (verbose > 1) {
207  amrex::Print() << "Testing old state and vels for NaNs before dycore" << std::endl;
208  }
209  check_state_for_nans(S_old);
210  check_vels_for_nans(rU_old[lev],rV_old[lev],rW_old[lev]);
211  }
212 
213  // We only test on low temp if we have a moisture model because we are protecting against
214  // the test on low temp inside the moisture models
215  if (solverChoice.moisture_type != MoistureType::None) {
216  if (verbose > 1) {
217  amrex::Print() << "Testing on low temperature before dycore" << std::endl;
218  }
219  check_for_low_temp(S_old);
220  } else {
221  if (verbose > 1) {
222  amrex::Print() << "Testing on negative temperature before dycore" << std::endl;
223  }
225  }
226 
227  // **************************************************************************************
228  // Update the dycore
229  // **************************************************************************************
230  advance_dycore(lev, state_old, state_new,
231  U_old, V_old, W_old,
232  U_new, V_new, W_new,
233  cc_source, xmom_source, ymom_source, zmom_source, buoyancy,
234  Geom(lev), dt_lev, time);
235 
236  // **************************************************************************************
237  // Tests on the reasonableness of the solution after the dycore
238  // **************************************************************************************
239  // Test for NaNs after dycore
240  if (check_for_nans > 0) {
241  if (verbose > 1) {
242  amrex::Print() << "Testing new state and vels for NaNs after dycore" << std::endl;
243  }
244  check_state_for_nans(S_new);
245  check_vels_for_nans(rU_new[lev],rV_new[lev],rW_new[lev]);
246  }
247 
248  // We only test on low temp if we have a moisture model because we are protecting against
249  // the test on low temp inside the moisture models
250  if (solverChoice.moisture_type != MoistureType::None) {
251  if (verbose > 1) {
252  amrex::Print() << "Testing on low temperature after dycore" << std::endl;
253  }
254  check_for_low_temp(S_new);
255  } else {
256  // Otherwise we will test on negative (rhotheta) coming out of the dycore
257  if (verbose > 1) {
258  amrex::Print() << "Testing on negative temperature after dycore" << std::endl;
259  }
261  }
262 
263  // **************************************************************************************
264  // Update the microphysics (moisture)
265  // **************************************************************************************
267  {
268  advance_microphysics(lev, S_new, dt_lev, iteration, time);
269 
270  // Test for NaNs after microphysics
271  if (check_for_nans > 0) {
272  amrex::Print() << "Testing new state for NaNs after advance_microphysics" << std::endl;
273  check_state_for_nans(S_new);
274  }
275  }
276 
277  // **************************************************************************************
278  // Update the land surface model
279  // **************************************************************************************
280  advance_lsm(lev, S_new, U_new, V_new, dt_lev);
281 
282 #ifdef ERF_USE_PARTICLES
283  // **************************************************************************************
284  // Update the particle positions
285  // **************************************************************************************
286  evolveTracers( lev, dt_lev, vars_new, z_phys_nd );
287 #endif
288 
289  // ***********************************************************************************************
290  // Impose domain boundary conditions here so that in FillPatching the fine data we won't
291  // need to re-fill these
292  // ***********************************************************************************************
293  if (lev < finest_level) {
294  IntVect ngvect_vels = vars_new[lev][Vars::xvel].nGrowVect();
296  0,vars_new[lev][Vars::cons].nComp(),
297  vars_new[lev][Vars::cons].nGrowVect(),time,BCVars::cons_bc,true);
298  (*physbcs_u[lev])(vars_new[lev][Vars::xvel], vars_new[lev][Vars::xvel], vars_new[lev][Vars::yvel],
299  ngvect_vels,time,BCVars::xvel_bc,true);
300  (*physbcs_v[lev])(vars_new[lev][Vars::yvel], vars_new[lev][Vars::xvel], vars_new[lev][Vars::yvel],
301  ngvect_vels,time,BCVars::yvel_bc,true);
302  (*physbcs_w[lev])(vars_new[lev][Vars::zvel], vars_new[lev][Vars::xvel], vars_new[lev][Vars::yvel],
303  ngvect_vels,time,BCVars::zvel_bc,true);
304  }
305 
306  // **************************************************************************************
307  // Register old and new coarse data if we are at a level less than the finest level
308  // **************************************************************************************
309  if (lev < finest_level) {
310  if (cf_width > 0) {
311  // We must fill the ghost cells of these so that the parallel copy works correctly
312  state_old[IntVars::cons].FillBoundary(geom[lev].periodicity());
313  state_new[IntVars::cons].FillBoundary(geom[lev].periodicity());
314  FPr_c[lev].RegisterCoarseData({&state_old[IntVars::cons], &state_new[IntVars::cons]},
315  {time, time+dt_lev});
316  }
317 
318  if (cf_width >= 0) {
319  // We must fill the ghost cells of these so that the parallel copy works correctly
320  state_old[IntVars::xmom].FillBoundary(geom[lev].periodicity());
321  state_new[IntVars::xmom].FillBoundary(geom[lev].periodicity());
322  FPr_u[lev].RegisterCoarseData({&state_old[IntVars::xmom], &state_new[IntVars::xmom]},
323  {time, time+dt_lev});
324 
325  state_old[IntVars::ymom].FillBoundary(geom[lev].periodicity());
326  state_new[IntVars::ymom].FillBoundary(geom[lev].periodicity());
327  FPr_v[lev].RegisterCoarseData({&state_old[IntVars::ymom], &state_new[IntVars::ymom]},
328  {time, time+dt_lev});
329 
330  state_old[IntVars::zmom].FillBoundary(geom[lev].periodicity());
331  state_new[IntVars::zmom].FillBoundary(geom[lev].periodicity());
332  FPr_w[lev].RegisterCoarseData({&state_old[IntVars::zmom], &state_new[IntVars::zmom]},
333  {time, time+dt_lev});
334  }
335 
336  //
337  // Now create a MultiFab that holds (S_new - S_old) / dt from the coarse level interpolated
338  // on to the coarse/fine boundary at the fine resolution
339  //
340  Interpolater* mapper_f = &face_cons_linear_interp;
341 
342  // PhysBCFunctNoOp null_bc;
343  // MultiFab tempx(vars_new[lev+1][Vars::xvel].boxArray(),vars_new[lev+1][Vars::xvel].DistributionMap(),1,0);
344  // tempx.setVal(0.0);
345  // xmom_crse_rhs[lev+1].setVal(0.0);
346  // FPr_u[lev].FillSet(tempx , time , null_bc, domain_bcs_type);
347  // FPr_u[lev].FillSet(xmom_crse_rhs[lev+1], time+dt_lev, null_bc, domain_bcs_type);
348  // MultiFab::Subtract(xmom_crse_rhs[lev+1],tempx,0,0,1,IntVect{0});
349  // xmom_crse_rhs[lev+1].mult(1.0/dt_lev,0,1,0);
350 
351  // MultiFab tempy(vars_new[lev+1][Vars::yvel].boxArray(),vars_new[lev+1][Vars::yvel].DistributionMap(),1,0);
352  // tempy.setVal(0.0);
353  // ymom_crse_rhs[lev+1].setVal(0.0);
354  // FPr_v[lev].FillSet(tempy , time , null_bc, domain_bcs_type);
355  // FPr_v[lev].FillSet(ymom_crse_rhs[lev+1], time+dt_lev, null_bc, domain_bcs_type);
356  // MultiFab::Subtract(ymom_crse_rhs[lev+1],tempy,0,0,1,IntVect{0});
357  // ymom_crse_rhs[lev+1].mult(1.0/dt_lev,0,1,0);
358 
359  MultiFab temp_state(zmom_crse_rhs[lev+1].boxArray(),zmom_crse_rhs[lev+1].DistributionMap(),1,0);
360  InterpFromCoarseLevel(temp_state, IntVect{0}, IntVect{0}, state_old[IntVars::zmom], 0, 0, 1,
361  geom[lev], geom[lev+1], refRatio(lev), mapper_f, domain_bcs_type, BCVars::zvel_bc);
362  InterpFromCoarseLevel(zmom_crse_rhs[lev+1], IntVect{0}, IntVect{0}, state_new[IntVars::zmom], 0, 0, 1,
363  geom[lev], geom[lev+1], refRatio(lev), mapper_f, domain_bcs_type, BCVars::zvel_bc);
364  MultiFab::Subtract(zmom_crse_rhs[lev+1],temp_state,0,0,1,IntVect{0});
365  zmom_crse_rhs[lev+1].mult(1.0/dt_lev,0,1,0);
366  }
367 
368  // ***********************************************************************************************
369  // Update the time averaged velocities if they are requested
370  // ***********************************************************************************************
372  Time_Avg_Vel_atCC(dt[lev], t_avg_cnt[lev], vel_t_avg[lev].get(), U_new, V_new, W_new);
373  }
374 }
@ tau23
Definition: ERF_DataStruct.H:32
@ tau13
Definition: ERF_DataStruct.H:32
@ nvars
Definition: ERF_DataStruct.H:97
#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
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:869
amrex::Vector< std::unique_ptr< amrex::MultiFab > > walldist
Definition: ERF.H:977
void check_vels_for_nans(amrex::MultiFab const &xvel, amrex::MultiFab const &yvel, amrex::MultiFab const &zvel)
Definition: ERF.cpp:3065
amrex::Vector< ERFFillPatcher > FPr_u
Definition: ERF.H:923
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q1fx3_lev
Definition: ERF.H:946
amrex::Vector< amrex::Vector< amrex::MultiFab > > vars_new
Definition: ERF.H:834
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_hfx3_lev
Definition: ERF.H:944
amrex::Vector< ERFFillPatcher > FPr_v
Definition: ERF.H:924
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_hfx1_lev
Definition: ERF.H:944
eb_ const & get_eb(int lev) const noexcept
Definition: ERF.H:1648
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_cons > > physbcs_cons
Definition: ERF.H:856
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_cc
Definition: ERF.H:954
amrex::Vector< std::unique_ptr< amrex::MultiFab > > eddyDiffs_lev
Definition: ERF.H:930
static SolverChoice solverChoice
Definition: ERF.H:1191
amrex::Vector< ERFFillPatcher > FPr_c
Definition: ERF.H:922
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > Tau
Definition: ERF.H:928
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vel_t_avg
Definition: ERF.H:841
static int verbose
Definition: ERF.H:1226
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_w > > physbcs_w
Definition: ERF.H:859
amrex::Vector< amrex::MultiFab > base_state
Definition: ERF.H:988
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Qv_prim
Definition: ERF.H:864
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q1fx2_lev
Definition: ERF.H:946
amrex::Vector< amrex::MultiFab > rV_new
Definition: ERF.H:871
amrex::Vector< amrex::BCRec > domain_bcs_type
Definition: ERF.H:1004
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Qr_prim
Definition: ERF.H:865
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_u > > physbcs_u
Definition: ERF.H:857
amrex::Vector< amrex::Real > t_avg_cnt
Definition: ERF.H:842
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:868
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Theta_prim
Definition: ERF.H:863
static int check_for_nans
Definition: ERF.H:1230
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_v > > physbcs_v
Definition: ERF.H:858
void check_state_for_nans(amrex::MultiFab const &S)
Definition: ERF.cpp:3042
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_nd
Definition: ERF.H:953
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:873
amrex::Vector< amrex::MultiFab > zmom_crse_rhs
Definition: ERF.H:877
void check_for_low_temp(amrex::MultiFab &S)
Definition: ERF.cpp:3092
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:1194
amrex::Vector< amrex::MultiFab > rW_old
Definition: ERF.H:872
void check_for_negative_theta(amrex::MultiFab &S)
Definition: ERF.cpp:3127
std::unique_ptr< SurfaceLayer > m_SurfaceLayer
Definition: ERF.H:1361
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_w_subsid
Definition: ERF.H:1312
amrex::Vector< ERFFillPatcher > FPr_w
Definition: ERF.H:925
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_hfx2_lev
Definition: ERF.H:944
amrex::Vector< amrex::Real > dt
Definition: ERF.H:828
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:920
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q1fx1_lev
Definition: ERF.H:946
amrex::GpuArray< ERF_BC, AMREX_SPACEDIM *2 > phys_bc_type
Definition: ERF.H:1017
amrex::Vector< amrex::MultiFab > rV_old
Definition: ERF.H:870
amrex::Vector< amrex::Vector< amrex::MultiFab > > vars_old
Definition: ERF.H:835
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:160
@ cons
Definition: ERF_IndexDefines.H:158
@ zmom
Definition: ERF_IndexDefines.H:161
@ xmom
Definition: ERF_IndexDefines.H:159
@ ng
Definition: ERF_Morrison.H:48
@ xvel
Definition: ERF_IndexDefines.H:141
@ cons
Definition: ERF_IndexDefines.H:140
@ zvel
Definition: ERF_IndexDefines.H:143
@ yvel
Definition: ERF_IndexDefines.H:142
int qr
Definition: ERF_DataStruct.H:109
bool use_shoc
Definition: ERF_DataStruct.H:1155
bool moisture_tight_coupling
Definition: ERF_DataStruct.H:1192
bool custom_w_subsidence
Definition: ERF_DataStruct.H:1139
MoistureType moisture_type
Definition: ERF_DataStruct.H:1171
static TerrainType terrain_type
Definition: ERF_DataStruct.H:1036
PerturbationType pert_type
Definition: ERF_DataStruct.H:1161
WindFarmType windfarm_type
Definition: ERF_DataStruct.H:1172
MoistureComponentIndices moisture_indices
Definition: ERF_DataStruct.H:1190
bool time_avg_vel
Definition: ERF_DataStruct.H:1158
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  ComputeStrain_N(bxcc, tbxxy, tbxxz, tbxyz, domain,
197  u, v, w,
198  tau11, tau22, tau33,
199  tau12, tau13, tau23,
200  dxInv,
201  mf_mx, mf_ux, mf_vx, mf_my, mf_uy, mf_vy, bc_ptr_h,
202  no_tau_corr_update_here, no_tau_corr_update_here);
203  }
204  } // mfi
205  } // l_use_diff
206  } // profile
207 
208 #include "ERF_TI_utils.H"
209 
210  // Additional SFS quantities, calculated once per timestep
211  MultiFab* Hfx1 = SFS_hfx1_lev[level].get();
212  MultiFab* Hfx2 = SFS_hfx2_lev[level].get();
213  MultiFab* Hfx3 = SFS_hfx3_lev[level].get();
214  MultiFab* Q1fx1 = SFS_q1fx1_lev[level].get();
215  MultiFab* Q1fx2 = SFS_q1fx2_lev[level].get();
216  MultiFab* Q1fx3 = SFS_q1fx3_lev[level].get();
217  MultiFab* Q2fx3 = SFS_q2fx3_lev[level].get();
218  MultiFab* Diss = SFS_diss_lev[level].get();
219 
220  // *************************************************************************
221  // Calculate cell-centered eddy viscosity & diffusivities
222  //
223  // Notes -- we fill all the data in ghost cells before calling this so
224  // that we can fill the eddy viscosity in the ghost regions and
225  // not have to call a boundary filler on this data itself
226  //
227  // LES - updates both horizontal and vertical eddy viscosity components
228  // PBL - only updates vertical eddy viscosity components so horizontal
229  // components come from the LES model or are left as zero.
230  // *************************************************************************
231  if (l_use_kturb)
232  {
233  // NOTE: state_new transfers to state_old for PBL (due to ptr swap in advance)
234  bool l_use_moisture = ( solverChoice.moisture_type != MoistureType::None );
235  const BCRec* bc_ptr_h = domain_bcs_type.data();
236  ComputeTurbulentViscosity(dt_advance, xvel_old, yvel_old,Tau[level],
237  state_old[IntVars::cons],
238  *walldist[level].get(),
239  *eddyDiffs, *Hfx1, *Hfx2, *Hfx3, *Diss, // to be updated
240  fine_geom, mapfac[level],
241  z_phys_nd[level], solverChoice,
242  m_SurfaceLayer, z_0, l_use_terrain_fitted_coords,
243  l_use_moisture, level,
244  bc_ptr_h);
245  }
246 
247  // ***********************************************************************************************
248  // Update user-defined source terms -- these are defined once per time step (not per RK stage)
249  // ***********************************************************************************************
251  prob->update_rhotheta_sources(old_time,
252  rhotheta_src_ptr,
253  fine_geom, z_phys_cc[level]);
254  }
255 
257  prob->update_rhoqt_sources(old_time,
258  rhoqt_src_ptr,
259  fine_geom, z_phys_cc[level]);
260  }
261 
263  prob->update_geostrophic_profile(old_time,
264  h_u_geos[level], d_u_geos[level],
265  h_v_geos[level], d_v_geos[level],
266  fine_geom, z_phys_cc[level]);
267  }
268 
270  prob->update_w_subsidence(old_time,
271  h_w_subsid[level], d_w_subsid[level],base_state[level],
272  fine_geom, z_phys_nd[level]);
273  }
274 
275  // ***********************************************************************************************
276  // Convert old velocity available on faces to old momentum on faces to be used in time integration
277  // ***********************************************************************************************
278  MultiFab density(state_old[IntVars::cons], make_alias, Rho_comp, 1);
279 
280  //
281  // This is an optimization since we won't need more than one ghost
282  // cell of momentum in the integrator if not using numerical diffusion
283  //
284  IntVect ngu = (!solverChoice.use_num_diff) ? IntVect(1,1,1) : xvel_old.nGrowVect();
285  IntVect ngv = (!solverChoice.use_num_diff) ? IntVect(1,1,1) : yvel_old.nGrowVect();
286  IntVect ngw = (!solverChoice.use_num_diff) ? IntVect(1,1,0) : zvel_old.nGrowVect();
287 
288  const MultiFab* c_vfrac = nullptr;
289  if (solverChoice.terrain_type == TerrainType::EB) {
290  c_vfrac = &((get_eb(level).get_const_factory())->getVolFrac());
291  }
292 
293  VelocityToMomentum(xvel_old, ngu, yvel_old, ngv, zvel_old, ngw, density,
294  state_old[IntVars::xmom],
295  state_old[IntVars::ymom],
296  state_old[IntVars::zmom],
297  domain, domain_bcs_type, c_vfrac);
298 
299  MultiFab::Copy(xvel_new,xvel_old,0,0,1,xvel_old.nGrowVect());
300  MultiFab::Copy(yvel_new,yvel_old,0,0,1,yvel_old.nGrowVect());
301  MultiFab::Copy(zvel_new,zvel_old,0,0,1,zvel_old.nGrowVect());
302 
303  bool fast_only = false;
304  bool vel_and_mom_synced = true;
305 
306  apply_bcs(state_old, old_time,
307  state_old[IntVars::cons].nGrow(), state_old[IntVars::xmom].nGrow(),
308  fast_only, vel_and_mom_synced);
309  cons_to_prim(state_old[IntVars::cons], state_old[IntVars::cons].nGrow());
310 
311  // ***********************************************************************************************
312  // Define a new MultiFab that holds q_total and fill it by summing the moisture components --
313  // to be used in buoyancy calculation and as part of the inertial weighting in the
314  // ***********************************************************************************************
315 
316  const bool l_eb_terrain = (solverChoice.terrain_type == TerrainType::EB);
317  MultiFab qt(grids[level], dmap[level], 1, (l_eb_terrain) ? 2 : 1);
318  qt.setVal(0.0);
319 
320 #include "ERF_TI_no_substep_fun.H"
321 #include "ERF_TI_substep_fun.H"
322 #include "ERF_TI_slow_rhs_pre.H"
323 #include "ERF_TI_slow_rhs_post.H"
324 
325  // ***************************************************************************************
326  // Setup the integrator and integrate for a single timestep
327  // **************************************************************************************
328  MRISplitIntegrator<Vector<MultiFab> >& mri_integrator = *mri_integrator_mem[level];
329 
330  // Define rhs and 'post update' utility function that is called after calculating
331  // any state data (e.g. at RK stages or at the end of a timestep)
332  mri_integrator.set_slow_rhs_pre(slow_rhs_fun_pre);
333  mri_integrator.set_slow_rhs_post(slow_rhs_fun_post);
334 
337  mri_integrator.set_no_substep(no_substep_fun);
338 
339  mri_integrator.advance(state_old, state_new, old_time, dt_advance);
340 
341  if (verbose) Print() << "Done with advance_dycore at level " << level << std::endl;
342 }
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, bool vert_only)
Definition: ERF_ComputeTurbulentViscosity.cpp:574
@ 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:97
@ wbar
Definition: ERF_DataStruct.H:97
@ vbar
Definition: ERF_DataStruct.H:97
@ thetabar
Definition: ERF_DataStruct.H:97
@ nvars_sponge
Definition: ERF_DataStruct.H:102
@ vbar_sponge
Definition: ERF_DataStruct.H:102
@ ubar_sponge
Definition: ERF_DataStruct.H:102
@ 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
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
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > mapfac
Definition: ERF.H:980
amrex::Vector< std::unique_ptr< MRISplitIntegrator< amrex::Vector< amrex::MultiFab > > > > mri_integrator_mem
Definition: ERF.H:844
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_sinesq_stag_ptrs
Definition: ERF.H:1343
amrex::Vector< amrex::Vector< amrex::Real > > h_w_subsid
Definition: ERF.H:1311
amrex::Vector< std::unique_ptr< amrex::MultiFab > > detJ_cc
Definition: ERF.H:956
amrex::Vector< amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > > d_sponge_ptrs
Definition: ERF.H:1339
amrex::Vector< long > dt_mri_ratio
Definition: ERF.H:829
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q2fx3_lev
Definition: ERF.H:947
std::unique_ptr< ProblemBase > prob
Definition: ERF.H:816
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > stretched_dz_d
Definition: ERF.H:986
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_diss_lev
Definition: ERF.H:945
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_sinesq_ptrs
Definition: ERF.H:1342
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_v_geos
Definition: ERF.H:1318
amrex::Vector< amrex::Vector< amrex::Real > > h_v_geos
Definition: ERF.H:1317
amrex::Vector< std::unique_ptr< amrex::MultiFab > > rhotheta_src
Definition: ERF.H:1308
amrex::Vector< amrex::Vector< amrex::Real > > h_u_geos
Definition: ERF.H:1314
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SmnSmn_lev
Definition: ERF.H:931
amrex::Vector< std::unique_ptr< amrex::MultiFab > > rhoqt_src
Definition: ERF.H:1309
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_u_geos
Definition: ERF.H:1315
static int fixed_mri_dt_ratio
Definition: ERF.H:1080
amrex::Vector< amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > > d_rayleigh_ptrs
Definition: ERF.H:1338
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:1048
DampingChoice dampingChoice
Definition: ERF_DataStruct.H:1058
DiffChoice diffChoice
Definition: ERF_DataStruct.H:1057
bool custom_rhotheta_forcing
Definition: ERF_DataStruct.H:1137
bool custom_geostrophic_profile
Definition: ERF_DataStruct.H:1142
bool use_num_diff
Definition: ERF_DataStruct.H:1164
bool custom_moisture_forcing
Definition: ERF_DataStruct.H:1138
amrex::Vector< TurbChoice > turbChoice
Definition: ERF_DataStruct.H:1060
SpongeChoice spongeChoice
Definition: ERF_DataStruct.H:1059
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:895
amrex::Vector< int > istep
Definition: ERF.H:822
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:1174

◆ 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:879
int real_width
Definition: ERF.H:1257

◆ 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  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  lsm_output_ptrs[i] = lsm.Get_Data_Ptr(lev,varIdx);
34  }
35 
36  // Enter radiation class driver
37  amrex::Real time_for_rad = t_new[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  sw_lw_fluxes[lev].get(), solar_zenith[lev].get(),
42  lsm_input_ptrs, lsm_output_ptrs,
43  qheating_rates[lev].get(), rad_fluxes[lev].get(),
44  z_phys_nd[lev].get() , lat_ptr, lon_ptr);
45  }
46 }
static amrex::Real start_time
Definition: ERF.H:1060
amrex::Vector< std::unique_ptr< amrex::MultiFab > > sw_lw_fluxes
Definition: ERF.H:913
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::iMultiFab > > > lmask_lev
Definition: ERF.H:936
amrex::Vector< std::unique_ptr< IRadiation > > rad
Definition: ERF.H:901
amrex::Vector< amrex::Real > t_new
Definition: ERF.H:826
amrex::Vector< std::unique_ptr< amrex::MultiFab > > solar_zenith
Definition: ERF.H:914
amrex::Vector< std::unique_ptr< amrex::MultiFab > > lon_m
Definition: ERF.H:779
amrex::Vector< std::unique_ptr< amrex::MultiFab > > lat_m
Definition: ERF.H:779
amrex::Vector< std::unique_ptr< amrex::MultiFab > > qheating_rates
Definition: ERF.H:902
amrex::Vector< std::unique_ptr< amrex::MultiFab > > rad_fluxes
Definition: ERF.H:903
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:1175

◆ 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 
)
140 {
141  ignore_unused(cons_pert);
142  ignore_unused(yvel_pert);
143  ignore_unused(zvel_pert);
144 
145  const Geometry& gm = geom[lev];
146  const Real dx = gm.CellSize(0);
147  const Real dy = gm.CellSize(1);
148 
149  const Real dmesh = std::min(dx, dy);
150  // ---- User choices ----
151  const Real sigma = solverChoice.pert_correlated_radius; // e.g. 2 km correlation length
152  const int r = static_cast<int>(3.0 * sigma / dmesh); // stencil radius
153 
154  // ---- Precompute Gaussian weights on host ----
155  const int wsize = 2*r + 1;
156  Vector<Real> w_host(wsize * wsize);
157 
158  Real Z = 0.0;
159  for (int m = -r; m <= r; ++m) {
160  for (int n = -r; n <= r; ++n) {
161  Real val = std::exp(-(m*m*dx*dx + n*n*dy*dy)/(2.0*sigma*sigma));
162  w_host[(m+r)*wsize + (n+r)] = val;
163  Z += val;
164  }
165  }
166  for (auto& v : w_host) {
167  v = v/Z;
168  }
169 
170  Gpu::DeviceVector<Real> w_dev;
171  w_dev.resize(w_host.size());
172  Gpu::copy(Gpu::hostToDevice, w_host.begin(), w_host.end(), w_dev.begin());
173 
174  Real const* w = w_dev.data();
175 
176  // 1. Define ngrow_big using the actual dimension macro
177  IntVect ngrow_big(AMREX_D_DECL(r, r, 0));
178 
179  // 2. Create the copy
180  MultiFab xvel_pert_copy(xvel_pert.boxArray(),
181  xvel_pert.DistributionMap(),
182  1, ngrow_big);
183  //MultiFab::Copy(xvel_pert_copy, xvel_pert, 0, 0, 1, 0);
184 
185  // 3. Use the built-in copy that includes ghost cell logic
186  // Copy(dst, src, src_comp, dst_comp, num_comp, ngrow)
187  // Setting ngrow to 0 ensures we only take valid data from the original
188  xvel_pert_copy.ParallelCopy(xvel_pert, 0, 0, 1, IntVect(0), ngrow_big, gm.periodicity());
189 
190  for (MFIter mfi(xvel_pert, TileNoZ()); mfi.isValid(); ++mfi)
191  {
192  const Box& tbx = mfi.tilebox();
193 
194  auto const& in = xvel_pert_copy.array(mfi);
195  auto const& out = xvel_pert.array(mfi);
196 
197  ParallelFor(tbx,
198  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
199  {
200  Real sum = 0.0;
201  for (int m = -r; m <= r; ++m) {
202  for (int n = -r; n <= r; ++n) {
203  Real wij = w[(m+r)*wsize + (n+r)];
204  sum += wij * in(i+m, j+n, k);
205  }
206  }
207  out(i,j,k) = sum;
208  });
209  }
210 }
struct @19 out
struct @19 in
amrex::Real pert_correlated_radius
Definition: ERF_DataStruct.H:1225
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 }
void AverageDownTo(int crse_lev, int scomp, int ncomp)
Definition: ERF_AverageDown.cpp:36
amrex::Vector< int > anelastic
Definition: ERF_DataStruct.H:1066
CouplingType coupling_type
Definition: ERF_DataStruct.H:1170

◆ 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 copyies 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:1246
@ 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 }

◆ check_for_low_temp()

void ERF::check_for_low_temp ( amrex::MultiFab &  S)
3093 {
3094  // *****************************************************************************
3095  // Test for low temp (low is defined as beyond the microphysics range of validity)
3096  // *****************************************************************************
3097  //
3098  // This value is defined in erf_dtesati in Source/Utils/ERF_MicrophysicsUtils.H
3099  Real t_low = 273.16 - 85.;
3100  //
3101  for (MFIter mfi(S); mfi.isValid(); ++mfi)
3102  {
3103  Box bx = mfi.tilebox();
3104  const Array4<Real> &s_arr = S.array(mfi);
3105  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
3106  {
3107  const Real rho = s_arr(i, j, k, Rho_comp);
3108  const Real rhotheta = s_arr(i, j, k, RhoTheta_comp);
3109  const Real qv = s_arr(i, j, k, RhoQ1_comp);
3110 
3111  Real temp = getTgivenRandRTh(rho, rhotheta, qv);
3112 
3113  if (temp < t_low) {
3114 #ifdef AMREX_USE_GPU
3115  AMREX_DEVICE_PRINTF("Temperature too low in cell: %d %d %d %e \n", i,j,k,temp);
3116 #else
3117  printf("Temperature too low in cell: %d %d %d \n", i,j,k);
3118  printf("Based on temp / rhotheta / rho %e %e %e \n", temp,rhotheta,rho);
3119 #endif
3120  Abort();
3121  }
3122  });
3123  }
3124 }
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_Kessler.H:22
@ 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)
3128 {
3129  // *****************************************************************************
3130  // Test for negative (rho theta)
3131  // *****************************************************************************
3132  for (MFIter mfi(S); mfi.isValid(); ++mfi)
3133  {
3134  Box bx = mfi.tilebox();
3135  const Array4<Real> &s_arr = S.array(mfi);
3136  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
3137  {
3138  const Real rhotheta = s_arr(i, j, k, RhoTheta_comp);
3139  if (rhotheta <= 0.) {
3140 #ifdef AMREX_USE_GPU
3141  AMREX_DEVICE_PRINTF("RhoTheta is negative at %d %d %d %e \n", i,j,k,rhotheta);
3142 #else
3143  printf("RhoTheta is negative at %d %d %d %e \n", i,j,k,rhotheta);
3144  Abort("Bad theta in check_for_negative_theta");
3145 #endif
3146  }
3147  });
3148  } // mfi
3149 }

◆ check_state_for_nans()

void ERF::check_state_for_nans ( amrex::MultiFab const &  S)
3043 {
3044  int ncomp = S.nComp();
3045  for (int lev = 0; lev <= finest_level; lev++)
3046  {
3047  //
3048  // Test at the end of every full timestep whether the solution data contains NaNs
3049  //
3050  bool any_have_nans = false;
3051  for (int i = 0; i < ncomp; i++) {
3052  if (S.contains_nan(i,1,0))
3053  {
3054  amrex::Print() << "Component " << i << " of conserved variables contains NaNs" << '\n';
3055  any_have_nans = true;
3056  }
3057  }
3058  if (any_have_nans) {
3059  exit(0);
3060  }
3061  }
3062 }

◆ check_vels_for_nans()

void ERF::check_vels_for_nans ( amrex::MultiFab const &  xvel,
amrex::MultiFab const &  yvel,
amrex::MultiFab const &  zvel 
)
3066 {
3067  //
3068  // Test at the end of every full timestep whether the solution data contains NaNs
3069  //
3070  bool any_have_nans = false;
3071  if (xvel.contains_nan(0,1,0))
3072  {
3073  amrex::Print() << "x-velocity contains NaNs " << '\n';
3074  any_have_nans = true;
3075  }
3076  if (yvel.contains_nan(0,1,0))
3077  {
3078  amrex::Print() << "y-velocity contains NaNs" << '\n';
3079  any_have_nans = true;
3080  }
3081  if (zvel.contains_nan(0,1,0))
3082  {
3083  amrex::Print() << "z-velocity contains NaNs" << '\n';
3084  any_have_nans = true;
3085  }
3086  if (any_have_nans) {
3087  exit(0);
3088  }
3089 }

◆ ClearLevel()

void ERF::ClearLevel ( int  lev)
override
769 {
770  for (int var_idx = 0; var_idx < Vars::NumTypes; ++var_idx) {
771  vars_new[lev][var_idx].clear();
772  vars_old[lev][var_idx].clear();
773  }
774 
775  base_state[lev].clear();
776 
777  rU_new[lev].clear();
778  rU_old[lev].clear();
779  rV_new[lev].clear();
780  rV_old[lev].clear();
781  rW_new[lev].clear();
782  rW_old[lev].clear();
783 
784  if (lev > 0) {
785  zmom_crse_rhs[lev].clear();
786  }
787 
788  if ( (solverChoice.anelastic[lev] == 1) || (solverChoice.project_initial_velocity[lev] == 1) ) {
789  pp_inc[lev].clear();
790  }
791  if (solverChoice.anelastic[lev] == 0) {
792  lagged_delta_rt[lev].clear();
793  }
794  avg_xmom[lev].clear();
795  avg_ymom[lev].clear();
796  avg_zmom[lev].clear();
797 
798  // Clears the integrator memory
799  mri_integrator_mem[lev].reset();
800 
801  // Clears the physical boundary condition routines
802  physbcs_cons[lev].reset();
803  physbcs_u[lev].reset();
804  physbcs_v[lev].reset();
805  physbcs_w[lev].reset();
806  physbcs_base[lev].reset();
807 
808  // Clears the flux register array
809  advflux_reg[lev]->reset();
810 
811  // Clears the 2D arrays
812  if (sst_lev[lev][0]) {
813  for (int n = 0; n < sst_lev[lev].size(); n++) {
814  sst_lev[lev][n].reset();
815  }
816  }
817  if (tsk_lev[lev][0]) {
818  for (int n = 0; n < tsk_lev[lev].size(); n++) {
819  tsk_lev[lev][n].reset();
820  }
821  }
822  if (lat_m[lev]) {
823  lat_m[lev].reset();
824  }
825  if (lon_m[lev]) {
826  lon_m[lev].reset();
827  }
828  if (sinPhi_m[lev]) {
829  sinPhi_m[lev].reset();
830  }
831  if (cosPhi_m[lev]) {
832  cosPhi_m[lev].reset();
833  }
834 }
amrex::Vector< amrex::MultiFab > avg_xmom
Definition: ERF.H:851
amrex::Vector< amrex::MultiFab > pp_inc
Definition: ERF.H:847
amrex::Vector< amrex::MultiFab > lagged_delta_rt
Definition: ERF.H:850
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > sst_lev
Definition: ERF.H:934
amrex::Vector< amrex::YAFluxRegister * > advflux_reg
Definition: ERF.H:999
amrex::Vector< std::unique_ptr< amrex::MultiFab > > sinPhi_m
Definition: ERF.H:781
amrex::Vector< std::unique_ptr< amrex::MultiFab > > cosPhi_m
Definition: ERF.H:781
amrex::Vector< amrex::MultiFab > avg_ymom
Definition: ERF.H:852
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_base > > physbcs_base
Definition: ERF.H:860
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > tsk_lev
Definition: ERF.H:935
amrex::Vector< amrex::MultiFab > avg_zmom
Definition: ERF.H:853
@ NumTypes
Definition: ERF_IndexDefines.H:144
amrex::Vector< int > project_initial_velocity
Definition: ERF_DataStruct.H:1068

◆ 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
@ 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:957
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ay
Definition: ERF.H:958

◆ 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  if (step == 0){
29  dt_0 *= init_shrink;
30  if (verbose && init_shrink != 1.0) {
31  Print() << "Timestep 0: shrink initial dt at level " << lev << " by " << init_shrink << std::endl;
32  }
33  }
34  }
35  // Limit dt's by the value of stop_time.
36  const Real eps = 1.e-3*dt_0;
37  if (t_new[0] + dt_0 > stop_time - eps) {
38  dt_0 = stop_time - t_new[0];
39  }
40 
41  dt[0] = dt_0;
42  for (int lev = 1; lev <= finest_level; ++lev) {
43  dt[lev] = dt[lev-1] / nsubsteps[lev];
44  }
45 }
amrex::Real estTimeStep(int lev, long &dt_fast_ratio) const
Definition: ERF_ComputeTimestep.cpp:54
static amrex::Real stop_time
Definition: ERF.H:1061
amrex::Vector< int > nsubsteps
Definition: ERF.H:823
static amrex::Real init_shrink
Definition: ERF.H:1072
static amrex::Real change_max
Definition: ERF.H:1073

◆ ComputeGhostCells()

static AMREX_FORCE_INLINE int ERF::ComputeGhostCells ( const SolverChoice sc)
inlinestaticprivate
1376  {
1377  int ngrow = 0;
1378 
1379  if (sc.use_num_diff)
1380  {
1381  ngrow = 3;
1382  } else {
1383  if (
1390  { ngrow = 3; }
1391  else if (
1398  { ngrow = 3; }
1399  else if (
1408  { ngrow = 3; }
1409  else if (
1418  { ngrow = 4; }
1419  else
1420  {
1421  if (sc.terrain_type == TerrainType::EB){
1422  ngrow = 4;
1423  } else {
1424  ngrow = 2;
1425  }
1426  }
1427  }
1428 
1429  return ngrow;
1430  }
@ 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:1056

◆ Construct_ERFFillPatchers()

void ERF::Construct_ERFFillPatchers ( int  lev)
private
2945 {
2946  auto& fine_new = vars_new[lev];
2947  auto& crse_new = vars_new[lev-1];
2948  auto& ba_fine = fine_new[Vars::cons].boxArray();
2949  auto& ba_crse = crse_new[Vars::cons].boxArray();
2950  auto& dm_fine = fine_new[Vars::cons].DistributionMap();
2951  auto& dm_crse = crse_new[Vars::cons].DistributionMap();
2952 
2953  int ncomp = vars_new[lev][Vars::cons].nComp();
2954 
2955  FPr_c.emplace_back(ba_fine, dm_fine, geom[lev] ,
2956  ba_crse, dm_crse, geom[lev-1],
2957  -cf_width, -cf_set_width, ncomp, &cell_cons_interp);
2958  FPr_u.emplace_back(convert(ba_fine, IntVect(1,0,0)), dm_fine, geom[lev] ,
2959  convert(ba_crse, IntVect(1,0,0)), dm_crse, geom[lev-1],
2960  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
2961  FPr_v.emplace_back(convert(ba_fine, IntVect(0,1,0)), dm_fine, geom[lev] ,
2962  convert(ba_crse, IntVect(0,1,0)), dm_crse, geom[lev-1],
2963  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
2964  FPr_w.emplace_back(convert(ba_fine, IntVect(0,0,1)), dm_fine, geom[lev] ,
2965  convert(ba_crse, IntVect(0,0,1)), dm_crse, geom[lev-1],
2966  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
2967 }
int cf_set_width
Definition: ERF.H:921

◆ 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 
)
118 {
119  ignore_unused(cons_pert);
120  ignore_unused(yvel_pert);
121  ignore_unused(zvel_pert);
122 
123  auto& lev_new = vars_new[lev];
124  for (MFIter mfi(lev_new[Vars::cons], TileNoZ()); mfi.isValid(); ++mfi) {
125  const auto &xvel_pert_arr = xvel_pert.array(mfi);
126  const Box &xbx = mfi.tilebox(IntVect(1,0,0));
127  ParallelForRNG(xbx, [=] AMREX_GPU_DEVICE(int i, int j, int k, const amrex::RandomEngine& engine) noexcept
128  {
129  xvel_pert_arr(i, j, k) = amrex::Random(engine);
130  });
131  }
132 }
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
1441  {
1442  return *datalog[i];
1443  }
amrex::Vector< std::unique_ptr< std::fstream > > datalog
Definition: ERF.H:1620

◆ DataLogName()

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

The filename of the ith datalog file.

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

◆ Define_ERFFillPatchers()

void ERF::Define_ERFFillPatchers ( int  lev)
private
2971 {
2972  auto& fine_new = vars_new[lev];
2973  auto& crse_new = vars_new[lev-1];
2974  auto& ba_fine = fine_new[Vars::cons].boxArray();
2975  auto& ba_crse = crse_new[Vars::cons].boxArray();
2976  auto& dm_fine = fine_new[Vars::cons].DistributionMap();
2977  auto& dm_crse = crse_new[Vars::cons].DistributionMap();
2978 
2979  int ncomp = fine_new[Vars::cons].nComp();
2980 
2981  FPr_c[lev-1].Define(ba_fine, dm_fine, geom[lev] ,
2982  ba_crse, dm_crse, geom[lev-1],
2983  -cf_width, -cf_set_width, ncomp, &cell_cons_interp);
2984  FPr_u[lev-1].Define(convert(ba_fine, IntVect(1,0,0)), dm_fine, geom[lev] ,
2985  convert(ba_crse, IntVect(1,0,0)), dm_crse, geom[lev-1],
2986  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
2987  FPr_v[lev-1].Define(convert(ba_fine, IntVect(0,1,0)), dm_fine, geom[lev] ,
2988  convert(ba_crse, IntVect(0,1,0)), dm_crse, geom[lev-1],
2989  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
2990  FPr_w[lev-1].Define(convert(ba_fine, IntVect(0,0,1)), dm_fine, geom[lev] ,
2991  convert(ba_crse, IntVect(0,0,1)), dm_crse, geom[lev-1],
2992  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
2993 }

◆ DerDataLog()

AMREX_FORCE_INLINE std::ostream& ERF::DerDataLog ( int  i)
inlineprivate
1448  {
1449  return *der_datalog[i];
1450  }
amrex::Vector< std::unique_ptr< std::fstream > > der_datalog
Definition: ERF.H:1621

◆ DerDataLogName()

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

◆ 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
@ Theta_v
Definition: ERF_IndexDefines.H:176
@ Mom_v
Definition: ERF_IndexDefines.H:175
@ 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 }

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

◆ derive_upwp()

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

◆ EBFactory()

amrex::EBFArrayBoxFactory const& ERF::EBFactory ( int  lev) const
inlineprivatenoexcept
1654  {
1655  return *(eb[lev]->get_const_factory());
1656  }
amrex::Vector< std::unique_ptr< eb_ > > eb
Definition: ERF.H:1646

◆ 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
167 {
168  Real l_gravity = solverChoice.gravity;
169  bool l_use_terrain = (solverChoice.mesh_type != MeshType::ConstantDz);
170 
171  const auto geomdata = geom[lev].data();
172  const Real dz = geomdata.CellSize(2);
173 
174  for ( MFIter mfi(dens, TileNoZ()); mfi.isValid(); ++mfi )
175  {
176  // Create a flat box with same horizontal extent but only one cell in vertical
177  const Box& tbz = mfi.nodaltilebox(2);
178  int klo = tbz.smallEnd(2);
179  int khi = tbz.bigEnd(2);
180 
181  // Note we only grow by 1 because that is how big z_cc is.
182  Box b2d = tbz; // Copy constructor
183  b2d.grow(0,1);
184  b2d.grow(1,1);
185  b2d.setRange(2,0);
186 
187  // Intersect this box with the domain
188  Box zdomain = convert(geom[lev].Domain(),tbz.ixType());
189  b2d &= zdomain;
190 
191  // We integrate to the first cell (and below) by using rho in this cell
192  // If gravity == 0 this is constant pressure
193  // If gravity != 0, hence this is a wall, this gives gp0 = dens[0] * gravity
194  // (dens_hse*gravity would also be dens[0]*gravity because we use foextrap for rho at k = -1)
195  // Note ng_pres_hse = 1
196 
197  // We start by assuming pressure on the ground is p_0 (in ERF_Constants.H)
198  // Note that gravity is positive
199 
200  Array4<Real> rho_arr = dens.array(mfi);
201  Array4<Real> pres_arr = pres.array(mfi);
202  Array4<Real> pi_arr = pi.array(mfi);
203  Array4<Real> th_arr = theta.array(mfi);
204  Array4<Real> zcc_arr;
205  if (l_use_terrain) {
206  zcc_arr = z_cc->array(mfi);
207  }
208 
209  const Real rdOcp = solverChoice.rdOcp;
210 
211  ParallelFor(b2d, [=] AMREX_GPU_DEVICE (int i, int j, int)
212  {
213  // Set value at surface from Newton iteration for rho
214  if (klo == 0)
215  {
216  // Physical height of the terrain at cell center
217  Real hz;
218  if (l_use_terrain) {
219  hz = zcc_arr(i,j,klo);
220  } else {
221  hz = 0.5*dz;
222  }
223 
224  pres_arr(i,j,klo) = p_0 - hz * rho_arr(i,j,klo) * l_gravity;
225  pi_arr(i,j,klo) = getExnergivenP(pres_arr(i,j,klo), rdOcp);
226  th_arr(i,j,klo) = getRhoThetagivenP(pres_arr(i,j,klo)) / rho_arr(i,j,klo);
227 
228  //
229  // Set ghost cell with dz and rho at boundary
230  // (We will set the rest of the ghost cells in the boundary condition routine)
231  //
232  pres_arr(i,j,klo-1) = p_0 + hz * rho_arr(i,j,klo) * l_gravity;
233  pi_arr(i,j,klo-1) = getExnergivenP(pres_arr(i,j,klo-1), rdOcp);
234  th_arr(i,j,klo-1) = getRhoThetagivenP(pres_arr(i,j,klo-1)) / rho_arr(i,j,klo-1);
235 
236  } else {
237 
238  // If level > 0 and klo > 0, we need to use the value of pres_arr(i,j,klo-1) which was
239  // filled from FillPatch-ing it.
240  Real dz_loc;
241  if (l_use_terrain) {
242  dz_loc = (zcc_arr(i,j,klo) - zcc_arr(i,j,klo-1));
243  } else {
244  dz_loc = dz;
245  }
246 
247  Real dens_interp = 0.5*(rho_arr(i,j,klo) + rho_arr(i,j,klo-1));
248  pres_arr(i,j,klo) = pres_arr(i,j,klo-1) - dz_loc * dens_interp * l_gravity;
249 
250  pi_arr(i,j,klo ) = getExnergivenP(pres_arr(i,j,klo ), rdOcp);
251  th_arr(i,j,klo ) = getRhoThetagivenP(pres_arr(i,j,klo )) / rho_arr(i,j,klo );
252 
253  pi_arr(i,j,klo-1) = getExnergivenP(pres_arr(i,j,klo-1), rdOcp);
254  th_arr(i,j,klo-1) = getRhoThetagivenP(pres_arr(i,j,klo-1)) / rho_arr(i,j,klo-1);
255  }
256 
257  Real dens_interp;
258  if (l_use_terrain) {
259  for (int k = klo+1; k <= khi; k++) {
260  Real dz_loc = (zcc_arr(i,j,k) - zcc_arr(i,j,k-1));
261  dens_interp = 0.5*(rho_arr(i,j,k) + rho_arr(i,j,k-1));
262  pres_arr(i,j,k) = pres_arr(i,j,k-1) - dz_loc * dens_interp * l_gravity;
263  pi_arr(i,j,k) = getExnergivenP(pres_arr(i,j,k), rdOcp);
264  th_arr(i,j,k) = getRhoThetagivenP(pres_arr(i,j,k)) / rho_arr(i,j,k);
265  }
266  } else {
267  for (int k = klo+1; k <= khi; k++) {
268  dens_interp = 0.5*(rho_arr(i,j,k) + rho_arr(i,j,k-1));
269  pres_arr(i,j,k) = pres_arr(i,j,k-1) - dz * dens_interp * l_gravity;
270  pi_arr(i,j,k) = getExnergivenP(pres_arr(i,j,k), rdOcp);
271  th_arr(i,j,k) = getRhoThetagivenP(pres_arr(i,j,k)) / rho_arr(i,j,k);
272  }
273  }
274  });
275 
276  } // mfi
277 
278  dens.FillBoundary(geom[lev].periodicity());
279  pres.FillBoundary(geom[lev].periodicity());
280  pi.FillBoundary(geom[lev].periodicity());
281  theta.FillBoundary(geom[lev].periodicity());
282  qv.FillBoundary(geom[lev].periodicity());
283 }
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
@ 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:1124
amrex::Real gravity
Definition: ERF_DataStruct.H:1122
Here is the call graph for this function:

◆ ERF_shared()

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

◆ ErrorEst()

void ERF::ErrorEst ( int  lev,
amrex::TagBoxArray &  tags,
amrex::Real  time,
int  ngrow 
)
override
25 {
26  const int clearval = TagBox::CLEAR;
27  const int tagval = TagBox::SET;
28 
29 #ifdef ERF_USE_NETCDF
30  if (solverChoice.init_type == InitType::WRFInput) {
31  int ratio;
32  Box subdomain;
33 
34  if (!nc_init_file[levc+1].empty())
35  {
36  Real levc_start_time = read_start_time_from_wrfinput(levc , nc_init_file[levc ][0]);
37  amrex::Print() << " WRFInput time at level " << levc << " is " << levc_start_time << std::endl;
38 
39  for (int isub = 0; isub < nc_init_file[levc+1].size(); isub++) {
40  if (!have_read_nc_init_file[levc+1][isub])
41  {
42  Real levf_start_time = read_start_time_from_wrfinput(levc+1, nc_init_file[levc+1][isub]);
43  amrex::Print() << " WRFInput start_time at level " << levc+1 << " is " << levf_start_time << std::endl;
44 
45  // We assume there is only one subdomain at levc; otherwise we don't know
46  // which one is the parent of the fine region we are trying to create
47  AMREX_ALWAYS_ASSERT(subdomains[levc].size() == 1);
48 
49  if ( (ref_ratio[levc][2]) != 1) {
50  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");
51  }
52 
53  if ( levf_start_time <= (levc_start_time + t_new[levc]) ) {
54  amrex::Print() << " WRFInput file to read: " << nc_init_file[levc+1][isub] << std::endl;
55  subdomain = read_subdomain_from_wrfinput(levc, nc_init_file[levc+1][isub], ratio);
56  amrex::Print() << " WRFInput subdomain " << isub << " at level " << levc+1 << " is " << subdomain << std::endl;
57 
58  if ( (ratio != ref_ratio[levc][0]) || (ratio != ref_ratio[levc][1]) ) {
59  amrex::Print() << "File " << nc_init_file[levc+1][0] << " has refinement ratio = " << ratio << std::endl;
60  amrex::Print() << "The inputs file has refinement ratio = " << ref_ratio[levc] << std::endl;
61  amrex::Abort("These must be the same -- please edit your inputs file and try again.");
62  }
63 
64  subdomain.coarsen(IntVect(ratio,ratio,1));
65 
66  Box coarser_level(subdomains[levc][isub].minimalBox());
67  subdomain.shift(coarser_level.smallEnd());
68 
69  if (verbose > 0) {
70  amrex::Print() << " Crse subdomain to be tagged is" << subdomain << std::endl;
71  }
72 
73  Box new_fine(subdomain); new_fine.refine(IntVect(ratio,ratio,1));
74  num_boxes_at_level[levc+1] = 1;
75  boxes_at_level[levc+1].push_back(new_fine);
76 
77  for (MFIter mfi(tags); mfi.isValid(); ++mfi) {
78  auto tag_arr = tags.array(mfi); // Get device-accessible array
79 
80  Box bx = mfi.validbox(); bx &= subdomain;
81 
82  if (!bx.isEmpty()) {
83  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
84  tag_arr(i,j,k) = TagBox::SET;
85  });
86  }
87  }
88  } // time is right
89  } else {
90  // Re-tag this region
91  for (MFIter mfi(tags); mfi.isValid(); ++mfi)
92  {
93  auto tag_arr = tags.array(mfi); // Get device-accessible array
94 
95  Box existing_bx_coarsened(boxes_at_level[levc+1][isub]);
96  existing_bx_coarsened.coarsen(ref_ratio[levc]);
97 
98  Box bx = mfi.validbox(); bx &= existing_bx_coarsened;
99 
100  if (!bx.isEmpty()) {
101  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
102  tag_arr(i,j,k) = TagBox::SET;
103  });
104  }
105  }
106  } // has file been read?
107  } // isub
108  return;
109  } // file not empty
110  }
111 #endif
112 
113  //
114  // Make sure the ghost cells of the level we are tagging at are filled
115  // in case we take differences that require them
116  // NOTE: We are Fillpatching only the cell-centered variables here
117  //
118  MultiFab& S_new = vars_new[levc][Vars::cons];
119  MultiFab& U_new = vars_new[levc][Vars::xvel];
120  MultiFab& V_new = vars_new[levc][Vars::yvel];
121  MultiFab& W_new = vars_new[levc][Vars::zvel];
122  //
123  if (levc == 0) {
124  FillPatchCrseLevel(levc, time, {&S_new, &U_new, &V_new, &W_new});
125  } else {
126  FillPatchFineLevel(levc, time, {&S_new, &U_new, &V_new, &W_new},
127  {&S_new, &rU_new[levc], &rV_new[levc], &rW_new[levc]},
128  base_state[levc], base_state[levc],
129  false, true);
130  }
131 
132  for (int j=0; j < ref_tags.size(); ++j)
133  {
134  //
135  // This mf must have ghost cells because we may take differences between adjacent values
136  //
137  std::unique_ptr<MultiFab> mf = std::make_unique<MultiFab>(grids[levc], dmap[levc], 1, 1);
138  mf->setVal(0.0);
139 
140  // This allows dynamic refinement based on the value of the density
141  if (ref_tags[j].Field() == "density")
142  {
143  MultiFab::Copy(*mf,vars_new[levc][Vars::cons],Rho_comp,0,1,1);
144 
145  // This allows dynamic refinement based on the value of qv
146  } else if ( ref_tags[j].Field() == "qv" ) {
147  MultiFab::Copy( *mf, vars_new[levc][Vars::cons], RhoQ1_comp, 0, 1, 1);
148  MultiFab::Divide(*mf, vars_new[levc][Vars::cons], Rho_comp, 0, 1, 1);
149 
150 
151  // This allows dynamic refinement based on the value of qc
152  } else if (ref_tags[j].Field() == "qc" ) {
153  MultiFab::Copy( *mf, vars_new[levc][Vars::cons], RhoQ2_comp, 0, 1, 1);
154  MultiFab::Divide(*mf, vars_new[levc][Vars::cons], Rho_comp, 0, 1, 1);
155 
156  // This allows dynamic refinement based on the value of the z-component of vorticity
157  } else if (ref_tags[j].Field() == "vorticity" ) {
158  Vector<MultiFab> mf_cc_vel(1);
159  mf_cc_vel[0].define(grids[levc], dmap[levc], AMREX_SPACEDIM, IntVect(1,1,1));
160  average_face_to_cellcenter(mf_cc_vel[0],0,Array<const MultiFab*,3>{&U_new, &V_new, &W_new});
161 
162  // Impose bc's at domain boundaries at all levels
163  FillBdyCCVels(mf_cc_vel,levc);
164 
165  mf->setVal(0.);
166 
167  for (MFIter mfi(*mf, TilingIfNotGPU()); mfi.isValid(); ++mfi)
168  {
169  const Box& bx = mfi.tilebox();
170  auto& dfab = (*mf)[mfi];
171  auto& sfab = mf_cc_vel[0][mfi];
172  derived::erf_dervortz(bx, dfab, 0, 1, sfab, Geom(levc), time, nullptr, levc);
173  }
174 
175  // This allows dynamic refinement based on the value of the scalar/theta
176  } else if ( (ref_tags[j].Field() == "scalar" ) ||
177  (ref_tags[j].Field() == "theta" ) )
178  {
179  for (MFIter mfi(*mf, TilingIfNotGPU()); mfi.isValid(); ++mfi)
180  {
181  const Box& bx = mfi.growntilebox();
182  auto& dfab = (*mf)[mfi];
183  auto& sfab = vars_new[levc][Vars::cons][mfi];
184  if (ref_tags[j].Field() == "scalar") {
185  derived::erf_derscalar(bx, dfab, 0, 1, sfab, Geom(levc), time, nullptr, levc);
186  } else if (ref_tags[j].Field() == "theta") {
187  derived::erf_dertheta(bx, dfab, 0, 1, sfab, Geom(levc), time, nullptr, levc);
188  }
189  } // mfi
190  // This allows dynamic refinement based on the value of the density
191  } else if ( (SolverChoice::terrain_type == TerrainType::ImmersedForcing) &&
192  (ref_tags[j].Field() == "terrain_blanking") )
193  {
194  MultiFab::Copy(*mf,*terrain_blanking[levc],0,0,1,1);
195  }
196  else if (ref_tags[j].Field() == "velmag")
197  {
198  ParmParse pp(pp_prefix);
199  Vector<std::string> refinement_indicators;
200  pp.queryarr("refinement_indicators",refinement_indicators,0,pp.countval("refinement_indicators"));
201  Real velmag_threshold;
202  bool is_hurricane_tracker = false;
203  for (int i=0; i<refinement_indicators.size(); ++i)
204  {
205  if (refinement_indicators[i]=="hurricane_tracker") {
206  is_hurricane_tracker = true;
207  std::string ref_prefix = pp_prefix + "." + refinement_indicators[i];
208  ParmParse ppr(ref_prefix);
209  ppr.get("value_greater", velmag_threshold);
210  break;
211  }
212  }
213 
214  Vector<MultiFab> mf_cc_vel(1);
215  mf_cc_vel[0].define(grids[levc], dmap[levc], AMREX_SPACEDIM, IntVect(0,0,0));
216  average_face_to_cellcenter(mf_cc_vel[0],0,Array<const MultiFab*,3>{&U_new, &V_new, &W_new});
217 
218  if (is_hurricane_tracker) {
219  HurricaneTracker(levc, time, mf_cc_vel[0], velmag_threshold, &tags);
220  } else {
221  for (MFIter mfi(*mf, TilingIfNotGPU()); mfi.isValid(); ++mfi)
222  {
223  const Box& bx = mfi.tilebox();
224  auto& dfab = (*mf)[mfi];
225  auto& sfab = mf_cc_vel[0][mfi];
226  derived::erf_dermagvel(bx, dfab, 0, 1, sfab, Geom(levc), time, nullptr, levc);
227  }
228  }
229 
230 #ifdef ERF_USE_PARTICLES
231  } else {
232  //
233  // This allows dynamic refinement based on the number of particles per cell
234  //
235  // Note that we must count all the particles in levels both at and above the current,
236  // since otherwise, e.g., if the particles are all at level 1, counting particles at
237  // level 0 will not trigger refinement when regridding so level 1 will disappear,
238  // then come back at the next regridding
239  //
240  const auto& particles_namelist( particleData.getNames() );
241  mf->setVal(0.0);
242  for (ParticlesNamesVector::size_type i = 0; i < particles_namelist.size(); i++)
243  {
244  std::string tmp_string(particles_namelist[i]+"_count");
245  IntVect rr = IntVect::TheUnitVector();
246  if (ref_tags[j].Field() == tmp_string) {
247  for (int lev = levc; lev <= finest_level; lev++)
248  {
249  MultiFab temp_dat(grids[lev], dmap[lev], 1, 0); temp_dat.setVal(0);
250  particleData[particles_namelist[i]]->IncrementWithTotal(temp_dat, lev);
251 
252  MultiFab temp_dat_crse(grids[levc], dmap[levc], 1, 0); temp_dat_crse.setVal(0);
253 
254  if (lev == levc) {
255  MultiFab::Copy(*mf, temp_dat, 0, 0, 1, 0);
256  } else {
257  for (int d = 0; d < AMREX_SPACEDIM; d++) {
258  rr[d] *= ref_ratio[levc][d];
259  }
260  average_down(temp_dat, temp_dat_crse, 0, 1, rr);
261  MultiFab::Add(*mf, temp_dat_crse, 0, 0, 1, 0);
262  }
263  }
264  }
265  }
266 #endif
267  }
268 
269  ref_tags[j](tags,mf.get(),clearval,tagval,time,levc,geom[levc]);
270  } // loop over j
271 
272  // ********************************************************************************************
273  // Refinement based on 2d distance from the "eye" which is defined here as the (x,y) location of
274  // the integrated qv
275  // ********************************************************************************************
276  ParmParse pp(pp_prefix);
277  Vector<std::string> refinement_indicators;
278  pp.queryarr("refinement_indicators",refinement_indicators,0,pp.countval("refinement_indicators"));
279  for (int i=0; i<refinement_indicators.size(); ++i)
280  {
281  if ( (refinement_indicators[i]=="storm_tracker") && (solverChoice.moisture_type != MoistureType::None) )
282  {
283  std::string ref_prefix = pp_prefix + "." + refinement_indicators[i];
284  ParmParse ppr(ref_prefix);
285 
286  Real ref_start_time = -1.0;
287  ppr.query("start_time",ref_start_time);
288 
289  if (time >= ref_start_time) {
290 
291  Real max_radius = -1.0;
292  ppr.get("max_radius", max_radius);
293 
294  // Create the volume-weighted sum of (rho qv) in each column
295  MultiFab mf_qv_int(ba2d[levc], dmap[levc], 1, 0); mf_qv_int.setVal(0.);
296 
297  // Define the 2D MultiFab holding the column-integrated (rho qv)
298  volWgtColumnSum(levc, S_new, RhoQ1_comp, mf_qv_int, *detJ_cc[levc]);
299 
300  // Find the max value in the domain
301  IntVect eye = mf_qv_int.maxIndex(0);
302 
303  const auto dx = geom[levc].CellSizeArray();
304  const auto prob_lo = geom[levc].ProbLoArray();
305 
306  Real eye_x = prob_lo[0] + (eye[0] + 0.5) * dx[0];
307  Real eye_y = prob_lo[1] + (eye[1] + 0.5) * dx[1];
308 
309  tag_on_distance_from_eye(geom[levc], &tags, eye_x, eye_y, max_radius);
310  }
311  }
312  }
313 }
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:619
amrex::Vector< amrex::Vector< amrex::Box > > boxes_at_level
Definition: ERF.H:820
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:648
static amrex::Vector< amrex::Vector< std::string > > nc_init_file
Definition: ERF.H:1252
amrex::Vector< amrex::Vector< amrex::BoxArray > > subdomains
Definition: ERF.H:1369
static amrex::Vector< amrex::Vector< int > > have_read_nc_init_file
Definition: ERF.H:1253
static amrex::Vector< amrex::AMRErrorTag > ref_tags
Definition: ERF.H:1367
amrex::Vector< int > num_boxes_at_level
Definition: ERF.H:818
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:1030
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
55 {
56  BL_PROFILE("ERF::estTimeStep()");
57 
58  Real estdt_comp = 1.e20;
59  Real estdt_lowM = 1.e20;
60 
61  // We intentionally use the level 0 domain to compute whether to use this direction in the dt calculation
62  const int nxc = geom[0].Domain().length(0);
63  const int nyc = geom[0].Domain().length(1);
64 
65  auto const dxinv = geom[level].InvCellSizeArray();
66  auto const dzinv = 1.0 / dz_min[level];
67 
68  MultiFab const& S_new = vars_new[level][Vars::cons];
69 
70  MultiFab ccvel(grids[level],dmap[level],3,0);
71 
72  average_face_to_cellcenter(ccvel,0,
73  Array<const MultiFab*,3>{&vars_new[level][Vars::xvel],
74  &vars_new[level][Vars::yvel],
75  &vars_new[level][Vars::zvel]});
76 
77  bool l_substepping = (solverChoice.substepping_type[level] == SubsteppingType::Implicit);
78  int l_anelastic = solverChoice.anelastic[level];
79 
80  bool l_comp_substepping_diag = (verbose && l_substepping && !l_anelastic && solverChoice.substepping_diag);
81 
82  Real estdt_comp_inv;
83  Real estdt_vert_comp_inv;
84  Real estdt_vert_lowM_inv;
85 
86  if (l_substepping && (nxc==1) && (nyc==1)) {
87  // SCM -- should not depend on dx or dy; force minimum number of substeps
88  estdt_comp_inv = std::numeric_limits<Real>::min();
89  }
90  else if (solverChoice.terrain_type == TerrainType::EB)
91  {
92  const eb_& eb_lev = get_eb(level);
93  const MultiFab& detJ = (eb_lev.get_const_factory())->getVolFrac();
94 
95  estdt_comp_inv = ReduceMax(S_new, ccvel, detJ, 0,
96  [=] AMREX_GPU_HOST_DEVICE (Box const& b,
97  Array4<Real const> const& s,
98  Array4<Real const> const& u,
99  Array4<Real const> const& vf) -> Real
100  {
101  Real new_comp_dt = -1.e100;
102  amrex::Loop(b, [=,&new_comp_dt] (int i, int j, int k) noexcept
103  {
104  if (vf(i,j,k) > 0.)
105  {
106  const Real rho = s(i, j, k, Rho_comp);
107  const Real rhotheta = s(i, j, k, RhoTheta_comp);
108 
109  // NOTE: even when moisture is present,
110  // we only use the partial pressure of the dry air
111  // to compute the soundspeed
112  Real pressure = getPgivenRTh(rhotheta);
113  Real c = std::sqrt(Gamma * pressure / rho);
114 
115  // If we are doing implicit acoustic substepping, then the z-direction does not contribute
116  // to the computation of the time step
117  if (l_substepping) {
118  if ((nxc > 1) && (nyc==1)) {
119  // 2-D in x-z
120  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]), new_comp_dt);
121  } else if ((nyc > 1) && (nxc==1)) {
122  // 2-D in y-z
123  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,1))+c)*dxinv[1]), new_comp_dt);
124  } else {
125  // 3-D
126  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]),
127  ((amrex::Math::abs(u(i,j,k,1))+c)*dxinv[1]), new_comp_dt);
128  }
129 
130  // If we are not doing implicit acoustic substepping, then the z-direction contributes
131  // to the computation of the time step
132  } else {
133  if (nxc > 1 && nyc > 1) {
134  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]),
135  ((amrex::Math::abs(u(i,j,k,1))+c)*dxinv[1]),
136  ((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
137  } else if (nxc > 1) {
138  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]),
139  ((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
140  } else if (nyc > 1) {
141  new_comp_dt = amrex::max(((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 {
144  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
145  }
146 
147  }
148  }
149  });
150  return new_comp_dt;
151  });
152 
153  } else {
154  estdt_comp_inv = ReduceMax(S_new, ccvel, 0,
155  [=] AMREX_GPU_HOST_DEVICE (Box const& b,
156  Array4<Real const> const& s,
157  Array4<Real const> const& u) -> Real
158  {
159  Real new_comp_dt = -1.e100;
160  amrex::Loop(b, [=,&new_comp_dt] (int i, int j, int k) noexcept
161  {
162  {
163  const Real rho = s(i, j, k, Rho_comp);
164  const Real rhotheta = s(i, j, k, RhoTheta_comp);
165 
166  // NOTE: even when moisture is present,
167  // we only use the partial pressure of the dry air
168  // to compute the soundspeed
169  Real pressure = getPgivenRTh(rhotheta);
170  Real c = std::sqrt(Gamma * pressure / rho);
171 
172  // If we are doing implicit acoustic substepping, then the z-direction does not contribute
173  // to the computation of the time step
174  if (l_substepping) {
175  if ((nxc > 1) && (nyc==1)) {
176  // 2-D in x-z
177  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]), new_comp_dt);
178  } else if ((nyc > 1) && (nxc==1)) {
179  // 2-D in y-z
180  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,1))+c)*dxinv[1]), new_comp_dt);
181  } else {
182  // 3-D
183  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]),
184  ((amrex::Math::abs(u(i,j,k,1))+c)*dxinv[1]), new_comp_dt);
185  }
186 
187  // If we are not doing implicit acoustic substepping, then the z-direction contributes
188  // to the computation of the time step
189  } else {
190  if (nxc > 1 && nyc > 1) {
191  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]),
192  ((amrex::Math::abs(u(i,j,k,1))+c)*dxinv[1]),
193  ((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
194  } else if (nxc > 1) {
195  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]),
196  ((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
197  } else if (nyc > 1) {
198  new_comp_dt = amrex::max(((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 {
201  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
202  }
203 
204  }
205  }
206  });
207  return new_comp_dt;
208  });
209  } // not EB
210 
211  ParallelDescriptor::ReduceRealMax(estdt_comp_inv);
212  estdt_comp = cfl / estdt_comp_inv;
213 
214  Real estdt_lowM_inv = ReduceMax(ccvel, 0,
215  [=] AMREX_GPU_HOST_DEVICE (Box const& b,
216  Array4<Real const> const& u) -> Real
217  {
218  Real new_lm_dt = -1.e100;
219  Loop(b, [=,&new_lm_dt] (int i, int j, int k) noexcept
220  {
221  new_lm_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0)))*dxinv[0]),
222  ((amrex::Math::abs(u(i,j,k,1)))*dxinv[1]),
223  ((amrex::Math::abs(u(i,j,k,2)))*dxinv[2]), new_lm_dt);
224  });
225  return new_lm_dt;
226  });
227 
228  ParallelDescriptor::ReduceRealMax(estdt_lowM_inv);
229  if (estdt_lowM_inv > 0.0_rt)
230  estdt_lowM = cfl / estdt_lowM_inv;
231 
232  // Additional vertical diagnostics
233  if (l_comp_substepping_diag) {
234  estdt_vert_comp_inv = ReduceMax(S_new, ccvel, 0,
235  [=] AMREX_GPU_HOST_DEVICE (Box const& b,
236  Array4<Real const> const& s,
237  Array4<Real const> const& u) -> Real
238  {
239  Real new_comp_dt = -1.e100;
240  amrex::Loop(b, [=,&new_comp_dt] (int i, int j, int k) noexcept
241  {
242  {
243  const Real rho = s(i, j, k, Rho_comp);
244  const Real rhotheta = s(i, j, k, RhoTheta_comp);
245 
246  // NOTE: even when moisture is present,
247  // we only use the partial pressure of the dry air
248  // to compute the soundspeed
249  Real pressure = getPgivenRTh(rhotheta);
250  Real c = std::sqrt(Gamma * pressure / rho);
251 
252  // Look at z-direction only
253  new_comp_dt = amrex::max((amrex::Math::abs(u(i,j,k,2)) + c) * dzinv, new_comp_dt);
254  }
255  });
256  return new_comp_dt;
257  });
258 
259  estdt_vert_lowM_inv = ReduceMax(ccvel, 0,
260  [=] AMREX_GPU_HOST_DEVICE (Box const& b,
261  Array4<Real const> const& u) -> Real
262  {
263  Real new_lowM_dt = -1.e100;
264  amrex::Loop(b, [=,&new_lowM_dt] (int i, int j, int k) noexcept
265  {
266  new_lowM_dt = amrex::max((amrex::Math::abs(u(i,j,k,2))) * dzinv, new_lowM_dt);
267  });
268  return new_lowM_dt;
269  });
270 
271  ParallelDescriptor::ReduceRealMax(estdt_vert_comp_inv);
272  ParallelDescriptor::ReduceRealMax(estdt_vert_lowM_inv);
273  }
274 
275  if (verbose) {
276  if (fixed_dt[level] <= 0.0) {
277  Print() << "Using cfl = " << cfl << " and dx/dy/dz_min = " <<
278  1.0/dxinv[0] << " " << 1.0/dxinv[1] << " " << dz_min[level] << std::endl;
279  Print() << "Compressible dt at level " << level << ": " << estdt_comp << std::endl;
280  if (estdt_lowM_inv > 0.0_rt) {
281  Print() << "Anelastic dt at level " << level << ": " << estdt_lowM << std::endl;
282  } else {
283  Print() << "Anelastic dt at level " << level << ": undefined " << std::endl;
284  }
285  }
286 
287  if (fixed_dt[level] > 0.0) {
288  Print() << "Based on cfl of 1.0 " << std::endl;
289  Print() << "Compressible dt at level " << level << " would be: " << estdt_comp/cfl << std::endl;
290  if (estdt_lowM_inv > 0.0_rt) {
291  Print() << "Anelastic dt at level " << level << " would be: " << estdt_lowM/cfl << std::endl;
292  } else {
293  Print() << "Anelastic dt at level " << level << " would be undefined " << std::endl;
294  }
295  Print() << "Fixed dt at level " << level << " is: " << fixed_dt[level] << std::endl;
296  if (fixed_fast_dt[level] > 0.0) {
297  Print() << "Fixed fast dt at level " << level << " is: " << fixed_fast_dt[level] << std::endl;
298  }
299  }
300  }
301 
302  if (solverChoice.substepping_type[level] != SubsteppingType::None) {
303  if (fixed_dt[level] > 0. && fixed_fast_dt[level] > 0.) {
304  dt_fast_ratio = static_cast<long>( fixed_dt[level] / fixed_fast_dt[level] );
305  } else if (fixed_dt[level] > 0.) {
306  // Max CFL_c = 1.0 for substeps by default, but we enforce a min of 4 substeps
307  auto dt_sub_max = (estdt_comp/cfl * sub_cfl);
308  dt_fast_ratio = static_cast<long>( std::max(fixed_dt[level]/dt_sub_max,4.) );
309  } else {
310  // auto dt_sub_max = (estdt_comp/cfl * sub_cfl);
311  // dt_fast_ratio = static_cast<long>( std::max(estdt_comp/dt_sub_max,4.) );
312  dt_fast_ratio = static_cast<long>( std::max(cfl / sub_cfl, 4.) );
313  }
314 
315  // Force time step ratio to be an even value
317  if ( dt_fast_ratio%2 != 0) dt_fast_ratio += 1;
318  } else {
319  if ( dt_fast_ratio%6 != 0) {
320  Print() << "mri_dt_ratio = " << dt_fast_ratio
321  << " not divisible by 6 for N/3 substeps in stage 1" << std::endl;
322  dt_fast_ratio = static_cast<int>(std::ceil(dt_fast_ratio/6.0) * 6);
323  }
324  }
325 
326  if (verbose) {
327  Print() << "smallest even ratio is: " << dt_fast_ratio << std::endl;
328  }
329  } // if substepping
330 
331  // Print out some extra diagnostics -- dt calcs are repeated so as to not
332  // disrupt the overall code flow...
333  if (l_comp_substepping_diag) {
334  Real dt_diag = (fixed_dt[level] > 0.0) ? fixed_dt[level] : estdt_comp;
335  int ns = (fixed_mri_dt_ratio > 0.0) ? fixed_mri_dt_ratio : dt_fast_ratio;
336 
337  // horizontal acoustic CFL must be < 1 (fully explicit)
338  // vertical acoustic CFL may be > 1
339  Print() << "effective horiz,vert acoustic CFL with " << ns << " substeps : "
340  << (dt_diag / ns) * estdt_comp_inv << " "
341  << (dt_diag / ns) * estdt_vert_comp_inv << std::endl;
342 
343  // vertical advective CFL should be < 1, otherwise w-damping may be needed
344  Print() << "effective vert advective CFL : "
345  << dt_diag * estdt_vert_lowM_inv << std::endl;
346  }
347 
348  if (fixed_dt[level] > 0.0) {
349  return fixed_dt[level];
350  } else {
351  // Anelastic (substepping is not allowed)
352  if (l_anelastic) {
353 
354  // Make sure that timestep is less than the dt_max
355  estdt_lowM = amrex::min(estdt_lowM, dt_max);
356 
357  // On the first timestep enforce dt_max_initial
358  if (istep[level] == 0) {
359  return amrex::min(dt_max_initial, estdt_lowM);
360  } else {
361  return estdt_lowM;
362  }
363 
364 
365  // Compressible with or without substepping
366  } else {
367  return estdt_comp;
368  }
369  }
370 }
constexpr amrex::Real Gamma
Definition: ERF_Constants.H:19
amrex::Vector< amrex::Real > dz_min
Definition: ERF.H:1371
amrex::Vector< amrex::Real > fixed_dt
Definition: ERF.H:1078
static amrex::Real dt_max
Definition: ERF.H:1075
amrex::Vector< amrex::Real > fixed_fast_dt
Definition: ERF.H:1079
static amrex::Real cfl
Definition: ERF.H:1070
static amrex::Real sub_cfl
Definition: ERF.H:1071
Definition: ERF_EB.H:13
@ ns
Definition: ERF_Morrison.H:47
int force_stage1_single_substep
Definition: ERF_DataStruct.H:1063
amrex::Vector< SubsteppingType > substepping_type
Definition: ERF_DataStruct.H:1065
bool substepping_diag
Definition: ERF_DataStruct.H:1072
Here is the call graph for this function:

◆ Evolve()

void ERF::Evolve ( )
577 {
578  BL_PROFILE_VAR("ERF::Evolve()", evolve);
579 
580  Real cur_time = t_new[0];
581 
582  // Take one coarse timestep by calling timeStep -- which recursively calls timeStep
583  // for finer levels (with or without subcycling)
584  for (int step = istep[0]; step < max_step && start_time+cur_time < stop_time; ++step)
585  {
586  if (use_datetime) {
587  Print() << "\n" << getTimestamp(start_time+cur_time, datetime_format)
588  << " (" << cur_time << " s elapsed)" << std::endl;
589  }
590  Print() << "\nCoarse STEP " << step+1 << " starts ..." << std::endl;
591 
592  ComputeDt(step);
593 
594  // Make sure we have read enough of the boundary plane data to make it through this timestep
595  if (input_bndry_planes)
596  {
597  m_r2d->read_input_files(cur_time,dt[0],m_bc_extdir_vals);
598  }
599 
600 #ifdef ERF_USE_PARTICLES
601  // We call this every time step with the knowledge that the particles may be
602  // initialized at a later time than the simulation start time.
603  // The ParticleContainer carries a "start time" so the initialization will happen
604  // only when a) time > start_time, and b) particles have not yet been initialized
605  initializeTracers((ParGDBBase*)GetParGDB(),z_phys_nd,cur_time);
606 #endif
607 
608  if(solverChoice.init_type == InitType::HindCast and
610  for(int lev=0;lev<finest_level+1;lev++){
611  WeatherDataInterpolation(lev,cur_time,z_phys_nd,false);
612  }
613  }
614 
615  if(solverChoice.init_type == InitType::HindCast and
617  for(int lev=0;lev<finest_level+1;lev++){
618  SurfaceDataInterpolation(lev,cur_time,z_phys_nd,false);
619  }
620  }
621 
622  auto dEvolveTime0 = amrex::second();
623 
624  int iteration = 1;
625  timeStep(0, cur_time, iteration);
626 
627  cur_time += dt[0];
628 
629  Print() << "Coarse STEP " << step+1 << " ends." << " TIME = " << cur_time
630  << " DT = " << dt[0] << std::endl;
631 
632  if (check_for_nans > 0) {
633  amrex::Print() << "Testing new state and vels for NaNs at end of timestep" << std::endl;
634  for (int lev = 0; lev <= finest_level; ++lev) {
637  }
638  }
639 
640  if (verbose > 0)
641  {
642  auto dEvolveTime = amrex::second() - dEvolveTime0;
643  ParallelDescriptor::ReduceRealMax(dEvolveTime,ParallelDescriptor::IOProcessorNumber());
644  amrex::Print() << "Timestep time = " << dEvolveTime << " seconds." << '\n';
645  }
646 
647  post_timestep(step, cur_time, dt[0]);
648 
649  if (writeNow(cur_time, step+1, m_plot3d_int_1, m_plot3d_per_1, dt[0], last_plot3d_file_time_1)) {
650  last_plot3d_file_step_1 = step+1;
652  for (int lev = 0; lev <= finest_level; ++lev) {lsm.Plot(lev, step+1);}
654  }
655  if (writeNow(cur_time, step+1, m_plot3d_int_2, m_plot3d_per_2, dt[0], last_plot3d_file_time_2)) {
656  last_plot3d_file_step_2 = step+1;
658  for (int lev = 0; lev <= finest_level; ++lev) {lsm.Plot(lev, step+1);}
660  }
661 
662  if (writeNow(cur_time, step+1, m_plot2d_int_1, m_plot2d_per_1, dt[0], last_plot2d_file_time_1)) {
663  last_plot2d_file_step_1 = step+1;
666  }
667 
668  if (writeNow(cur_time, step+1, m_plot2d_int_2, m_plot2d_per_2, dt[0], last_plot2d_file_time_2)) {
669  last_plot2d_file_step_2 = step+1;
672  }
673 
674  for (int i = 0; i < m_subvol_int.size(); i++) {
675  if (writeNow(cur_time, step+1, m_subvol_int[i], m_subvol_per[i], dt[0], last_subvol_time[i])) {
676  last_subvol_step[i] = step+1;
678  if (m_subvol_per[i] > 0.) {last_subvol_time[i] += m_subvol_per[i];}
679  }
680  }
681 
682  if (writeNow(cur_time, step+1, m_check_int, m_check_per, dt[0], last_check_file_time)) {
683  last_check_file_step = step+1;
686  }
687 
688 #ifdef AMREX_MEM_PROFILING
689  {
690  std::ostringstream ss;
691  ss << "[STEP " << step+1 << "]";
692  MemProfiler::report(ss.str());
693  }
694 #endif
695 
696  if (cur_time >= stop_time - 1.e-6*dt[0]) break;
697  }
698 
699  // Write plotfiles at final time
700  if ( (m_plot3d_int_1 > 0 || m_plot3d_per_1 > 0.) && istep[0] > last_plot3d_file_step_1 ) {
703  }
704  if ( (m_plot3d_int_2 > 0 || m_plot3d_per_2 > 0.) && istep[0] > last_plot3d_file_step_2) {
707  }
708  if ( (m_plot2d_int_1 > 0 || m_plot2d_per_1 > 0.) && istep[0] > last_plot2d_file_step_1 ) {
711  }
712  if ( (m_plot2d_int_2 > 0 || m_plot2d_per_2 > 0.) && istep[0] > last_plot2d_file_step_2) {
715  }
716 
717  for (int i = 0; i < m_subvol_int.size(); i++) {
718  if ( (m_subvol_int[i] > 0 || m_subvol_per[i] > 0.) && istep[0] > last_subvol_step[i]) {
720  if (m_subvol_per[i] > 0.) {last_subvol_time[i] += m_subvol_per[i];}
721  }
722  }
723 
724  if ( (m_check_int > 0 || m_check_per > 0.) && istep[0] > last_check_file_step) {
727  }
728 
729  BL_PROFILE_VAR_STOP(evolve);
730 }
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:1034
int max_step
Definition: ERF.H:1057
static amrex::Real last_plot2d_file_time_2
Definition: ERF.H:1039
amrex::Vector< std::string > subvol3d_var_names
Definition: ERF.H:1122
amrex::Real m_plot2d_per_1
Definition: ERF.H:1107
static amrex::Real last_plot2d_file_time_1
Definition: ERF.H:1038
static int last_plot2d_file_step_2
Definition: ERF.H:1033
amrex::Array< amrex::Array< amrex::Real, AMREX_SPACEDIM *2 >, AMREX_SPACEDIM+NBCVAR_max > m_bc_extdir_vals
Definition: ERF.H:1011
static amrex::Real last_plot3d_file_time_2
Definition: ERF.H:1037
int m_plot2d_int_2
Definition: ERF.H:1100
int m_plot3d_int_1
Definition: ERF.H:1097
static int last_plot3d_file_step_2
Definition: ERF.H:1031
void post_timestep(int nstep, amrex::Real time, amrex::Real dt_lev)
Definition: ERF.cpp:734
amrex::Real m_plot2d_per_2
Definition: ERF.H:1108
amrex::Real m_check_per
Definition: ERF.H:1120
int m_check_int
Definition: ERF.H:1119
static int input_bndry_planes
Definition: ERF.H:1302
void Write2DPlotFile(int which, PlotFileType plotfile_type, amrex::Vector< std::string > plot_var_names)
Definition: ERF_Plotfile.cpp:1965
const std::string datetime_format
Definition: ERF.H:1064
bool use_datetime
Definition: ERF.H:1063
amrex::Vector< amrex::Real > m_subvol_per
Definition: ERF.H:1103
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:1106
amrex::Vector< int > last_subvol_step
Definition: ERF.H:1042
static PlotFileType plotfile3d_type_2
Definition: ERF.H:1239
static PlotFileType plotfile2d_type_2
Definition: ERF.H:1241
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:3021
int m_plot2d_int_1
Definition: ERF.H:1099
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:1032
amrex::Real m_plot3d_per_1
Definition: ERF.H:1105
std::unique_ptr< ReadBndryPlanes > m_r2d
Definition: ERF.H:1360
amrex::Vector< amrex::Real > last_subvol_time
Definition: ERF.H:1043
static amrex::Real last_check_file_time
Definition: ERF.H:1040
static int last_plot3d_file_step_1
Definition: ERF.H:1030
static amrex::Real last_plot3d_file_time_1
Definition: ERF.H:1036
static PlotFileType plotfile2d_type_1
Definition: ERF.H:1240
static PlotFileType plotfile3d_type_1
Definition: ERF.H:1238
amrex::Vector< int > m_subvol_int
Definition: ERF.H:1102
int m_plot3d_int_2
Definition: ERF.H:1098
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:1215
bool hindcast_surface_bcs
Definition: ERF_DataStruct.H:1216

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  //
18  AMREX_ALWAYS_ASSERT(m_r2d);
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  Vector<std::unique_ptr<PlaneVector>>& bndry_data = m_r2d->interp_in_time(time);
27 
28  const BCRec* bc_ptr = domain_bcs_type_d.data();
29 
30  // xlo: ori = 0
31  // ylo: ori = 1
32  // zlo: ori = 2
33  // xhi: ori = 3
34  // yhi: ori = 4
35  // zhi: ori = 5
36  const auto& bdatxlo = (*bndry_data[0])[lev].const_array();
37  const auto& bdatylo = (*bndry_data[1])[lev].const_array();
38  const auto& bdatxhi = (*bndry_data[3])[lev].const_array();
39  const auto& bdatyhi = (*bndry_data[4])[lev].const_array();
40 
41  int bccomp;
42 
43  for (int var_idx = 0; var_idx < Vars::NumTypes; ++var_idx)
44  {
45  MultiFab& mf = *mfs[var_idx];
46  const int icomp = 0;
47  const int ncomp = mf.nComp();
48 
49  if (var_idx == Vars::xvel) {
50  bccomp = BCVars::xvel_bc;
51  } else if (var_idx == Vars::yvel) {
52  bccomp = BCVars::yvel_bc;
53  } else if (var_idx == Vars::zvel) {
54  bccomp = BCVars::zvel_bc;
55  } else if (var_idx == Vars::cons) {
56  bccomp = BCVars::cons_bc;
57  }
58 
59 #ifdef AMREX_USE_OMP
60 #pragma omp parallel if (Gpu::notInLaunchRegion())
61 #endif
62  for (MFIter mfi(mf); mfi.isValid(); ++mfi)
63  {
64  const Array4<Real>& dest_arr = mf.array(mfi);
65  Box bx = mfi.growntilebox();
66 
67  // x-faces
68  {
69  Box bx_xlo(bx); bx_xlo.setBig(0,dom_lo.x-1);
70  if (var_idx == Vars::xvel) bx_xlo.setBig(0,dom_lo.x);
71 
72  Box bx_xhi(bx); bx_xhi.setSmall(0,dom_hi.x+1);
73  if (var_idx == Vars::xvel) bx_xhi.setSmall(0,dom_hi.x);
74 
75  ParallelFor(
76  bx_xlo, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) {
77  int bc_comp = (icomp+n >= RhoScalar_comp && icomp+n < RhoScalar_comp+NSCALARS) ?
78  BCVars::RhoScalar_bc_comp : icomp+n;
79  if (bc_ptr[bc_comp].lo(0) == ERFBCType::ext_dir_ingested) {
80  int jb = std::min(std::max(j,dom_lo.y),dom_hi.y);
81  int kb = std::min(std::max(k,dom_lo.z),dom_hi.z);
82  dest_arr(i,j,k,icomp+n) = bdatxlo(dom_lo.x-1,jb,kb,bccomp+n);
83  }
84  },
85  bx_xhi, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) {
86  int bc_comp = (icomp+n >= RhoScalar_comp && icomp+n < RhoScalar_comp+NSCALARS) ?
87  BCVars::RhoScalar_bc_comp : icomp+n;
88  if (bc_ptr[bc_comp].hi(0) == ERFBCType::ext_dir_ingested) {
89  int jb = std::min(std::max(j,dom_lo.y),dom_hi.y);
90  int kb = std::min(std::max(k,dom_lo.z),dom_hi.z);
91  dest_arr(i,j,k,icomp+n) = bdatxhi(dom_hi.x+1,jb,kb,bccomp+n);
92  }
93  }
94  );
95  } // x-faces
96 
97  // y-faces
98  {
99  Box bx_ylo(bx); bx_ylo.setBig (1,dom_lo.y-1);
100  if (var_idx == Vars::yvel) bx_ylo.setBig(1,dom_lo.y);
101 
102  Box bx_yhi(bx); bx_yhi.setSmall(1,dom_hi.y+1);
103  if (var_idx == Vars::yvel) bx_yhi.setSmall(1,dom_hi.y);
104 
105  ParallelFor(
106  bx_ylo, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) {
107  int bc_comp = (icomp+n >= RhoScalar_comp && icomp+n < RhoScalar_comp+NSCALARS) ?
108  BCVars::RhoScalar_bc_comp : icomp+n;
109  if (bc_ptr[bc_comp].lo(1) == ERFBCType::ext_dir_ingested) {
110  int ib = std::min(std::max(i,dom_lo.x),dom_hi.x);
111  int kb = std::min(std::max(k,dom_lo.z),dom_hi.z);
112  dest_arr(i,j,k,icomp+n) = bdatylo(ib,dom_lo.y-1,kb,bccomp+n);
113  }
114  },
115  bx_yhi, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) {
116  int bc_comp = (icomp+n >= RhoScalar_comp && icomp+n < RhoScalar_comp+NSCALARS) ?
117  BCVars::RhoScalar_bc_comp : icomp+n;
118  if (bc_ptr[bc_comp].hi(1) == ERFBCType::ext_dir_ingested) {
119  int ib = std::min(std::max(i,dom_lo.x),dom_hi.x);
120  int kb = std::min(std::max(k,dom_lo.z),dom_hi.z);
121  dest_arr(i,j,k,icomp+n) = bdatyhi(ib,dom_hi.y+1,kb,bccomp+n);
122  }
123  }
124  );
125  } // y-faces
126  } // mf
127  } // var_idx
128 }
#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:1005
@ RhoScalar_bc_comp
Definition: ERF_IndexDefines.H:80
@ ext_dir_ingested
Definition: ERF_IndexDefines.H:212

◆ 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

◆ 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  // *****************************************************************
66  // Interpolate all cell-centered variables from coarse to fine level
67  // *****************************************************************
68  //
69  Interpolater* mapper_c = &cell_cons_interp;
70  Interpolater* mapper_f = &face_cons_linear_interp;
71 
72  //
73  //************************************************************************************************
74  // Interpolate cell-centered data from coarse to fine level
75  // with InterpFromCoarseLevel which ASSUMES that all ghost cells at lev-1 have already been filled
76  // ************************************************************************************************
77  IntVect ngvect_cons = vars_new[lev][Vars::cons].nGrowVect();
78  int ncomp_cons = vars_new[lev][Vars::cons].nComp();
79 
80  InterpFromCoarseLevel(vars_new[lev ][Vars::cons], ngvect_cons, IntVect(0,0,0),
81  vars_new[lev-1][Vars::cons], 0, 0, ncomp_cons,
82  geom[lev-1], geom[lev],
83  refRatio(lev-1), mapper_c, domain_bcs_type, BCVars::cons_bc);
84 
85  // ***************************************************************************
86  // Physical bc's for cell centered variables at domain boundary
87  // ***************************************************************************
89  0,ncomp_cons,ngvect_cons,time,BCVars::cons_bc,true);
90 
91  //
92  //************************************************************************************************
93  // Interpolate x-momentum from coarse to fine level
94  // with InterpFromCoarseLevel which ASSUMES that all ghost cells at lev-1 have already been filled
95  // ************************************************************************************************
96  //
97  InterpFromCoarseLevel(rU_new[lev], IntVect{0}, IntVect{0}, rU_new[lev-1], 0, 0, 1,
98  geom[lev-1], geom[lev],
99  refRatio(lev-1), mapper_f, domain_bcs_type, BCVars::xvel_bc);
100 
101  //
102  //************************************************************************************************
103  // Interpolate y-momentum from coarse to fine level
104  // with InterpFromCoarseLevel which ASSUMES that all ghost cells at lev-1 have already been filled
105  // ************************************************************************************************
106  //
107  InterpFromCoarseLevel(rV_new[lev], IntVect{0}, IntVect{0}, rV_new[lev-1], 0, 0, 1,
108  geom[lev-1], geom[lev],
109  refRatio(lev-1), mapper_f, domain_bcs_type, BCVars::yvel_bc);
110 
111  //************************************************************************************************
112  // Interpolate z-momentum from coarse to fine level
113  // with InterpFromCoarseLevel which ASSUMES that all ghost cells at lev-1 have already been filled
114  // ************************************************************************************************
115  InterpFromCoarseLevel(rW_new[lev], IntVect{0}, IntVect{0}, rW_new[lev-1], 0, 0, 1,
116  geom[lev-1], geom[lev],
117  refRatio(lev-1), mapper_f, domain_bcs_type, BCVars::zvel_bc);
118  //
119  // *********************************************************
120  // After interpolation of momentum, convert back to velocity
121  // *********************************************************
122  //
123  for (int which_lev = lev-1; which_lev <= lev; which_lev++)
124  {
125  c_vfrac = nullptr;
126  if (solverChoice.terrain_type == TerrainType::EB) {
127  c_vfrac = &((get_eb(which_lev).get_const_factory())->getVolFrac());
128  }
129 
131  vars_new[which_lev][Vars::yvel],
132  vars_new[which_lev][Vars::zvel],
133  vars_new[which_lev][Vars::cons],
134  rU_new[which_lev],
135  rV_new[which_lev],
136  rW_new[which_lev],
137  Geom(which_lev).Domain(),
138  domain_bcs_type, c_vfrac);
139  }
140 
141  // ***************************************************************************
142  // Physical bc's at domain boundary
143  // ***************************************************************************
144  IntVect ngvect_vels = vars_new[lev][Vars::xvel].nGrowVect();
145 
147  ngvect_vels,time,BCVars::xvel_bc,true);
149  ngvect_vels,time,BCVars::yvel_bc,true);
151  ngvect_vels,time,BCVars::zvel_bc,true);
152 
153  // ***************************************************************************
154  // Since lev > 0 here we don't worry about m_r2d or wrfbdy data
155  // ***************************************************************************
156 }
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
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 #ifdef ERF_USE_NETCDF
324  // We call this here because it is an ERF routine
325  if (solverChoice.use_real_bcs && (lev==0)) {
327  fill_from_realbdy_upwind(mfs_vel,time,cons_only,icomp_cons,ncomp_cons,ngvect_cons,ngvect_vels);
328  } else {
329  fill_from_realbdy(mfs_vel,time,cons_only,icomp_cons,ncomp_cons,ngvect_cons,ngvect_vels);
330  }
331  do_fb = false;
332  }
333 #endif
334 
335  if (m_r2d) fill_from_bndryregs(mfs_vel,time);
336 
337  // We call this even if use_real_bcs is true because these will fill the vertical bcs
338  (*physbcs_cons[lev])(*mfs_vel[Vars::cons],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
339  icomp_cons,ncomp_cons,ngvect_cons,time,BCVars::cons_bc, do_fb);
340  if (!cons_only) {
341  (*physbcs_u[lev])(*mfs_vel[Vars::xvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
342  ngvect_vels,time,BCVars::xvel_bc, do_fb);
343  (*physbcs_v[lev])(*mfs_vel[Vars::yvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
344  ngvect_vels,time,BCVars::yvel_bc, do_fb);
345  (*physbcs_w[lev])(*mfs_vel[Vars::zvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
346  ngvect_vels,time,BCVars::zvel_bc, do_fb);
347  }
348  // ***************************************************************************
349 
350  // We always come in to this call with momenta so we need to leave with momenta!
351  // We need to make sure we convert back on all ghost cells/faces because this is
352  // how velocity from fine-fine copies (as well as physical and interpolated bcs) will be filled
353  if (!cons_only)
354  {
355  IntVect ngu = (!solverChoice.use_num_diff) ? IntVect(1,1,1) : mfs_vel[Vars::xvel]->nGrowVect();
356  IntVect ngv = (!solverChoice.use_num_diff) ? IntVect(1,1,1) : mfs_vel[Vars::yvel]->nGrowVect();
357  IntVect ngw = (!solverChoice.use_num_diff) ? IntVect(1,1,0) : mfs_vel[Vars::zvel]->nGrowVect();
358 
359  const MultiFab* c_vfrac = nullptr;
360  if (solverChoice.terrain_type == TerrainType::EB) {
361  c_vfrac = &((get_eb(lev).get_const_factory())->getVolFrac());
362  }
363 
364  VelocityToMomentum(*mfs_vel[Vars::xvel], ngu,
365  *mfs_vel[Vars::yvel], ngv,
366  *mfs_vel[Vars::zvel], ngw,
367  *mfs_vel[Vars::cons],
368  *mfs_mom[IntVars::xmom], *mfs_mom[IntVars::ymom], *mfs_mom[IntVars::zmom],
369  Geom(lev).Domain(),
370  domain_bcs_type, c_vfrac);
371  }
372 
373  // NOTE: There are not FillBoundary calls here for the following reasons:
374  // Removal of the FillBoundary (FB) calls has bee completed for the following reasons:
375  //
376  // 1. physbc_cons is called before VelocityToMomentum and a FB is completed in that functor.
377  // Therefore, the conserved CC vars have their inter-rank ghost cells filled and then their
378  // domain ghost cells filled from the BC operations. We should not call FB on this MF again.
379  //
380  // 2. physbc_u/v/w is also called before VelocityToMomentum and a FB is completed those functors.
381  // Furthermore, VelocityToMomentum operates on a growntilebox so we exit that routine with momentum
382  // filled everywhere---i.e., physbc_u/v/w fills velocity ghost cells (inter-rank and domain)
383  // and then V2M does the conversion to momenta everywhere; so there is again no need to do a FB on momenta.
384 }
AMREX_GPU_HOST AMREX_FORCE_INLINE void ApplyMask(amrex::MultiFab &dst, const amrex::iMultiFab &imask, const int nghost=0)
Definition: ERF_Utils.H:457
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:162
static bool upwind_real_bcs
Definition: ERF_DataStruct.H:1045
static bool use_real_bcs
Definition: ERF_DataStruct.H:1042
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 #ifdef ERF_USE_NETCDF
356  // We call this here because it is an ERF routine
357  if(solverChoice.use_real_bcs && (lev==0)) {
359  fill_from_realbdy_upwind(mfs_vel,time,cons_only,icomp_cons,ncomp_cons,ngvect_cons,ngvect_vels);
360  } else {
361  fill_from_realbdy(mfs_vel,time,cons_only,icomp_cons,ncomp_cons,ngvect_cons,ngvect_vels);
362  }
363  do_fb = false;
364  }
365 #endif
366 
367  if (m_r2d) fill_from_bndryregs(mfs_vel,time);
368 
369  // We call this even if use_real_bcs is true because these will fill the vertical bcs
370  // Note that we call FillBoundary inside the physbcs call
371  (*physbcs_cons[lev])(*mfs_vel[Vars::cons],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
372  icomp_cons,ncomp_cons,ngvect_cons,time,BCVars::cons_bc, do_fb);
373  if (!cons_only) {
374  (*physbcs_u[lev])(*mfs_vel[Vars::xvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
375  ngvect_vels,time,BCVars::xvel_bc, do_fb);
376  (*physbcs_v[lev])(*mfs_vel[Vars::yvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
377  ngvect_vels,time,BCVars::yvel_bc, do_fb);
378  (*physbcs_w[lev])(*mfs_vel[Vars::zvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
379  ngvect_vels,time,BCVars::zvel_bc, do_fb);
380  }
381 }

◆ 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) 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 
)
552 {
553  const auto dx = geom[levc].CellSizeArray();
554  const auto prob_lo = geom[levc].ProbLoArray();
555 
556  Gpu::DeviceVector<Real> d_coords(2, 0.0);
557  Gpu::DeviceVector<int> d_found(1,0);
558 
559  Real* d_coords_ptr = d_coords.data();
560  int* d_found_ptr = d_found.data();
561 
562  for (MFIter mfi(mf_cc_vel); mfi.isValid(); ++mfi)
563  {
564  const Box& box = mfi.validbox();
565  const Array4<const Real>& vel_arr = mf_cc_vel.const_array(mfi);
566 
567  ParallelFor(box, [=] AMREX_GPU_DEVICE(int i, int j, int k)
568  {
569  Real magnitude = std::sqrt(vel_arr(i,j,k,0) * vel_arr(i,j,k,0) +
570  vel_arr(i,j,k,1) * vel_arr(i,j,k,1) +
571  vel_arr(i,j,k,2) * vel_arr(i,j,k,2));
572 
573  magnitude *= 3.6;
574 
575  Real z = prob_lo[2] + (k + 0.5) * dx[2];
576 
577  // Check if magnitude exceeds threshold
578  if (z < 2000. && magnitude > velmag_threshold) {
579  // Use atomic operations to set found flag and store coordinates
580  Gpu::Atomic::Add(&d_found_ptr[0], 1); // Mark as found
581 
582  Real x = prob_lo[0] + (i + 0.5) * dx[0];
583  Real y = prob_lo[1] + (j + 0.5) * dx[1];
584 
585  // Store coordinates
586  Gpu::Atomic::Add(&d_coords_ptr[0],x); // Store x index
587  Gpu::Atomic::Add(&d_coords_ptr[1],y); // Store x index
588  }
589  });
590  }
591 
592  // Synchronize to ensure all threads complete their execution
593  amrex::Gpu::streamSynchronize(); // Wait for all GPU threads to finish
594 
595  Vector<int> h_found(1,0);
596  Gpu::copy(Gpu::deviceToHost, d_found.begin(), d_found.end(), h_found.begin());
597  ParallelAllReduce::Sum(h_found.data(), h_found.size(), ParallelContext::CommunicatorAll());
598 
599  // Broadcast coordinates if found
600  if (h_found[0] > 0) {
601  Vector<Real> h_coords(2,-1e10);
602  Gpu::copy(Gpu::deviceToHost, d_coords.begin(), d_coords.end(), h_coords.begin());
603 
604  ParallelAllReduce::Sum(h_coords.data(), h_coords.size(), ParallelContext::CommunicatorAll());
605 
606  eye_x = h_coords[0]/h_found[0];
607  eye_y = h_coords[1]/h_found[0];
608 
609  } else {
610  // Random large negative numbers so we don't trigger refinement in this case
611  eye_x = -1.e20;
612  eye_y = -1.e20;
613  }
614 
615  return (h_found[0] > 0);
616 }

◆ get_eb()

eb_ const& ERF::get_eb ( int  lev) const
inlineprivatenoexcept
1648  {
1649  AMREX_ASSERT(lev >= 0 && lev < eb.size() && eb[lev] != nullptr);
1650  return *eb[lev];
1651  }

◆ getAdvFluxReg()

AMREX_FORCE_INLINE amrex::YAFluxRegister* ERF::getAdvFluxReg ( int  lev)
inlineprivate
1434  {
1435  return advflux_reg[lev];
1436  }

◆ getCPUTime()

static amrex::Real ERF::getCPUTime ( )
inlinestaticprivate
1526  {
1527  int numCores = amrex::ParallelDescriptor::NProcs();
1528 #ifdef _OPENMP
1529  numCores = numCores * omp_get_max_threads();
1530 #endif
1531 
1532  amrex::Real T =
1533  numCores * (amrex::ParallelDescriptor::second() - startCPUTime) +
1535 
1536  return T;
1537  }
static amrex::Real previousCPUTimeUsed
Definition: ERF.H:1522
static amrex::Real startCPUTime
Definition: ERF.H:1521
@ T
Definition: ERF_IndexDefines.H:110

◆ 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 
)
653 {
654  bool is_found;
655 
656  Real eye_x, eye_y;
657 
658  if (time==0.0) {
659  is_found = FindInitialEye(levc, mf_cc_vel, velmag_threshold, eye_x, eye_y);
660  } else {
661  is_found = true;
662  const auto& last = hurricane_eye_track_xy.back();
663  eye_x = last[0];
664  eye_y = last[1];
665  }
666 
667  if (is_found) {
668  Real rad_tag = 4.e5 * std::pow(2, max_level-1-levc);
669  tag_on_distance_from_eye(geom[levc], tags, eye_x, eye_y, rad_tag);
670  }
671 }
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:548
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:1008

◆ 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:1014
@ 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:213
@ open
Definition: ERF_IndexDefines.H:215
@ reflect_odd
Definition: ERF_IndexDefines.H:205
@ hoextrap
Definition: ERF_IndexDefines.H:216
@ foextrap
Definition: ERF_IndexDefines.H:208
@ ext_dir
Definition: ERF_IndexDefines.H:209
@ ext_dir_prim
Definition: ERF_IndexDefines.H:211
@ ext_dir_upwind
Definition: ERF_IndexDefines.H:217
@ int_dir
Definition: ERF_IndexDefines.H:206
@ neumann_int
Definition: ERF_IndexDefines.H:214
@ reflect_even
Definition: ERF_IndexDefines.H:207

◆ 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, xbx, ybx, zbx, cons_arr, cons_pert_arr,
81  xvel_pert_arr, yvel_pert_arr, zvel_pert_arr,
82  r_hse_arr, p_hse_arr, z_nd_arr, z_cc_arr,
83  geom[lev].data(), mf_m, mf_u, mf_v,
84  solverChoice, lev);
85  } //mfi
86 
87  // Add problem-specific perturbation to background flow if not doing anelastic with fixed-in-time density
88  if (!solverChoice.fixed_density[lev]) {
89  MultiFab::Add(lev_new[Vars::cons], cons_pert, Rho_comp, Rho_comp, 1, cons_pert.nGrow());
90  }
91  MultiFab::Add(lev_new[Vars::cons], cons_pert, RhoTheta_comp, RhoTheta_comp, 1, cons_pert.nGrow());
92  MultiFab::Add(lev_new[Vars::cons], cons_pert, RhoScalar_comp,RhoScalar_comp,NSCALARS, cons_pert.nGrow());
93 
94  // RhoKE is relevant if using Deardorff with LES, k-equation for RANS, or MYNN with PBL
95  if (solverChoice.turbChoice[lev].use_tke) {
96  MultiFab::Add(lev_new[Vars::cons], cons_pert, RhoKE_comp, RhoKE_comp, 1, cons_pert.nGrow());
97  }
98 
99  if (solverChoice.moisture_type != MoistureType::None) {
100  int qstate_size = micro->Get_Qstate_Size();
101  for (int q_offset(0); q_offset<qstate_size; ++q_offset) {
102  int q_idx = RhoQ1_comp+q_offset;
103  MultiFab::Add(lev_new[Vars::cons], cons_pert, q_idx, q_idx, 1, cons_pert.nGrow());
104  }
105  }
106 
107  MultiFab::Add(lev_new[Vars::xvel], xvel_pert, 0, 0, 1, xvel_pert.nGrowVect());
108  MultiFab::Add(lev_new[Vars::yvel], yvel_pert, 0, 0, 1, yvel_pert.nGrowVect());
109  MultiFab::Add(lev_new[Vars::zvel], zvel_pert, 0, 0, 1, zvel_pert.nGrowVect());
110 }
const Box ybx
Definition: ERF_SetupDiff.H:8
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:135
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:113
bool is_init_with_correlated_pert
Definition: ERF_DataStruct.H:1224
amrex::Vector< int > fixed_density
Definition: ERF_DataStruct.H:1067
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  z = rval_v[0];
718  u = rval_v[1];
719  v = rval_v[2];
720  w = rval_v[3];
721 
722  // Format without theta
723  if (rval_v.size() == 4) {
724  if (z == zbot) {
725  u_inp_tmp[0] = u;
726  v_inp_tmp[0] = v;
727  w_inp_tmp[0] = w;
728  } else {
729  AMREX_ALWAYS_ASSERT(z > z_inp_tmp[z_inp_tmp.size()-1]); // sounding is increasing in height
730  z_inp_tmp.push_back(z);
731  u_inp_tmp.push_back(u);
732  v_inp_tmp.push_back(v);
733  w_inp_tmp.push_back(w);
734  if (z >= ztop) break;
735  }
736  } else if (rval_v.size() == 5) {
737  th_read = true;
738  th = rval_v[4];
739  if (z == zbot) {
740  u_inp_tmp[0] = u;
741  v_inp_tmp[0] = v;
742  w_inp_tmp[0] = w;
743  th_inp_tmp[0] = th;
744  } else {
745  AMREX_ALWAYS_ASSERT(z > z_inp_tmp[z_inp_tmp.size()-1]); // sounding is increasing in height
746  z_inp_tmp.push_back(z);
747  u_inp_tmp.push_back(u);
748  v_inp_tmp.push_back(v);
749  w_inp_tmp.push_back(w);
750  th_inp_tmp.push_back(th);
751  if (z >= ztop) break;
752  }
753  } else {
754  Abort("Unknown inflow file format!");
755  }
756  }
757 
758  // Ensure we set a reasonable theta surface
759  if (th_read) {
760  if (th_inp_tmp[0] == th_init) {
761  Real slope = (th_inp_tmp[2] - th_inp_tmp[1]) / (z_inp_tmp[2] - z_inp_tmp[1]);
762  Real dz = z_inp_tmp[0] - z_inp_tmp[1];
763  th_inp_tmp[0] = slope * dz + th_inp_tmp[1];
764  }
765  }
766 
767  amrex::Print() << "Successfully read and interpolated the dirichlet_input file..." << std::endl;
768  input_reader.close();
769 
770  for (int lev = 0; lev <= max_level; lev++) {
771 
772  const int Nz = geom[lev].Domain().size()[2];
773 
774  // Size of Nz (domain grid)
775  Vector<Real> zcc_inp(Nz );
776  Vector<Real> znd_inp(Nz+1);
777  Vector<Real> u_inp(Nz ); xvel_bc_data[lev].resize(Nz ,0.0);
778  Vector<Real> v_inp(Nz ); yvel_bc_data[lev].resize(Nz ,0.0);
779  Vector<Real> w_inp(Nz+1); zvel_bc_data[lev].resize(Nz+1,0.0);
780  Vector<Real> th_inp;
781  if (th_read) {
782  th_inp.resize(Nz);
783  th_bc_data[lev].resize(Nz, 0.0);
784  }
785 
786  // At this point, we have an input from zbot up to
787  // z_inp_tmp[N-1] >= ztop. Now, interpolate to grid level 0 heights
788  const int Ninp = z_inp_tmp.size();
789  for (int k(0); k<Nz; ++k) {
790  zcc_inp[k] = 0.5 * (zlevels_stag[lev][k] + zlevels_stag[lev][k+1]);
791  znd_inp[k] = zlevels_stag[lev][k+1];
792  u_inp[k] = interpolate_1d(z_inp_tmp.dataPtr(), u_inp_tmp.dataPtr(), zcc_inp[k], Ninp);
793  v_inp[k] = interpolate_1d(z_inp_tmp.dataPtr(), v_inp_tmp.dataPtr(), zcc_inp[k], Ninp);
794  w_inp[k] = interpolate_1d(z_inp_tmp.dataPtr(), w_inp_tmp.dataPtr(), znd_inp[k], Ninp);
795  if (th_read) {
796  th_inp[k] = interpolate_1d(z_inp_tmp.dataPtr(), th_inp_tmp.dataPtr(), zcc_inp[k], Ninp);
797  }
798  }
799  znd_inp[Nz] = ztop;
800  w_inp[Nz] = interpolate_1d(z_inp_tmp.dataPtr(), w_inp_tmp.dataPtr(), ztop, Ninp);
801 
802  // Copy host data to the device
803  Gpu::copy(Gpu::hostToDevice, u_inp.begin(), u_inp.end(), xvel_bc_data[lev].begin());
804  Gpu::copy(Gpu::hostToDevice, v_inp.begin(), v_inp.end(), yvel_bc_data[lev].begin());
805  Gpu::copy(Gpu::hostToDevice, w_inp.begin(), w_inp.end(), zvel_bc_data[lev].begin());
806  if (th_read) {
807  Gpu::copy(Gpu::hostToDevice, th_inp.begin(), th_inp.end(), th_bc_data[lev].begin());
808  }
809 
810  // NOTE: These device vectors are passed to the PhysBC constructors when that
811  // class is instantiated in ERF_MakeNewArrays.cpp.
812  } // lev
813 }
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
53 {
54  // We only want to read the file once -- here we fill one FArrayBox (per variable) that spans the domain
55  if (lev == 0) {
57  Error("input_sounding file name must be provided via input");
58  }
59 
61 
62  // this will interpolate the input profiles to the nominal height levels
63  // (ranging from 0 to the domain top)
64  for (int n = 0; n < input_sounding_data.n_sounding_files; n++) {
66  }
67 
68  // this will calculate the hydrostatically balanced density and pressure
69  // profiles following WRF ideal.exe
70  if (solverChoice.sounding_type == SoundingType::Ideal) {
72  } else if (solverChoice.sounding_type == SoundingType::Isentropic ||
73  solverChoice.sounding_type == SoundingType::DryIsentropic) {
74  input_sounding_data.assume_dry = (solverChoice.sounding_type == SoundingType::DryIsentropic);
76  }
77 
78  } else {
79  //
80  // We need to do this interp from coarse level in order to set the values of
81  // the base state inside the domain but outside of the fine region
82  //
83  base_state[lev-1].FillBoundary(geom[lev-1].periodicity());
84  //
85  // NOTE: this interpolater assumes that ALL ghost cells of the coarse MultiFab
86  // have been pre-filled - this includes ghost cells both inside and outside
87  // the domain
88  //
89  InterpFromCoarseLevel(base_state[lev], base_state[lev].nGrowVect(),
90  IntVect(0,0,0), // do not fill ghost cells outside the domain
91  base_state[lev-1], 0, 0, base_state[lev].nComp(),
92  geom[lev-1], geom[lev],
93  refRatio(lev-1), &cell_cons_interp,
95 
96  // We need to do this here because the interpolation above may leave corners unfilled
97  // when the corners need to be filled by, for example, reflection of the fine ghost
98  // cell outside the fine region but inide the domain.
99  (*physbcs_base[lev])(base_state[lev],0,base_state[lev].nComp(),base_state[lev].nGrowVect());
100  }
101 
102  auto& lev_new = vars_new[lev];
103 
104  // updated if sounding is ideal (following WRF) or isentropic
105  const bool l_isentropic = (solverChoice.sounding_type == SoundingType::Isentropic ||
106  solverChoice.sounding_type == SoundingType::DryIsentropic);
107  const bool sounding_ideal_or_isentropic = (solverChoice.sounding_type == SoundingType::Ideal ||
108  l_isentropic);
109  MultiFab r_hse (base_state[lev], make_alias, BaseState::r0_comp, 1);
110  MultiFab p_hse (base_state[lev], make_alias, BaseState::p0_comp, 1);
111  MultiFab pi_hse(base_state[lev], make_alias, BaseState::pi0_comp, 1);
112  MultiFab th_hse(base_state[lev], make_alias, BaseState::th0_comp, 1);
113  MultiFab qv_hse(base_state[lev], make_alias, BaseState::qv0_comp, 1);
114 
115  const Real l_gravity = solverChoice.gravity;
116  const Real l_rdOcp = solverChoice.rdOcp;
117  const bool l_moist = (solverChoice.moisture_type != MoistureType::None);
118 
119 #ifdef _OPENMP
120 #pragma omp parallel if (Gpu::notInLaunchRegion())
121 #endif
122  for (MFIter mfi(lev_new[Vars::cons], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
123  const Box &bx = mfi.tilebox();
124  const auto &cons_arr = lev_new[Vars::cons].array(mfi);
125  const auto &xvel_arr = lev_new[Vars::xvel].array(mfi);
126  const auto &yvel_arr = lev_new[Vars::yvel].array(mfi);
127  const auto &zvel_arr = lev_new[Vars::zvel].array(mfi);
128  Array4<Real> r_hse_arr = r_hse.array(mfi);
129  Array4<Real> p_hse_arr = p_hse.array(mfi);
130  Array4<Real> pi_hse_arr = pi_hse.array(mfi);
131  Array4<Real> th_hse_arr = th_hse.array(mfi);
132  Array4<Real> qv_hse_arr = qv_hse.array(mfi);
133 
134  Array4<Real const> z_cc_arr = (z_phys_cc[lev]) ? z_phys_cc[lev]->const_array(mfi) : Array4<Real const>{};
135  Array4<Real const> z_nd_arr = (z_phys_nd[lev]) ? z_phys_nd[lev]->const_array(mfi) : Array4<Real const>{};
136 
137  if (sounding_ideal_or_isentropic)
138  {
139  // HSE will be initialized here, interpolated from values previously
140  // calculated by calc_rho_p or calc_rho_p_isentropic
142  bx, cons_arr,
143  r_hse_arr, p_hse_arr, pi_hse_arr, th_hse_arr, qv_hse_arr,
144  geom[lev].data(), z_cc_arr,
145  l_gravity, l_rdOcp, l_moist, input_sounding_data,
146  l_isentropic);
147  }
148  else
149  {
150  // This assumes rho_0 = 1.0
151  // HSE will be calculated later with call to initHSE
153  bx, cons_arr,
154  geom[lev].data(), z_cc_arr,
155  l_moist, input_sounding_data);
156  }
157 
159  bx, xvel_arr, yvel_arr, zvel_arr,
160  geom[lev].data(), z_nd_arr,
162 
163  } //mfi
164 }
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:176
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)
Definition: ERF_InitFromInputSounding.cpp:238
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:374
InputSoundingData input_sounding_data
Definition: ERF.H:784
@ 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:1033
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
37  ParallelFor(xbx, ybx, zbx,
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 
)
2098 {
2099  t_new[lev] = time;
2100  t_old[lev] = time - 1.e200;
2101 
2102  auto& lev_new = vars_new[lev];
2103  auto& lev_old = vars_old[lev];
2104 
2105  // Loop over grids at this level to initialize our grid data
2106  lev_new[Vars::cons].setVal(0.0); lev_old[Vars::cons].setVal(0.0);
2107  lev_new[Vars::xvel].setVal(0.0); lev_old[Vars::xvel].setVal(0.0);
2108  lev_new[Vars::yvel].setVal(0.0); lev_old[Vars::yvel].setVal(0.0);
2109  lev_new[Vars::zvel].setVal(0.0); lev_old[Vars::zvel].setVal(0.0);
2110 
2111  // Initialize background flow (optional)
2112  if (solverChoice.init_type == InitType::Input_Sounding) {
2113  // The physbc's need the terrain but are needed for initHSE
2114  // We have already made the terrain in the call to init_zphys
2115  // in MakeNewLevelFromScratch
2116  make_physbcs(lev);
2117 
2118  // Now init the base state and the data itself
2120 
2121  // The base state has been initialized by integrating vertically
2122  // through the sounding for ideal (like WRF) or isentropic approaches
2123  if (solverChoice.sounding_type == SoundingType::Ideal ||
2124  solverChoice.sounding_type == SoundingType::Isentropic ||
2125  solverChoice.sounding_type == SoundingType::DryIsentropic) {
2126  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(solverChoice.use_gravity,
2127  "Gravity should be on to be consistent with sounding initialization.");
2128  } else { // SoundingType::ConstantDensity
2129  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(!solverChoice.use_gravity || (solverChoice.anelastic[lev] == 1),
2130  "Constant density probably doesn't make sense for compressible flow with gravity");
2131  initHSE();
2132  }
2133 
2134 #ifdef ERF_USE_NETCDF
2135  }
2136  else if (solverChoice.init_type == InitType::WRFInput && !nc_init_file[lev].empty())
2137  {
2138  // The base state is initialized from WRF wrfinput data, output by
2139  // ideal.exe or real.exe
2140 
2141  init_from_wrfinput(lev, *mf_C1H, *mf_C2H, *mf_MUB, *mf_PSFC[lev]);
2142 
2143  // The physbc's need the terrain but are needed for initHSE
2144  if (!solverChoice.use_real_bcs) {
2145  make_physbcs(lev);
2146  }
2147  }
2148  else if (solverChoice.init_type == InitType::WRFInput && nc_init_file[lev].empty())
2149  {
2150  amrex::Abort("This pathway is not quite implemented yet");
2151  }
2152  else if (solverChoice.init_type == InitType::NCFile)
2153  {
2154  // The state is initialized by reading from a Netcdf file
2155  init_from_ncfile(lev);
2156 
2157  // The physbc's need the terrain but are needed for initHSE
2158  make_physbcs(lev);
2159  }
2160  else if (solverChoice.init_type == InitType::Metgrid)
2161  {
2162  // The base state is initialized from data output by WPS metgrid;
2163  // we will rebalance after interpolation
2164  init_from_metgrid(lev);
2165 #endif
2166  } else if (solverChoice.init_type == InitType::Uniform) {
2167  // Initialize a uniform background field and base state based on the
2168  // problem-specified reference density and temperature
2169 
2170  // The physbc's need the terrain but are needed for initHSE
2171  make_physbcs(lev);
2172 
2173  init_uniform(lev);
2174  initHSE(lev);
2175  } else {
2176  // No background flow initialization specified, initialize the
2177  // background field to be equal to the base state, calculated from the
2178  // problem-specific erf_init_dens_hse
2179 
2180  // The bc's need the terrain but are needed for initHSE
2181  make_physbcs(lev);
2182 
2183  // We will initialize the state from the background state so must set that first
2184  initHSE(lev);
2185  init_from_hse(lev);
2186  }
2187 
2188  // Add problem-specific flow features
2189  //
2190  // Notes:
2191  // - This calls init_custom_pert that is defined for each problem
2192  // - This may modify the base state
2193  // - The fields set by init_custom_pert are **perturbations** to the
2194  // background flow set based on init_type
2195  if (solverChoice.init_type != InitType::NCFile) {
2196  init_custom(lev);
2197  }
2198 
2199  // Ensure that the face-based data are the same on both sides of a periodic domain.
2200  // The data associated with the lower grid ID is considered the correct value.
2201  lev_new[Vars::xvel].OverrideSync(geom[lev].periodicity());
2202  lev_new[Vars::yvel].OverrideSync(geom[lev].periodicity());
2203  lev_new[Vars::zvel].OverrideSync(geom[lev].periodicity());
2204 
2205  if(solverChoice.spongeChoice.sponge_type == "input_sponge"){
2206  input_sponge(lev);
2207  }
2208 
2209  // Initialize turbulent perturbation
2210  if (solverChoice.pert_type == PerturbationType::Source ||
2211  solverChoice.pert_type == PerturbationType::Direct ||
2212  solverChoice.pert_type == PerturbationType::CPM) {
2213  turbPert_update(lev, 0.);
2214  turbPert_amplitude(lev);
2215  }
2216 
2217  // Set initial velocity field for immersed cells to be close to 0
2218  if (solverChoice.terrain_type == TerrainType::ImmersedForcing ||
2219  solverChoice.buildings_type == BuildingsType::ImmersedForcing) {
2220  init_immersed_forcing(lev);
2221  }
2222 }
void init_from_input_sounding(int lev)
Definition: ERF_InitFromInputSounding.cpp:52
std::unique_ptr< amrex::MultiFab > mf_MUB
Definition: ERF.H:1283
std::unique_ptr< amrex::MultiFab > mf_C2H
Definition: ERF.H:1282
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:146
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:857
void init_immersed_forcing(int lev)
Definition: ERF_InitImmersedForcing.cpp:15
void init_uniform(int lev)
Definition: ERF_InitUniform.cpp:17
std::unique_ptr< amrex::MultiFab > mf_C1H
Definition: ERF.H:1281
void turbPert_amplitude(const int lev)
Definition: ERF_InitTurbPert.cpp:32
bool use_gravity
Definition: ERF_DataStruct.H:1097

◆ 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 }
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,1);
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  lev_new[Vars::xvel].define(convert(ba, IntVect(1,0,0)), dm, 1, ngrow_vels);
144  lev_old[Vars::xvel].define(convert(ba, IntVect(1,0,0)), dm, 1, ngrow_vels);
145 
146  lev_new[Vars::yvel].define(convert(ba, IntVect(0,1,0)), dm, 1, ngrow_vels);
147  lev_old[Vars::yvel].define(convert(ba, IntVect(0,1,0)), dm, 1, ngrow_vels);
148 
149  gradp[lev][GpVars::gpx].define(convert(ba, IntVect(1,0,0)), dm, 1, 1); gradp[lev][GpVars::gpx].setVal(0.);
150  gradp[lev][GpVars::gpy].define(convert(ba, IntVect(0,1,0)), dm, 1, 1); gradp[lev][GpVars::gpy].setVal(0.);
151  gradp[lev][GpVars::gpz].define(convert(ba, IntVect(0,0,1)), dm, 1, 1); gradp[lev][GpVars::gpz].setVal(0.);
152 
153  // Note that we need the ghost cells in the z-direction if we are doing any
154  // kind of domain decomposition in the vertical (at level 0 or above)
155  lev_new[Vars::zvel].define(convert(ba, IntVect(0,0,1)), dm, 1, ngrow_vels);
156  lev_old[Vars::zvel].define(convert(ba, IntVect(0,0,1)), dm, 1, ngrow_vels);
157 
158  if ( (solverChoice.anelastic[lev] == 1) || (solverChoice.project_initial_velocity[lev] == 1) ) {
159  pp_inc[lev].define(ba, dm, 1, 1);
160  pp_inc[lev].setVal(0.0);
161  }
162 
163  // We use this in the fast substepping only
164  if (solverChoice.anelastic[lev] == 0) {
165  lagged_delta_rt[lev].define(ba, dm, 1, 1);
166  lagged_delta_rt[lev].setVal(0.0);
167  }
168 
169  // We use these for advecting the slow variables, whether anelastic or compressible
170  avg_xmom[lev].define(convert(ba, IntVect(1,0,0)), dm, 1, 1);
171  avg_ymom[lev].define(convert(ba, IntVect(0,1,0)), dm, 1, 1);
172  avg_zmom[lev].define(convert(ba, IntVect(0,0,1)), dm, 1, 1);
173  avg_xmom[lev].setVal(0.0); avg_ymom[lev].setVal(0.0); avg_zmom[lev].setVal(0.0);
174 
175  // ********************************************************************************************
176  // These are just used for scratch in the time integrator but we might as well define them here
177  // ********************************************************************************************
178  if (solverChoice.terrain_type != TerrainType::EB) {
179  rU_old[lev].define(convert(ba, IntVect(1,0,0)), dm, 1, ngrow_vels);
180  rU_new[lev].define(convert(ba, IntVect(1,0,0)), dm, 1, ngrow_vels);
181 
182  rV_old[lev].define(convert(ba, IntVect(0,1,0)), dm, 1, ngrow_vels);
183  rV_new[lev].define(convert(ba, IntVect(0,1,0)), dm, 1, ngrow_vels);
184 
185  rW_old[lev].define(convert(ba, IntVect(0,0,1)), dm, 1, ngrow_vels);
186  rW_new[lev].define(convert(ba, IntVect(0,0,1)), dm, 1, ngrow_vels);
187  } else {
188  // EB: Define the MultiFabs with the EBFactory
189  rU_old[lev].define(convert(ba, IntVect(1,0,0)), dm, 1, ngrow_vels, MFInfo(), EBFactory(lev));
190  rU_new[lev].define(convert(ba, IntVect(1,0,0)), dm, 1, ngrow_vels, MFInfo(), EBFactory(lev));
191 
192  rV_old[lev].define(convert(ba, IntVect(0,1,0)), dm, 1, ngrow_vels, MFInfo(), EBFactory(lev));
193  rV_new[lev].define(convert(ba, IntVect(0,1,0)), dm, 1, ngrow_vels, MFInfo(), EBFactory(lev));
194 
195  rW_old[lev].define(convert(ba, IntVect(0,0,1)), dm, 1, ngrow_vels, MFInfo(), EBFactory(lev));
196  rW_new[lev].define(convert(ba, IntVect(0,0,1)), dm, 1, ngrow_vels, MFInfo(), EBFactory(lev));
197  }
198 
199  if (lev > 0) {
200  //xmom_crse_rhs[lev].define(convert(ba, IntVect(1,0,0)), dm, 1, IntVect{0});
201  //ymom_crse_rhs[lev].define(convert(ba, IntVect(0,1,0)), dm, 1, IntVect{0});
202  zmom_crse_rhs[lev].define(convert(ba, IntVect(0,0,1)), dm, 1, IntVect{0});
203  }
204 
205  // We do this here just so they won't be undefined in the initial FillPatch
206  rU_old[lev].setVal(1.2e21);
207  rV_old[lev].setVal(3.4e22);
208  rW_old[lev].setVal(5.6e23);
209  rU_new[lev].setVal(1.2e21);
210  rV_new[lev].setVal(3.4e22);
211  rW_new[lev].setVal(5.6e23);
212 
213  // ********************************************************************************************
214  // These are just time averaged fields for diagnostics
215  // ********************************************************************************************
216 
217  // NOTE: We are not completing a fillpach call on the time averaged data;
218  // which would copy on intersection and interpolate from coarse.
219  // Therefore, we are restarting the averaging when the ba changes,
220  // this may give poor statistics for dynamic mesh refinement.
221  vel_t_avg[lev] = nullptr;
223  vel_t_avg[lev] = std::make_unique<MultiFab>(ba, dm, 4, 0); // Each vel comp and the mag
224  vel_t_avg[lev]->setVal(0.0);
225  t_avg_cnt[lev] = 0.0;
226  }
227 
228  // ********************************************************************************************
229  // Initialize flux registers whenever we create/re-create a level
230  // ********************************************************************************************
231  if (solverChoice.coupling_type == CouplingType::TwoWay) {
232  if (lev == 0) {
233  advflux_reg[0] = nullptr;
234  } else {
235  int ncomp_reflux = vars_new[0][Vars::cons].nComp();
236  advflux_reg[lev] = new YAFluxRegister(ba , grids[lev-1],
237  dm , dmap[lev-1],
238  geom[lev], geom[lev-1],
239  ref_ratio[lev-1], lev, ncomp_reflux);
240  }
241  }
242 
243  // ********************************************************************************************
244  // Define Theta_prim storage if using surface_layer BC
245  // ********************************************************************************************
246  if (phys_bc_type[Orientation(Direction::z,Orientation::low)] == ERF_BC::surface_layer) {
247  Theta_prim[lev] = std::make_unique<MultiFab>(ba,dm,1,IntVect(ngrow_state,ngrow_state,1));
248  if (solverChoice.moisture_type != MoistureType::None) {
249  Qv_prim[lev] = std::make_unique<MultiFab>(ba,dm,1,IntVect(ngrow_state,ngrow_state,1));
250  Qr_prim[lev] = std::make_unique<MultiFab>(ba,dm,1,IntVect(ngrow_state,ngrow_state,1));
251  } else {
252  Qv_prim[lev] = nullptr;
253  Qr_prim[lev] = nullptr;
254  }
255  } else {
256  Theta_prim[lev] = nullptr;
257  Qv_prim[lev] = nullptr;
258  Qr_prim[lev] = nullptr;
259  }
260 
261  // ********************************************************************************************
262  // Map factors
263  // ********************************************************************************************
264  BoxList bl2d_mf = ba.boxList();
265  for (auto& b : bl2d_mf) {
266  b.setRange(2,0);
267  }
268  BoxArray ba2d_mf(std::move(bl2d_mf));
269 
270  mapfac[lev].resize(MapFacType::num);
271  mapfac[lev][MapFacType::m_x] = std::make_unique<MultiFab>( ba2d_mf,dm,1,IntVect(3,3,0));
272  mapfac[lev][MapFacType::u_x] = std::make_unique<MultiFab>(convert(ba2d_mf,IntVect(1,0,0)),dm,1,IntVect(3,3,0));
273  mapfac[lev][MapFacType::v_x] = std::make_unique<MultiFab>(convert(ba2d_mf,IntVect(0,1,0)),dm,1,IntVect(3,3,0));
274 
275 #if 0
276  // For now we comment this out to avoid CI failures but we will need to re-enable
277  // this if using non-conformal mappings
279  mapfac[lev][MapFacType::m_y] = std::make_unique<MultiFab>(ba2d_mf,dm,1,IntVect(3,3,0));
280  }
282  mapfac[lev][MapFacType::u_y] = std::make_unique<MultiFab>(convert(ba2d_mf,IntVect(1,0,0)),dm,1,IntVect(3,3,0));
283  }
285  mapfac[lev][MapFacType::v_y] = std::make_unique<MultiFab>(convert(ba2d_mf,IntVect(0,1,0)),dm,1,IntVect(3,3,0));
286  }
287 #endif
288 
290  for (int i = 0; i < 3; i++) {
291  mapfac[lev][i]->setVal(0.5);
292  }
293  for (int i = 3; i < mapfac[lev].size(); i++) {
294  mapfac[lev][i]->setVal(0.25);
295  }
296  } else {
297  for (int i = 0; i < mapfac[lev].size(); i++) {
298  mapfac[lev][i]->setVal(1.0);
299  }
300  }
301 
302  // ********************************************************************************************
303  // Build 1D BA and 2D BA
304  // ********************************************************************************************
305  BoxList bl1d = ba.boxList();
306  for (auto& b : bl1d) {
307  b.setRange(0,0);
308  b.setRange(1,0);
309  }
310  ba1d[lev] = BoxArray(std::move(bl1d));
311 
312  // Build 2D BA
313  BoxList bl2d = ba.boxList();
314  for (auto& b : bl2d) {
315  b.setRange(2,0);
316  }
317  ba2d[lev] = BoxArray(std::move(bl2d));
318 
319  IntVect ng = vars_new[lev][Vars::cons].nGrowVect();
320 
321  if (lev == 0) {
322  mf_C1H = std::make_unique<MultiFab>(ba1d[lev],dm,1,IntVect(ng[0],ng[1],ng[2]));
323  mf_C2H = std::make_unique<MultiFab>(ba1d[lev],dm,1,IntVect(ng[0],ng[1],ng[2]));
324  mf_MUB = std::make_unique<MultiFab>(ba2d[lev],dm,1,IntVect(ng[0],ng[1],ng[2]));
325  }
326 
327  mf_PSFC[lev] = std::make_unique<MultiFab>(ba2d[lev],dm,1,ng);
328 
329  //*********************************************************
330  // Variables for Fitch model for windfarm parametrization
331  //*********************************************************
332 #if defined(ERF_USE_WINDFARM)
333  if (solverChoice.windfarm_type == WindFarmType::Fitch){
334  vars_windfarm[lev].define(ba, dm, 5, ngrow_state); // V, dVabsdt, dudt, dvdt, dTKEdt
335  }
336  if (solverChoice.windfarm_type == WindFarmType::EWP){
337  vars_windfarm[lev].define(ba, dm, 3, ngrow_state); // dudt, dvdt, dTKEdt
338  }
339  if (solverChoice.windfarm_type == WindFarmType::SimpleAD) {
340  vars_windfarm[lev].define(ba, dm, 2, ngrow_state);// dudt, dvdt
341  }
342  if (solverChoice.windfarm_type == WindFarmType::GeneralAD) {
343  vars_windfarm[lev].define(ba, dm, 3, ngrow_state);// dudt, dvdt, dwdt
344  }
345  Nturb[lev].define(ba, dm, 1, ngrow_state); // Number of turbines in a cell
346  SMark[lev].define(ba, dm, 2, 1); // Free stream velocity/source term
347  // sampling marker in a cell - 2 components
348 #endif
349 
350  if(solverChoice.init_type == InitType::HindCast and
352 
353  int ncomp_extra = 2;
354  int nvars = vars_new[lev].size();
355 
356  // Resize all containers
357  forecast_state_1[lev].resize(nvars + 1);
358  forecast_state_2[lev].resize(nvars + 1);
359  forecast_state_interp[lev].resize(nvars + 1);
360 
361  // Define the "normal" components
362  for (int comp = 0; comp < nvars; ++comp) {
363  const MultiFab& src = vars_new[lev][comp];
364  ncomp = src.nComp();
365  ngrow = src.nGrow();
366 
367  forecast_state_1[lev][comp].define(ba, dm, ncomp, ng);
368  forecast_state_2[lev][comp].define(ba, dm, ncomp, ng);
369  forecast_state_interp[lev][comp].define(ba, dm, ncomp, ng);
370  }
371 
372  // Define the "extra" component (last slot)
373  {
374  const MultiFab& src0 = vars_new[lev][0];
375  ngrow = src0.nGrow();
376  int idx = nvars;
377 
378  forecast_state_1[lev][idx].define(ba, dm, ncomp_extra, ngrow);
379  forecast_state_2[lev][idx].define(ba, dm, ncomp_extra, ngrow);
380  forecast_state_interp[lev][idx].define(ba, dm, ncomp_extra, ngrow);
381  }
382  bool regrid_forces_file_read = true;
383  WeatherDataInterpolation(lev, t_new[0],z_phys_nd, regrid_forces_file_read);
384  }
385 
386 
387  if(solverChoice.init_type == InitType::HindCast and
389 
390  {
391  const MultiFab& src = vars_new[lev][0];
392  BoxArray ba_hc = src.boxArray();
393  BoxList bl2d_hc = ba_hc.boxList();
394  for (auto& b : bl2d_hc) {
395  b.setRange(2, 0);
396  }
397  BoxArray ba2d_hc(std::move(bl2d_hc));
398  const amrex::DistributionMapping& dm_hc = src.DistributionMap();
399 
400  surface_state_1[lev].define(ba2d_hc, dm_hc, 2, src.nGrow());
401  surface_state_2[lev].define(ba2d_hc, dm_hc, 2, src.nGrow());
402  surface_state_interp[lev].define(ba2d_hc, dm_hc, 2, src.nGrow());
403 
404  bool regrid_forces_file_read = true;
405  SurfaceDataInterpolation(lev, t_new[0], z_phys_nd, regrid_forces_file_read);
406  }
407 
408 #ifdef ERF_USE_WW3_COUPLING
409  // create a new BoxArray and DistributionMapping for a MultiFab with 1 box
410  BoxArray ba_onegrid(geom[lev].Domain());
411  BoxList bl2d_onegrid = ba_onegrid.boxList();
412  for (auto& b : bl2d_onegrid) {
413  b.setRange(2,0);
414  }
415  BoxArray ba2d_onegrid(std::move(bl2d_onegrid));
416  Vector<int> pmap;
417  pmap.resize(1);
418  pmap[0]=0;
419  DistributionMapping dm_onegrid(ba2d_onegrid);
420  dm_onegrid.define(pmap);
421 
422  Hwave_onegrid[lev] = std::make_unique<MultiFab>(ba2d_onegrid,dm_onegrid,1,IntVect(1,1,0));
423  Lwave_onegrid[lev] = std::make_unique<MultiFab>(ba2d_onegrid,dm_onegrid,1,IntVect(1,1,0));
424 
425  BoxList bl2d_wave = ba.boxList();
426  for (auto& b : bl2d_wave) {
427  b.setRange(2,0);
428  }
429  BoxArray ba2d_wave(std::move(bl2d_wave));
430 
431  Hwave[lev] = std::make_unique<MultiFab>(ba2d_wave,dm,1,IntVect(3,3,0));
432  Lwave[lev] = std::make_unique<MultiFab>(ba2d_wave,dm,1,IntVect(3,3,0));
433 
434  std::cout<<ba_onegrid<<std::endl;
435  std::cout<<ba2d_onegrid<<std::endl;
436  std::cout<<dm_onegrid<<std::endl;
437 #endif
438 
439 
440  //*********************************************************
441  // Radiation heating source terms
442  //*********************************************************
443  if (solverChoice.rad_type != RadiationType::None)
444  {
445  qheating_rates[lev] = std::make_unique<MultiFab>(ba, dm, 2, 0);
446  rad_fluxes[lev] = std::make_unique<MultiFab>(ba, dm, 4, 0);
447  qheating_rates[lev]->setVal(0.);
448  rad_fluxes[lev]->setVal(0.);
449  }
450 
451  //*********************************************************
452  // Radiation fluxes for coupling to LSM
453  //*********************************************************
454 
455  // NOTE: Finer levels do not need to coincide with the bottom domain boundary
456  // at k=0. We make slabs here with the kmin for a given box. Therefore,
457  // care must be taken before applying these fluxes to an LSM model. For
458 
459  // Radiative fluxes for LSM
460  if (solverChoice.lsm_type != LandSurfaceType::None &&
461  solverChoice.rad_type != RadiationType::None)
462  {
463  BoxList m_bl = ba.boxList();
464  for (auto& b : m_bl) {
465  int kmin = b.smallEnd(2);
466  b.setRange(2,kmin);
467  }
468  BoxArray m_ba(std::move(m_bl));
469 
470  sw_lw_fluxes[lev] = std::make_unique<MultiFab>(m_ba, dm, 6, 0); // DIR/DIF VIS/NIR (4), NET SW (1), LW (1)
471  solar_zenith[lev] = std::make_unique<MultiFab>(m_ba, dm, 1, 0);
472 
473  sw_lw_fluxes[lev]->setVal(0.);
474  solar_zenith[lev]->setVal(0.);
475  }
476 
477  //*********************************************************
478  // Turbulent perturbation region initialization
479  //*********************************************************
480  if (solverChoice.pert_type == PerturbationType::Source ||
481  solverChoice.pert_type == PerturbationType::Direct ||
482  solverChoice.pert_type == PerturbationType::CPM)
483  {
484  amrex::Box bnd_bx = ba.minimalBox();
486  turbPert.init_tpi(lev, bnd_bx.smallEnd(), bnd_bx.bigEnd(), geom[lev].CellSizeArray(),
487  ba, dm, ngrow_state, pp_prefix, refRatio(), max_level);
488  }
489 
490  //
491  // Define the land mask here and set it to all land by default
492  // NOTE: the logic below will BREAK if we have any grids not touching the bottom boundary
493  //
494  {
495  lmask_lev[lev].resize(1);
496  auto ngv = lev_new[Vars::cons].nGrowVect(); ngv[2] = 0;
497  BoxList bl2d_mask = ba.boxList();
498  for (auto& b : bl2d_mask) {
499  b.setRange(2,0);
500  }
501  BoxArray ba2d_mask(std::move(bl2d_mask));
502  lmask_lev[lev][0] = std::make_unique<iMultiFab>(ba2d_mask,dm,1,ngv);
503  lmask_lev[lev][0]->setVal(1);
504  lmask_lev[lev][0]->FillBoundary(geom[lev].periodicity());
505 
506  land_type_lev[lev].resize(1);
507  land_type_lev[lev][0] = std::make_unique<iMultiFab>(ba2d_mask,dm,1,ngv);
508  land_type_lev[lev][0]->setVal(0);
509  land_type_lev[lev][0]->FillBoundary(geom[lev].periodicity());
510 
511  soil_type_lev[lev].resize(1);
512  soil_type_lev[lev][0] = std::make_unique<iMultiFab>(ba2d_mask,dm,1,ngv);
513  soil_type_lev[lev][0]->setVal(0);
514  soil_type_lev[lev][0]->FillBoundary(geom[lev].periodicity());
515 
516  urb_frac_lev[lev].resize(1);
517  urb_frac_lev[lev][0] = std::make_unique<MultiFab>(ba2d_mask,dm,1,ngv);
518  urb_frac_lev[lev][0]->setVal(1.0);
519  urb_frac_lev[lev][0]->FillBoundary(geom[lev].periodicity());
520  }
521 
522  // Read in tables needed for windfarm simulations
523  // fill in Nturb multifab - number of turbines in each mesh cell
524  // write out the vtk files for wind turbine location and/or
525  // actuator disks
526  #ifdef ERF_USE_WINDFARM
527  //init_windfarm(lev);
528  #endif
529 
530  if (lev > 0) {
531  fine_mask[lev] = std::make_unique<MultiFab>(grids[lev-1], dmap[lev-1], 1, 0);
532  build_fine_mask(lev, *fine_mask[lev].get());
533  }
534 }
@ 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:1375
amrex::EBFArrayBoxFactory const & EBFactory(int lev) const noexcept
Definition: ERF.H:1654
@ num_comps
Definition: ERF_IndexDefines.H:68
@ gpz
Definition: ERF_IndexDefines.H:152
@ gpy
Definition: ERF_IndexDefines.H:151
@ gpx
Definition: ERF_IndexDefines.H:150
bool test_mapfactor
Definition: ERF_DataStruct.H:1092
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 
)
838 {
839  //********************************************************************************************
840  // Thin immersed body
841  // *******************************************************************************************
842 #if 0
843  if ((solverChoice.advChoice.zero_xflux.size() > 0) ||
844  (solverChoice.advChoice.zero_yflux.size() > 0) ||
845  (solverChoice.advChoice.zero_zflux.size() > 0))
846  {
847  overset_imask[lev] = std::make_unique<iMultiFab>(ba,dm,1,0);
848  overset_imask[lev]->setVal(1); // == value is unknown (to be solved)
849  }
850 #endif
851 
852  if (solverChoice.advChoice.zero_xflux.size() > 0) {
853  amrex::Print() << "Setting up thin immersed body for "
854  << solverChoice.advChoice.zero_xflux.size() << " xfaces" << std::endl;
855  BoxArray ba_xf(ba);
856  ba_xf.surroundingNodes(0);
857  thin_xforce[lev] = std::make_unique<MultiFab>(ba_xf,dm,1,0);
858  thin_xforce[lev]->setVal(0.0);
859  xflux_imask[lev] = std::make_unique<iMultiFab>(ba_xf,dm,1,0);
860  xflux_imask[lev]->setVal(1);
861  for ( MFIter mfi(*xflux_imask[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi )
862  {
863  Array4<int> const& imask_arr = xflux_imask[lev]->array(mfi);
864  //Array4<int> const& imask_cell_arr = overset_imask[lev]->array(mfi);
865  Box xbx = mfi.nodaltilebox(0);
866  for (int iv=0; iv < solverChoice.advChoice.zero_xflux.size(); ++iv) {
867  const auto& faceidx = solverChoice.advChoice.zero_xflux[iv];
868  if ((faceidx[0] >= xbx.smallEnd(0)) && (faceidx[0] <= xbx.bigEnd(0)) &&
869  (faceidx[1] >= xbx.smallEnd(1)) && (faceidx[1] <= xbx.bigEnd(1)) &&
870  (faceidx[2] >= xbx.smallEnd(2)) && (faceidx[2] <= xbx.bigEnd(2)))
871  {
872  imask_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
873  //imask_cell_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
874  //imask_cell_arr(faceidx[0]-1,faceidx[1],faceidx[2]) = 0;
875  amrex::AllPrint() << " mask xface at " << faceidx << std::endl;
876  }
877  }
878  }
879  } else {
880  thin_xforce[lev] = nullptr;
881  xflux_imask[lev] = nullptr;
882  }
883 
884  if (solverChoice.advChoice.zero_yflux.size() > 0) {
885  amrex::Print() << "Setting up thin immersed body for "
886  << solverChoice.advChoice.zero_yflux.size() << " yfaces" << std::endl;
887  BoxArray ba_yf(ba);
888  ba_yf.surroundingNodes(1);
889  thin_yforce[lev] = std::make_unique<MultiFab>(ba_yf,dm,1,0);
890  thin_yforce[lev]->setVal(0.0);
891  yflux_imask[lev] = std::make_unique<iMultiFab>(ba_yf,dm,1,0);
892  yflux_imask[lev]->setVal(1);
893  for ( MFIter mfi(*yflux_imask[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi )
894  {
895  Array4<int> const& imask_arr = yflux_imask[lev]->array(mfi);
896  //Array4<int> const& imask_cell_arr = overset_imask[lev]->array(mfi);
897  Box ybx = mfi.nodaltilebox(1);
898  for (int iv=0; iv < solverChoice.advChoice.zero_yflux.size(); ++iv) {
899  const auto& faceidx = solverChoice.advChoice.zero_yflux[iv];
900  if ((faceidx[0] >= ybx.smallEnd(0)) && (faceidx[0] <= ybx.bigEnd(0)) &&
901  (faceidx[1] >= ybx.smallEnd(1)) && (faceidx[1] <= ybx.bigEnd(1)) &&
902  (faceidx[2] >= ybx.smallEnd(2)) && (faceidx[2] <= ybx.bigEnd(2)))
903  {
904  imask_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
905  //imask_cell_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
906  //imask_cell_arr(faceidx[0],faceidx[1]-1,faceidx[2]) = 0;
907  amrex::AllPrint() << " mask yface at " << faceidx << std::endl;
908  }
909  }
910  }
911  } else {
912  thin_yforce[lev] = nullptr;
913  yflux_imask[lev] = nullptr;
914  }
915 
916  if (solverChoice.advChoice.zero_zflux.size() > 0) {
917  amrex::Print() << "Setting up thin immersed body for "
918  << solverChoice.advChoice.zero_zflux.size() << " zfaces" << std::endl;
919  BoxArray ba_zf(ba);
920  ba_zf.surroundingNodes(2);
921  thin_zforce[lev] = std::make_unique<MultiFab>(ba_zf,dm,1,0);
922  thin_zforce[lev]->setVal(0.0);
923  zflux_imask[lev] = std::make_unique<iMultiFab>(ba_zf,dm,1,0);
924  zflux_imask[lev]->setVal(1);
925  for ( MFIter mfi(*zflux_imask[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi )
926  {
927  Array4<int> const& imask_arr = zflux_imask[lev]->array(mfi);
928  //Array4<int> const& imask_cell_arr = overset_imask[lev]->array(mfi);
929  Box zbx = mfi.nodaltilebox(2);
930  for (int iv=0; iv < solverChoice.advChoice.zero_zflux.size(); ++iv) {
931  const auto& faceidx = solverChoice.advChoice.zero_zflux[iv];
932  if ((faceidx[0] >= zbx.smallEnd(0)) && (faceidx[0] <= zbx.bigEnd(0)) &&
933  (faceidx[1] >= zbx.smallEnd(1)) && (faceidx[1] <= zbx.bigEnd(1)) &&
934  (faceidx[2] >= zbx.smallEnd(2)) && (faceidx[2] <= zbx.bigEnd(2)))
935  {
936  imask_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
937  //imask_cell_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
938  //imask_cell_arr(faceidx[0],faceidx[1],faceidx[2]-1) = 0;
939  amrex::AllPrint() << " mask zface at " << faceidx << std::endl;
940  }
941  }
942  }
943  } else {
944  thin_zforce[lev] = nullptr;
945  zflux_imask[lev] = nullptr;
946  }
947 }
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_uniform()

void ERF::init_uniform ( int  lev)
private

Use problem-specific reference density and temperature to set the background state to a uniform value.

Parameters
levInteger specifying the current level
18 {
19  auto& lev_new = vars_new[lev];
20  for (MFIter mfi(lev_new[Vars::cons], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
21  const Box &gbx = mfi.growntilebox(1);
22  const auto &cons_arr = lev_new[Vars::cons].array(mfi);
23  prob->init_uniform(gbx, cons_arr);
24  }
25 }

◆ init_zphys()

void ERF::init_zphys ( int  lev,
amrex::Real  time 
)
663 {
664  if (solverChoice.init_type != InitType::WRFInput && solverChoice.init_type != InitType::Metgrid)
665  {
666  if (lev > 0) {
667  //
668  // First interpolate from coarser level if there is one
669  // NOTE: this interpolater assumes that ALL ghost cells of the coarse MultiFab
670  // have been pre-filled - this includes ghost cells both inside and outside
671  // the domain
672  //
673  InterpFromCoarseLevel(*z_phys_nd[lev], z_phys_nd[lev]->nGrowVect(),
674  IntVect(0,0,0), // do NOT fill ghost cells outside the domain
675  *z_phys_nd[lev-1], 0, 0, 1,
676  geom[lev-1], geom[lev],
677  refRatio(lev-1), &node_bilinear_interp,
679  }
680 
681  int ngrow = ComputeGhostCells(solverChoice) + 2;
682  Box bx(surroundingNodes(Geom(lev).Domain())); bx.grow(ngrow);
683  FArrayBox terrain_fab(makeSlab(bx,2,0),1);
684 
685  //
686  // If we are using fitted mesh then we use the surface as defined above
687  // If we are not using fitted mesh but are using z_levels, we still need z_phys (for now)
688  // but we need to use a flat terrain for the mesh itself (the EB data has already been made
689  // from the correct terrain)
690  //
691  if (solverChoice.terrain_type != TerrainType::StaticFittedMesh &&
692  solverChoice.terrain_type != TerrainType::MovingFittedMesh) {
693  terrain_fab.template setVal<RunOn::Device>(0.0);
694  } else {
695  //
696  // Fill the values of the terrain height at k=0 only
697  //
698  prob->init_terrain_surface(geom[lev],terrain_fab,time);
699  }
700 
701  for (MFIter mfi(*z_phys_nd[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
702  {
703  Box isect = terrain_fab.box() & (*z_phys_nd[lev])[mfi].box();
704  if (!isect.isEmpty()) {
705  (*z_phys_nd[lev])[mfi].template copy<RunOn::Device>(terrain_fab,isect,0,isect,0,1);
706  }
707  }
708 
710 
711  z_phys_nd[lev]->FillBoundary(geom[lev].periodicity());
712 
713  if (lev == 0) {
714  Real zmax = z_phys_nd[0]->max(0,0,false);
715  Real rel_diff = (zmax - zlevels_stag[0][zlevels_stag[0].size()-1]) / zmax;
716  if (rel_diff < 1.e-8) {
717  amrex::Print() << "max of zphys_nd " << zmax << std::endl;
718  amrex::Print() << "max of zlevels " << zlevels_stag[0][zlevels_stag[0].size()-1] << std::endl;
719  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(rel_diff < 1.e-8, "Terrain is taller than domain top!");
720  }
721  } // lev == 0
722 
723  } else {
724  // NOTE: If a WRFInput file is NOT provided for a finer level,
725  // we simply interpolate from the coarse. This is necessary
726  // since we average_down the terrain (ERF_MakeNewLevel.cpp L351).
727  // If a WRFInput file IS present, it overwrites the terrain data.
728  if (lev > 0) {
729  //
730  // First interpolate from coarser level if there is one
731  // NOTE: this interpolater assumes that ALL ghost cells of the coarse MultiFab
732  // have been pre-filled - this includes ghost cells both inside and outside
733  // the domain
734  //
735  InterpFromCoarseLevel(*z_phys_nd[lev], z_phys_nd[lev]->nGrowVect(),
736  z_phys_nd[lev]->nGrowVect(), // DO fill ghost cells outside the domain
737  *z_phys_nd[lev-1], 0, 0, 1,
738  geom[lev-1], geom[lev],
739  refRatio(lev-1), &node_bilinear_interp,
741  }
742  } // init_type
743 
744  if (solverChoice.terrain_type == TerrainType::ImmersedForcing ||
745  solverChoice.buildings_type == BuildingsType::ImmersedForcing) {
746  terrain_blanking[lev]->setVal(1.0);
747  MultiFab::Subtract(*terrain_blanking[lev], EBFactory(lev).getVolFrac(), 0, 0, 1, ComputeGhostCells(solverChoice) + 2);
748  terrain_blanking[lev]->FillBoundary(geom[lev].periodicity());
749  init_immersed_forcing(lev); // needed for real cases
750  }
751 
752  // Compute the min dz and pass to the micro model
753  Real dzmin = get_dzmin_terrain(*z_phys_nd[lev]);
754  micro->Set_dzmin(lev, dzmin);
755 }
Real get_dzmin_terrain(MultiFab &z_phys_nd)
Definition: ERF_TerrainMetrics.cpp:651
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 ( )
948 {
949  BL_PROFILE_VAR("ERF::InitData()", InitData);
950  InitData_pre();
951  InitData_post();
952  BL_PROFILE_VAR_STOP(InitData);
953 }
void InitData_pre()
Definition: ERF.cpp:956
void InitData_post()
Definition: ERF.cpp:980
void InitData()
Definition: ERF.cpp:947

Referenced by main().

Here is the caller graph for this function:

◆ InitData_post()

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

◆ InitData_pre()

void ERF::InitData_pre ( )
957 {
958  // Initialize the start time for our CPU-time tracker
959  startCPUTime = ParallelDescriptor::second();
960 
961  // Create the ReadBndryPlanes object so we can read boundary plane data
962  // m_r2d is used by init_bcs so we must instantiate this class before
963  if (input_bndry_planes) {
964  Print() << "Defining r2d for the first time " << std::endl;
965  m_r2d = std::make_unique<ReadBndryPlanes>(geom[0], solverChoice.rdOcp);
966  }
967 
968  if (restart_chkfile.empty()) {
969  // Start simulation from the beginning
970  InitFromScratch(0.0);
971  } else {
972  // For initialization this is done in init_only; it is done here for restart
973  init_bcs();
974  }
975 
976  solverChoice.check_params(max_level,geom,phys_bc_type);
977 }
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:747

◆ initHSE() [1/2]

void ERF::initHSE ( )
private

Initialize HSE.

147 {
148  for (int lev = 0; lev <= finest_level; lev++)
149  {
150  initHSE(lev);
151  }
152 }

◆ initHSE() [2/2]

void ERF::initHSE ( int  lev)
private

Initialize density and pressure base state in hydrostatic equilibrium.

21 {
22  // This integrates up through column to update p_hse, pi_hse, th_hse;
23  // r_hse is not const b/c FillBoundary is called at the end for r_hse and p_hse
24 
25  MultiFab r_hse (base_state[lev], make_alias, BaseState::r0_comp, 1);
26  MultiFab p_hse (base_state[lev], make_alias, BaseState::p0_comp, 1);
27  MultiFab pi_hse(base_state[lev], make_alias, BaseState::pi0_comp, 1);
28  MultiFab th_hse(base_state[lev], make_alias, BaseState::th0_comp, 1);
29  MultiFab qv_hse(base_state[lev], make_alias, BaseState::qv0_comp, 1);
30 
31  bool all_boxes_touch_bottom = true;
32  Box domain(geom[lev].Domain());
33 
34  int icomp = 0; int ncomp = BaseState::num_comps;
35 
36  if (lev == 0) {
37  BoxArray ba(base_state[lev].boxArray());
38  for (int i = 0; i < ba.size(); i++) {
39  if (ba[i].smallEnd(2) != domain.smallEnd(2)) {
40  all_boxes_touch_bottom = false;
41  }
42  }
43  }
44  else
45  {
46  //
47  // We need to do this interp from coarse level in order to set the values of
48  // the base state inside the domain but outside of the fine region
49  //
50  base_state[lev-1].FillBoundary(geom[lev-1].periodicity());
51  //
52  // NOTE: this interpolater assumes that ALL ghost cells of the coarse MultiFab
53  // have been pre-filled - this includes ghost cells both inside and outside
54  // the domain
55  //
56  InterpFromCoarseLevel(base_state[lev], base_state[lev].nGrowVect(),
57  IntVect(0,0,0), // do not fill ghost cells outside the domain
58  base_state[lev-1], icomp, icomp, ncomp,
59  geom[lev-1], geom[lev],
60  refRatio(lev-1), &cell_cons_interp,
62 
63  // We need to do this here because the interpolation above may leave corners unfilled
64  // when the corners need to be filled by, for example, reflection of the fine ghost
65  // cell outside the fine region but inide the domain.
66  (*physbcs_base[lev])(base_state[lev],icomp,ncomp,base_state[lev].nGrowVect());
67  }
68 
69  if (all_boxes_touch_bottom || lev > 0) {
70 
71  // Initial r_hse may or may not be in HSE -- defined in ERF_Prob.cpp
73  prob->erf_init_dens_hse_moist(r_hse, z_phys_nd[lev], geom[lev]);
74  } else {
75  prob->erf_init_dens_hse(r_hse, z_phys_nd[lev], z_phys_cc[lev], geom[lev]);
76  }
77 
78  erf_enforce_hse(lev, r_hse, p_hse, pi_hse, th_hse, qv_hse, z_phys_cc[lev]);
79 
80  //
81  // Impose physical bc's on the base state
82  //
83  (*physbcs_base[lev])(base_state[lev],0,base_state[lev].nComp(),base_state[lev].nGrowVect());
84 
85  } else {
86 
87  BoxArray ba_new(domain);
88 
89  ChopGrids2D(ba_new, domain, ParallelDescriptor::NProcs());
90 
91  DistributionMapping dm_new(ba_new);
92 
93  MultiFab new_base_state(ba_new, dm_new, BaseState::num_comps, base_state[lev].nGrowVect());
94  new_base_state.ParallelCopy(base_state[lev],0,0,base_state[lev].nComp(),
95  base_state[lev].nGrowVect(),base_state[lev].nGrowVect());
96 
97  MultiFab new_r_hse (new_base_state, make_alias, BaseState::r0_comp, 1);
98  MultiFab new_p_hse (new_base_state, make_alias, BaseState::p0_comp, 1);
99  MultiFab new_pi_hse(new_base_state, make_alias, BaseState::pi0_comp, 1);
100  MultiFab new_th_hse(new_base_state, make_alias, BaseState::th0_comp, 1);
101  MultiFab new_qv_hse(new_base_state, make_alias, BaseState::qv0_comp, 1);
102 
103  std::unique_ptr<MultiFab> new_z_phys_cc;
104  std::unique_ptr<MultiFab> new_z_phys_nd;
105  if (solverChoice.mesh_type != MeshType::ConstantDz) {
106  new_z_phys_cc = std::make_unique<MultiFab>(ba_new,dm_new,1,1);
107  new_z_phys_cc->ParallelCopy(*z_phys_cc[lev],0,0,1,1,1);
108 
109  BoxArray ba_new_nd(ba_new);
110  ba_new_nd.surroundingNodes();
111  new_z_phys_nd = std::make_unique<MultiFab>(ba_new_nd,dm_new,1,1);
112  new_z_phys_nd->ParallelCopy(*z_phys_nd[lev],0,0,1,1,1);
113  }
114 
115  // Initial r_hse may or may not be in HSE -- defined in ERF_Prob.cpp
117  prob->erf_init_dens_hse_moist(new_r_hse, new_z_phys_nd, geom[lev]);
118  } else {
119  prob->erf_init_dens_hse(new_r_hse, new_z_phys_nd, new_z_phys_cc, geom[lev]);
120  }
121 
122  erf_enforce_hse(lev, new_r_hse, new_p_hse, new_pi_hse, new_th_hse, new_qv_hse, new_z_phys_cc);
123 
124  //
125  // Impose physical bc's on the base state (we must make new, temporary bcs object because the z_phys_nd is different)
126  //
127  ERFPhysBCFunct_base* temp_physbcs_base =
128  new ERFPhysBCFunct_base(lev, geom[lev], domain_bcs_type, domain_bcs_type_d, new_z_phys_nd,
129  (solverChoice.terrain_type == TerrainType::MovingFittedMesh));
130  (*temp_physbcs_base)(new_base_state,0,new_base_state.nComp(),new_base_state.nGrowVect());
131  delete temp_physbcs_base;
132 
133  // Now copy back into the original arrays
134  base_state[lev].ParallelCopy(new_base_state,0,0,base_state[lev].nComp(),
135  base_state[lev].nGrowVect(),base_state[lev].nGrowVect());
136  }
137 
138  //
139  // Impose physical bc's on the base state -- the values outside the fine region
140  // but inside the domain have already been filled in the call above to InterpFromCoarseLevel
141  //
142  (*physbcs_base[lev])(base_state[lev],0,base_state[lev].nComp(),base_state[lev].nGrowVect());
143 }
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:164
bool use_moist_background
Definition: ERF_DataStruct.H:1189
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
836 {
837  const BoxArray& ba(cons_mf.boxArray());
838  const DistributionMapping& dm(cons_mf.DistributionMap());
839 
840  int ncomp_cons = cons_mf.nComp();
841 
842  // Initialize the integrator memory
843  Vector<MultiFab> int_state; // integration state data structure example
844  int_state.push_back(MultiFab(cons_mf, make_alias, 0, ncomp_cons)); // cons
845  int_state.push_back(MultiFab(convert(ba,IntVect(1,0,0)), dm, 1, vel_mf.nGrow())); // xmom
846  int_state.push_back(MultiFab(convert(ba,IntVect(0,1,0)), dm, 1, vel_mf.nGrow())); // ymom
847  int_state.push_back(MultiFab(convert(ba,IntVect(0,0,1)), dm, 1, vel_mf.nGrow())); // zmom
848 
849  mri_integrator_mem[lev] = std::make_unique<MRISplitIntegrator<Vector<MultiFab> > >(int_state);
850  mri_integrator_mem[lev]->setNoSubstepping((solverChoice.substepping_type[lev] == SubsteppingType::None));
851  mri_integrator_mem[lev]->setAnelastic(solverChoice.anelastic[lev]);
852  mri_integrator_mem[lev]->setNcompCons(ncomp_cons);
853  mri_integrator_mem[lev]->setForceFirstStageSingleSubstep(solverChoice.force_stage1_single_substep);
854 }

◆ 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
2002 {
2003  if (Microphysics::modelType(solverChoice.moisture_type) == MoistureModelType::Eulerian) {
2004 
2005  micro = std::make_unique<EulerianMicrophysics>(a_nlevsmax, solverChoice.moisture_type);
2006 
2007  } else if (Microphysics::modelType(solverChoice.moisture_type) == MoistureModelType::Lagrangian) {
2008 #ifdef ERF_USE_PARTICLES
2009  micro = std::make_unique<LagrangianMicrophysics>(a_nlevsmax, solverChoice.moisture_type);
2010  /* Lagrangian microphysics models will have a particle container; it needs to be added
2011  to ERF::particleData */
2012  const auto& pc_name( dynamic_cast<LagrangianMicrophysics&>(*micro).getName() );
2013  /* The particle container has not yet been constructed and initialized, so just add
2014  its name here for now (so that functions to set plotting variables can see it). */
2015  particleData.addName( pc_name );
2016 
2017 #else
2018  Abort("Lagrangian microphysics can be used when compiled with ERF_USE_PARTICLES");
2019 #endif
2020  }
2021 
2022  qmoist.resize(a_nlevsmax);
2023  return;
2024 }
amrex::Vector< amrex::Vector< amrex::MultiFab * > > qmoist
Definition: ERF.H:880
Here is the call graph for this function:

◆ initRayleigh()

void ERF::initRayleigh ( )
private

Initialize Rayleigh damping profiles.

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  h_rayleigh_ptrs.resize(max_level+1);
20  d_rayleigh_ptrs.resize(max_level+1);
21 
22  h_sinesq_ptrs.resize(max_level+1);
23  d_sinesq_ptrs.resize(max_level+1);
24 
25  h_sinesq_stag_ptrs.resize(max_level+1);
26  d_sinesq_stag_ptrs.resize(max_level+1);
27 
28  for (int lev = 0; lev <= finest_level; lev++)
29  {
30  // These have 4 components: ubar, vbar, wbar, thetabar
31  h_rayleigh_ptrs[lev].resize(Rayleigh::nvars);
32  d_rayleigh_ptrs[lev].resize(Rayleigh::nvars);
33 
34  const int zlen_rayleigh = geom[lev].Domain().length(2);
35 
36  // Allocate space for these 1D vectors
37  for (int n = 0; n < Rayleigh::nvars; n++) {
38  h_rayleigh_ptrs[lev][n].resize(zlen_rayleigh, 0.0_rt);
39  d_rayleigh_ptrs[lev][n].resize(zlen_rayleigh, 0.0_rt);
40  }
41 
42  h_sinesq_ptrs[lev].resize(zlen_rayleigh);
43  d_sinesq_ptrs[lev].resize(zlen_rayleigh);
44 
45  h_sinesq_stag_ptrs[lev].resize(zlen_rayleigh+1);
46  d_sinesq_stag_ptrs[lev].resize(zlen_rayleigh+1);
47 
50 
51  for (int k = 0; k < zlen_rayleigh; k++) {
52  Real z = 0.5 * (zlevels_stag[lev][k] + zlevels_stag[lev][k+1]);
53  if (z > (ztop - zdamp)) {
54  Real zfrac = 1.0 - (ztop - z) / zdamp;
55  Real s = std::sin(PIoTwo*zfrac);
56  h_sinesq_ptrs[lev][k] = s*s;
57  } else {
58  h_sinesq_ptrs[lev][k] = 0.0;
59  }
60  }
61 
62  for (int k = 0; k < zlen_rayleigh+1; k++) {
63  Real z = zlevels_stag[lev][k];
64  if (z > (ztop - zdamp)) {
65  Real zfrac = 1.0 - (ztop - z) / zdamp;
66  Real s = std::sin(PIoTwo*zfrac);
67  h_sinesq_stag_ptrs[lev][k] = s*s;
68  } else {
69  h_sinesq_stag_ptrs[lev][k] = 0.0;
70  }
71  }
72 
73  // Init the host vectors for the reference states
74  prob->erf_init_rayleigh(h_rayleigh_ptrs[lev], geom[lev], z_phys_nd[lev], solverChoice.dampingChoice.rayleigh_zdamp);
75 
76  // Copy from host vectors to device vectors
77  for (int n = 0; n < Rayleigh::nvars; n++) {
78  Gpu::copy(Gpu::hostToDevice, h_rayleigh_ptrs[lev][n].begin(), h_rayleigh_ptrs[lev][n].end(),
79  d_rayleigh_ptrs[lev][n].begin());
80  }
81  Gpu::copy(Gpu::hostToDevice, h_sinesq_ptrs[lev].begin(), h_sinesq_ptrs[lev].end(), d_sinesq_ptrs[lev].begin());
82  Gpu::copy(Gpu::hostToDevice, h_sinesq_stag_ptrs[lev].begin(), h_sinesq_stag_ptrs[lev].end(), d_sinesq_stag_ptrs[lev].begin());
83  }
84 }
constexpr amrex::Real PIoTwo
Definition: ERF_Constants.H:7
amrex::Vector< amrex::Vector< amrex::Real > > h_sinesq_ptrs
Definition: ERF.H:1334
amrex::Vector< amrex::Vector< amrex::Real > > h_sinesq_stag_ptrs
Definition: ERF.H:1335
amrex::Vector< amrex::Vector< amrex::Vector< amrex::Real > > > h_rayleigh_ptrs
Definition: ERF.H:1330
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:1331

◆ 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:787
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 
)
1852 {
1853  if (lon_m[lev-1] && !lon_m[lev]) {
1854  auto ngv = lon_m[lev-1]->nGrowVect(); ngv[2] = 0;
1855  lon_m[lev] = std::make_unique<MultiFab>(my_ba2d,my_dm,1,ngv);
1856  InterpFromCoarseLevel(*lon_m[lev], ngv, IntVect(0,0,0), // do not fill ghost cells outside the domain
1857  *lon_m[lev-1], 0, 0, 1,
1858  geom[lev-1], geom[lev],
1859  refRatio(lev-1), &cell_cons_interp,
1861  }
1862  if (lat_m[lev-1] && !lat_m[lev]) {
1863  auto ngv = lat_m[lev-1]->nGrowVect(); ngv[2] = 0;
1864  lat_m[lev] = std::make_unique<MultiFab>(my_ba2d,my_dm,1,ngv);
1865  InterpFromCoarseLevel(*lat_m[lev], ngv, IntVect(0,0,0), // do not fill ghost cells outside the domain
1866  *lat_m[lev-1], 0, 0, 1,
1867  geom[lev-1], geom[lev],
1868  refRatio(lev-1), &cell_cons_interp,
1870  }
1871  if (sinPhi_m[lev-1] && !sinPhi_m[lev]) {
1872  auto ngv = sinPhi_m[lev-1]->nGrowVect(); ngv[2] = 0;
1873  sinPhi_m[lev] = std::make_unique<MultiFab>(my_ba2d,my_dm,1,ngv);
1874  InterpFromCoarseLevel(*sinPhi_m[lev], ngv, IntVect(0,0,0), // do not fill ghost cells outside the domain
1875  *sinPhi_m[lev-1], 0, 0, 1,
1876  geom[lev-1], geom[lev],
1877  refRatio(lev-1), &cell_cons_interp,
1879  }
1880  if (cosPhi_m[lev-1] && !cosPhi_m[lev]) {
1881  auto ngv = cosPhi_m[lev-1]->nGrowVect(); ngv[2] = 0;
1882  cosPhi_m[lev] = std::make_unique<MultiFab>(my_ba2d,my_dm,1,ngv);
1883  InterpFromCoarseLevel(*cosPhi_m[lev], ngv, IntVect(0,0,0), // do not fill ghost cells outside the domain
1884  *cosPhi_m[lev-1], 0, 0, 1,
1885  geom[lev-1], geom[lev],
1886  refRatio(lev-1), &cell_cons_interp,
1888  }
1889  if (sst_lev[lev-1][0] && !sst_lev[lev][0]) {
1890  int ntimes = sst_lev[lev-1].size();
1891  sst_lev[lev].resize(ntimes);
1892  auto ngv = sst_lev[lev-1][0]->nGrowVect(); ngv[2] = 0;
1893  for (int n = 0; n < ntimes; n++) {
1894  sst_lev[lev][n] = std::make_unique<MultiFab>(my_ba2d,my_dm,1,ngv);
1895  InterpFromCoarseLevel(*sst_lev[lev][n], ngv, IntVect(0,0,0), // do not fill ghost cells outside the domain
1896  *sst_lev[lev-1][n], 0, 0, 1,
1897  geom[lev-1], geom[lev],
1898  refRatio(lev-1), &cell_cons_interp,
1900  }
1901  }
1902  if (tsk_lev[lev-1][0] && !tsk_lev[lev][0]) {
1903  int ntimes = tsk_lev[lev-1].size();
1904  tsk_lev[lev].resize(ntimes);
1905  auto ngv = tsk_lev[lev-1][0]->nGrowVect(); ngv[2] = 0;
1906  for (int n = 0; n < ntimes; n++) {
1907  tsk_lev[lev][n] = std::make_unique<MultiFab>(my_ba2d,my_dm,1,ngv);
1908  InterpFromCoarseLevel(*tsk_lev[lev][n], ngv, IntVect(0,0,0), // do not fill ghost cells outside the domain
1909  *tsk_lev[lev-1][n], 0, 0, 1,
1910  geom[lev-1], geom[lev],
1911  refRatio(lev-1), &cell_cons_interp,
1913  }
1914  }
1915 
1916  Real time_for_fp = 0.; // This is not actually used
1917  Vector<Real> ftime = {time_for_fp, time_for_fp};
1918  Vector<Real> ctime = {time_for_fp, time_for_fp};
1919  if (lat_m[lev]) {
1920  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
1921  Vector<MultiFab*> fmf = {lat_m[lev ].get(), lat_m[lev ].get()};
1922  Vector<MultiFab*> cmf = {lat_m[lev-1].get(), lat_m[lev-1].get()};
1923  IntVect ngv = lat_m[lev]->nGrowVect(); ngv[2] = 0;
1924  Interpolater* mapper = &cell_cons_interp;
1925  FillPatchTwoLevels(*lat_m[lev].get(), ngv, IntVect(0,0,0),
1926  time_for_fp, cmf, ctime, fmf, ftime,
1927  0, 0, 1, geom[lev-1], geom[lev],
1928  refRatio(lev-1), mapper, domain_bcs_type,
1929  BCVars::cons_bc);
1930  }
1931  if (lon_m[lev]) {
1932  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
1933  Vector<MultiFab*> fmf = {lon_m[lev ].get(), lon_m[lev ].get()};
1934  Vector<MultiFab*> cmf = {lon_m[lev-1].get(), lon_m[lev-1].get()};
1935  IntVect ngv = lon_m[lev]->nGrowVect(); ngv[2] = 0;
1936  Interpolater* mapper = &cell_cons_interp;
1937  FillPatchTwoLevels(*lon_m[lev].get(), ngv, IntVect(0,0,0),
1938  time_for_fp, cmf, ctime, fmf, ftime,
1939  0, 0, 1, geom[lev-1], geom[lev],
1940  refRatio(lev-1), mapper, domain_bcs_type,
1941  BCVars::cons_bc);
1942  } // lon_m
1943  if (sinPhi_m[lev]) {
1944  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
1945  Vector<MultiFab*> fmf = {sinPhi_m[lev ].get(), sinPhi_m[lev ].get()};
1946  Vector<MultiFab*> cmf = {sinPhi_m[lev-1].get(), sinPhi_m[lev-1].get()};
1947  IntVect ngv = sinPhi_m[lev]->nGrowVect(); ngv[2] = 0;
1948  Interpolater* mapper = &cell_cons_interp;
1949  FillPatchTwoLevels(*sinPhi_m[lev].get(), ngv, IntVect(0,0,0),
1950  time_for_fp, cmf, ctime, fmf, ftime,
1951  0, 0, 1, geom[lev-1], geom[lev],
1952  refRatio(lev-1), mapper, domain_bcs_type,
1953  BCVars::cons_bc);
1954  } // sinPhi
1955  if (cosPhi_m[lev]) {
1956  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
1957  Vector<MultiFab*> fmf = {cosPhi_m[lev ].get(), cosPhi_m[lev ].get()};
1958  Vector<MultiFab*> cmf = {cosPhi_m[lev-1].get(), cosPhi_m[lev-1].get()};
1959  IntVect ngv = cosPhi_m[lev]->nGrowVect(); ngv[2] = 0;
1960  Interpolater* mapper = &cell_cons_interp;
1961  FillPatchTwoLevels(*cosPhi_m[lev].get(), ngv, IntVect(0,0,0),
1962  time_for_fp, cmf, ctime, fmf, ftime,
1963  0, 0, 1, geom[lev-1], geom[lev],
1964  refRatio(lev-1), mapper, domain_bcs_type,
1965  BCVars::cons_bc);
1966  } // cosPhi
1967  if (sst_lev[lev][0]) {
1968  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
1969  int ntimes = sst_lev[lev].size();
1970  for (int n = 0; n < ntimes; n++) {
1971  Vector<MultiFab*> fmf = {sst_lev[lev ][n].get(), sst_lev[lev ][n].get()};
1972  Vector<MultiFab*> cmf = {sst_lev[lev-1][n].get(), sst_lev[lev-1][n].get()};
1973  IntVect ngv = sst_lev[lev][n]->nGrowVect(); ngv[2] = 0;
1974  Interpolater* mapper = &cell_cons_interp;
1975  FillPatchTwoLevels(*sst_lev[lev][n].get(), ngv, IntVect(0,0,0),
1976  time_for_fp, cmf, ctime, fmf, ftime,
1977  0, 0, 1, geom[lev-1], geom[lev],
1978  refRatio(lev-1), mapper, domain_bcs_type,
1979  BCVars::cons_bc);
1980  } // ntimes
1981  } // sst_lev
1982  if (tsk_lev[lev][0]) {
1983  // Call FillPatchTwoLevels which ASSUMES that all ghost cells at lev-1 have already been filled
1984  int ntimes = tsk_lev[lev].size();
1985  for (int n = 0; n < ntimes; n++) {
1986  Vector<MultiFab*> fmf = {tsk_lev[lev ][n].get(), tsk_lev[lev ][n].get()};
1987  Vector<MultiFab*> cmf = {tsk_lev[lev-1][n].get(), tsk_lev[lev-1][n].get()};
1988  IntVect ngv = tsk_lev[lev][n]->nGrowVect(); ngv[2] = 0;
1989  Interpolater* mapper = &cell_cons_interp;
1990  FillPatchTwoLevels(*tsk_lev[lev][n].get(), ngv, IntVect(0,0,0),
1991  time_for_fp, cmf, ctime, fmf, ftime,
1992  0, 0, 1, geom[lev-1], geom[lev],
1993  refRatio(lev-1), mapper, domain_bcs_type,
1994  BCVars::cons_bc);
1995  } // ntimes
1996  } // tsk_lev
1997 }

◆ 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
858 {
859  if (SolverChoice::mesh_type == MeshType::VariableDz) {
860  AMREX_ALWAYS_ASSERT(z_phys_nd[lev] != nullptr);
861  }
862 
863  physbcs_cons[lev] = std::make_unique<ERFPhysBCFunct_cons> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
865  z_phys_nd[lev], solverChoice.use_real_bcs, th_bc_data[lev].data());
866  physbcs_u[lev] = std::make_unique<ERFPhysBCFunct_u> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
868  z_phys_nd[lev], solverChoice.use_real_bcs, xvel_bc_data[lev].data());
869  physbcs_v[lev] = std::make_unique<ERFPhysBCFunct_v> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
871  z_phys_nd[lev], solverChoice.use_real_bcs, yvel_bc_data[lev].data());
872  physbcs_w[lev] = std::make_unique<ERFPhysBCFunct_w> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
875  solverChoice.use_real_bcs, zvel_bc_data[lev].data());
876  physbcs_base[lev] = std::make_unique<ERFPhysBCFunct_base> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d, z_phys_nd[lev],
877  (solverChoice.terrain_type == TerrainType::MovingFittedMesh));
878 }

◆ 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 
)
2899 {
2900  // Get the number of cells in z at level 0
2901  int dir_z = AMREX_SPACEDIM-1;
2902  auto domain = geom[0].Domain();
2903  int size_z = domain.length(dir_z);
2904  int start_z = domain.smallEnd()[dir_z];
2905  Real area_z = static_cast<Real>(domain.length(0)*domain.length(1));
2906 
2907  // resize the level 0 horizontal average vectors
2908  h_havg.resize(size_z, 0.0_rt);
2909 
2910  // Get the cell centered data and construct sums
2911 #ifdef _OPENMP
2912 #pragma omp parallel if (Gpu::notInLaunchRegion())
2913 #endif
2914  for (MFIter mfi(S); mfi.isValid(); ++mfi) {
2915  const Box& box = mfi.validbox();
2916  const IntVect& se = box.smallEnd();
2917  const IntVect& be = box.bigEnd();
2918 
2919  auto fab_arr = S[mfi].array();
2920 
2921  FArrayBox fab_reduce(box, 1, The_Async_Arena());
2922  auto arr_reduce = fab_reduce.array();
2923 
2924  ParallelFor(box, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
2925  arr_reduce(i, j, k, 0) = fab_arr(i,j,k,n);
2926  });
2927 
2928  for (int k=se[dir_z]; k <= be[dir_z]; ++k) {
2929  Box kbox(box); kbox.setSmall(dir_z,k); kbox.setBig(dir_z,k);
2930  h_havg[k-start_z] += fab_reduce.sum<RunOn::Device>(kbox,0);
2931  }
2932  }
2933 
2934  // combine sums from different MPI ranks
2935  ParallelDescriptor::ReduceRealSum(h_havg.dataPtr(), h_havg.size());
2936 
2937  // divide by the total number of cells we are averaging over
2938  for (int k = 0; k < size_z; ++k) {
2939  h_havg[k] /= area_z;
2940  }
2941 }

◆ 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 ( )
2793 {
2794  int lev = 0;
2795 
2796  // First, average down all levels (if doing two-way coupling)
2797  if (solverChoice.coupling_type == CouplingType::TwoWay) {
2798  AverageDown();
2799  }
2800 
2801  MultiFab mf(grids[lev], dmap[lev], 5, 0);
2802 
2803  int zdir = 2;
2804  auto domain = geom[0].Domain();
2805 
2806  bool use_moisture = (solverChoice.moisture_type != MoistureType::None);
2807  bool is_anelastic = (solverChoice.anelastic[lev] == 1);
2808 
2809  for (MFIter mfi(mf); mfi.isValid(); ++mfi) {
2810  const Box& bx = mfi.validbox();
2811  auto fab_arr = mf.array(mfi);
2812  auto const hse_arr = base_state[lev].const_array(mfi);
2813  auto const cons_arr = vars_new[lev][Vars::cons].const_array(mfi);
2814  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
2815  Real dens = cons_arr(i, j, k, Rho_comp);
2816  fab_arr(i, j, k, 0) = dens;
2817  fab_arr(i, j, k, 1) = cons_arr(i, j, k, RhoTheta_comp) / dens;
2818  if (!use_moisture) {
2819  if (is_anelastic) {
2820  fab_arr(i,j,k,2) = hse_arr(i,j,k,BaseState::p0_comp);
2821  } else {
2822  fab_arr(i,j,k,2) = getPgivenRTh(cons_arr(i,j,k,RhoTheta_comp));
2823  }
2824  }
2825  });
2826  }
2827 
2828  if (use_moisture)
2829  {
2830  for (MFIter mfi(mf); mfi.isValid(); ++mfi) {
2831  const Box& bx = mfi.validbox();
2832  auto fab_arr = mf.array(mfi);
2833  auto const hse_arr = base_state[lev].const_array(mfi);
2834  auto const cons_arr = vars_new[lev][Vars::cons].const_array(mfi);
2835  int ncomp = vars_new[lev][Vars::cons].nComp();
2836 
2837  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
2838  Real dens = cons_arr(i, j, k, Rho_comp);
2839  if (is_anelastic) {
2840  fab_arr(i,j,k,2) = hse_arr(i,j,k,BaseState::p0_comp);
2841  } else {
2842  Real qv = cons_arr(i, j, k, RhoQ1_comp) / dens;
2843  fab_arr(i, j, k, 2) = getPgivenRTh(cons_arr(i, j, k, RhoTheta_comp), qv);
2844  }
2845  fab_arr(i, j, k, 3) = (ncomp > RhoQ1_comp ? cons_arr(i, j, k, RhoQ1_comp) / dens : 0.0);
2846  fab_arr(i, j, k, 4) = (ncomp > RhoQ2_comp ? cons_arr(i, j, k, RhoQ2_comp) / dens : 0.0);
2847  });
2848  }
2849 
2850  Gpu::HostVector<Real> h_avg_qv = sumToLine(mf,3,1,domain,zdir);
2851  Gpu::HostVector<Real> h_avg_qc = sumToLine(mf,4,1,domain,zdir);
2852  }
2853 
2854  // Sum in the horizontal plane
2855  Gpu::HostVector<Real> h_avg_density = sumToLine(mf,0,1,domain,zdir);
2856  Gpu::HostVector<Real> h_avg_temperature = sumToLine(mf,1,1,domain,zdir);
2857  Gpu::HostVector<Real> h_avg_pressure = sumToLine(mf,2,1,domain,zdir);
2858 
2859  // Divide by the total number of cells we are averaging over
2860  int size_z = domain.length(zdir);
2861  Real area_z = static_cast<Real>(domain.length(0)*domain.length(1));
2862  int klen = static_cast<int>(h_avg_density.size());
2863 
2864  for (int k = 0; k < klen; ++k) {
2865  h_havg_density[k] /= area_z;
2866  h_havg_temperature[k] /= area_z;
2867  h_havg_pressure[k] /= area_z;
2868  if (solverChoice.moisture_type != MoistureType::None)
2869  {
2870  h_havg_qc[k] /= area_z;
2871  h_havg_qv[k] /= area_z;
2872  }
2873  } // k
2874 
2875  // resize device vectors
2876  d_havg_density.resize(size_z, 0.0_rt);
2877  d_havg_temperature.resize(size_z, 0.0_rt);
2878  d_havg_pressure.resize(size_z, 0.0_rt);
2879 
2880  // copy host vectors to device vectors
2881  Gpu::copy(Gpu::hostToDevice, h_havg_density.begin(), h_havg_density.end(), d_havg_density.begin());
2882  Gpu::copy(Gpu::hostToDevice, h_havg_temperature.begin(), h_havg_temperature.end(), d_havg_temperature.begin());
2883  Gpu::copy(Gpu::hostToDevice, h_havg_pressure.begin(), h_havg_pressure.end(), d_havg_pressure.begin());
2884 
2885  if (solverChoice.moisture_type != MoistureType::None)
2886  {
2887  d_havg_qv.resize(size_z, 0.0_rt);
2888  d_havg_qc.resize(size_z, 0.0_rt);
2889  Gpu::copy(Gpu::hostToDevice, h_havg_qv.begin(), h_havg_qv.end(), d_havg_qv.begin());
2890  Gpu::copy(Gpu::hostToDevice, h_havg_qc.begin(), h_havg_qc.end(), d_havg_qc.begin());
2891  }
2892 }
amrex::Gpu::DeviceVector< amrex::Real > d_havg_temperature
Definition: ERF.H:1352
amrex::Gpu::DeviceVector< amrex::Real > d_havg_qv
Definition: ERF.H:1354
amrex::Vector< amrex::Real > h_havg_pressure
Definition: ERF.H:1347
amrex::Vector< amrex::Real > h_havg_qc
Definition: ERF.H:1349
amrex::Vector< amrex::Real > h_havg_density
Definition: ERF.H:1345
amrex::Gpu::DeviceVector< amrex::Real > d_havg_qc
Definition: ERF.H:1355
amrex::Gpu::DeviceVector< amrex::Real > d_havg_density
Definition: ERF.H:1351
amrex::Vector< amrex::Real > h_havg_temperature
Definition: ERF.H:1346
amrex::Gpu::DeviceVector< amrex::Real > d_havg_pressure
Definition: ERF.H:1353
amrex::Vector< amrex::Real > h_havg_qv
Definition: ERF.H:1348
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
274 {
275  AMREX_ALWAYS_ASSERT(lev > 0);
276 
277  if (verbose) {
278  amrex::Print() <<" NEW BA FROM COARSE AT LEVEL " << lev << " " << ba << std::endl;
279  }
280 
281  //
282  // Grow the subdomains vector and build the subdomains vector at this level
283  //
284  subdomains.resize(lev+1);
285  //
286  // Create subdomains at each level within the domain such that
287  // 1) all boxes in a given subdomain are "connected"
288  // 2) no boxes in a subdomain touch any boxes in any other subdomain
289  //
290  if ( (solverChoice.anelastic[lev] == 0) && (solverChoice.project_initial_velocity[lev] == 0) ) {
291  BoxArray dom(geom[lev].Domain());
292  subdomains[lev].push_back(dom);
293  } else {
294  make_subdomains(ba.simplified_list(), subdomains[lev]);
295  }
296 
297  if (lev == 0) init_bcs();
298 
299  //********************************************************************************************
300  // This allocates all kinds of things, including but not limited to: solution arrays,
301  // terrain arrays, ba2d, metric terms and base state.
302  // *******************************************************************************************
303  init_stuff(lev, ba, dm, vars_new[lev], vars_old[lev], base_state[lev], z_phys_nd[lev]);
304 
305  t_new[lev] = time;
306  t_old[lev] = time - 1.e200;
307 
308  // ********************************************************************************************
309  // Build the data structures for metric quantities used with terrain-fitted coordinates
310  // ********************************************************************************************
311  if ( solverChoice.terrain_type == TerrainType::EB ||
312  solverChoice.terrain_type == TerrainType::ImmersedForcing ||
313  solverChoice.buildings_type == BuildingsType::ImmersedForcing)
314  {
315  const amrex::EB2::IndexSpace& ebis = amrex::EB2::IndexSpace::top();
316  const EB2::Level& eb_level = ebis.getLevel(geom[lev]);
317  if (solverChoice.terrain_type == TerrainType::EB) {
318  eb[lev]->make_all_factories(lev, geom[lev], ba, dm, eb_level);
319  } else if (solverChoice.terrain_type == TerrainType::ImmersedForcing ||
320  solverChoice.buildings_type == BuildingsType::ImmersedForcing) {
321  eb[lev]->make_cc_factory(lev, geom[lev], ba, dm, eb_level);
322  }
323  }
324  init_zphys(lev, time);
326 
327  //
328  // Make sure that detJ and z_phys_cc are the average of the data on a finer level if there is one
329  // *and* if there is two-way coupling
330  //
331  if ( (SolverChoice::mesh_type != MeshType::ConstantDz) && (solverChoice.coupling_type == CouplingType::TwoWay) ) {
332  for (int crse_lev = lev-1; crse_lev >= 0; crse_lev--) {
333  average_down( *detJ_cc[crse_lev+1], *detJ_cc[crse_lev], 0, 1, refRatio(crse_lev));
334  average_down(*z_phys_cc[crse_lev+1], *z_phys_cc[crse_lev], 0, 1, refRatio(crse_lev));
335  }
336  }
337 
338  // ********************************************************************************************
339  // Build the data structures for canopy model (depends upon z_phys)
340  // ********************************************************************************************
342  m_forest_drag[lev]->define_drag_field(ba, dm, geom[lev], z_phys_cc[lev].get(), z_phys_nd[lev].get());
343  }
344 
345  //********************************************************************************************
346  // Radiation
347  // *******************************************************************************************
348  if (solverChoice.rad_type != RadiationType::None)
349  {
350  rad[lev]->Init(geom[lev], ba, &vars_new[lev][Vars::cons]);
351  }
352 
353  // *****************************************************************************************************
354  // Initialize the boundary conditions (after initializing the terrain but before calling
355  // initHSE or FillCoarsePatch)
356  // *****************************************************************************************************
357  make_physbcs(lev);
358 
359  // ********************************************************************************************
360  // Update the base state at this level by interpolation from coarser level
361  // ********************************************************************************************
362  InterpFromCoarseLevel(base_state[lev], base_state[lev].nGrowVect(),
363  IntVect(0,0,0), // do not fill ghost cells outside the domain
364  base_state[lev-1], 0, 0, base_state[lev].nComp(),
365  geom[lev-1], geom[lev],
366  refRatio(lev-1), &cell_cons_interp,
368 
369  // Impose bc's outside the domain
370  (*physbcs_base[lev])(base_state[lev],0,base_state[lev].nComp(),base_state[lev].nGrowVect());
371 
372  //********************************************************************************************
373  // Microphysics
374  // *******************************************************************************************
375  int q_size = micro->Get_Qmoist_Size(lev);
376  qmoist[lev].resize(q_size);
377  micro->Define(lev, solverChoice);
378  if (solverChoice.moisture_type != MoistureType::None)
379  {
380  micro->Init(lev, vars_new[lev][Vars::cons],
381  grids[lev], Geom(lev), 0.0,
382  z_phys_nd[lev], detJ_cc[lev]); // dummy dt value
383  }
384  for (int mvar(0); mvar<qmoist[lev].size(); ++mvar) {
385  qmoist[lev][mvar] = micro->Get_Qmoist_Ptr(lev,mvar);
386  }
387 
388  // ********************************************************************************************
389  // Build the data structures for calculating diffusive/turbulent terms
390  // ********************************************************************************************
391  update_diffusive_arrays(lev, ba, dm);
392 
393  // ********************************************************************************************
394  // Build the data structures for holding sea surface temps and skin temps
395  // ********************************************************************************************
396  sst_lev[lev].resize(1); sst_lev[lev][0] = nullptr;
397  tsk_lev[lev].resize(1); tsk_lev[lev][0] = nullptr;
398 
399  // ********************************************************************************************
400  // Fill data at the new level by interpolation from the coarser level
401  // Note that internal to FillCoarsePatch we will convert velocity to momentum,
402  // then interpolate momentum, then convert momentum back to velocity
403  // Also note that FillCoarsePatch is hard-wired to act only on lev_new at coarse and fine
404  // ********************************************************************************************
405 
406 #ifdef ERF_USE_NETCDF
407  if ( ( (solverChoice.init_type == InitType::WRFInput) || (solverChoice.init_type == InitType::Metgrid) ) &&
408  !nc_init_file[lev].empty() )
409  {
410  // Just making sure that ghost cells aren't uninitialized...
411  vars_new[lev][Vars::cons].setVal(0.0); vars_old[lev][Vars::cons].setVal(0.0);
412  vars_new[lev][Vars::xvel].setVal(0.0); vars_old[lev][Vars::xvel].setVal(0.0);
413  vars_new[lev][Vars::yvel].setVal(0.0); vars_old[lev][Vars::yvel].setVal(0.0);
414  vars_new[lev][Vars::zvel].setVal(0.0); vars_old[lev][Vars::zvel].setVal(0.0);
415 
416  AMREX_ALWAYS_ASSERT(solverChoice.terrain_type == TerrainType::StaticFittedMesh);
417  if (solverChoice.init_type == InitType::Metgrid) {
418  init_from_metgrid(lev);
419  } else if (solverChoice.init_type == InitType::WRFInput) {
420  init_from_wrfinput(lev, *mf_C1H, *mf_C2H, *mf_MUB, *mf_PSFC[lev]);
421  }
422  init_zphys(lev, time);
424  make_physbcs(lev);
425 
426  dz_min[lev] = (*detJ_cc[lev]).min(0) * geom[lev].CellSize(2);
427 
428  } else {
429 #endif
430  //
431  // Interpolate the solution data
432  //
433  FillCoarsePatch(lev, time);
434 
435  //
436  // Interpolate the 2D arrays at the lower boundary
437  // Note that ba2d is constructed already in init_stuff, but we have not yet defined dmap[lev]
438  // so we must explicitly pass dm.
439  Interp2DArrays(lev,ba2d[lev],dm);
440 #ifdef ERF_USE_NETCDF
441  }
442 #endif
443 
444  // ********************************************************************************************
445  // Initialize the integrator class
446  // ********************************************************************************************
447  dt_mri_ratio[lev] = dt_mri_ratio[lev-1];
449 
450  // ********************************************************************************************
451  // If we are making a new level then the FillPatcher for this level hasn't been allocated yet
452  // ********************************************************************************************
453  if (lev > 0 && cf_width >= 0) {
456  }
457 
458  //********************************************************************************************
459  // Land Surface Model
460  // *******************************************************************************************
461  int lsm_data_size = lsm.Get_Data_Size();
462  int lsm_flux_size = lsm.Get_Flux_Size();
463  lsm_data[lev].resize(lsm_data_size);
464  lsm_data_name.resize(lsm_data_size);
465  lsm_flux[lev].resize(lsm_flux_size);
466  lsm_flux_name.resize(lsm_flux_size);
467  lsm.Define(lev, solverChoice);
468  if (solverChoice.lsm_type != LandSurfaceType::None)
469  {
470  lsm.Init(lev, vars_new[lev][Vars::cons], Geom(lev), 0.0); // dummy dt value
471  }
472  for (int mvar(0); mvar<lsm_data[lev].size(); ++mvar) {
473  lsm_data[lev][mvar] = lsm.Get_Data_Ptr(lev,mvar);
474  lsm_data_name[mvar] = lsm.Get_DataName(mvar);
475  }
476  for (int mvar(0); mvar<lsm_flux[lev].size(); ++mvar) {
477  lsm_flux[lev][mvar] = lsm.Get_Flux_Ptr(lev,mvar);
478  lsm_flux_name[mvar] = lsm.Get_FluxName(mvar);
479  }
480 
481  // ********************************************************************************************
482  // Create the SurfaceLayer arrays at this (new) level
483  // ********************************************************************************************
484  if (phys_bc_type[Orientation(Direction::z,Orientation::low)] == ERF_BC::surface_layer) {
485  Vector<MultiFab*> mfv_old = {&vars_old[lev][Vars::cons], &vars_old[lev][Vars::xvel],
486  &vars_old[lev][Vars::yvel], &vars_old[lev][Vars::zvel]};
487  m_SurfaceLayer->make_SurfaceLayer_at_level(lev,lev+1,
488  mfv_old, Theta_prim[lev], Qv_prim[lev],
489  Qr_prim[lev], z_phys_nd[lev],
490  Hwave[lev].get(), Lwave[lev].get(), eddyDiffs_lev[lev].get(),
492  sst_lev[lev], tsk_lev[lev], lmask_lev[lev]);
493  }
494 
495 #ifdef ERF_USE_PARTICLES
496  // particleData.Redistribute();
497 #endif
498 }
void update_diffusive_arrays(int lev, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm)
Definition: ERF_MakeNewArrays.cpp:537
void initialize_integrator(int lev, amrex::MultiFab &cons_mf, amrex::MultiFab &vel_mf)
Definition: ERF_MakeNewArrays.cpp:835
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:818
void init_zphys(int lev, amrex::Real time)
Definition: ERF_MakeNewArrays.cpp:662
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:2970
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

◆ MakeNewLevelFromScratch()

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

◆ nghost_eb_full()

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

◆ nghost_eb_volume()

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

◆ NumDataLogs()

AMREX_FORCE_INLINE int ERF::NumDataLogs ( )
inlineprivatenoexcept
1455  {
1456  return datalog.size();
1457  }

◆ NumDerDataLogs()

AMREX_FORCE_INLINE int ERF::NumDerDataLogs ( )
inlineprivatenoexcept
1462  {
1463  return der_datalog.size();
1464  }

◆ NumSampleLineLogs()

AMREX_FORCE_INLINE int ERF::NumSampleLineLogs ( )
inlineprivatenoexcept
1491  {
1492  return samplelinelog.size();
1493  }

◆ NumSampleLines()

AMREX_FORCE_INLINE int ERF::NumSampleLines ( )
inlineprivatenoexcept
1517  {
1518  return sampleline.size();
1519  }

◆ NumSamplePointLogs()

AMREX_FORCE_INLINE int ERF::NumSamplePointLogs ( )
inlineprivatenoexcept
1477  {
1478  return sampleptlog.size();
1479  }

◆ NumSamplePoints()

AMREX_FORCE_INLINE int ERF::NumSamplePoints ( )
inlineprivatenoexcept
1504  {
1505  return samplepoint.size();
1506  }

◆ operator=() [1/2]

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

◆ operator=() [2/2]

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

◆ ParameterSanityChecks()

void ERF::ParameterSanityChecks ( )
private
2726 {
2727  AMREX_ALWAYS_ASSERT(cfl > 0. || fixed_dt[0] > 0.);
2728 
2729  // We don't allow use_real_bcs to be true if init_type is not either InitType::WRFInput or InitType::Metgrid
2730  AMREX_ALWAYS_ASSERT( !solverChoice.use_real_bcs ||
2731  ((solverChoice.init_type == InitType::WRFInput) || (solverChoice.init_type == InitType::Metgrid)) );
2732 
2733  AMREX_ALWAYS_ASSERT(real_width >= 0);
2734  AMREX_ALWAYS_ASSERT(real_set_width >= 0);
2735  AMREX_ALWAYS_ASSERT(real_width >= real_set_width);
2736 
2737  if (cf_width < 0 || cf_set_width < 0 || cf_width < cf_set_width) {
2738  Abort("You must set cf_width >= cf_set_width >= 0");
2739  }
2740  if (max_level > 0 && cf_set_width > 0) {
2741  for (int lev = 1; lev <= max_level; lev++) {
2742  if (cf_set_width%ref_ratio[lev-1][0] != 0 ||
2743  cf_set_width%ref_ratio[lev-1][1] != 0 ||
2744  cf_set_width%ref_ratio[lev-1][2] != 0 ) {
2745  Abort("You must set cf_width to be a multiple of ref_ratio");
2746  }
2747  }
2748  }
2749 
2750  // If fixed_mri_dt_ratio is set, it must be even
2751  if (fixed_mri_dt_ratio > 0 && (fixed_mri_dt_ratio%2 != 0) )
2752  {
2753  Abort("If you specify fixed_mri_dt_ratio, it must be even");
2754  }
2755 
2756  for (int lev = 0; lev <= max_level; lev++)
2757  {
2758  // We ignore fixed_fast_dt if not substepping
2759  if (solverChoice.substepping_type[lev] == SubsteppingType::None) {
2760  fixed_fast_dt[lev] = -1.0;
2761  }
2762 
2763  // If both fixed_dt and fast_dt are specified, their ratio must be an even integer
2764  if (fixed_dt[lev] > 0. && fixed_fast_dt[lev] > 0. && fixed_mri_dt_ratio <= 0)
2765  {
2766  Real eps = 1.e-12;
2767  int ratio = static_cast<int>( ( (1.0+eps) * fixed_dt[lev] ) / fixed_fast_dt[lev] );
2768  if (fixed_dt[lev] / fixed_fast_dt[lev] != ratio)
2769  {
2770  Abort("Ratio of fixed_dt to fixed_fast_dt must be an even integer");
2771  }
2772  }
2773 
2774  // If all three are specified, they must be consistent
2775  if (fixed_dt[lev] > 0. && fixed_fast_dt[lev] > 0. && fixed_mri_dt_ratio > 0)
2776  {
2777  if (fixed_dt[lev] / fixed_fast_dt[lev] != fixed_mri_dt_ratio)
2778  {
2779  Abort("Dt is over-specfied");
2780  }
2781  }
2782  } // lev
2783 
2784  if (solverChoice.coupling_type == CouplingType::TwoWay && cf_width > 0) {
2785  Abort("For two-way coupling you must set cf_width = 0");
2786  }
2787 }
int real_set_width
Definition: ERF.H:1258

◆ 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(lev, 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(lev, 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(lev, 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_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:1227
amrex::Real poisson_reltol
Definition: ERF_DataStruct.H:1090
int ncorr
Definition: ERF_DataStruct.H:1088
amrex::Real poisson_abstol
Definition: ERF_DataStruct.H:1089
Here is the call graph for this function:

◆ post_timestep()

void ERF::post_timestep ( int  nstep,
amrex::Real  time,
amrex::Real  dt_lev 
)
735 {
736  BL_PROFILE("ERF::post_timestep()");
737 
738 #ifdef ERF_USE_PARTICLES
739  particleData.Redistribute();
740 #endif
741 
742  if (solverChoice.coupling_type == CouplingType::TwoWay)
743  {
744  int ncomp = vars_new[0][Vars::cons].nComp();
745  for (int lev = finest_level-1; lev >= 0; lev--)
746  {
747  // The quantity that is conserved is not (rho S), but rather (rho S / m^2) where
748  // m is the map scale factor at cell centers
749  // Here we pre-divide (rho S) by m^2 before refluxing
750  for (MFIter mfi(vars_new[lev][Vars::cons], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
751  const Box& bx = mfi.tilebox();
752  const Array4< Real> cons_arr = vars_new[lev][Vars::cons].array(mfi);
753  const Array4<const Real> mfx_arr = mapfac[lev][MapFacType::m_x]->const_array(mfi);
754  const Array4<const Real> mfy_arr = mapfac[lev][MapFacType::m_y]->const_array(mfi);
755  if (SolverChoice::mesh_type == MeshType::ConstantDz) {
756  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
757  {
758  cons_arr(i,j,k,n) /= (mfx_arr(i,j,0)*mfy_arr(i,j,0));
759  });
760  } else {
761  const Array4<const Real> detJ_arr = detJ_cc[lev]->const_array(mfi);
762  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
763  {
764  cons_arr(i,j,k,n) *= detJ_arr(i,j,k) / (mfx_arr(i,j,0)*mfy_arr(i,j,0));
765  });
766  }
767  } // mfi
768 
769  // This call refluxes all "slow" cell-centered variables
770  // (i.e. not density or (rho theta) or velocities) from the lev/lev+1 interface onto lev
771  getAdvFluxReg(lev+1)->Reflux(vars_new[lev][Vars::cons], 2, 2, ncomp-2);
772 
773  // Here we multiply (rho S) by m^2 after refluxing
774  for (MFIter mfi(vars_new[lev][Vars::cons], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
775  const Box& bx = mfi.tilebox();
776  const Array4< Real> cons_arr = vars_new[lev][Vars::cons].array(mfi);
777  const Array4<const Real> mfx_arr = mapfac[lev][MapFacType::m_x]->const_array(mfi);
778  const Array4<const Real> mfy_arr = mapfac[lev][MapFacType::m_y]->const_array(mfi);
779  if (SolverChoice::mesh_type == MeshType::ConstantDz) {
780  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
781  {
782  cons_arr(i,j,k,n) *= (mfx_arr(i,j,0)*mfy_arr(i,j,0));
783  });
784  } else {
785  const Array4<const Real> detJ_arr = detJ_cc[lev]->const_array(mfi);
786  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
787  {
788  cons_arr(i,j,k,n) *= (mfx_arr(i,j,0)*mfy_arr(i,j,0)) / detJ_arr(i,j,k);
789  });
790  }
791  } // mfi
792 
793  // We need to do this before anything else because refluxing changes the
794  // values of coarse cells underneath fine grids with the assumption they'll
795  // be over-written by averaging down
796  int src_comp;
797  if (solverChoice.anelastic[lev]) {
798  src_comp = 1;
799  } else {
800  src_comp = 0;
801  }
802  int num_comp = ncomp - src_comp;
803  AverageDownTo(lev,src_comp,num_comp);
804  }
805  }
806 
807  if (is_it_time_for_action(nstep, time, dt_lev0, sum_interval, sum_per)) {
810  sum_energy_quantities(time);
811  }
812 
813  if (solverChoice.pert_type == PerturbationType::Source ||
814  solverChoice.pert_type == PerturbationType::Direct ||
815  solverChoice.pert_type == PerturbationType::CPM) {
816  if (is_it_time_for_action(nstep, time, dt_lev0, pert_interval, -1.)) {
817  turbPert.debug(time);
818  }
819  }
820 
821  if (profile_int > 0 && (nstep+1) % profile_int == 0) {
822  if (destag_profiles) {
823  // all variables cell-centered
824  write_1D_profiles(time);
825  } else {
826  // some variables staggered
828  }
829  }
830 
831  if (solverChoice.rad_type != RadiationType::None)
832  {
833  if ( rad_datalog_int > 0 &&
834  (((nstep+1) % rad_datalog_int == 0) || (nstep==0)) ) {
835  if (rad[0]->hasDatalog()) {
836  rad[0]->WriteDataLog(time+start_time);
837  }
838  }
839  }
840 
841  if (output_1d_column) {
842 #ifdef ERF_USE_NETCDF
843  if (is_it_time_for_action(nstep, time, dt_lev0, column_interval, column_per))
844  {
845  int lev_column = 0;
846  for (int lev = finest_level; lev >= 0; lev--)
847  {
848  Real dx_lev = geom[lev].CellSize(0);
849  Real dy_lev = geom[lev].CellSize(1);
850  int i_lev = static_cast<int>(std::floor(column_loc_x / dx_lev));
851  int j_lev = static_cast<int>(std::floor(column_loc_y / dy_lev));
852  if (grids[lev].contains(IntVect(i_lev,j_lev,0))) lev_column = lev;
853  }
854  writeToNCColumnFile(lev_column, column_file_name, column_loc_x, column_loc_y, time);
855  }
856 #else
857  Abort("To output 1D column files ERF must be compiled with NetCDF");
858 #endif
859  }
860 
862  {
865  {
866  bool is_moist = (micro->Get_Qstate_Moist_Size() > 0);
867  m_w2d->write_planes(istep[0], time, vars_new, is_moist);
868  }
869  }
870 
871  // Write plane/line sampler data
873  line_sampler->get_sample_data(geom, vars_new);
874  line_sampler->write_sample_data(t_new, istep, ref_ratio, geom);
875  }
877  plane_sampler->get_sample_data(geom, vars_new);
878  plane_sampler->write_sample_data(t_new, istep, ref_ratio, geom);
879  }
880 
881  // Moving terrain
882  if ( solverChoice.terrain_type == TerrainType::MovingFittedMesh )
883  {
884  for (int lev = finest_level; lev >= 0; lev--)
885  {
886  // Copy z_phs_nd and detJ_cc at end of timestep
887  MultiFab::Copy(*z_phys_nd[lev], *z_phys_nd_new[lev], 0, 0, 1, z_phys_nd[lev]->nGrowVect());
888  MultiFab::Copy( *detJ_cc[lev], *detJ_cc_new[lev], 0, 0, 1, detJ_cc[lev]->nGrowVect());
889  MultiFab::Copy(base_state[lev],base_state_new[lev],0,0,BaseState::num_comps,base_state[lev].nGrowVect());
890 
891  make_zcc(geom[lev],*z_phys_nd[lev],*z_phys_cc[lev]);
892  }
893  }
894 
895  if ( solverChoice.io_hurricane_eye_tracker and (nstep == 0 or (nstep+1)%m_plot3d_int_1 == 0) )
896  {
897  int levc=finest_level;
898 
899  HurricaneEyeTracker(geom[levc],
900  vars_new[levc],
908 
909  MultiFab& U_new = vars_new[levc][Vars::xvel];
910  MultiFab& V_new = vars_new[levc][Vars::yvel];
911  MultiFab& W_new = vars_new[levc][Vars::zvel];
912 
913  MultiFab mf_cc_vel(grids[levc], dmap[levc], AMREX_SPACEDIM, IntVect(0,0,0));
914  average_face_to_cellcenter(mf_cc_vel,0,{AMREX_D_DECL(&U_new,&V_new,&W_new)},0);
915 
916  HurricaneMaxVelTracker(geom[levc],
917  mf_cc_vel,
918  t_new[0],
921 
923  geom[levc],
924  vars_new[levc][Vars::cons],
925  t_new[0],
928 
929  std::string filename_tracker = MakeVTKFilename_TrackerCircle(nstep);
930  std::string filename_xy = MakeVTKFilename_EyeTracker_xy(nstep);
931  std::string filename_latlon = MakeFilename_EyeTracker_latlon(nstep);
932  std::string filename_maxvel = MakeFilename_EyeTracker_maxvel(nstep);
933  std::string filename_minpressure = MakeFilename_EyeTracker_minpressure(nstep);
934 
935  if (ParallelDescriptor::IOProcessor()) {
936  WriteVTKPolyline(filename_tracker, hurricane_tracker_circle);
938  WriteLinePlot(filename_latlon, hurricane_eye_track_latlon);
939  WriteLinePlot(filename_maxvel, hurricane_maxvel_vs_time);
940  WriteLinePlot(filename_minpressure, hurricane_minpressure_vs_time);
941  }
942  }
943 } // 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:626
std::string MakeFilename_EyeTracker_maxvel(int nstep)
Definition: ERF_TrackerOutput.cpp:66
static amrex::Real column_loc_y
Definition: ERF.H:1292
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:1293
AMREX_FORCE_INLINE amrex::YAFluxRegister * getAdvFluxReg(int lev)
Definition: ERF.H:1433
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:1298
static amrex::Real column_per
Definition: ERF.H:1290
static amrex::Real column_loc_x
Definition: ERF.H:1291
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:1297
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:1288
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:1289
amrex::Real hurricane_eye_latitude
Definition: ERF_DataStruct.H:1222
amrex::Real hurricane_eye_longitude
Definition: ERF_DataStruct.H:1222
bool io_hurricane_eye_tracker
Definition: ERF_DataStruct.H:1221
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:134
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  Real l_time = 0.0;
86  project_momenta(lev, l_time, l_dt, tmp_mom);
87 
89  vars_new[lev][Vars::yvel],
90  vars_new[lev][Vars::zvel],
91  vars_new[lev][Vars::cons],
92  rU_new[lev], rV_new[lev], rW_new[lev],
93  Geom(lev).Domain(), domain_bcs_type, c_vfrac);
94  }
void project_momenta(int lev, amrex::Real l_time, amrex::Real l_dt, amrex::Vector< amrex::MultiFab > &vars)
Definition: ERF_PoissonSolve.cpp:100
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.

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

◆ ReadCheckpointFile()

void ERF::ReadCheckpointFile ( )

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

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

1059 {
1060  for (int lev = 0; lev <= finest_level; ++lev)
1061  {
1062  amrex::Print() << "Reading MOST variables" << std::endl;
1063 
1064  IntVect ng(1,1,0);
1065  MultiFab m_var(ba2d[lev],dmap[lev],1,ng);
1066  MultiFab* dst = nullptr;
1067 
1068  // U*
1069  std::string UstarFileName(restart_chkfile + "/Level_0/Ustar_H");
1070  if (amrex::FileExists(UstarFileName)) {
1071  dst = m_SurfaceLayer->get_u_star(lev);
1072  VisMF::Read(m_var, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Ustar"));
1073  MultiFab::Copy(*dst,m_var,0,0,1,ng);
1074  }
1075 
1076  // W*
1077  std::string WstarFileName(restart_chkfile + "/Level_0/Wstar_H");
1078  if (amrex::FileExists(WstarFileName)) {
1079  dst = m_SurfaceLayer->get_w_star(lev);
1080  VisMF::Read(m_var, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Wstar"));
1081  MultiFab::Copy(*dst,m_var,0,0,1,ng);
1082  }
1083 
1084  // T*
1085  std::string TstarFileName(restart_chkfile + "/Level_0/Tstar_H");
1086  if (amrex::FileExists(TstarFileName)) {
1087  dst = m_SurfaceLayer->get_t_star(lev);
1088  VisMF::Read(m_var, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Tstar"));
1089  MultiFab::Copy(*dst,m_var,0,0,1,ng);
1090  }
1091 
1092  // Q*
1093  std::string QstarFileName(restart_chkfile + "/Level_0/Qstar_H");
1094  if (amrex::FileExists(QstarFileName)) {
1095  dst = m_SurfaceLayer->get_q_star(lev);
1096  VisMF::Read(m_var, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Qstar"));
1097  MultiFab::Copy(*dst,m_var,0,0,1,ng);
1098  }
1099 
1100  // Olen
1101  std::string OlenFileName(restart_chkfile + "/Level_0/Olen_H");
1102  if (amrex::FileExists(OlenFileName)) {
1103  dst = m_SurfaceLayer->get_olen(lev);
1104  VisMF::Read(m_var, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Olen"));
1105  MultiFab::Copy(*dst,m_var,0,0,1,ng);
1106  }
1107 
1108  // Qsurf
1109  std::string QsurfFileName(restart_chkfile + "/Level_0/Qsurf_H");
1110  if (amrex::FileExists(QsurfFileName)) {
1111  dst = m_SurfaceLayer->get_q_surf(lev);
1112  VisMF::Read(m_var, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Qsurf"));
1113  MultiFab::Copy(*dst,m_var,0,0,1,ng);
1114  }
1115 
1116  // PBLH
1117  std::string PBLHFileName(restart_chkfile + "/Level_0/PBLH_H");
1118  if (amrex::FileExists(PBLHFileName)) {
1119  dst = m_SurfaceLayer->get_pblh(lev);
1120  VisMF::Read(m_var, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "PBLH"));
1121  MultiFab::Copy(*dst,m_var,0,0,1,ng);
1122  }
1123 
1124  // Z0
1125  std::string Z0FileName(restart_chkfile + "/Level_0/Z0_H");
1126  if (amrex::FileExists(Z0FileName)) {
1127  dst = m_SurfaceLayer->get_z0(lev);
1128  VisMF::Read(m_var, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Z0"));
1129  MultiFab::Copy(*dst,m_var,0,0,1,ng);
1130  }
1131  }
1132 }

◆ ReadParameters()

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

321 {
322  if (max_level > 0)
323  {
324  ParmParse pp(pp_prefix);
325  Vector<std::string> refinement_indicators;
326  pp.queryarr("refinement_indicators",refinement_indicators,0,pp.countval("refinement_indicators"));
327 
328  for (int i=0; i<refinement_indicators.size(); ++i)
329  {
330  std::string ref_prefix = pp_prefix + "." + refinement_indicators[i];
331 
332  ParmParse ppr(ref_prefix);
333  RealBox realbox;
334  int lev_for_box;
335 
336  int num_real_lo = ppr.countval("in_box_lo");
337  int num_indx_lo = ppr.countval("in_box_lo_indices");
338  int num_real_hi = ppr.countval("in_box_hi");
339  int num_indx_hi = ppr.countval("in_box_hi_indices");
340 
341  AMREX_ALWAYS_ASSERT(num_real_lo == num_real_hi);
342  AMREX_ALWAYS_ASSERT(num_indx_lo == num_indx_hi);
343 
344  if ( !((num_real_lo >= AMREX_SPACEDIM-1 && num_indx_lo == 0) ||
345  (num_indx_lo >= AMREX_SPACEDIM-1 && num_real_lo == 0) ||
346  (num_indx_lo == 0 && num_real_lo == 0)) )
347  {
348  amrex::Abort("Must only specify box for refinement using real OR index space");
349  }
350 
351  if (num_real_lo > 0) {
352  std::vector<Real> rbox_lo(3), rbox_hi(3);
353  ppr.get("max_level",lev_for_box);
354  if (lev_for_box <= max_level)
355  {
356  if (n_error_buf[0] != IntVect::TheZeroVector()) {
357  amrex::Abort("Don't use n_error_buf > 0 when setting the box explicitly");
358  }
359 
360  const Real* plo = geom[lev_for_box].ProbLo();
361  const Real* phi = geom[lev_for_box].ProbHi();
362 
363  ppr.getarr("in_box_lo",rbox_lo,0,num_real_lo);
364  ppr.getarr("in_box_hi",rbox_hi,0,num_real_hi);
365 
366  if (rbox_lo[0] < plo[0]) rbox_lo[0] = plo[0];
367  if (rbox_lo[1] < plo[1]) rbox_lo[1] = plo[1];
368  if (rbox_hi[0] > phi[0]) rbox_hi[0] = phi[0];
369  if (rbox_hi[1] > phi[1]) rbox_hi[1] = phi[1];
370  if (num_real_lo < AMREX_SPACEDIM) {
371  rbox_lo[2] = plo[2];
372  rbox_hi[2] = phi[2];
373  }
374 
375  realbox = RealBox(&(rbox_lo[0]),&(rbox_hi[0]));
376 
377  Print() << "Realbox read in and intersected laterally with domain is " << realbox << std::endl;
378 
379  num_boxes_at_level[lev_for_box] += 1;
380 
381  int ilo, jlo, klo;
382  int ihi, jhi, khi;
383  const auto* dx = geom[lev_for_box].CellSize();
384  ilo = static_cast<int>((rbox_lo[0] - plo[0])/dx[0]);
385  jlo = static_cast<int>((rbox_lo[1] - plo[1])/dx[1]);
386  ihi = static_cast<int>((rbox_hi[0] - plo[0])/dx[0]-1);
387  jhi = static_cast<int>((rbox_hi[1] - plo[1])/dx[1]-1);
388  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
389  // Search for k indices corresponding to nominal grid
390  // AGL heights
391  const Box& domain = geom[lev_for_box].Domain();
392  klo = domain.smallEnd(2) - 1;
393  khi = domain.smallEnd(2) - 1;
394 
395  if (rbox_lo[2] <= zlevels_stag[lev_for_box][domain.smallEnd(2)])
396  {
397  klo = domain.smallEnd(2);
398  }
399  else
400  {
401  for (int k=domain.smallEnd(2); k<=domain.bigEnd(2)+1; ++k) {
402  if (zlevels_stag[lev_for_box][k] > rbox_lo[2]) {
403  klo = k-1;
404  break;
405  }
406  }
407  }
408  AMREX_ASSERT(klo >= domain.smallEnd(2));
409 
410  if (rbox_hi[2] >= zlevels_stag[lev_for_box][domain.bigEnd(2)+1])
411  {
412  khi = domain.bigEnd(2);
413  }
414  else
415  {
416  for (int k=klo+1; k<=domain.bigEnd(2)+1; ++k) {
417  if (zlevels_stag[lev_for_box][k] > rbox_hi[2]) {
418  khi = k-1;
419  break;
420  }
421  }
422  }
423  AMREX_ASSERT((khi <= domain.bigEnd(2)) && (khi > klo));
424 
425  // Need to update realbox because tagging is based on
426  // the initial _un_deformed grid
427  realbox = RealBox(plo[0]+ ilo *dx[0], plo[1]+ jlo *dx[1], plo[2]+ klo *dx[2],
428  plo[0]+(ihi+1)*dx[0], plo[1]+(jhi+1)*dx[1], plo[2]+(khi+1)*dx[2]);
429  } else {
430  klo = static_cast<int>((rbox_lo[2] - plo[2])/dx[2]);
431  khi = static_cast<int>((rbox_hi[2] - plo[2])/dx[2]-1);
432  }
433 
434  Box bx(IntVect(ilo,jlo,klo),IntVect(ihi,jhi,khi));
435  if ( (ilo%ref_ratio[lev_for_box-1][0] != 0) || ((ihi+1)%ref_ratio[lev_for_box-1][0] != 0) ||
436  (jlo%ref_ratio[lev_for_box-1][1] != 0) || ((jhi+1)%ref_ratio[lev_for_box-1][1] != 0) ||
437  (klo%ref_ratio[lev_for_box-1][2] != 0) || ((khi+1)%ref_ratio[lev_for_box-1][2] != 0) )
438  {
439  amrex::Print() << "Box : " << bx << std::endl;
440  amrex::Print() << "RealBox : " << realbox << std::endl;
441  amrex::Print() << "ilo, ihi+1, jlo, jhi+1, klo, khi+1 by ref_ratio : "
442  << ilo%ref_ratio[lev_for_box-1][0] << " " << (ihi+1)%ref_ratio[lev_for_box-1][0] << " "
443  << jlo%ref_ratio[lev_for_box-1][1] << " " << (jhi+1)%ref_ratio[lev_for_box-1][1] << " "
444  << klo%ref_ratio[lev_for_box-1][2] << " " << (khi+1)%ref_ratio[lev_for_box-1][2] << std::endl;
445  amrex::Error("Fine box is not legit with this ref_ratio");
446  }
447  boxes_at_level[lev_for_box].push_back(bx);
448  Print() << "Saving in 'boxes at level' as " << bx << std::endl;
449  } // lev
450 
451  if (solverChoice.init_type == InitType::WRFInput) {
452  if (num_boxes_at_level[lev_for_box] != num_files_at_level[lev_for_box]) {
453  amrex::Error("Number of boxes doesn't match number of input files");
454 
455  }
456  }
457 
458  } else if (num_indx_lo > 0) {
459 
460  std::vector<int> box_lo(3), box_hi(3);
461  ppr.get("max_level",lev_for_box);
462  if (lev_for_box <= max_level)
463  {
464  if (n_error_buf[0] != IntVect::TheZeroVector()) {
465  amrex::Abort("Don't use n_error_buf > 0 when setting the box explicitly");
466  }
467 
468  ppr.getarr("in_box_lo_indices",box_lo,0,AMREX_SPACEDIM);
469  ppr.getarr("in_box_hi_indices",box_hi,0,AMREX_SPACEDIM);
470 
471  Box bx(IntVect(box_lo[0],box_lo[1],box_lo[2]),IntVect(box_hi[0],box_hi[1],box_hi[2]));
472  amrex::Print() << "BOX " << bx << std::endl;
473 
474  const auto* dx = geom[lev_for_box].CellSize();
475  const Real* plo = geom[lev_for_box].ProbLo();
476  realbox = RealBox(plo[0]+ box_lo[0] *dx[0], plo[1]+ box_lo[1] *dx[1], plo[2]+ box_lo[2] *dx[2],
477  plo[0]+(box_hi[0]+1)*dx[0], plo[1]+(box_hi[1]+1)*dx[1], plo[2]+(box_hi[2]+1)*dx[2]);
478 
479  Print() << "Reading " << bx << " at level " << lev_for_box << std::endl;
480  num_boxes_at_level[lev_for_box] += 1;
481 
482  if ( (box_lo[0]%ref_ratio[lev_for_box-1][0] != 0) || ((box_hi[0]+1)%ref_ratio[lev_for_box-1][0] != 0) ||
483  (box_lo[1]%ref_ratio[lev_for_box-1][1] != 0) || ((box_hi[1]+1)%ref_ratio[lev_for_box-1][1] != 0) ||
484  (box_lo[2]%ref_ratio[lev_for_box-1][2] != 0) || ((box_hi[2]+1)%ref_ratio[lev_for_box-1][2] != 0) )
485  amrex::Error("Fine box is not legit with this ref_ratio");
486  boxes_at_level[lev_for_box].push_back(bx);
487  Print() << "Saving in 'boxes at level' as " << bx << std::endl;
488  } // lev
489 
490  if (solverChoice.init_type == InitType::WRFInput) {
491  if (num_boxes_at_level[lev_for_box] != num_files_at_level[lev_for_box]) {
492  amrex::Error("Number of boxes doesn't match number of input files");
493 
494  }
495  }
496  }
497 
498  AMRErrorTagInfo info;
499 
500  if (realbox.ok()) {
501  info.SetRealBox(realbox);
502  }
503  if (ppr.countval("start_time") > 0) {
504  Real ref_min_time; ppr.get("start_time",ref_min_time);
505  info.SetMinTime(ref_min_time);
506  }
507  if (ppr.countval("end_time") > 0) {
508  Real ref_max_time; ppr.get("end_time",ref_max_time);
509  info.SetMaxTime(ref_max_time);
510  }
511  if (ppr.countval("max_level") > 0) {
512  int ref_max_level; ppr.get("max_level",ref_max_level);
513  info.SetMaxLevel(ref_max_level);
514  }
515 
516  if (ppr.countval("value_greater")) {
517  int num_val = ppr.countval("value_greater");
518  Vector<Real> value(num_val);
519  ppr.getarr("value_greater",value,0,num_val);
520  std::string field; ppr.get("field_name",field);
521  ref_tags.push_back(AMRErrorTag(value,AMRErrorTag::GREATER,field,info));
522  }
523  else if (ppr.countval("value_less")) {
524  int num_val = ppr.countval("value_less");
525  Vector<Real> value(num_val);
526  ppr.getarr("value_less",value,0,num_val);
527  std::string field; ppr.get("field_name",field);
528  ref_tags.push_back(AMRErrorTag(value,AMRErrorTag::LESS,field,info));
529  }
530  else if (ppr.countval("adjacent_difference_greater")) {
531  int num_val = ppr.countval("adjacent_difference_greater");
532  Vector<Real> value(num_val);
533  ppr.getarr("adjacent_difference_greater",value,0,num_val);
534  std::string field; ppr.get("field_name",field);
535  ref_tags.push_back(AMRErrorTag(value,AMRErrorTag::GRAD,field,info));
536  }
537  else if (realbox.ok())
538  {
539  ref_tags.push_back(AMRErrorTag(info));
540  } else if (refinement_indicators[i] != "storm_tracker") {
541  Abort(std::string("Unrecognized refinement indicator for " + refinement_indicators[i]).c_str());
542  }
543  } // loop over criteria
544  } // if max_level > 0
545 }
Here is the call graph for this function:

◆ remake_zphys()

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

◆ restart()

void ERF::restart ( )
2036 {
2037  auto dRestartTime0 = amrex::second();
2038 
2040 
2042  //
2043  // Coarsening before we split the grids ensures that each resulting
2044  // grid will have an even number of cells in each direction.
2045  //
2046  BoxArray new_ba(amrex::coarsen(Geom(0).Domain(),2));
2047  //
2048  // Now split up into list of grids within max_grid_size[0] limit.
2049  //
2050  new_ba.maxSize(max_grid_size[0]/2);
2051  //
2052  // Now refine these boxes back to level 0.
2053  //
2054  new_ba.refine(2);
2055 
2056  if (refine_grid_layout) {
2057  ChopGrids(0, new_ba, ParallelDescriptor::NProcs());
2058  }
2059 
2060  if (new_ba != grids[0]) {
2061  DistributionMapping new_dm(new_ba);
2062  RemakeLevel(0,t_new[0],new_ba,new_dm);
2063  }
2064  }
2065 
2066 #ifdef ERF_USE_PARTICLES
2067  // We call this here without knowing whether the particles have already been initialized or not
2068  initializeTracers((ParGDBBase*)GetParGDB(),z_phys_nd,t_new[0]);
2069 #endif
2070 
2071  Real cur_time = t_new[0];
2072  if (m_check_per > 0.) {last_check_file_time = cur_time;}
2073  if (m_plot2d_per_1 > 0.) {last_plot2d_file_time_1 = std::floor(cur_time/m_plot2d_per_1) * m_plot2d_per_1;}
2074  if (m_plot2d_per_2 > 0.) {last_plot2d_file_time_2 = std::floor(cur_time/m_plot2d_per_2) * m_plot2d_per_2;}
2075  if (m_plot3d_per_1 > 0.) {last_plot3d_file_time_1 = std::floor(cur_time/m_plot3d_per_1) * m_plot3d_per_1;}
2076  if (m_plot3d_per_2 > 0.) {last_plot3d_file_time_2 = std::floor(cur_time/m_plot3d_per_2) * m_plot3d_per_2;}
2077 
2078  if (m_check_int > 0.) {last_check_file_step = istep[0];}
2079  if (m_plot2d_int_1 > 0.) {last_plot2d_file_step_1 = istep[0];}
2080  if (m_plot2d_int_2 > 0.) {last_plot2d_file_step_2 = istep[0];}
2081  if (m_plot3d_int_1 > 0.) {last_plot3d_file_step_1 = istep[0];}
2082  if (m_plot3d_int_2 > 0.) {last_plot3d_file_step_2 = istep[0];}
2083 
2084  if (verbose > 0)
2085  {
2086  auto dRestartTime = amrex::second() - dRestartTime0;
2087  ParallelDescriptor::ReduceRealMax(dRestartTime,ParallelDescriptor::IOProcessorNumber());
2088  amrex::Print() << "Restart time = " << dRestartTime << " seconds." << '\n';
2089  }
2090 }
void RemakeLevel(int lev, amrex::Real time, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm) override
Definition: ERF_MakeNewLevel.cpp:505
void ReadCheckpointFile()
Definition: ERF_Checkpoint.cpp:458

◆ 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:1048
AMREX_FORCE_INLINE std::ostream & SampleLineLog(int i)
Definition: ERF.H:1483
const int datprecision
Definition: ERF.H:1049

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

◆ SampleLine()

amrex::IntVect& ERF::SampleLine ( int  i)
inlineprivate
1510  {
1511  return sampleline[i];
1512  }

◆ SampleLineLog()

AMREX_FORCE_INLINE std::ostream& ERF::SampleLineLog ( int  i)
inlineprivate
1484  {
1485  return *samplelinelog[i];
1486  }

◆ SampleLineLogName()

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

The filename of the ith samplelinelog file.

1643 { return samplelinelogname[i]; }

◆ SamplePoint()

amrex::IntVect& ERF::SamplePoint ( int  i)
inlineprivate
1497  {
1498  return samplepoint[i];
1499  }

◆ SamplePointLog()

AMREX_FORCE_INLINE std::ostream& ERF::SamplePointLog ( int  i)
inlineprivate
1470  {
1471  return *sampleptlog[i];
1472  }

◆ SamplePointLogName()

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

The filename of the ith sampleptlog file.

1640 { 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:1135
const amrex::Vector< std::string > cons_names
Definition: ERF.H:1128
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:1178
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.
95 {
96  // If we are restarting then we haven't read the input_sounding file yet
97  // so we need to read it here
98  // TODO: should we store this information in the checkpoint file instead?
99  if (restarting) {
101  for (int n = 0; n < input_sounding_data.n_sounding_files; n++) {
103  }
104  }
105 
106  const Real* z_inp_sound = input_sounding_data.z_inp_sound[0].dataPtr();
107  const Real* U_inp_sound = input_sounding_data.U_inp_sound[0].dataPtr();
108  const Real* V_inp_sound = input_sounding_data.V_inp_sound[0].dataPtr();
109  const Real* theta_inp_sound = input_sounding_data.theta_inp_sound[0].dataPtr();
110  const int inp_sound_size = input_sounding_data.size(0);
111 
112  int refine_fac{1};
113  for (int lev = 0; lev <= finest_level; lev++)
114  {
115  const int klo = geom[lev].Domain().smallEnd(2);
116  const int khi = geom[lev].Domain().bigEnd(2);
117  const int Nz = khi - klo + 1;
118 
119  Vector<Real> zcc(Nz);
120  Vector<Real> zlevels_sub(zlevels_stag[0].begin()+klo/refine_fac,
121  zlevels_stag[0].begin()+khi/refine_fac+2);
122  expand_and_interpolate_1d(zcc, zlevels_sub, refine_fac, true);
123 #if 0
124  amrex::AllPrint() << "lev="<<lev<<" : (refine_fac="<<refine_fac<<",klo="<<klo<<",khi="<<khi<<") ";
125  for (int k = 0; k < zlevels_sub.size(); k++) { amrex::AllPrint() << zlevels_sub[k] << " "; }
126  amrex::AllPrint() << " --> ";
127  for (int k = 0; k < Nz; k++) { amrex::AllPrint() << zcc[k] << " "; }
128  amrex::AllPrint() << std::endl;
129 #endif
130 
131  for (int k = 0; k < Nz; k++)
132  {
133  h_rayleigh_ptrs[lev][Rayleigh::ubar][k] = interpolate_1d(z_inp_sound, U_inp_sound, zcc[k], inp_sound_size);
134  h_rayleigh_ptrs[lev][Rayleigh::vbar][k] = interpolate_1d(z_inp_sound, V_inp_sound, zcc[k], inp_sound_size);
135  h_rayleigh_ptrs[lev][Rayleigh::wbar][k] = Real(0.0);
136  h_rayleigh_ptrs[lev][Rayleigh::thetabar][k] = interpolate_1d(z_inp_sound, theta_inp_sound, zcc[k], inp_sound_size);
137  }
138 
139  // Copy from host version to device version
140  Gpu::copy(Gpu::hostToDevice, h_rayleigh_ptrs[lev][Rayleigh::ubar].begin(), h_rayleigh_ptrs[lev][Rayleigh::ubar].end(),
141  d_rayleigh_ptrs[lev][Rayleigh::ubar].begin());
142  Gpu::copy(Gpu::hostToDevice, h_rayleigh_ptrs[lev][Rayleigh::vbar].begin(), h_rayleigh_ptrs[lev][Rayleigh::vbar].end(),
143  d_rayleigh_ptrs[lev][Rayleigh::vbar].begin());
144  Gpu::copy(Gpu::hostToDevice, h_rayleigh_ptrs[lev][Rayleigh::wbar].begin(), h_rayleigh_ptrs[lev][Rayleigh::wbar].end(),
145  d_rayleigh_ptrs[lev][Rayleigh::wbar].begin());
146  Gpu::copy(Gpu::hostToDevice, h_rayleigh_ptrs[lev][Rayleigh::thetabar].begin(), h_rayleigh_ptrs[lev][Rayleigh::thetabar].end(),
147  d_rayleigh_ptrs[lev][Rayleigh::thetabar].begin());
148 
149  refine_fac *= ref_ratio[lev][2];
150  }
151 }
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
1540  {
1541  if (amrex::ParallelDescriptor::IOProcessor())
1542  {
1543  datalog[i] = std::make_unique<std::fstream>();
1544  datalog[i]->open(filename.c_str(),std::ios::out|std::ios::app);
1545  if (!datalog[i]->good()) {
1546  amrex::FileOpenFailed(filename);
1547  }
1548  }
1549  amrex::ParallelDescriptor::Barrier("ERF::setRecordDataInfo");
1550  }

◆ setRecordDerDataInfo()

void ERF::setRecordDerDataInfo ( int  i,
const std::string &  filename 
)
inlineprivate
1553  {
1554  if (amrex::ParallelDescriptor::IOProcessor())
1555  {
1556  der_datalog[i] = std::make_unique<std::fstream>();
1557  der_datalog[i]->open(filename.c_str(),std::ios::out|std::ios::app);
1558  if (!der_datalog[i]->good()) {
1559  amrex::FileOpenFailed(filename);
1560  }
1561  }
1562  amrex::ParallelDescriptor::Barrier("ERF::setRecordDerDataInfo");
1563  }

◆ setRecordEnergyDataInfo()

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

◆ setRecordSampleLineInfo()

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

◆ setRecordSamplePointInfo()

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

◆ 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:1188
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);
79  ParallelFor(xbx,ybx,
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

◆ 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:1447
const int timeprecision
Definition: ERF.H:1050
AMREX_FORCE_INLINE int NumDerDataLogs() noexcept
Definition: ERF.H:1461
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  Print() << " RHO SCALAR = " << scal_sl << '\n';
121  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  Print() << " RHO SCALAR SL/ML = " << scal_sl << " " << scal_ml << '\n';
130  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:1490
AMREX_FORCE_INLINE int NumSamplePointLogs() noexcept
Definition: ERF.H:1476
amrex::IntVect & SampleLine(int i)
Definition: ERF.H:1509
AMREX_FORCE_INLINE int NumSamplePoints() noexcept
Definition: ERF.H:1503
AMREX_FORCE_INLINE int NumSampleLines() noexcept
Definition: ERF.H:1516
amrex::IntVect & SamplePoint(int i)
Definition: ERF.H:1496
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:1440
AMREX_FORCE_INLINE int NumDataLogs() noexcept
Definition: ERF.H:1454
void sample_lines(int lev, amrex::Real time, amrex::IntVect cell, amrex::MultiFab &mf)
Definition: ERF_WriteScalarProfiles.cpp:563

◆ 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:1213
amrex::Real hindcast_data_interval_in_hrs
Definition: ERF_DataStruct.H:1214

◆ 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  Real dT = bdy_time_interval;
36 
37  int n_time_old = static_cast<int>( (time ) / dT);
38  int n_time_new = static_cast<int>( (time+dt[lev]) / dT);
39 
40  int ntimes = bdy_data_xlo.size();
41  for (int itime = 0; itime < ntimes; itime++)
42  {
43  //if (bdy_data_xlo[itime].size() > 0) {
44  // amrex::Print() << "HAVE DATA AT TIME " << itime << std::endl;
45  //} else {
46  // amrex::Print() << " NO DATA AT TIME " << itime << std::endl;
47  //}
48 
49  bool clear_itime = (itime < n_time_old);
50 
51  if (clear_itime && bdy_data_xlo[itime].size() > 0) {
52  bdy_data_xlo[itime].clear();
53  bdy_data_xhi[itime].clear();
54  bdy_data_ylo[itime].clear();
55  bdy_data_yhi[itime].clear();
56  //amrex::Print() << "CLEAR BDY DATA AT TIME " << itime << std::endl;
57  }
58 
59  bool need_itime = (itime >= n_time_old && itime <= n_time_new+1);
60  //if (need_itime) amrex::Print() << "NEED BDY DATA AT TIME " << itime << std::endl;
61 
62  if (bdy_data_xlo[itime].size() == 0 && need_itime) {
63  read_from_wrfbdy(itime,nc_bdy_file,geom[0].Domain(),
64  bdy_data_xlo,bdy_data_xhi,bdy_data_ylo,bdy_data_yhi,
65  real_width);
66 
67  convert_all_wrfbdy_data(itime, geom[0].Domain(), bdy_data_xlo, bdy_data_xhi, bdy_data_ylo, bdy_data_yhi,
68  *mf_MUB, *mf_C1H, *mf_C2H,
70  geom[lev], use_moist);
71  }
72  } // itime
73  } // use_real_bcs && lev == 0
74 
75  if (!nc_low_file.empty() && (lev==0)) {
76  Real dT = low_time_interval;
77 
78  int n_time_old = static_cast<int>( (time ) / dT);
79  int n_time_new = static_cast<int>( (time+dt[lev]) / dT);
80 
81  int ntimes = bdy_data_xlo.size();
82  for (int itime = 0; itime < ntimes; itime++)
83  {
84  bool clear_itime = (itime < n_time_old);
85 
86  if (clear_itime && low_data_zlo[itime].size() > 0) {
87  low_data_zlo[itime].clear();
88  //amrex::Print() << "CLEAR LOW DATA AT TIME " << itime << std::endl;
89  }
90 
91  bool need_itime = (itime >= n_time_old && itime <= n_time_new+1);
92  //if (need_itime) amrex::Print() << "NEED LOW DATA AT TIME " << itime << std::endl;
93 
94  if (low_data_zlo[itime].size() == 0 && need_itime) {
95  read_from_wrflow(itime, nc_low_file, geom[lev].Domain(), low_data_zlo);
96 
97  update_sst_tsk(itime, geom[lev], ba2d[lev],
98  sst_lev[lev], tsk_lev[lev],
99  m_SurfaceLayer, low_data_zlo,
100  S_new, *mf_PSFC[lev],
101  solverChoice.rdOcp, lmask_lev[lev][0], use_moist);
102  }
103  } // itime
104  } // have nc_low_file && lev == 0
105 #endif
106 
107  //
108  // NOTE: the momenta here are not fillpatched (they are only used as scratch space)
109  //
110  if (lev == 0) {
111  FillPatchCrseLevel(lev, time, {&S_new, &U_new, &V_new, &W_new});
112  } else if (lev < finest_level) {
113  FillPatchFineLevel(lev, time, {&S_new, &U_new, &V_new, &W_new},
114  {&S_new, &rU_new[lev], &rV_new[lev], &rW_new[lev]},
115  base_state[lev], base_state[lev]);
116  }
117 
118  if (regrid_int > 0) // We may need to regrid
119  {
120  // help keep track of whether a level was already regridded
121  // from a coarser level call to regrid
122  static Vector<int> last_regrid_step(max_level+1, 0);
123 
124  // regrid changes level "lev+1" so we don't regrid on max_level
125  // also make sure we don't regrid fine levels again if
126  // it was taken care of during a coarser regrid
127  if (lev < max_level)
128  {
129  if ( (istep[lev] % regrid_int == 0) && (istep[lev] > last_regrid_step[lev]) )
130  {
131  // regrid could add newly refine levels (if finest_level < max_level)
132  // so we save the previous finest level index
133  int old_finest = finest_level;
134 
135  regrid(lev, time);
136 
137 #ifdef ERF_USE_PARTICLES
138  if (finest_level != old_finest) {
139  particleData.Redistribute();
140  }
141 #endif
142 
143  // mark that we have regridded this level already
144  for (int k = lev; k <= finest_level; ++k) {
145  last_regrid_step[k] = istep[k];
146  }
147 
148  // if there are newly created levels, set the time step
149  for (int k = old_finest+1; k <= finest_level; ++k) {
150  dt[k] = dt[k-1] / static_cast<Real>(nsubsteps[k]);
151  }
152  } // if
153  } // lev
154  }
155 
156  // Update what we call "old" and "new" time
157  t_old[lev] = t_new[lev];
158  t_new[lev] += dt[lev];
159 
160  if (Verbose()) {
161  amrex::Print() << "[Level " << lev << " step " << istep[lev]+1 << "] ";
162  amrex::Print() << std::setprecision(timeprecision)
163  << "ADVANCE from elapsed time = " << t_old[lev] << " to " << t_new[lev]
164  << " with dt = " << dt[lev] << std::endl;
165  }
166 
167 #ifdef ERF_USE_WW3_COUPLING
168  amrex::Print() << " About to call send_to_ww3 from ERF_Timestep" << std::endl;
169  send_to_ww3(lev);
170  amrex::Print() << " About to call read_waves from ERF_Timestep" << std::endl;
171  read_waves(lev);
172  //send_to_ww3(lev);
173  //read_waves(lev);
174  //send_to_ww3(lev);
175 #endif
176 
177  // Advance a single level for a single time step
178  Advance(lev, time, dt[lev], istep[lev], nsubsteps[lev]);
179 
180  ++istep[lev];
181 
182  if (Verbose()) {
183  amrex::Print() << "[Level " << lev << " step " << istep[lev] << "] ";
184  amrex::Print() << "Advanced " << CountCells(lev) << " cells" << std::endl;
185  }
186 
187  if (lev < finest_level)
188  {
189  // recursive call for next-finer level
190  for (int i = 1; i <= nsubsteps[lev+1]; ++i)
191  {
192  Real strt_time_for_fine = time + (i-1)*dt[lev+1];
193  timeStep(lev+1, strt_time_for_fine, i);
194  }
195  }
196 
197  if (verbose && lev == 0 && solverChoice.moisture_type != MoistureType::None) {
198  amrex::Print() << "Cloud fraction " << time << " " << cloud_fraction(time) << std::endl;
199  }
200 }
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
538 {
539  // ********************************************************************************************
540  // Diffusive terms
541  // ********************************************************************************************
542  bool l_use_terrain = (SolverChoice::terrain_type != TerrainType::None);
543  bool l_use_kturb = solverChoice.turbChoice[lev].use_kturb;
544  bool l_use_diff = ( (solverChoice.diffChoice.molec_diff_type != MolecDiffType::None) ||
545  l_use_kturb );
546  bool l_need_SmnSmn = solverChoice.turbChoice[lev].use_keqn;
547  bool l_use_moist = ( solverChoice.moisture_type != MoistureType::None );
548  bool l_rotate = ( solverChoice.use_rotate_surface_flux );
549 
550  bool l_implicit_diff = (solverChoice.vert_implicit_fac[0] > 0 ||
553 
554  BoxArray ba12 = convert(ba, IntVect(1,1,0));
555  BoxArray ba13 = convert(ba, IntVect(1,0,1));
556  BoxArray ba23 = convert(ba, IntVect(0,1,1));
557 
558  Tau[lev].resize(9);
559  Tau_corr[lev].resize(3);
560 
561  if (l_use_diff) {
562  //
563  // NOTE: We require ghost cells in the vertical when allowing grids that don't
564  // cover the entire vertical extent of the domain at this level
565  //
566  for (int i = 0; i < 3; i++) {
567  Tau[lev][i] = std::make_unique<MultiFab>( ba , dm, 1, IntVect(1,1,1) );
568  }
569  Tau[lev][TauType::tau12] = std::make_unique<MultiFab>( ba12, dm, 1, IntVect(1,1,1) );
570  Tau[lev][TauType::tau13] = std::make_unique<MultiFab>( ba13, dm, 1, IntVect(1,1,1) );
571  Tau[lev][TauType::tau23] = std::make_unique<MultiFab>( ba23, dm, 1, IntVect(1,1,1) );
572  Tau[lev][TauType::tau12]->setVal(0.);
573  Tau[lev][TauType::tau13]->setVal(0.);
574  Tau[lev][TauType::tau23]->setVal(0.);
575  if (l_use_terrain) {
576  Tau[lev][TauType::tau21] = std::make_unique<MultiFab>( ba12, dm, 1, IntVect(1,1,1) );
577  Tau[lev][TauType::tau31] = std::make_unique<MultiFab>( ba13, dm, 1, IntVect(1,1,1) );
578  Tau[lev][TauType::tau32] = std::make_unique<MultiFab>( ba23, dm, 1, IntVect(1,1,1) );
579  Tau[lev][TauType::tau21]->setVal(0.);
580  Tau[lev][TauType::tau31]->setVal(0.);
581  Tau[lev][TauType::tau32]->setVal(0.);
582  } else if (l_implicit_diff) {
583  Tau[lev][TauType::tau31] = std::make_unique<MultiFab>( ba13, dm, 1, IntVect(1,1,1) );
584  Tau[lev][TauType::tau32] = std::make_unique<MultiFab>( ba23, dm, 1, IntVect(1,1,1) );
585  Tau[lev][TauType::tau31]->setVal(0.);
586  Tau[lev][TauType::tau32]->setVal(0.);
587  } else {
588  Tau[lev][TauType::tau21] = nullptr;
589  Tau[lev][TauType::tau31] = nullptr;
590  Tau[lev][TauType::tau32] = nullptr;
591  }
592 
593  if (l_implicit_diff && solverChoice.implicit_momentum_diffusion)
594  {
595  Tau_corr[lev][0] = std::make_unique<MultiFab>( ba13, dm, 1, IntVect(1,1,1) ); // Tau31
596  Tau_corr[lev][1] = std::make_unique<MultiFab>( ba23, dm, 1, IntVect(1,1,1) ); // Tau32
597  Tau_corr[lev][0]->setVal(0.);
598  Tau_corr[lev][1]->setVal(0.);
599 #ifdef ERF_IMPLICIT_W
600  Tau_corr[lev][2] = std::make_unique<MultiFab>( ba , dm, 1, IntVect(1,1,1) ); // Tau33
601  Tau_corr[lev][2]->setVal(0.);
602 #else
603  Tau_corr[lev][2] = nullptr;
604 #endif
605  } else {
606  Tau_corr[lev][0] = nullptr;
607  Tau_corr[lev][1] = nullptr;
608  Tau_corr[lev][2] = nullptr;
609  }
610 
611  SFS_hfx1_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(1,0,0)), dm, 1, IntVect(1,1,1) );
612  SFS_hfx2_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(0,1,0)), dm, 1, IntVect(1,1,1) );
613  SFS_hfx3_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(0,0,1)), dm, 1, IntVect(1,1,1) );
614  SFS_diss_lev[lev] = std::make_unique<MultiFab>( ba , dm, 1, IntVect(1,1,1) );
615  SFS_hfx1_lev[lev]->setVal(0.);
616  SFS_hfx2_lev[lev]->setVal(0.);
617  SFS_hfx3_lev[lev]->setVal(0.);
618  SFS_diss_lev[lev]->setVal(0.);
619  if (l_use_moist) {
620  SFS_q1fx3_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(0,0,1)), dm, 1, IntVect(1,1,1) );
621  SFS_q2fx3_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(0,0,1)), dm, 1, IntVect(1,1,1) );
622  SFS_q1fx3_lev[lev]->setVal(0.0);
623  SFS_q2fx3_lev[lev]->setVal(0.0);
624  if (l_rotate) {
625  SFS_q1fx1_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(1,0,0)), dm, 1, IntVect(1,1,1) );
626  SFS_q1fx2_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(0,1,0)), dm, 1, IntVect(1,1,1) );
627  SFS_q1fx1_lev[lev]->setVal(0.0);
628  SFS_q1fx2_lev[lev]->setVal(0.0);
629  } else {
630  SFS_q1fx1_lev[lev] = nullptr;
631  SFS_q1fx2_lev[lev] = nullptr;
632  }
633  } else {
634  SFS_q1fx1_lev[lev] = nullptr;
635  SFS_q1fx2_lev[lev] = nullptr;
636  SFS_q1fx3_lev[lev] = nullptr;
637  SFS_q2fx3_lev[lev] = nullptr;
638  }
639  } else {
640  for (int i = 0; i < 9; i++) {
641  Tau[lev][i] = nullptr;
642  }
643  SFS_hfx1_lev[lev] = nullptr; SFS_hfx2_lev[lev] = nullptr; SFS_hfx3_lev[lev] = nullptr;
644  SFS_diss_lev[lev] = nullptr;
645  }
646 
647  if (l_use_kturb) {
648  eddyDiffs_lev[lev] = std::make_unique<MultiFab>(ba, dm, EddyDiff::NumDiffs, 2);
649  eddyDiffs_lev[lev]->setVal(0.0);
650  if(l_need_SmnSmn) {
651  SmnSmn_lev[lev] = std::make_unique<MultiFab>( ba, dm, 1, 0 );
652  } else {
653  SmnSmn_lev[lev] = nullptr;
654  }
655  } else {
656  eddyDiffs_lev[lev] = nullptr;
657  SmnSmn_lev[lev] = nullptr;
658  }
659 }
@ NumDiffs
Definition: ERF_IndexDefines.H:181

◆ update_terrain_arrays()

void ERF::update_terrain_arrays ( int  lev)
819 {
820  if (SolverChoice::mesh_type == MeshType::StretchedDz ||
821  SolverChoice::mesh_type == MeshType::VariableDz) {
822  make_J(geom[lev],*z_phys_nd[lev],*detJ_cc[lev]);
823  make_areas(geom[lev],*z_phys_nd[lev],*ax[lev],*ay[lev],*az[lev]);
824  make_zcc(geom[lev],*z_phys_nd[lev],*z_phys_cc[lev]);
825  } else { // MeshType::ConstantDz
826  if (SolverChoice::terrain_type == TerrainType::EB) {
827  const auto& ebfact = *eb[lev]->get_const_factory();
828  const MultiFab& volfrac = ebfact.getVolFrac();
829  detJ_cc[lev] = std::make_unique<MultiFab>(volfrac, amrex::make_alias, 0, volfrac.nComp());
830  }
831  }
832 }
void make_areas(const Geometry &geom, MultiFab &z_phys_nd, MultiFab &ax, MultiFab &ay, MultiFab &az)
Definition: ERF_TerrainMetrics.cpp:559
void make_J(const Geometry &geom, MultiFab &z_phys_nd, MultiFab &detJ_cc)
Definition: ERF_TerrainMetrics.cpp:521
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 }

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

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

◆ Write2DPlotFile()

void ERF::Write2DPlotFile ( int  which,
PlotFileType  plotfile_type,
amrex::Vector< std::string >  plot_var_names 
)
1966 {
1967  const Vector<std::string> varnames = PlotFileVarNames(plot_var_names);
1968  const int ncomp_mf = varnames.size();
1969 
1970  if (ncomp_mf == 0) return;
1971 
1972  // Vector of MultiFabs for cell-centered data
1973  Vector<MultiFab> mf(finest_level+1);
1974  for (int lev = 0; lev <= finest_level; ++lev) {
1975  mf[lev].define(ba2d[lev], dmap[lev], ncomp_mf, 0);
1976  }
1977 
1978 
1979  // **********************************************************************************************
1980  // (Effectively) 2D arrays
1981  // **********************************************************************************************
1982  for (int lev = 0; lev <= finest_level; ++lev)
1983  {
1984  // Make sure getPgivenRTh and getTgivenRandRTh don't fail
1985  if (check_for_nans) {
1987  }
1988 
1989  int mf_comp = 0;
1990 
1991  // Set all components to zero in case they aren't defined below
1992  mf[lev].setVal(0.0);
1993 
1994  // Expose domain khi and klo at each level
1995  int klo = geom[lev].Domain().smallEnd(2);
1996  int khi = geom[lev].Domain().bigEnd(2);
1997 
1998  if (containerHasElement(plot_var_names, "z_surf")) {
1999 #ifdef _OPENMP
2000 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2001 #endif
2002  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2003  {
2004  const Box& bx = mfi.tilebox();
2005  const Array4<Real>& derdat = mf[lev].array(mfi);
2006  const Array4<const Real>& z_phys_arr = z_phys_nd[lev]->const_array(mfi);
2007  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2008  derdat(i, j, k, mf_comp) = Compute_Z_AtWFace(i, j, 0, z_phys_arr);
2009  });
2010  }
2011  mf_comp++;
2012  }
2013 
2014  if (containerHasElement(plot_var_names, "landmask")) {
2015 #ifdef _OPENMP
2016 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2017 #endif
2018  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2019  {
2020  const Box& bx = mfi.tilebox();
2021  const Array4<Real>& derdat = mf[lev].array(mfi);
2022  const Array4<const int>& lmask_arr = lmask_lev[lev][0]->const_array(mfi);
2023  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2024  derdat(i, j, k, mf_comp) = lmask_arr(i, j, 0);
2025  });
2026  }
2027  mf_comp++;
2028  }
2029 
2030  if (containerHasElement(plot_var_names, "mapfac")) {
2031 #ifdef _OPENMP
2032 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2033 #endif
2034  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2035  {
2036  const Box& bx = mfi.tilebox();
2037  const Array4<Real>& derdat = mf[lev].array(mfi);
2038  const Array4<Real>& mf_m = mapfac[lev][MapFacType::m_x]->array(mfi);
2039  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2040  derdat(i ,j ,k, mf_comp) = mf_m(i,j,0);
2041  });
2042  }
2043  mf_comp++;
2044  }
2045 
2046  if (containerHasElement(plot_var_names, "lat_m")) {
2047  if (lat_m[lev]) {
2048 #ifdef _OPENMP
2049 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2050 #endif
2051  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2052  {
2053  const Box& bx = mfi.tilebox();
2054  const Array4<Real>& derdat = mf[lev].array(mfi);
2055  const Array4<Real>& data = lat_m[lev]->array(mfi);
2056  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2057  derdat(i, j, k, mf_comp) = data(i,j,0);
2058  });
2059  }
2060  }
2061  mf_comp++;
2062  } // lat_m
2063 
2064  if (containerHasElement(plot_var_names, "lon_m")) {
2065  if (lon_m[lev]) {
2066 #ifdef _OPENMP
2067 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2068 #endif
2069  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2070  {
2071  const Box& bx = mfi.tilebox();
2072  const Array4<Real>& derdat = mf[lev].array(mfi);
2073  const Array4<Real>& data = lon_m[lev]->array(mfi);
2074  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2075  derdat(i, j, k, mf_comp) = data(i,j,0);
2076  });
2077  }
2078  } else {
2079  mf[lev].setVal(0.0,mf_comp,1,0);
2080  }
2081 
2082  mf_comp++;
2083 
2084  } // lon_m
2085 
2086  ///////////////////////////////////////////////////////////////////////
2087  // These quantities are diagnosed by the surface layer
2088  if (containerHasElement(plot_var_names, "u_star")) {
2089 #ifdef _OPENMP
2090 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2091 #endif
2092  if (m_SurfaceLayer) {
2093  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2094  {
2095  const Box& bx = mfi.tilebox();
2096  const auto& derdat = mf[lev].array(mfi);
2097  const auto& ustar = m_SurfaceLayer->get_u_star(lev)->const_array(mfi);
2098  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2099  derdat(i, j, k, mf_comp) = ustar(i, j, 0);
2100  });
2101  }
2102  } else {
2103  mf[lev].setVal(-999,mf_comp,1,0);
2104  }
2105  mf_comp++;
2106  } // ustar
2107 
2108  if (containerHasElement(plot_var_names, "w_star")) {
2109 #ifdef _OPENMP
2110 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2111 #endif
2112  if (m_SurfaceLayer) {
2113  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2114  {
2115  const Box& bx = mfi.tilebox();
2116  const auto& derdat = mf[lev].array(mfi);
2117  const auto& ustar = m_SurfaceLayer->get_w_star(lev)->const_array(mfi);
2118  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2119  derdat(i, j, k, mf_comp) = ustar(i, j, 0);
2120  });
2121  }
2122  } else {
2123  mf[lev].setVal(-999,mf_comp,1,0);
2124  }
2125  mf_comp++;
2126  } // wstar
2127 
2128  if (containerHasElement(plot_var_names, "t_star")) {
2129 #ifdef _OPENMP
2130 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2131 #endif
2132  if (m_SurfaceLayer) {
2133  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2134  {
2135  const Box& bx = mfi.tilebox();
2136  const auto& derdat = mf[lev].array(mfi);
2137  const auto& ustar = m_SurfaceLayer->get_t_star(lev)->const_array(mfi);
2138  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2139  derdat(i, j, k, mf_comp) = ustar(i, j, 0);
2140  });
2141  }
2142  } else {
2143  mf[lev].setVal(-999,mf_comp,1,0);
2144  }
2145  mf_comp++;
2146  } // tstar
2147 
2148  if (containerHasElement(plot_var_names, "q_star")) {
2149 #ifdef _OPENMP
2150 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2151 #endif
2152  if (m_SurfaceLayer) {
2153  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2154  {
2155  const Box& bx = mfi.tilebox();
2156  const auto& derdat = mf[lev].array(mfi);
2157  const auto& ustar = m_SurfaceLayer->get_q_star(lev)->const_array(mfi);
2158  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2159  derdat(i, j, k, mf_comp) = ustar(i, j, 0);
2160  });
2161  }
2162  } else {
2163  mf[lev].setVal(-999,mf_comp,1,0);
2164  }
2165  mf_comp++;
2166  } // qstar
2167 
2168  if (containerHasElement(plot_var_names, "Olen")) {
2169 #ifdef _OPENMP
2170 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2171 #endif
2172  if (m_SurfaceLayer) {
2173  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2174  {
2175  const Box& bx = mfi.tilebox();
2176  const auto& derdat = mf[lev].array(mfi);
2177  const auto& ustar = m_SurfaceLayer->get_olen(lev)->const_array(mfi);
2178  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2179  derdat(i, j, k, mf_comp) = ustar(i, j, 0);
2180  });
2181  }
2182  } else {
2183  mf[lev].setVal(-999,mf_comp,1,0);
2184  }
2185  mf_comp++;
2186  } // Olen
2187 
2188  if (containerHasElement(plot_var_names, "pblh")) {
2189 #ifdef _OPENMP
2190 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2191 #endif
2192  if (m_SurfaceLayer) {
2193  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2194  {
2195  const Box& bx = mfi.tilebox();
2196  const auto& derdat = mf[lev].array(mfi);
2197  const auto& ustar = m_SurfaceLayer->get_pblh(lev)->const_array(mfi);
2198  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2199  derdat(i, j, k, mf_comp) = ustar(i, j, 0);
2200  });
2201  }
2202  } else {
2203  mf[lev].setVal(-999,mf_comp,1,0);
2204  }
2205  mf_comp++;
2206  } // pblh
2207 
2208  if (containerHasElement(plot_var_names, "t_surf")) {
2209 #ifdef _OPENMP
2210 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2211 #endif
2212  if (m_SurfaceLayer) {
2213  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2214  {
2215  const Box& bx = mfi.tilebox();
2216  const auto& derdat = mf[lev].array(mfi);
2217  const auto& tsurf = m_SurfaceLayer->get_t_surf(lev)->const_array(mfi);
2218  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2219  derdat(i, j, k, mf_comp) = tsurf(i, j, 0);
2220  });
2221  }
2222  } else {
2223  mf[lev].setVal(-999,mf_comp,1,0);
2224  }
2225  mf_comp++;
2226  } // tsurf
2227 
2228  if (containerHasElement(plot_var_names, "q_surf")) {
2229 #ifdef _OPENMP
2230 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2231 #endif
2232  if (m_SurfaceLayer) {
2233  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2234  {
2235  const Box& bx = mfi.tilebox();
2236  const auto& derdat = mf[lev].array(mfi);
2237  const auto& ustar = m_SurfaceLayer->get_q_surf(lev)->const_array(mfi);
2238  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2239  derdat(i, j, k, mf_comp) = ustar(i, j, 0);
2240  });
2241  }
2242  } else {
2243  mf[lev].setVal(-999,mf_comp,1,0);
2244  }
2245  mf_comp++;
2246  } // qsurf
2247 
2248  if (containerHasElement(plot_var_names, "z0")) {
2249 #ifdef _OPENMP
2250 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2251 #endif
2252  if (m_SurfaceLayer) {
2253  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2254  {
2255  const Box& bx = mfi.tilebox();
2256  const auto& derdat = mf[lev].array(mfi);
2257  const auto& ustar = m_SurfaceLayer->get_z0(lev)->const_array(mfi);
2258  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2259  derdat(i, j, k, mf_comp) = ustar(i, j, 0);
2260  });
2261  }
2262  } else {
2263  mf[lev].setVal(-999,mf_comp,1,0);
2264  }
2265  mf_comp++;
2266  } // z0
2267 
2268  if (containerHasElement(plot_var_names, "OLR")) {
2269 #ifdef _OPENMP
2270 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2271 #endif
2272  if (solverChoice.rad_type != RadiationType::None) {
2273  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2274  {
2275  const Box& bx = mfi.tilebox();
2276  const auto& derdat = mf[lev].array(mfi);
2277  const auto& olr = rad_fluxes[lev]->const_array(mfi);
2278  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2279  derdat(i, j, k, mf_comp) = olr(i, j, khi, 2);
2280  });
2281  }
2282  } else {
2283  mf[lev].setVal(-999,mf_comp,1,0);
2284  }
2285  mf_comp++;
2286  } // OLR
2287 
2288  if (containerHasElement(plot_var_names, "sens_flux")) {
2289 #ifdef _OPENMP
2290 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2291 #endif
2292  if (SFS_hfx3_lev[lev]) {
2293  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2294  {
2295  const Box& bx = mfi.tilebox();
2296  const auto& derdat = mf[lev].array(mfi);
2297  const auto& hfx_arr = SFS_hfx3_lev[lev]->const_array(mfi);
2298  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2299  derdat(i, j, k, mf_comp) = hfx_arr(i, j, klo);
2300  });
2301  }
2302  } else {
2303  mf[lev].setVal(-999,mf_comp,1,0);
2304  }
2305  mf_comp++;
2306  } // sens_flux
2307 
2308  if (containerHasElement(plot_var_names, "laten_flux")) {
2309 #ifdef _OPENMP
2310 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2311 #endif
2312  if (SFS_hfx3_lev[lev]) {
2313  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2314  {
2315  const Box& bx = mfi.tilebox();
2316  const auto& derdat = mf[lev].array(mfi);
2317  const auto& qfx_arr = SFS_q1fx3_lev[lev]->const_array(mfi);
2318  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2319  derdat(i, j, k, mf_comp) = qfx_arr(i, j, klo);
2320  });
2321  }
2322  } else {
2323  mf[lev].setVal(-999,mf_comp,1,0);
2324  }
2325  mf_comp++;
2326  } // laten_flux
2327 
2328  if (containerHasElement(plot_var_names, "surf_pres")) {
2329  bool moist = (solverChoice.moisture_type != MoistureType::None);
2330 #ifdef _OPENMP
2331 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
2332 #endif
2333  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
2334  {
2335  const Box& bx = mfi.tilebox();
2336  const auto& derdat = mf[lev].array(mfi);
2337  const auto& cons_arr = vars_new[lev][Vars::cons].const_array(mfi);
2338  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
2339  auto rt = cons_arr(i,j,klo,RhoTheta_comp);
2340  auto qv = (moist) ? cons_arr(i,j,klo,RhoQ1_comp)/cons_arr(i,j,klo,Rho_comp)
2341  : 0.0;
2342  derdat(i, j, k, mf_comp) = getPgivenRTh(rt, qv);
2343  });
2344  }
2345  mf_comp++;
2346  } // surf_pres
2347 
2348  if (containerHasElement(plot_var_names, "integrated_qv")) {
2349  MultiFab mf_qv_int(mf[lev],make_alias,mf_comp,1);
2350  if (solverChoice.moisture_type != MoistureType::None) {
2351  volWgtColumnSum(lev, vars_new[lev][Vars::cons], RhoQ1_comp, mf_qv_int, *detJ_cc[lev]);
2352  } else {
2353  mf_qv_int.setVal(0.);
2354  }
2355  mf_comp++;
2356  }
2357  } // lev
2358 
2359  std::string plotfilename;
2360  if (which == 1) {
2361  plotfilename = Concatenate(plot2d_file_1, istep[0], file_name_digits);
2362  } else if (which == 2) {
2363  plotfilename = Concatenate(plot2d_file_2, istep[0], file_name_digits);
2364  }
2365 
2366  Vector<Geometry> my_geom(finest_level+1);
2367 
2368  Array<int,AMREX_SPACEDIM> is_per; is_per[0] = 0; is_per[1] = 0; is_per[2] = 0;
2369  if (geom[0].isPeriodic(0)) { is_per[0] = 1;}
2370  if (geom[0].isPeriodic(1)) { is_per[1] = 1;}
2371 
2372  int coord_sys = 0;
2373 
2374  for (int lev = 0; lev <= finest_level; lev++)
2375  {
2376  Box slab = makeSlab(geom[lev].Domain(),2,0);
2377  auto const slab_lo = lbound(slab);
2378  auto const slab_hi = ubound(slab);
2379 
2380  // Create a new geometry based only on the 2D slab
2381  Real dz = geom[lev].CellSize(2);
2382  RealBox rb = geom[lev].ProbDomain();
2383  rb.setLo(2, slab_lo.z *dz);
2384  rb.setHi(2, (slab_hi.z+1)*dz);
2385  my_geom[lev].define(slab, rb, coord_sys, is_per);
2386  }
2387 
2388  if (plotfile_type == PlotFileType::Amrex)
2389  {
2390  Print() << "Writing 2D native plotfile " << plotfilename << "\n";
2391  WriteMultiLevelPlotfile(plotfilename, finest_level+1,
2392  GetVecOfConstPtrs(mf),
2393  varnames, my_geom, t_new[0], istep, refRatio());
2394  writeJobInfo(plotfilename);
2395 
2396 #ifdef ERF_USE_NETCDF
2397  } else if (plotfile_type == PlotFileType::Netcdf) {
2398  int lev = 0;
2399  int l_which = 0;
2400  const Real* p_lo = my_geom[lev].ProbLo();
2401  const Real* p_hi = my_geom[lev].ProbHi();
2402  const auto dx = my_geom[lev].CellSize();
2403  writeNCPlotFile(lev, l_which, plotfilename, GetVecOfConstPtrs(mf), varnames, istep,
2404  {p_lo[0],p_lo[1],p_lo[2]},{p_hi[0],p_hi[1],dx[2]}, {dx[0],dx[1],dx[2]},
2405  my_geom[lev].Domain(), t_new[0], start_bdy_time);
2406 #endif
2407  } else {
2408  // Here we assume the plotfile_type is PlotFileType::None
2409  Print() << "Writing no 2D plotfile since plotfile_type is none" << std::endl;
2410  }
2411 }
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 #ifdef ERF_USE_WINDFARM
665  if ( containerHasElement(plot_var_names, "num_turb") and
666  (solverChoice.windfarm_type == WindFarmType::Fitch or solverChoice.windfarm_type == WindFarmType::EWP or
667  solverChoice.windfarm_type == WindFarmType::SimpleAD or solverChoice.windfarm_type == WindFarmType::GeneralAD) )
668  {
669  MultiFab::Copy(mf[lev],Nturb[lev],0,mf_comp,1,0);
670  mf_comp ++;
671  }
672 
673  if ( containerHasElement(plot_var_names, "SMark0") and
674  (solverChoice.windfarm_type == WindFarmType::Fitch or solverChoice.windfarm_type == WindFarmType::EWP or
675  solverChoice.windfarm_type == WindFarmType::SimpleAD or solverChoice.windfarm_type == WindFarmType::GeneralAD) )
676  {
677  MultiFab::Copy(mf[lev],SMark[lev],0,mf_comp,1,0);
678  mf_comp ++;
679  }
680 
681  if (containerHasElement(plot_var_names, "SMark1") and
682  (solverChoice.windfarm_type == WindFarmType::SimpleAD or solverChoice.windfarm_type == WindFarmType::GeneralAD))
683  {
684  MultiFab::Copy(mf[lev],SMark[lev],1,mf_comp,1,0);
685  mf_comp ++;
686  }
687 #endif
688 
689  // **********************************************************************************************
690  // Allocate space if we are computing any pressure gradients
691  // **********************************************************************************************
692 
693  Vector<MultiFab> gradp_temp; gradp_temp.resize(AMREX_SPACEDIM);
694  if (containerHasElement(plot_var_names, "dpdx") ||
695  containerHasElement(plot_var_names, "dpdy") ||
696  containerHasElement(plot_var_names, "dpdz") ||
697  containerHasElement(plot_var_names, "pres_hse_x") ||
698  containerHasElement(plot_var_names, "pres_hse_y"))
699  {
700  gradp_temp[GpVars::gpx].define(convert(ba, IntVect(1,0,0)), dm, 1, 1); gradp_temp[GpVars::gpx].setVal(0.);
701  gradp_temp[GpVars::gpy].define(convert(ba, IntVect(0,1,0)), dm, 1, 1); gradp_temp[GpVars::gpy].setVal(0.);
702  gradp_temp[GpVars::gpz].define(convert(ba, IntVect(0,0,1)), dm, 1, 1); gradp_temp[GpVars::gpz].setVal(0.);
703  }
704 
705  // **********************************************************************************************
706  // These are based on computing gradient of full pressure
707  // **********************************************************************************************
708 
709  if (solverChoice.anelastic[lev] == 0) {
710  if ( (containerHasElement(plot_var_names, "dpdx")) ||
711  (containerHasElement(plot_var_names, "dpdy")) ||
712  (containerHasElement(plot_var_names, "dpdz")) ) {
713  compute_gradp(pressure, geom[lev], *z_phys_nd[lev].get(), *z_phys_cc[lev].get(), mapfac[lev],
714  get_eb(lev), gradp_temp, solverChoice);
715  }
716  }
717 
718  if (containerHasElement(plot_var_names, "dpdx"))
719  {
720  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
721  {
722  const Box& bx = mfi.tilebox();
723  const Array4<Real >& derdat = mf[lev].array(mfi);
724  const Array4<Real const>& gpx_arr = (solverChoice.anelastic[lev] == 1) ?
725  gradp[lev][GpVars::gpx].array(mfi) : gradp_temp[GpVars::gpx].array(mfi);
726  const Array4<Real const>& mf_mx_arr = mapfac[lev][MapFacType::m_x]->const_array(mfi);
727  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
728  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);
729  });
730  }
731  mf_comp ++;
732  } // dpdx
733  if (containerHasElement(plot_var_names, "dpdy"))
734  {
735  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
736  {
737  const Box& bx = mfi.tilebox();
738  const Array4<Real >& derdat = mf[lev].array(mfi);
739  const Array4<Real const>& gpy_arr = (solverChoice.anelastic[lev] == 1) ?
740  gradp[lev][GpVars::gpy].array(mfi) : gradp_temp[GpVars::gpy].array(mfi);
741  const Array4<Real const>& mf_my_arr = mapfac[lev][MapFacType::m_y]->const_array(mfi);
742  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
743  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);
744  });
745  }
746  mf_comp ++;
747  } // dpdy
748  if (containerHasElement(plot_var_names, "dpdz"))
749  {
750  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
751  {
752  const Box& bx = mfi.tilebox();
753  const Array4<Real >& derdat = mf[lev].array(mfi);
754  const Array4<Real const>& gpz_arr = (solverChoice.anelastic[lev] == 1) ?
755  gradp[lev][GpVars::gpz].array(mfi) : gradp_temp[GpVars::gpz].array(mfi);
756  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
757  derdat(i ,j ,k, mf_comp) = 0.5 * (gpz_arr(i,j,k+1) + gpz_arr(i,j,k));
758  });
759  }
760  mf_comp ++;
761  } // dpdz
762 
763  // **********************************************************************************************
764  // These are based on computing gradient of basestate pressure
765  // **********************************************************************************************
766 
767  if ( (containerHasElement(plot_var_names, "pres_hse_x")) ||
768  (containerHasElement(plot_var_names, "pres_hse_y")) ) {
769  compute_gradp(p_hse, geom[lev], *z_phys_nd[lev].get(), *z_phys_cc[lev].get(), mapfac[lev],
770  get_eb(lev), gradp_temp, solverChoice);
771  }
772 
773  if (containerHasElement(plot_var_names, "pres_hse_x"))
774  {
775  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
776  {
777  const Box& bx = mfi.tilebox();
778  const Array4<Real >& derdat = mf[lev].array(mfi);
779  const Array4<Real const>& gpx_arr = gradp_temp[0].array(mfi);
780  const Array4<Real const>& mf_mx_arr = mapfac[lev][MapFacType::m_x]->const_array(mfi);
781  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
782  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);
783  });
784  }
785  mf_comp += 1;
786  } // pres_hse_x
787 
788  if (containerHasElement(plot_var_names, "pres_hse_y"))
789  {
790  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
791  {
792  const Box& bx = mfi.tilebox();
793  const Array4<Real >& derdat = mf[lev].array(mfi);
794  const Array4<Real const>& gpy_arr = gradp_temp[1].array(mfi);
795  const Array4<Real const>& mf_my_arr = mapfac[lev][MapFacType::m_y]->const_array(mfi);
796  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
797  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);
798  });
799  }
800  mf_comp += 1;
801  } // pres_hse_y
802 
803  // **********************************************************************************************
804  // Metric terms
805  // **********************************************************************************************
806 
807  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
808  if (containerHasElement(plot_var_names, "z_phys"))
809  {
810  MultiFab::Copy(mf[lev],*z_phys_cc[lev],0,mf_comp,1,0);
811  mf_comp ++;
812  }
813 
814  if (containerHasElement(plot_var_names, "detJ"))
815  {
816  MultiFab::Copy(mf[lev],*detJ_cc[lev],0,mf_comp,1,0);
817  mf_comp ++;
818  }
819  } // use_terrain
820 
821  if (containerHasElement(plot_var_names, "mapfac")) {
822  amrex::Print() << "You are plotting a 3D version of mapfac; we suggest using the 2D plotfile instead" << std::endl;
823 #ifdef _OPENMP
824 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
825 #endif
826  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
827  {
828  const Box& bx = mfi.tilebox();
829  const Array4<Real>& derdat = mf[lev].array(mfi);
830  const Array4<Real>& mf_m = mapfac[lev][MapFacType::m_x]->array(mfi);
831  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
832  derdat(i ,j ,k, mf_comp) = mf_m(i,j,0);
833  });
834  }
835  mf_comp ++;
836  }
837 
838  if (containerHasElement(plot_var_names, "lat_m")) {
839  amrex::Print() << "You are plotting a 3D version of lat_m; we suggest using the 2D plotfile instead" << std::endl;
840  if (lat_m[lev]) {
841 #ifdef _OPENMP
842 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
843 #endif
844  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
845  {
846  const Box& bx = mfi.tilebox();
847  const Array4<Real>& derdat = mf[lev].array(mfi);
848  const Array4<Real>& data = lat_m[lev]->array(mfi);
849  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
850  derdat(i, j, k, mf_comp) = data(i,j,0);
851  });
852  }
853  } else {
854  mf[lev].setVal(0.0,mf_comp,1,0);
855  }
856  mf_comp++;
857  } // lat_m
858 
859  if (containerHasElement(plot_var_names, "lon_m")) {
860  amrex::Print() << "You are plotting a 3D version of lon_m; we suggest using the 2D plotfile instead" << std::endl;
861  if (lon_m[lev]) {
862 #ifdef _OPENMP
863 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
864 #endif
865  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
866  {
867  const Box& bx = mfi.tilebox();
868  const Array4<Real>& derdat = mf[lev].array(mfi);
869  const Array4<Real>& data = lon_m[lev]->array(mfi);
870  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
871  derdat(i, j, k, mf_comp) = data(i,j,0);
872  });
873  }
874  } else {
875  mf[lev].setVal(0.0,mf_comp,1,0);
876  }
877  mf_comp++;
878  } // lon_m
879 
881  if (containerHasElement(plot_var_names, "u_t_avg")) {
882 #ifdef _OPENMP
883 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
884 #endif
885  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
886  {
887  const Box& bx = mfi.tilebox();
888  const Array4<Real>& derdat = mf[lev].array(mfi);
889  const Array4<Real>& data = vel_t_avg[lev]->array(mfi);
890  const Real norm = t_avg_cnt[lev];
891  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
892  {
893  derdat(i ,j ,k, mf_comp) = data(i,j,k,0) / norm;
894  });
895  }
896  mf_comp ++;
897  }
898 
899  if (containerHasElement(plot_var_names, "v_t_avg")) {
900 #ifdef _OPENMP
901 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
902 #endif
903  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
904  {
905  const Box& bx = mfi.tilebox();
906  const Array4<Real>& derdat = mf[lev].array(mfi);
907  const Array4<Real>& data = vel_t_avg[lev]->array(mfi);
908  const Real norm = t_avg_cnt[lev];
909  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
910  {
911  derdat(i ,j ,k, mf_comp) = data(i,j,k,1) / norm;
912  });
913  }
914  mf_comp ++;
915  }
916 
917  if (containerHasElement(plot_var_names, "w_t_avg")) {
918 #ifdef _OPENMP
919 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
920 #endif
921  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
922  {
923  const Box& bx = mfi.tilebox();
924  const Array4<Real>& derdat = mf[lev].array(mfi);
925  const Array4<Real>& data = vel_t_avg[lev]->array(mfi);
926  const Real norm = t_avg_cnt[lev];
927  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
928  {
929  derdat(i ,j ,k, mf_comp) = data(i,j,k,2) / norm;
930  });
931  }
932  mf_comp ++;
933  }
934 
935  if (containerHasElement(plot_var_names, "umag_t_avg")) {
936 #ifdef _OPENMP
937 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
938 #endif
939  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
940  {
941  const Box& bx = mfi.tilebox();
942  const Array4<Real>& derdat = mf[lev].array(mfi);
943  const Array4<Real>& data = vel_t_avg[lev]->array(mfi);
944  const Real norm = t_avg_cnt[lev];
945  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
946  {
947  derdat(i ,j ,k, mf_comp) = data(i,j,k,3) / norm;
948  });
949  }
950  mf_comp ++;
951  }
952  }
953 
954  if (containerHasElement(plot_var_names, "nut")) {
955  MultiFab dmf(mf[lev], make_alias, mf_comp, 1);
956  MultiFab cmf(vars_new[lev][Vars::cons], make_alias, 0, 1); // to provide rho only
957 #ifdef _OPENMP
958 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
959 #endif
960  for (MFIter mfi(dmf, TilingIfNotGPU()); mfi.isValid(); ++mfi)
961  {
962  const Box& bx = mfi.tilebox();
963  auto prim = dmf[mfi].array();
964  auto const cons = cmf[mfi].const_array();
965  auto const diff = (*eddyDiffs_lev[lev])[mfi].const_array();
966  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
967  {
968  const Real rho = cons(i, j, k, Rho_comp);
969  const Real Kmv = diff(i, j, k, EddyDiff::Mom_v);
970  prim(i,j,k) = Kmv / rho;
971  });
972  }
973 
974  mf_comp++;
975  }
976 
977  if (containerHasElement(plot_var_names, "Kmv")) {
978  MultiFab::Copy(mf[lev],*eddyDiffs_lev[lev],EddyDiff::Mom_v,mf_comp,1,0);
979  mf_comp ++;
980  }
981  if (containerHasElement(plot_var_names, "Kmh")) {
982  MultiFab::Copy(mf[lev],*eddyDiffs_lev[lev],EddyDiff::Mom_h,mf_comp,1,0);
983  mf_comp ++;
984  }
985  if (containerHasElement(plot_var_names, "Khv")) {
986  MultiFab::Copy(mf[lev],*eddyDiffs_lev[lev],EddyDiff::Theta_v,mf_comp,1,0);
987  mf_comp ++;
988  }
989  if (containerHasElement(plot_var_names, "Khh")) {
990  MultiFab::Copy(mf[lev],*eddyDiffs_lev[lev],EddyDiff::Theta_h,mf_comp,1,0);
991  mf_comp ++;
992  }
993  if (containerHasElement(plot_var_names, "Lturb")) {
994  MultiFab::Copy(mf[lev],*eddyDiffs_lev[lev],EddyDiff::Turb_lengthscale,mf_comp,1,0);
995  mf_comp ++;
996  }
997  if (containerHasElement(plot_var_names, "walldist")) {
998  MultiFab::Copy(mf[lev],*walldist[lev],0,mf_comp,1,0);
999  mf_comp ++;
1000  }
1001  if (containerHasElement(plot_var_names, "diss")) {
1002  MultiFab::Copy(mf[lev],*SFS_diss_lev[lev],0,mf_comp,1,0);
1003  mf_comp ++;
1004  }
1005 
1006  // TODO: The size of the q variables can vary with different
1007  // moisture models. Therefore, certain components may
1008  // reside at different indices. For example, Kessler is
1009  // warm but precipitating. This puts qp at index 3.
1010  // However, SAM is cold and precipitating so qp is index 4.
1011  // Need to built an external enum struct or a better pathway.
1012 
1013  // NOTE: Protect against accessing non-existent data
1014  if (use_moisture) {
1015  int n_qstate_moist = micro->Get_Qstate_Moist_Size();
1016 
1017  // Moist density
1018  if(containerHasElement(plot_var_names, "moist_density"))
1019  {
1020  int n_start = RhoQ1_comp; // qv
1021  int n_end = RhoQ2_comp; // qc
1022  if (n_qstate_moist > 3) n_end = RhoQ3_comp; // qi
1023  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], Rho_comp, mf_comp, 1, 0);
1024  for (int n_comp(n_start); n_comp <= n_end; ++n_comp) {
1025  MultiFab::Add(mf[lev], vars_new[lev][Vars::cons], n_comp, mf_comp, 1, 0);
1026  }
1027  mf_comp += 1;
1028  }
1029 
1030  if(containerHasElement(plot_var_names, "qv") && (n_qstate_moist >= 1))
1031  {
1032  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], RhoQ1_comp, mf_comp, 1, 0);
1033  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp , mf_comp, 1, 0);
1034  mf_comp += 1;
1035  }
1036 
1037  if(containerHasElement(plot_var_names, "qc") && (n_qstate_moist >= 2))
1038  {
1039  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], RhoQ2_comp, mf_comp, 1, 0);
1040  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp , mf_comp, 1, 0);
1041  mf_comp += 1;
1042  }
1043 
1044  if(containerHasElement(plot_var_names, "qi") && (n_qstate_moist >= 4))
1045  {
1046  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], RhoQ3_comp, mf_comp, 1, 0);
1047  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp , mf_comp, 1, 0);
1048  mf_comp += 1;
1049  }
1050 
1051  if(containerHasElement(plot_var_names, "qrain") && (n_qstate_moist >= 3))
1052  {
1053  int n_start = (n_qstate_moist > 3) ? RhoQ4_comp : RhoQ3_comp;
1054  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], n_start , mf_comp, 1, 0);
1055  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp, mf_comp, 1, 0);
1056  mf_comp += 1;
1057  }
1058 
1059  if(containerHasElement(plot_var_names, "qsnow") && (n_qstate_moist >= 5))
1060  {
1061  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], RhoQ5_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, "qgraup") && (n_qstate_moist >= 6))
1067  {
1068  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], RhoQ6_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  // Precipitating + non-precipitating components
1074  //--------------------------------------------------------------------------
1075  if(containerHasElement(plot_var_names, "qt"))
1076  {
1077  int n_start = RhoQ1_comp; // qv
1078  int n_end = n_start + n_qstate_moist;
1079  MultiFab::Copy(mf[lev], vars_new[lev][Vars::cons], n_start, mf_comp, 1, 0);
1080  for (int n_comp(n_start+1); n_comp < n_end; ++n_comp) {
1081  MultiFab::Add(mf[lev], vars_new[lev][Vars::cons], n_comp, mf_comp, 1, 0);
1082  }
1083  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp , mf_comp, 1, 0);
1084  mf_comp += 1;
1085  }
1086 
1087  // Non-precipitating components
1088  //--------------------------------------------------------------------------
1089  if (containerHasElement(plot_var_names, "qn"))
1090  {
1091  int n_start = RhoQ1_comp; // qv
1092  int n_end = RhoQ2_comp; // qc
1093  if (n_qstate_moist > 3) n_end = RhoQ3_comp; // qi
1094  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], n_start, mf_comp, 1, 0);
1095  for (int n_comp(n_start+1); n_comp <= n_end; ++n_comp) {
1096  MultiFab::Add(mf[lev], vars_new[lev][Vars::cons], n_comp, mf_comp, 1, 0);
1097  }
1098  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp , mf_comp, 1, 0);
1099  mf_comp += 1;
1100  }
1101 
1102  // Precipitating components
1103  //--------------------------------------------------------------------------
1104  if(containerHasElement(plot_var_names, "qp") && (n_qstate_moist >= 3))
1105  {
1106  int n_start = (n_qstate_moist > 3) ? RhoQ4_comp : RhoQ3_comp;
1107  int n_end = ncomp_cons - 1;
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  if (containerHasElement(plot_var_names, "qsat"))
1117  {
1118 #ifdef _OPENMP
1119 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
1120 #endif
1121  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
1122  {
1123  const Box& bx = mfi.tilebox();
1124  const Array4<Real>& derdat = mf[lev].array(mfi);
1125  const Array4<Real const>& p_arr = pressure.array(mfi);
1126  const Array4<Real const>& S_arr = vars_new[lev][Vars::cons].const_array(mfi);
1127  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
1128  {
1129  Real qv = S_arr(i,j,k,RhoQ1_comp) / S_arr(i,j,k,Rho_comp);
1130  Real T = getTgivenRandRTh(S_arr(i,j,k,Rho_comp), S_arr(i,j,k,RhoTheta_comp), qv);
1131  Real p = p_arr(i,j,k) * Real(0.01);
1132  erf_qsatw(T, p, derdat(i,j,k,mf_comp));
1133  });
1134  }
1135  mf_comp ++;
1136  }
1137 
1138  if ( (solverChoice.moisture_type == MoistureType::Kessler) ||
1139  (solverChoice.moisture_type == MoistureType::Morrison_NoIce) ||
1140  (solverChoice.moisture_type == MoistureType::SAM_NoIce) )
1141  {
1142  int offset = (solverChoice.moisture_type == MoistureType::Morrison_NoIce) ? 5 : 0;
1143  if (containerHasElement(plot_var_names, "rain_accum"))
1144  {
1145  MultiFab::Copy(mf[lev],*(qmoist[lev][offset]),0,mf_comp,1,0);
1146  mf_comp += 1;
1147  }
1148  if (containerHasElement(plot_var_names, "rel_humidity")) {
1149  Print() << "Warning: plot variable \"rel_humidity\" is not available with Kessler moisture model.\n";
1150  mf[lev].setVal(0.0, mf_comp, 1, 0);
1151  mf_comp += 1;
1152  }
1153  }
1154  else if ( (solverChoice.moisture_type == MoistureType::SAM) ||
1155  (solverChoice.moisture_type == MoistureType::Morrison) )
1156  {
1157  int offset = (solverChoice.moisture_type == MoistureType::Morrison) ? 5 : 0;
1158  if (containerHasElement(plot_var_names, "rain_accum"))
1159  {
1160  MultiFab::Copy(mf[lev],*(qmoist[lev][offset]),0,mf_comp,1,0);
1161  mf_comp += 1;
1162  }
1163  if (containerHasElement(plot_var_names, "snow_accum"))
1164  {
1165  MultiFab::Copy(mf[lev],*(qmoist[lev][offset+1]),0,mf_comp,1,0);
1166  mf_comp += 1;
1167  }
1168  if (containerHasElement(plot_var_names, "graup_accum"))
1169  {
1170  MultiFab::Copy(mf[lev],*(qmoist[lev][offset+2]),0,mf_comp,1,0);
1171  mf_comp += 1;
1172  }
1173  if (containerHasElement(plot_var_names, "rel_humidity")) {
1174  Print() << "Warning: plot variable \"rel_humidity\" is not available with SAM moisture model.\n";
1175  mf[lev].setVal(0.0, mf_comp, 1, 0);
1176  mf_comp += 1;
1177  }
1178  }
1179  else if(solverChoice.moisture_type == MoistureType::SuperDroplets) {
1180  if (containerHasElement(plot_var_names, "rain_accum")) {
1181  MultiFab::Copy(mf[lev],*(qmoist[lev][6]),0,mf_comp,1,0);
1182  mf_comp += 1;
1183  }
1184  if (containerHasElement(plot_var_names, "rel_humidity")) {
1185  MultiFab::Copy(mf[lev],*(qmoist[lev][5]),0,mf_comp,1,0);
1186  mf_comp += 1;
1187  }
1188  if (containerHasElement(plot_var_names, "condensation_rate")) {
1189  MultiFab::Copy(mf[lev],*(qmoist[lev][3]),0,mf_comp,1,0);
1190  mf_comp += 1;
1191  }
1192  }
1193 
1194  if (containerHasElement(plot_var_names, "reflectivity")) {
1195  if (solverChoice.moisture_type == MoistureType::Morrison) {
1196 
1197  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi) {
1198  const Box& bx = mfi.tilebox();
1199  const Array4<Real>& derdat = mf[lev].array(mfi);
1200  const Array4<Real const>& S_arr = vars_new[lev][Vars::cons].const_array(mfi);
1201  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
1202 
1203  Real rho = S_arr(i,j,k,Rho_comp);
1204  Real qv = std::max(0.0,S_arr(i,j,k,RhoQ1_comp)/S_arr(i,j,k,Rho_comp));
1205  Real qpr = std::max(0.0,S_arr(i,j,k,RhoQ4_comp)/S_arr(i,j,k,Rho_comp));
1206  Real qps = std::max(0.0,S_arr(i,j,k,RhoQ5_comp)/S_arr(i,j,k,Rho_comp));
1207  Real qpg = std::max(0.0,S_arr(i,j,k,RhoQ6_comp)/S_arr(i,j,k,Rho_comp));
1208 
1209  Real temp = getTgivenRandRTh(S_arr(i,j,k,Rho_comp),
1210  S_arr(i,j,k,RhoTheta_comp),
1211  qv);
1212  derdat(i, j, k, mf_comp) = compute_max_reflectivity_dbz(rho, temp, qpr, qps, qpg,
1213  1, 1, 1, 1) ;
1214  });
1215  }
1216  mf_comp ++;
1217  }
1218  }
1219 
1220  if (solverChoice.moisture_type == MoistureType::Morrison) {
1221  if (containerHasElement(plot_var_names, "max_reflectivity")) {
1222  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi) {
1223  const Box& bx = mfi.tilebox();
1224 
1225  const Array4<Real>& derdat = mf[lev].array(mfi);
1226  const Array4<Real const>& S_arr = vars_new[lev][Vars::cons].const_array(mfi);
1227 
1228  // collapse to i,j box (ignore vertical for now)
1229  Box b2d = bx;
1230  b2d.setSmall(2,0);
1231  b2d.setBig(2,0);
1232 
1233  ParallelFor(b2d, [=] AMREX_GPU_DEVICE(int i, int j, int) noexcept {
1234 
1235  Real max_dbz = -1.0e30;
1236 
1237  // find max reflectivity over k
1238  for (int k = bx.smallEnd(2); k <= bx.bigEnd(2); ++k) {
1239  Real rho = S_arr(i,j,k,Rho_comp);
1240  Real qv = std::max(0.0, S_arr(i,j,k,RhoQ1_comp)/rho);
1241  Real qpr = std::max(0.0, S_arr(i,j,k,RhoQ4_comp)/rho);
1242  Real qps = std::max(0.0, S_arr(i,j,k,RhoQ5_comp)/rho);
1243  Real qpg = std::max(0.0, S_arr(i,j,k,RhoQ6_comp)/rho);
1244 
1245  Real temp = getTgivenRandRTh(rho, S_arr(i,j,k,RhoTheta_comp), qv);
1246 
1247  Real dbz = compute_max_reflectivity_dbz(rho, temp, qpr, qps, qpg,
1248  1, 1, 1, 1);
1249  max_dbz = amrex::max(max_dbz, dbz);
1250  }
1251 
1252  // store max_dbz into *all* levels for this (i,j)
1253  for (int k = bx.smallEnd(2); k <= bx.bigEnd(2); ++k) {
1254  derdat(i, j, k, mf_comp) = max_dbz;
1255  }
1256  });
1257  }
1258  mf_comp++;
1259  }
1260  }
1261  } // use_moisture
1262 
1263  if (containerHasElement(plot_var_names, "terrain_IB_mask"))
1264  {
1265  MultiFab* terrain_blank = terrain_blanking[lev].get();
1266  MultiFab::Copy(mf[lev],*terrain_blank,0,mf_comp,1,0);
1267  mf_comp ++;
1268  }
1269 
1270  if (containerHasElement(plot_var_names, "volfrac")) {
1271  if ( solverChoice.terrain_type == TerrainType::EB ||
1272  solverChoice.terrain_type == TerrainType::ImmersedForcing)
1273  {
1274  MultiFab::Copy(mf[lev], EBFactory(lev).getVolFrac(), 0, mf_comp, 1, 0);
1275  } else {
1276  mf[lev].setVal(1.0, mf_comp, 1, 0);
1277  }
1278  mf_comp += 1;
1279  }
1280 
1281 #ifdef ERF_COMPUTE_ERROR
1282  // Next, check for error in velocities and if desired, output them -- note we output none or all, not just some
1283  if (containerHasElement(plot_var_names, "xvel_err") ||
1284  containerHasElement(plot_var_names, "yvel_err") ||
1285  containerHasElement(plot_var_names, "zvel_err"))
1286  {
1287  //
1288  // Moving terrain ANALYTICAL
1289  //
1290  Real H = geom[lev].ProbHi()[2];
1291  Real Ampl = 0.16;
1292  Real wavelength = 100.;
1293  Real kp = 2. * PI / wavelength;
1294  Real g = CONST_GRAV;
1295  Real omega = std::sqrt(g * kp);
1296  Real omega_t = omega * t_new[lev];
1297 
1298  const auto dx = geom[lev].CellSizeArray();
1299 
1300 #ifdef _OPENMP
1301 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
1302 #endif
1303  for (MFIter mfi(mf[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi)
1304  {
1305  const Box& bx = mfi.validbox();
1306  Box xbx(bx); xbx.surroundingNodes(0);
1307  const Array4<Real> xvel_arr = vars_new[lev][Vars::xvel].array(mfi);
1308  const Array4<Real> zvel_arr = vars_new[lev][Vars::zvel].array(mfi);
1309 
1310  const Array4<Real const>& z_nd = z_phys_nd[lev]->const_array(mfi);
1311 
1312  ParallelFor(xbx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
1313  {
1314  Real x = i * dx[0];
1315  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));
1316 
1317  Real z_base = Ampl * std::sin(kp * x - omega_t);
1318  z -= z_base;
1319 
1320  Real fac = std::cosh( kp * (z - H) ) / std::sinh(kp * H);
1321 
1322  xvel_arr(i,j,k) -= -Ampl * omega * fac * std::sin(kp * x - omega_t);
1323  });
1324 
1325  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
1326  {
1327  Real x = (i + 0.5) * dx[0];
1328  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));
1329 
1330  Real z_base = Ampl * std::sin(kp * x - omega_t);
1331  z -= z_base;
1332 
1333  Real fac = std::sinh( kp * (z - H) ) / std::sinh(kp * H);
1334 
1335  zvel_arr(i,j,k) -= Ampl * omega * fac * std::cos(kp * x - omega_t);
1336  });
1337  }
1338 
1339  MultiFab temp_mf(mf[lev].boxArray(), mf[lev].DistributionMap(), AMREX_SPACEDIM, 0);
1340  average_face_to_cellcenter(temp_mf,0,
1341  Array<const MultiFab*,3>{&vars_new[lev][Vars::xvel],&vars_new[lev][Vars::yvel],&vars_new[lev][Vars::zvel]});
1342 
1343  if (containerHasElement(plot_var_names, "xvel_err")) {
1344  MultiFab::Copy(mf[lev],temp_mf,0,mf_comp,1,0);
1345  mf_comp += 1;
1346  }
1347  if (containerHasElement(plot_var_names, "yvel_err")) {
1348  MultiFab::Copy(mf[lev],temp_mf,1,mf_comp,1,0);
1349  mf_comp += 1;
1350  }
1351  if (containerHasElement(plot_var_names, "zvel_err")) {
1352  MultiFab::Copy(mf[lev],temp_mf,2,mf_comp,1,0);
1353  mf_comp += 1;
1354  }
1355 
1356  // Now restore the velocities to what they were
1357 #ifdef _OPENMP
1358 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
1359 #endif
1360  for (MFIter mfi(mf[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi)
1361  {
1362  const Box& bx = mfi.validbox();
1363  Box xbx(bx); xbx.surroundingNodes(0);
1364 
1365  const Array4<Real> xvel_arr = vars_new[lev][Vars::xvel].array(mfi);
1366  const Array4<Real> zvel_arr = vars_new[lev][Vars::zvel].array(mfi);
1367 
1368  const Array4<Real const>& z_nd = z_phys_nd[lev]->const_array(mfi);
1369 
1370  ParallelFor(xbx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
1371  {
1372  Real x = i * dx[0];
1373  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));
1374  Real z_base = Ampl * std::sin(kp * x - omega_t);
1375 
1376  z -= z_base;
1377 
1378  Real fac = std::cosh( kp * (z - H) ) / std::sinh(kp * H);
1379  xvel_arr(i,j,k) += -Ampl * omega * fac * std::sin(kp * x - omega_t);
1380  });
1381  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
1382  {
1383  Real x = (i + 0.5) * dx[0];
1384  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));
1385  Real z_base = Ampl * std::sin(kp * x - omega_t);
1386 
1387  z -= z_base;
1388  Real fac = std::sinh( kp * (z - H) ) / std::sinh(kp * H);
1389 
1390  zvel_arr(i,j,k) += Ampl * omega * fac * std::cos(kp * x - omega_t);
1391  });
1392  }
1393  } // end xvel_err, yvel_err, zvel_err
1394 
1395  if (containerHasElement(plot_var_names, "pp_err"))
1396  {
1397  // Moving terrain ANALYTICAL
1398 #ifdef _OPENMP
1399 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
1400 #endif
1401  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
1402  {
1403  const Box& bx = mfi.tilebox();
1404  const Array4<Real>& derdat = mf[lev].array(mfi);
1405  const Array4<Real const>& p0_arr = p_hse.const_array(mfi);
1406  const Array4<Real const>& S_arr = vars_new[lev][Vars::cons].const_array(mfi);
1407 
1408  const auto dx = geom[lev].CellSizeArray();
1409  const Array4<Real const>& z_nd = z_phys_nd[lev]->const_array(mfi);
1410  const Array4<Real const>& p_arr = pressure.const_array(mfi);
1411  const Array4<Real const>& r0_arr = r_hse.const_array(mfi);
1412 
1413  Real H = geom[lev].ProbHi()[2];
1414  Real Ampl = 0.16;
1415  Real wavelength = 100.;
1416  Real kp = 2. * PI / wavelength;
1417  Real g = CONST_GRAV;
1418  Real omega = std::sqrt(g * kp);
1419  Real omega_t = omega * t_new[lev];
1420 
1421  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
1422  {
1423  derdat(i, j, k, mf_comp) = p_arr(i,j,k) - p0_arr(i,j,k);
1424 
1425  Real rho_hse = r0_arr(i,j,k);
1426 
1427  Real x = (i + 0.5) * dx[0];
1428  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 )
1429  +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) );
1430  Real z_base = Ampl * std::sin(kp * x - omega_t);
1431 
1432  z -= z_base;
1433  Real fac = std::cosh( kp * (z - H) ) / std::sinh(kp * H);
1434  Real pprime_exact = -(Ampl * omega * omega / kp) * fac *
1435  std::sin(kp * x - omega_t) * r0_arr(i,j,k);
1436 
1437  derdat(i,j,k,mf_comp) -= pprime_exact;
1438  });
1439  }
1440  mf_comp += 1;
1441  }
1442 #endif
1443 
1444  if (solverChoice.rad_type != RadiationType::None) {
1445  if (containerHasElement(plot_var_names, "qsrc_sw")) {
1446  MultiFab::Copy(mf[lev], *(qheating_rates[lev]), 0, mf_comp, 1, 0);
1447  mf_comp += 1;
1448  }
1449  if (containerHasElement(plot_var_names, "qsrc_lw")) {
1450  MultiFab::Copy(mf[lev], *(qheating_rates[lev]), 1, mf_comp, 1, 0);
1451  mf_comp += 1;
1452  }
1453  }
1454 
1455  // *****************************************************************************************
1456  // End of derived variables corresponding to "derived_names" in ERF.H
1457  //
1458  // Particles and microphysics can provide additional outputs, which are handled below.
1459  // *****************************************************************************************
1460 
1461 #ifdef ERF_USE_PARTICLES
1462  const auto& particles_namelist( particleData.getNames() );
1463 
1464  if (containerHasElement(plot_var_names, "tracer_particles_count")) {
1465  if (particles_namelist.size() == 0) {
1466  MultiFab temp_dat(mf[lev].boxArray(), mf[lev].DistributionMap(), 1, 0);
1467  temp_dat.setVal(0);
1468  MultiFab::Copy(mf[lev], temp_dat, 0, mf_comp, 1, 0);
1469  mf_comp += 1;
1470  } else {
1471  for (ParticlesNamesVector::size_type i = 0; i < particles_namelist.size(); i++) {
1472  if (containerHasElement(plot_var_names, std::string(particles_namelist[i]+"_count"))) {
1473  MultiFab temp_dat(mf[lev].boxArray(), mf[lev].DistributionMap(), 1, 0);
1474  temp_dat.setVal(0);
1475  if (particleData.HasSpecies(particles_namelist[i])) {
1476  particleData[particles_namelist[i]]->Increment(temp_dat, lev);
1477  }
1478  MultiFab::Copy(mf[lev], temp_dat, 0, mf_comp, 1, 0);
1479  mf_comp += 1;
1480  }
1481  }
1482  }
1483  }
1484 
1485  Vector<std::string> particle_mesh_plot_names(0);
1486  particleData.GetMeshPlotVarNames( particle_mesh_plot_names );
1487 
1488  for (int i = 0; i < particle_mesh_plot_names.size(); i++) {
1489  std::string plot_var_name(particle_mesh_plot_names[i]);
1490  if (containerHasElement(plot_var_names, plot_var_name) ) {
1491  MultiFab temp_dat(mf[lev].boxArray(), mf[lev].DistributionMap(), 1, 1);
1492  temp_dat.setVal(0);
1493  particleData.GetMeshPlotVar(plot_var_name, temp_dat, lev);
1494  MultiFab::Copy(mf[lev], temp_dat, 0, mf_comp, 1, 0);
1495  mf_comp += 1;
1496  }
1497  }
1498 #endif
1499 
1500  {
1501  Vector<std::string> microphysics_plot_names;
1502  micro->GetPlotVarNames(microphysics_plot_names);
1503  for (auto& plot_name : microphysics_plot_names) {
1504  if (containerHasElement(plot_var_names, plot_name)) {
1505  MultiFab temp_dat(mf[lev].boxArray(), mf[lev].DistributionMap(), 1, 1);
1506  temp_dat.setVal(0);
1507  micro->GetPlotVar(plot_name, temp_dat, lev);
1508  MultiFab::Copy(mf[lev], temp_dat, 0, mf_comp, 1, 0);
1509  mf_comp += 1;
1510  }
1511  }
1512  }
1513 
1514 
1515  }
1516 
1517  if (solverChoice.terrain_type == TerrainType::EB)
1518  {
1519  for (int lev = 0; lev <= finest_level; ++lev) {
1520  EB_set_covered(mf[lev], 0.0);
1521  }
1522  }
1523 
1524  // Fill terrain distortion MF (nu_nd)
1525  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
1526  for (int lev(0); lev <= finest_level; ++lev) {
1527  MultiFab::Copy(mf_nd[lev],*z_phys_nd[lev],0,2,1,0);
1528  Real dz = Geom()[lev].CellSizeArray()[2];
1529  for (MFIter mfi(mf_nd[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
1530  const Box& bx = mfi.tilebox();
1531  Array4<Real> mf_arr = mf_nd[lev].array(mfi);
1532  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
1533  {
1534  mf_arr(i,j,k,2) -= k * dz;
1535  });
1536  }
1537  }
1538  }
1539 
1540  std::string plotfilename;
1541  std::string plotfilenameU;
1542  std::string plotfilenameV;
1543  std::string plotfilenameW;
1544 
1545  if (which == 1) {
1547  const std::string dt_format = "%Y-%m-%d_%H:%M:%S"; // ISO 8601 standard
1548  plotfilename = plot3d_file_1+"_"+getTimestamp(start_time+t_new[0], dt_format,false);
1549  } else {
1550  plotfilename = Concatenate(plot3d_file_1, istep[0], file_name_digits);
1551  }
1552  plotfilenameU = Concatenate(plot3d_file_1+"U", istep[0], file_name_digits);
1553  plotfilenameV = Concatenate(plot3d_file_1+"V", istep[0], file_name_digits);
1554  plotfilenameW = Concatenate(plot3d_file_1+"W", istep[0], file_name_digits);
1555  } else if (which == 2) {
1557  const std::string dt_format = "%Y-%m-%d_%H:%M:%S"; // ISO 8601 standard
1558  plotfilename = plot3d_file_2+"_"+getTimestamp(start_time+t_new[0], dt_format,false);
1559  } else {
1560  plotfilename = Concatenate(plot3d_file_2, istep[0], file_name_digits);
1561  }
1562  plotfilenameU = Concatenate(plot3d_file_2+"U", istep[0], file_name_digits);
1563  plotfilenameV = Concatenate(plot3d_file_2+"V", istep[0], file_name_digits);
1564  plotfilenameW = Concatenate(plot3d_file_2+"W", istep[0], file_name_digits);
1565  }
1566 
1567  // LSM writes it's own data
1568  if (which==1 && plot_lsm) {
1569  lsm.Plot_Lsm_Data(t_new[0], istep, refRatio());
1570  }
1571 
1572 #ifdef ERF_USE_RRTMGP
1573  /*
1574  // write additional RRTMGP data
1575  // TODO: currently single level only
1576  if (which==1 && plot_rad) {
1577  rad[0]->writePlotfile(plot_file_1, t_new[0], istep[0]);
1578  }
1579  */
1580 #endif
1581 
1582  // Single level
1583  if (finest_level == 0)
1584  {
1585  if (plotfile_type == PlotFileType::Amrex)
1586  {
1587  Print() << "Writing native 3D plotfile " << plotfilename << "\n";
1588  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
1589  WriteMultiLevelPlotfileWithTerrain(plotfilename, finest_level+1,
1590  GetVecOfConstPtrs(mf),
1591  GetVecOfConstPtrs(mf_nd),
1592  varnames,
1593  Geom(), t_new[0], istep, refRatio());
1594  } else {
1595  WriteMultiLevelPlotfile(plotfilename, finest_level+1,
1596  GetVecOfConstPtrs(mf),
1597  varnames,
1598  Geom(), t_new[0], istep, refRatio());
1599  }
1600  writeJobInfo(plotfilename);
1601 
1602  if (m_plot_face_vels) {
1603  Print() << "Writing face velocities" << std::endl;
1604  WriteMultiLevelPlotfile(plotfilenameU, finest_level+1,
1605  GetVecOfConstPtrs(mf_u),
1606  {"x_velocity_stag"},
1607  Geom(), t_new[0], istep, refRatio());
1608  WriteMultiLevelPlotfile(plotfilenameV, finest_level+1,
1609  GetVecOfConstPtrs(mf_v),
1610  {"y_velocity_stag"},
1611  Geom(), t_new[0], istep, refRatio());
1612  WriteMultiLevelPlotfile(plotfilenameW, finest_level+1,
1613  GetVecOfConstPtrs(mf_w),
1614  {"z_velocity_stag"},
1615  Geom(), t_new[0], istep, refRatio());
1616  }
1617 
1618 #ifdef ERF_USE_PARTICLES
1619  particleData.writePlotFile(plotfilename);
1620 #endif
1621 #ifdef ERF_USE_NETCDF
1622  } else if (plotfile_type == PlotFileType::Netcdf) {
1623  AMREX_ALWAYS_ASSERT(solverChoice.terrain_type != TerrainType::StaticFittedMesh);
1624  int lev = 0;
1625  int l_which = 0;
1626  const Real* p_lo = geom[lev].ProbLo();
1627  const Real* p_hi = geom[lev].ProbHi();
1628  const auto dx = geom[lev].CellSize();
1629  writeNCPlotFile(lev, l_which, plotfilename, GetVecOfConstPtrs(mf), varnames, istep,
1630  {p_lo[0],p_lo[1],p_lo[2]},{p_hi[0],p_hi[1],p_hi[2]}, {dx[0],dx[1],dx[2]},
1631  geom[lev].Domain(), t_new[0], start_bdy_time);
1632 #endif
1633  } else {
1634  // Here we assume the plotfile_type is PlotFileType::None
1635  Print() << "Writing no 3D plotfile since plotfile_type is none" << std::endl;
1636  }
1637 
1638  } else { // Multilevel
1639 
1640  if (plotfile_type == PlotFileType::Amrex) {
1641 
1642  int lev0 = 0;
1643  int desired_ratio = std::max(std::max(ref_ratio[lev0][0],ref_ratio[lev0][1]),ref_ratio[lev0][2]);
1644  bool any_ratio_one = ( ( (ref_ratio[lev0][0] == 1) || (ref_ratio[lev0][1] == 1) ) ||
1645  (ref_ratio[lev0][2] == 1) );
1646  for (int lev = 1; lev < finest_level; lev++) {
1647  any_ratio_one = any_ratio_one ||
1648  ( ( (ref_ratio[lev][0] == 1) || (ref_ratio[lev][1] == 1) ) ||
1649  (ref_ratio[lev][2] == 1) );
1650  }
1651 
1652  if (any_ratio_one && m_expand_plotvars_to_unif_rr)
1653  {
1654  Vector<IntVect> r2(finest_level);
1655  Vector<Geometry> g2(finest_level+1);
1656  Vector<MultiFab> mf2(finest_level+1);
1657 
1658  mf2[0].define(grids[0], dmap[0], ncomp_mf, 0);
1659 
1660  // Copy level 0 as is
1661  MultiFab::Copy(mf2[0],mf[0],0,0,mf[0].nComp(),0);
1662 
1663  // Define a new multi-level array of Geometry's so that we pass the new "domain" at lev > 0
1664  Array<int,AMREX_SPACEDIM> periodicity =
1665  {Geom()[lev0].isPeriodic(0),Geom()[lev0].isPeriodic(1),Geom()[lev0].isPeriodic(2)};
1666  g2[lev0].define(Geom()[lev0].Domain(),&(Geom()[lev0].ProbDomain()),0,periodicity.data());
1667 
1668  r2[0] = IntVect(desired_ratio/ref_ratio[lev0][0],
1669  desired_ratio/ref_ratio[lev0][1],
1670  desired_ratio/ref_ratio[lev0][2]);
1671 
1672  for (int lev = 1; lev <= finest_level; ++lev) {
1673  if (lev > 1) {
1674  r2[lev-1][0] = r2[lev-2][0] * desired_ratio / ref_ratio[lev-1][0];
1675  r2[lev-1][1] = r2[lev-2][1] * desired_ratio / ref_ratio[lev-1][1];
1676  r2[lev-1][2] = r2[lev-2][2] * desired_ratio / ref_ratio[lev-1][2];
1677  }
1678 
1679  mf2[lev].define(refine(grids[lev],r2[lev-1]), dmap[lev], ncomp_mf, 0);
1680 
1681  // Set the new problem domain
1682  Box d2(Geom()[lev].Domain());
1683  d2.refine(r2[lev-1]);
1684 
1685  g2[lev].define(d2,&(Geom()[lev].ProbDomain()),0,periodicity.data());
1686  }
1687 
1688  //
1689  // We need to make a temporary that is the size of ncomp_mf
1690  // in order to not get an out of bounds error
1691  // even though the values will not be used
1692  //
1693  Vector<BCRec> temp_domain_bcs_type;
1694  temp_domain_bcs_type.resize(ncomp_mf);
1695 
1696  //
1697  // Do piecewise constant interpolation of mf into mf2
1698  //
1699  for (int lev = 1; lev <= finest_level; ++lev) {
1700  Interpolater* mapper_c = &pc_interp;
1701  InterpFromCoarseLevel(mf2[lev], t_new[lev], mf[lev],
1702  0, 0, ncomp_mf,
1703  geom[lev], g2[lev],
1705  r2[lev-1], mapper_c, temp_domain_bcs_type, 0);
1706  }
1707 
1708  // Define an effective ref_ratio which is isotropic to be passed into WriteMultiLevelPlotfile
1709  Vector<IntVect> rr(finest_level);
1710  for (int lev = 0; lev < finest_level; ++lev) {
1711  rr[lev] = IntVect(desired_ratio);
1712  }
1713 
1714  Print() << "Writing 3D plotfile " << plotfilename << "\n";
1715  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
1716  WriteMultiLevelPlotfileWithTerrain(plotfilename, finest_level+1,
1717  GetVecOfConstPtrs(mf2),
1718  GetVecOfConstPtrs(mf_nd),
1719  varnames,
1720  g2, t_new[0], istep, rr);
1721  } else {
1722  WriteMultiLevelPlotfile(plotfilename, finest_level+1,
1723  GetVecOfConstPtrs(mf2), varnames,
1724  g2, t_new[0], istep, rr);
1725  }
1726 
1727  } else {
1728  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
1729  WriteMultiLevelPlotfileWithTerrain(plotfilename, finest_level+1,
1730  GetVecOfConstPtrs(mf),
1731  GetVecOfConstPtrs(mf_nd),
1732  varnames,
1733  geom, t_new[0], istep, ref_ratio);
1734  } else {
1735  WriteMultiLevelPlotfile(plotfilename, finest_level+1,
1736  GetVecOfConstPtrs(mf), varnames,
1737  geom, t_new[0], istep, ref_ratio);
1738  }
1739  if (m_plot_face_vels) {
1740  Print() << "Writing face velocities" << std::endl;
1741  WriteMultiLevelPlotfile(plotfilenameU, finest_level+1,
1742  GetVecOfConstPtrs(mf_u),
1743  {"x_velocity_stag"},
1744  geom, t_new[0], istep, ref_ratio);
1745  WriteMultiLevelPlotfile(plotfilenameV, finest_level+1,
1746  GetVecOfConstPtrs(mf_v),
1747  {"y_velocity_stag"},
1748  geom, t_new[0], istep, ref_ratio);
1749  WriteMultiLevelPlotfile(plotfilenameW, finest_level+1,
1750  GetVecOfConstPtrs(mf_w),
1751  {"z_velocity_stag"},
1752  geom, t_new[0], istep, ref_ratio);
1753  }
1754  } // ref_ratio test
1755 
1756  writeJobInfo(plotfilename);
1757 
1758 #ifdef ERF_USE_PARTICLES
1759  particleData.writePlotFile(plotfilename);
1760 #endif
1761 
1762 #ifdef ERF_USE_NETCDF
1763  } else if (plotfile_type == PlotFileType::Netcdf) {
1764  AMREX_ALWAYS_ASSERT(solverChoice.terrain_type != TerrainType::StaticFittedMesh);
1765  for (int lev = 0; lev <= finest_level; ++lev) {
1766  for (int which_box = 0; which_box < num_boxes_at_level[lev]; which_box++) {
1767  Box bounding_region = (lev == 0) ? geom[lev].Domain() : boxes_at_level[lev][which_box];
1768  const Real* p_lo = geom[lev].ProbLo();
1769  const Real* p_hi = geom[lev].ProbHi();
1770  const auto dx = geom[lev].CellSizeArray();
1771  writeNCPlotFile(lev, which_box, plotfilename, GetVecOfConstPtrs(mf), varnames, istep,
1772  {p_lo[0],p_lo[1],p_lo[2]},{p_hi[0],p_hi[1],p_hi[2]}, {dx[0],dx[1],dx[2]},
1773  bounding_region, t_new[0], start_bdy_time);
1774  }
1775  }
1776 #endif
1777  }
1778  } // end multi-level
1779 
1780  if (verbose > 0)
1781  {
1782  auto dPlotTime = amrex::second() - dPlotTime0;
1783  ParallelDescriptor::ReduceRealMax(dPlotTime,ParallelDescriptor::IOProcessorNumber());
1784  amrex::Print() << "3DPlotfile write time = " << dPlotTime << " seconds." << '\n';
1785  }
1786 }
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
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 amrex::Real erf_esatw(amrex::Real t)
Definition: ERF_MicrophysicsUtils.H:68
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void erf_qsatw(amrex::Real t, amrex::Real p, amrex::Real &qsatw)
Definition: ERF_MicrophysicsUtils.H:166
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:1789
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:180
@ Mom_h
Definition: ERF_IndexDefines.H:170
@ Theta_h
Definition: ERF_IndexDefines.H:171
@ 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  IntVect ng = mapfac[lev][MapFacType::m_x]->nGrowVect();
231  MultiFab mf_m(ba2d[lev],dmap[lev],1,ng);
232  MultiFab::Copy(mf_m,*mapfac[lev][MapFacType::m_x],0,0,1,ng);
233  VisMF::Write(mf_m, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "MapFactor_mx"));
234 
235 #if 0
237  MultiFab::Copy(mf_m,*mapfac[lev][MapFacType::m_y],0,0,1,ng);
238  VisMF::Write(mf_m, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "MapFactor_my"));
239  }
240 #endif
241 
242  ng = mapfac[lev][MapFacType::u_x]->nGrowVect();
243  MultiFab mf_u(convert(ba2d[lev],IntVect(1,0,0)),dmap[lev],1,ng);
244  MultiFab::Copy(mf_u,*mapfac[lev][MapFacType::u_x],0,0,1,ng);
245  VisMF::Write(mf_u, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "MapFactor_ux"));
246 
247 #if 0
249  MultiFab::Copy(mf_u,*mapfac[lev][MapFacType::u_y],0,0,1,ng);
250  VisMF::Write(mf_u, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "MapFactor_uy"));
251  }
252 #endif
253 
254  ng = mapfac[lev][MapFacType::v_x]->nGrowVect();
255  MultiFab mf_v(convert(ba2d[lev],IntVect(0,1,0)),dmap[lev],1,ng);
256  MultiFab::Copy(mf_v,*mapfac[lev][MapFacType::v_x],0,0,1,ng);
257  VisMF::Write(mf_v, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "MapFactor_vx"));
258 
259 #if 0
261  MultiFab::Copy(mf_v,*mapfac[lev][MapFacType::v_y],0,0,1,ng);
262  VisMF::Write(mf_v, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "MapFactor_vy"));
263  }
264 #endif
265 
266  if (m_SurfaceLayer) {
267  amrex::Print() << "Writing SurfaceLayer variables at level " << lev << std::endl;
268  ng = IntVect(1,1,0);
269  MultiFab m_var(ba2d[lev],dmap[lev],1,ng);
270  MultiFab* src = nullptr;
271 
272  // U*
273  src = m_SurfaceLayer->get_u_star(lev);
274  MultiFab::Copy(m_var,*src,0,0,1,ng);
275  VisMF::Write(m_var, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Ustar"));
276 
277  // W*
278  src = m_SurfaceLayer->get_w_star(lev);
279  MultiFab::Copy(m_var,*src,0,0,1,ng);
280  VisMF::Write(m_var, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Wstar"));
281 
282  // T*
283  src = m_SurfaceLayer->get_t_star(lev);
284  MultiFab::Copy(m_var,*src,0,0,1,ng);
285  VisMF::Write(m_var, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Tstar"));
286 
287  // Q*
288  src = m_SurfaceLayer->get_q_star(lev);
289  MultiFab::Copy(m_var,*src,0,0,1,ng);
290  VisMF::Write(m_var, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Qstar"));
291 
292  // Olen
293  src = m_SurfaceLayer->get_olen(lev);
294  MultiFab::Copy(m_var,*src,0,0,1,ng);
295  VisMF::Write(m_var, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Olen"));
296 
297  // Qsurf
298  src = m_SurfaceLayer->get_q_surf(lev);
299  MultiFab::Copy(m_var,*src,0,0,1,ng);
300  VisMF::Write(m_var, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Qsurf"));
301 
302  // PBLH
303  src = m_SurfaceLayer->get_pblh(lev);
304  MultiFab::Copy(m_var,*src,0,0,1,ng);
305  VisMF::Write(m_var, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "PBLH"));
306 
307  // Z0
308  src = m_SurfaceLayer->get_z0(lev);
309  MultiFab::Copy(m_var,*src,0,0,1,ng);
310  VisMF::Write(m_var, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Z0"));
311  }
312 
313  if (sst_lev[lev][0]) {
314  int ntimes = 1;
315  ng = vars_new[lev][Vars::cons].nGrowVect(); ng[2]=0;
316  MultiFab sst_at_t(ba2d[lev],dmap[lev],1,ng);
317  for (int nt(0); nt<ntimes; ++nt) {
318  MultiFab::Copy(sst_at_t,*sst_lev[lev][nt],0,0,1,ng);
319  VisMF::Write(sst_at_t, MultiFabFileFullPrefix(lev, checkpointname, "Level_",
320  "SST_" + std::to_string(nt)));
321  }
322  }
323 
324  if (tsk_lev[lev][0]) {
325  int ntimes = 1;
326  ng = vars_new[lev][Vars::cons].nGrowVect(); ng[2]=0;
327  MultiFab tsk_at_t(ba2d[lev],dmap[lev],1,ng);
328  for (int nt(0); nt<ntimes; ++nt) {
329  MultiFab::Copy(tsk_at_t,*tsk_lev[lev][nt],0,0,1,ng);
330  VisMF::Write(tsk_at_t, MultiFabFileFullPrefix(lev, checkpointname, "Level_",
331  "TSK_" + std::to_string(nt)));
332  }
333  }
334 
335  {
336  int ntimes = 1;
337  ng = vars_new[lev][Vars::cons].nGrowVect(); ng[2]=0;
338  MultiFab lmask_at_t(ba2d[lev],dmap[lev],1,ng);
339  for (int nt(0); nt<ntimes; ++nt) {
340  for (MFIter mfi(lmask_at_t); mfi.isValid(); ++mfi) {
341  const Box& bx = mfi.growntilebox();
342  Array4<int> const& src_arr = lmask_lev[lev][nt]->array(mfi);
343  Array4<Real> const& dst_arr = lmask_at_t.array(mfi);
344  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
345  {
346  dst_arr(i,j,k) = Real(src_arr(i,j,k));
347  });
348  }
349  VisMF::Write(lmask_at_t, MultiFabFileFullPrefix(lev, checkpointname, "Level_",
350  "LMASK_" + std::to_string(nt)));
351  }
352  }
353 
354  IntVect ngv = ng; ngv[2] = 0;
355 
356  // Write lat/lon if it exists
357  if (lat_m[lev] && lon_m[lev] && solverChoice.has_lat_lon) {
358  amrex::Print() << "Writing Lat/Lon variables at level " << lev << std::endl;
359  MultiFab lat(ba2d[lev],dmap[lev],1,ngv);
360  MultiFab lon(ba2d[lev],dmap[lev],1,ngv);
361  MultiFab::Copy(lat,*lat_m[lev],0,0,1,ngv);
362  MultiFab::Copy(lon,*lon_m[lev],0,0,1,ngv);
363  VisMF::Write(lat, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "LAT"));
364  VisMF::Write(lon, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "LON"));
365  }
366 
367 
368 #ifdef ERF_USE_NETCDF
369  // Write sinPhi and cosPhi if it exists
370  if (cosPhi_m[lev] && sinPhi_m[lev] && solverChoice.variable_coriolis) {
371  amrex::Print() << "Writing Coriolis factors at level " << lev << std::endl;
372  MultiFab sphi(ba2d[lev],dmap[lev],1,ngv);
373  MultiFab cphi(ba2d[lev],dmap[lev],1,ngv);
374  MultiFab::Copy(sphi,*sinPhi_m[lev],0,0,1,ngv);
375  MultiFab::Copy(cphi,*cosPhi_m[lev],0,0,1,ngv);
376  VisMF::Write(sphi, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "SinPhi"));
377  VisMF::Write(cphi, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "CosPhi"));
378  }
379 
380  if (solverChoice.use_real_bcs && solverChoice.init_type == InitType::WRFInput) {
381  if (lev == 0) {
382  amrex::Print() << "Writing C1H/C2H/MUB variables at level " << lev << std::endl;
383  MultiFab tmp1d(ba1d[0],dmap[0],1,0);
384 
385  MultiFab::Copy(tmp1d,*mf_C1H,0,0,1,0);
386  VisMF::Write(tmp1d, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "C1H"));
387 
388  MultiFab::Copy(tmp1d,*mf_C2H,0,0,1,0);
389  VisMF::Write(tmp1d, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "C2H"));
390 
391  MultiFab tmp2d(ba2d[0],dmap[0],1,mf_MUB->nGrowVect());
392 
393  MultiFab::Copy(tmp2d,*mf_MUB,0,0,1,mf_MUB->nGrowVect());
394  VisMF::Write(tmp2d, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "MUB"));
395  }
396  }
397 #endif
398  } // for lev
399 
400 #ifdef ERF_USE_PARTICLES
401  particleData.Checkpoint(checkpointname);
402 #endif
403 
404 #if 0
405 #ifdef ERF_USE_NETCDF
406  // Write bdy_data files
407  if ( ParallelDescriptor::IOProcessor() &&
408  ((solverChoice.init_type==InitType::WRFInput) || (solverChoice.init_type==InitType::Metgrid)) &&
410  {
411  // Vector dimensions
412  int num_time = bdy_data_xlo.size();
413  int num_var = bdy_data_xlo[0].size();
414 
415  // Open header file and write to it
416  std::ofstream bdy_h_file(MultiFabFileFullPrefix(0, checkpointname, "Level_", "bdy_H"));
417  bdy_h_file << std::setprecision(1) << std::fixed;
418  bdy_h_file << num_time << "\n";
419  bdy_h_file << num_var << "\n";
420  bdy_h_file << start_bdy_time << "\n";
421  bdy_h_file << bdy_time_interval << "\n";
422  bdy_h_file << real_width << "\n";
423  for (int ivar(0); ivar<num_var; ++ivar) {
424  bdy_h_file << bdy_data_xlo[0][ivar].box() << "\n";
425  bdy_h_file << bdy_data_xhi[0][ivar].box() << "\n";
426  bdy_h_file << bdy_data_ylo[0][ivar].box() << "\n";
427  bdy_h_file << bdy_data_yhi[0][ivar].box() << "\n";
428  }
429 
430  // Open data file and write to it
431  std::ofstream bdy_d_file(MultiFabFileFullPrefix(0, checkpointname, "Level_", "bdy_D"));
432  for (int itime(0); itime<num_time; ++itime) {
433  if (bdy_data_xlo[itime].size() > 0) {
434  for (int ivar(0); ivar<num_var; ++ivar) {
435  bdy_data_xlo[itime][ivar].writeOn(bdy_d_file,0,1);
436  bdy_data_xhi[itime][ivar].writeOn(bdy_d_file,0,1);
437  bdy_data_ylo[itime][ivar].writeOn(bdy_d_file,0,1);
438  bdy_data_yhi[itime][ivar].writeOn(bdy_d_file,0,1);
439  }
440  }
441  }
442  }
443 #endif
444 #endif
445 
446  if (verbose > 0)
447  {
448  auto dCheckTime = amrex::second() - dCheckTime0;
449  ParallelDescriptor::ReduceRealMax(dCheckTime,ParallelDescriptor::IOProcessorNumber());
450  amrex::Print() << "Checkpoint write time = " << dCheckTime << " seconds." << '\n';
451  }
452 }

◆ 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
1887 {
1888  AMREX_ALWAYS_ASSERT(nlevels <= bArray.size());
1889  AMREX_ALWAYS_ASSERT(nlevels <= my_ref_ratio.size()+1);
1890  AMREX_ALWAYS_ASSERT(nlevels <= level_steps.size());
1891 
1892  HeaderFile.precision(17);
1893 
1894  // ---- this is the generic plot file type name
1895  HeaderFile << versionName << '\n';
1896 
1897  HeaderFile << varnames.size() << '\n';
1898 
1899  for (int ivar = 0; ivar < varnames.size(); ++ivar) {
1900  HeaderFile << varnames[ivar] << "\n";
1901  }
1902  HeaderFile << AMREX_SPACEDIM << '\n';
1903  HeaderFile << my_time << '\n';
1904  HeaderFile << finest_level << '\n';
1905  for (int i = 0; i < AMREX_SPACEDIM; ++i) {
1906  HeaderFile << my_geom[0].ProbLo(i) << ' ';
1907  }
1908  HeaderFile << '\n';
1909  for (int i = 0; i < AMREX_SPACEDIM; ++i) {
1910  HeaderFile << my_geom[0].ProbHi(i) << ' ';
1911  }
1912  HeaderFile << '\n';
1913  for (int i = 0; i < finest_level; ++i) {
1914  HeaderFile << my_ref_ratio[i][0] << ' ';
1915  }
1916  HeaderFile << '\n';
1917  for (int i = 0; i <= finest_level; ++i) {
1918  HeaderFile << my_geom[i].Domain() << ' ';
1919  }
1920  HeaderFile << '\n';
1921  for (int i = 0; i <= finest_level; ++i) {
1922  HeaderFile << level_steps[i] << ' ';
1923  }
1924  HeaderFile << '\n';
1925  for (int i = 0; i <= finest_level; ++i) {
1926  for (int k = 0; k < AMREX_SPACEDIM; ++k) {
1927  HeaderFile << my_geom[i].CellSize()[k] << ' ';
1928  }
1929  HeaderFile << '\n';
1930  }
1931  HeaderFile << (int) my_geom[0].Coord() << '\n';
1932  HeaderFile << "0\n";
1933 
1934  for (int level = 0; level <= finest_level; ++level) {
1935  HeaderFile << level << ' ' << bArray[level].size() << ' ' << my_time << '\n';
1936  HeaderFile << level_steps[level] << '\n';
1937 
1938  const IntVect& domain_lo = my_geom[level].Domain().smallEnd();
1939  for (int i = 0; i < bArray[level].size(); ++i)
1940  {
1941  // Need to shift because the RealBox ctor we call takes the
1942  // physical location of index (0,0,0). This does not affect
1943  // the usual cases where the domain index starts with 0.
1944  const Box& b = shift(bArray[level][i], -domain_lo);
1945  RealBox loc = RealBox(b, my_geom[level].CellSize(), my_geom[level].ProbLo());
1946  for (int n = 0; n < AMREX_SPACEDIM; ++n) {
1947  HeaderFile << loc.lo(n) << ' ' << loc.hi(n) << '\n';
1948  }
1949  }
1950 
1951  HeaderFile << MultiFabHeaderPath(level, levelPrefix, mfPrefix) << '\n';
1952  }
1953  HeaderFile << "1" << "\n";
1954  HeaderFile << "3" << "\n";
1955  HeaderFile << "amrexvec_nu_x" << "\n";
1956  HeaderFile << "amrexvec_nu_y" << "\n";
1957  HeaderFile << "amrexvec_nu_z" << "\n";
1958  std::string mf_nodal_prefix = "Nu_nd";
1959  for (int level = 0; level <= finest_level; ++level) {
1960  HeaderFile << MultiFabHeaderPath(level, levelPrefix, mf_nodal_prefix) << '\n';
1961  }
1962 }
Coord
Definition: ERF_DataStruct.H:91

◆ 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:1525
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
1801 {
1802  BL_PROFILE("WriteMultiLevelPlotfileWithTerrain()");
1803 
1804  AMREX_ALWAYS_ASSERT(nlevels <= mf.size());
1805  AMREX_ALWAYS_ASSERT(nlevels <= rr.size()+1);
1806  AMREX_ALWAYS_ASSERT(nlevels <= level_steps.size());
1807  AMREX_ALWAYS_ASSERT(mf[0]->nComp() == varnames.size());
1808 
1809  bool callBarrier(false);
1810  PreBuildDirectorHierarchy(plotfilename, levelPrefix, nlevels, callBarrier);
1811  if (!extra_dirs.empty()) {
1812  for (const auto& d : extra_dirs) {
1813  const std::string ed = plotfilename+"/"+d;
1814  PreBuildDirectorHierarchy(ed, levelPrefix, nlevels, callBarrier);
1815  }
1816  }
1817  ParallelDescriptor::Barrier();
1818 
1819  if (ParallelDescriptor::MyProc() == ParallelDescriptor::NProcs()-1) {
1820  Vector<BoxArray> boxArrays(nlevels);
1821  for(int level(0); level < boxArrays.size(); ++level) {
1822  boxArrays[level] = mf[level]->boxArray();
1823  }
1824 
1825  auto f = [=]() {
1826  VisMF::IO_Buffer io_buffer(VisMF::IO_Buffer_Size);
1827  std::string HeaderFileName(plotfilename + "/Header");
1828  std::ofstream HeaderFile;
1829  HeaderFile.rdbuf()->pubsetbuf(io_buffer.dataPtr(), io_buffer.size());
1830  HeaderFile.open(HeaderFileName.c_str(), std::ofstream::out |
1831  std::ofstream::trunc |
1832  std::ofstream::binary);
1833  if( ! HeaderFile.good()) FileOpenFailed(HeaderFileName);
1834  WriteGenericPlotfileHeaderWithTerrain(HeaderFile, nlevels, boxArrays, varnames,
1835  my_geom, time, level_steps, rr, versionName,
1836  levelPrefix, mfPrefix);
1837  };
1838 
1839  if (AsyncOut::UseAsyncOut()) {
1840  AsyncOut::Submit(std::move(f));
1841  } else {
1842  f();
1843  }
1844  }
1845 
1846  std::string mf_nodal_prefix = "Nu_nd";
1847  for (int level = 0; level <= finest_level; ++level)
1848  {
1849  if (AsyncOut::UseAsyncOut()) {
1850  VisMF::AsyncWrite(*mf[level],
1851  MultiFabFileFullPrefix(level, plotfilename, levelPrefix, mfPrefix),
1852  true);
1853  VisMF::AsyncWrite(*mf_nd[level],
1854  MultiFabFileFullPrefix(level, plotfilename, levelPrefix, mf_nodal_prefix),
1855  true);
1856  } else {
1857  const MultiFab* data;
1858  std::unique_ptr<MultiFab> mf_tmp;
1859  if (mf[level]->nGrowVect() != 0) {
1860  mf_tmp = std::make_unique<MultiFab>(mf[level]->boxArray(),
1861  mf[level]->DistributionMap(),
1862  mf[level]->nComp(), 0, MFInfo(),
1863  mf[level]->Factory());
1864  MultiFab::Copy(*mf_tmp, *mf[level], 0, 0, mf[level]->nComp(), 0);
1865  data = mf_tmp.get();
1866  } else {
1867  data = mf[level];
1868  }
1869  VisMF::Write(*data , MultiFabFileFullPrefix(level, plotfilename, levelPrefix, mfPrefix));
1870  VisMF::Write(*mf_nd[level], MultiFabFileFullPrefix(level, plotfilename, levelPrefix, mf_nodal_prefix));
1871  }
1872  }
1873 }
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:1876

◆ 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 
)
3023 {
3024  bool write_now = false;
3025 
3026  if ( plot_int > 0) {
3027 
3028  write_now = (nstep % plot_int == 0);
3029 
3030  } else if (plot_per > 0.0) {
3031 
3032  amrex::Print() << "CUR NEXT PER " << cur_time << " " << next_file_time << " " << plot_per << std::endl;
3033 
3034  // Only write now if nstep newly matches the number of elapsed periods
3035  write_now = (cur_time > (next_file_time - Real(0.1)*dt_0));
3036  }
3037 
3038  return write_now;
3039 }

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

int ERF::real_set_width {0}
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

◆ solar_zenith

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ERF::solar_zenith
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

◆ sw_lw_fluxes

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

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