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 InitData ()
 
void InitData_pre ()
 
void InitData_post ()
 
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_velocities (int lev, amrex::Real dt, amrex::Vector< amrex::MultiFab > &vars, amrex::MultiFab &p)
 
void project_velocities_tb (int lev, amrex::Real dt, amrex::Vector< amrex::MultiFab > &vars, amrex::MultiFab &p)
 
void poisson_wall_dist (int lev)
 
void solve_with_gmres (int lev, amrex::Vector< amrex::MultiFab > &rhs, amrex::Vector< amrex::MultiFab > &p, amrex::Vector< amrex::Array< amrex::MultiFab, AMREX_SPACEDIM >> &fluxes)
 
void solve_with_mlmg (int lev, amrex::Vector< amrex::MultiFab > &rhs, amrex::Vector< amrex::MultiFab > &p, amrex::Vector< amrex::Array< amrex::MultiFab, AMREX_SPACEDIM >> &fluxes)
 
amrex::Array< amrex::LinOpBCType, AMREX_SPACEDIM > get_projection_bc (amrex::Orientation::Side side) const noexcept
 
bool projection_has_dirichlet (amrex::Array< amrex::LinOpBCType, AMREX_SPACEDIM > bcs) const
 
void init_only (int lev, amrex::Real time)
 
void restart ()
 
bool writeNow (const amrex::Real cur_time, const amrex::Real dt, const int nstep, const int plot_int, const amrex::Real plot_per)
 
void post_timestep (int nstep, amrex::Real time, amrex::Real dt_lev)
 
void sum_integrated_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)
 
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 &mapfac, bool local, bool finemask)
 
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::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 &, const amrex::Real &dt_advance)
 
amrex::MultiFab & build_fine_mask (int lev)
 
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 WritePlotFile (int which, PlotFileType plotfile_type, amrex::Vector< std::string > plot_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, std::unique_ptr< amrex::MultiFab > &z_cc)
 
void init_from_input_sounding (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 fill_from_bndryregs (const amrex::Vector< amrex::MultiFab * > &mfs, amrex::Real time)
 
void AverageDownTo (int crse_lev, int scomp, int ncomp)
 
void WriteCheckpointFile () const
 
void ReadCheckpointFile ()
 
void ReadCheckpointFileMOST ()
 
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

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 init_zphys (int lev, amrex::Real time)
 
void remake_zphys (int lev, std::unique_ptr< amrex::MultiFab > &temp_zphys_nd)
 
void update_terrain_arrays (int lev)
 
void Construct_ERFFillPatchers (int lev)
 
void Define_ERFFillPatchers (int lev)
 
void init1DArrays ()
 
void init_bcs ()
 
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 FillPatch (int lev, amrex::Real time, const amrex::Vector< amrex::MultiFab * > &mfs_vel, bool cons_only=false)
 
void FillPatch (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, bool allow_most_bcs=true)
 
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 appendPlotVariables (const std::string &pp_plot_var_names, amrex::Vector< std::string > &plot_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 int NumDataLogs () 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 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 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...
 

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 AdvChoice &advChoice, bool use_num_diff)
 
static amrex::Real getCPUTime ()
 

Private Attributes

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
 
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::Real > t_new
 
amrex::Vector< amrex::Real > t_old
 
amrex::Vector< amrex::Real > dt
 
amrex::Vector< long > dt_mri_ratio
 
amrex::Vector< amrex::Vector< amrex::MultiFab > > vars_new
 
amrex::Vector< amrex::Vector< amrex::MultiFab > > vars_old
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vel_t_avg
 
amrex::Vector< amrex::Real > t_avg_cnt
 
amrex::Vector< std::unique_ptr< MRISplitIntegrator< amrex::Vector< amrex::MultiFab > > > > mri_integrator_mem
 
amrex::Vector< amrex::MultiFab > pp_inc
 
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< amrex::Vector< amrex::MultiFab * > > lsm_data
 
amrex::Vector< amrex::Vector< amrex::MultiFab * > > lsm_flux
 
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< std::unique_ptr< amrex::MultiFab > > Tau11_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau22_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau33_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau12_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau21_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau13_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau31_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau23_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau32_lev
 
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::iMultiFab > > > lmask_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 > > 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 > > ax_new
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ay_new
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > az_new
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_t_rk
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > walldist
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > mapfac_m
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > mapfac_u
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > mapfac_v
 
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
 
int last_plot_file_step_1
 
int last_plot_file_step_2
 
int last_check_file_step
 
int plot_file_on_restart = 1
 
int max_step = std::numeric_limits<int>::max()
 
amrex::Real start_time = 0.0
 
amrex::Real stop_time = std::numeric_limits<amrex::Real>::max()
 
std::string restart_chkfile = ""
 
amrex::Vector< amrex::Real > fixed_dt
 
amrex::Vector< amrex::Real > fixed_fast_dt
 
int regrid_int = -1
 
std::string plot_file_1 {"plt_1_"}
 
std::string plot_file_2 {"plt_2_"}
 
bool m_expand_plotvars_to_unif_rr = false
 
int m_plot_int_1 = -1
 
int m_plot_int_2 = -1
 
amrex::Real m_plot_per_1 = -1.0
 
amrex::Real m_plot_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"}
 
std::string check_type {"native"}
 
std::string restart_type {"native"}
 
int m_check_int = -1
 
amrex::Real m_check_per = -1.0
 
amrex::Vector< std::string > plot_var_names_1
 
amrex::Vector< std::string > plot_var_names_2
 
const amrex::Vector< std::string > cons_names
 
const amrex::Vector< std::string > derived_names
 
TurbulentPerturbation turbPert
 
int real_width {0}
 
int real_set_width {0}
 
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 {1000.0}
 
int metgrid_order {2}
 
int metgrid_force_sfc_k {0}
 
amrex::Vector< amrex::Vector< amrex::Real > > h_rhotheta_src
 
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_rhotheta_src
 
amrex::Vector< amrex::Vector< amrex::Real > > h_rhoqt_src
 
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_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::Gpu::DeviceVector< amrex::Real > > > d_rayleigh_ptrs
 
amrex::Vector< amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > > d_sponge_ptrs
 
amrex::Vector< amrex::Real > h_havg_density
 
amrex::Vector< amrex::Real > h_havg_temperature
 
amrex::Vector< amrex::Real > h_havg_pressure
 
amrex::Vector< amrex::Real > h_havg_qv
 
amrex::Vector< amrex::Real > h_havg_qc
 
amrex::Gpu::DeviceVector< amrex::Real > d_havg_density
 
amrex::Gpu::DeviceVector< amrex::Real > d_havg_temperature
 
amrex::Gpu::DeviceVector< amrex::Real > d_havg_pressure
 
amrex::Gpu::DeviceVector< amrex::Real > d_havg_qv
 
amrex::Gpu::DeviceVector< amrex::Real > d_havg_qc
 
std::unique_ptr< WriteBndryPlanesm_w2d = nullptr
 
std::unique_ptr< ReadBndryPlanesm_r2d = nullptr
 
std::unique_ptr< ABLMostm_most = nullptr
 
amrex::Vector< std::unique_ptr< ForestDrag > > m_forest_drag
 
amrex::Vector< std::unique_ptr< TerrainDrag > > m_terrain_drag
 
amrex::MultiFab fine_mask
 
amrex::Vector< amrex::Real > dz_min
 
int sampler_interval = -1
 
amrex::Real sampler_per = -1.0
 
std::unique_ptr< SampleDatadata_sampler = nullptr
 
amrex::Vector< std::unique_ptr< std::fstream > > datalog
 
amrex::Vector< std::string > 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< amrex::FabFactory< amrex::FArrayBox > > > m_factory
 

Static Private Attributes

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 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 sum_interval = -1
 
static int pert_interval = -1
 
static amrex::Real sum_per = -1.0
 
static PlotFileType plotfile_type_1 = PlotFileType::None
 
static PlotFileType plotfile_type_2 = PlotFileType::None
 
static InitType init_type
 
static StateInterpType interpolation_type
 
static std::string sponge_type
 
static bool use_real_bcs
 
static amrex::Vector< amrex::Vector< std::string > > nc_init_file = {{""}}
 
static std::string nc_bdy_file
 
static bool init_sounding_ideal = false
 
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 ( )
88 {
89  int fix_random_seed = 0;
90  ParmParse pp("erf"); pp.query("fix_random_seed", fix_random_seed);
91  // Note that the value of 1024UL is not significant -- the point here is just to set the
92  // same seed for all MPI processes for the purpose of regression testing
93  if (fix_random_seed) {
94  Print() << "Fixing the random seed" << std::endl;
95  InitRandom(1024UL);
96  }
97 
98  ERF_shared();
99 }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real pp(amrex::Real y)
Definition: ERF_MicrophysicsUtils.H:219
void ERF_shared()
Definition: ERF.cpp:102
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 // FillPatch(lev, time, {&S_old, &U_old, &V_old, &W_old});
50 // } else {
51  if (lev > 0) {
52  FillPatch(lev, time, {&S_old, &U_old, &V_old, &W_old},
53  {&S_old, &rU_old[lev], &rV_old[lev], &rW_old[lev]},
54  base_state[lev], base_state[lev]);
55  }
56 
57  //
58  // So we must convert the fillpatched to momenta, including the ghost values
59  //
60  VelocityToMomentum(U_old, rU_old[lev].nGrowVect(),
61  V_old, rV_old[lev].nGrowVect(),
62  W_old, rW_old[lev].nGrowVect(),
63  S_old, rU_old[lev], rV_old[lev], rW_old[lev],
64  Geom(lev).Domain(),
66 
67  // TODO: Can test on multiple levels later
68  // Update the inflow perturbation update time and amplitude
69  if (lev == 0) {
70  if (solverChoice.pert_type == PerturbationType::Source ||
71  solverChoice.pert_type == PerturbationType::Direct)
72  {
73  turbPert.calc_tpi_update(lev, dt_lev, U_old, V_old, S_old);
74  }
75 
76  // If PerturbationType::Direct is selected, directly add the computed perturbation
77  // on the conserved field
78  if (solverChoice.pert_type == PerturbationType::Direct)
79  {
80  auto m_ixtype = S_old.boxArray().ixType(); // Conserved term
81  for (MFIter mfi(S_old,TileNoZ()); mfi.isValid(); ++mfi) {
82  Box bx = mfi.tilebox();
83  const Array4<Real> &cell_data = S_old.array(mfi);
84  const Array4<const Real> &pert_cell = turbPert.pb_cell.array(mfi);
85  turbPert.apply_tpi(lev, bx, RhoTheta_comp, m_ixtype, cell_data, pert_cell);
86  }
87  }
88  }
89 
90  // configure ABLMost params if used MostWall boundary condition
91  if (phys_bc_type[Orientation(Direction::z,Orientation::low)] == ERF_BC::MOST) {
92  if (m_most) {
93  IntVect ng = Theta_prim[lev]->nGrowVect();
94  MultiFab::Copy( *Theta_prim[lev], S_old, RhoTheta_comp, 0, 1, ng);
95  MultiFab::Divide(*Theta_prim[lev], S_old, Rho_comp , 0, 1, ng);
96  if (solverChoice.moisture_type != MoistureType::None) {
97  ng = Qv_prim[lev]->nGrowVect();
98 
99  MultiFab::Copy( *Qv_prim[lev], S_old, RhoQ1_comp, 0, 1, ng);
100  MultiFab::Divide(*Qv_prim[lev], S_old, Rho_comp , 0, 1, ng);
101 
102  if (solverChoice.RhoQr_comp > -1) {
103  MultiFab::Copy( *Qr_prim[lev], S_old, solverChoice.RhoQr_comp, 0, 1, ng);
104  MultiFab::Divide(*Qr_prim[lev], S_old, Rho_comp , 0, 1, ng);
105  } else {
106  Qr_prim[lev]->setVal(0.0);
107  }
108  }
109  // NOTE: std::swap above causes the field ptrs to be out of date.
110  // Reassign the field ptrs for MAC avg computation.
111  m_most->update_mac_ptrs(lev, vars_old, Theta_prim, Qv_prim, Qr_prim);
112  m_most->update_pblh(lev, vars_old, z_phys_cc[lev].get(),
116  m_most->update_fluxes(lev, time);
117  }
118  }
119 
120 #if defined(ERF_USE_WINDFARM)
121  if (solverChoice.windfarm_type != WindFarmType::None) {
122  advance_windfarm(Geom(lev), dt_lev, S_old,
123  U_old, V_old, W_old, vars_windfarm[lev], Nturb[lev], SMark[lev], time);
124  }
125 
126 #endif
127 
128  const BoxArray& ba = S_old.boxArray();
129  const DistributionMapping& dm = S_old.DistributionMap();
130 
131  int nvars = S_old.nComp();
132 
133  // Source array for conserved cell-centered quantities -- this will be filled
134  // in the call to make_sources in ERF_TI_slow_rhs_fun.H
135  MultiFab cc_source(ba,dm,nvars,1); cc_source.setVal(0.0);
136 
137  // Source arrays for momenta -- these will be filled
138  // in the call to make_mom_sources in ERF_TI_slow_rhs_fun.H
139  BoxArray ba_x(ba); ba_x.surroundingNodes(0);
140  MultiFab xmom_source(ba_x,dm,nvars,1); xmom_source.setVal(0.0);
141 
142  BoxArray ba_y(ba); ba_y.surroundingNodes(1);
143  MultiFab ymom_source(ba_y,dm,nvars,1); ymom_source.setVal(0.0);
144 
145  BoxArray ba_z(ba); ba_z.surroundingNodes(2);
146  MultiFab zmom_source(ba_z,dm,nvars,1); zmom_source.setVal(0.0);
147 
148  // We don't need to call FillPatch on cons_mf because we have fillpatch'ed S_old above
149  MultiFab cons_mf(ba,dm,nvars,S_old.nGrowVect());
150  MultiFab::Copy(cons_mf,S_old,0,0,S_old.nComp(),S_old.nGrowVect());
151 
152  amrex::Vector<MultiFab> state_old;
153  amrex::Vector<MultiFab> state_new;
154 
155  // **************************************************************************************
156  // Here we define state_old and state_new which are to be advanced
157  // **************************************************************************************
158  // Initial solution
159  // Note that "old" and "new" here are relative to each RK stage.
160  state_old.push_back(MultiFab(cons_mf , amrex::make_alias, 0, nvars)); // cons
161  state_old.push_back(MultiFab(rU_old[lev], amrex::make_alias, 0, 1)); // xmom
162  state_old.push_back(MultiFab(rV_old[lev], amrex::make_alias, 0, 1)); // ymom
163  state_old.push_back(MultiFab(rW_old[lev], amrex::make_alias, 0, 1)); // zmom
164 
165  // Final solution
166  // state_new at the end of the last RK stage holds the t^{n+1} data
167  state_new.push_back(MultiFab(S_new , amrex::make_alias, 0, nvars)); // cons
168  state_new.push_back(MultiFab(rU_new[lev], amrex::make_alias, 0, 1)); // xmom
169  state_new.push_back(MultiFab(rV_new[lev], amrex::make_alias, 0, 1)); // ymom
170  state_new.push_back(MultiFab(rW_new[lev], amrex::make_alias, 0, 1)); // zmom
171 
172  // **************************************************************************************
173  // Update the dycore
174  // **************************************************************************************
175  advance_dycore(lev, state_old, state_new,
176  U_old, V_old, W_old,
177  U_new, V_new, W_new,
178  cc_source, xmom_source, ymom_source, zmom_source,
179  Geom(lev), dt_lev, time);
180 
181  // **************************************************************************************
182  // Update the microphysics (moisture)
183  // **************************************************************************************
184  advance_microphysics(lev, S_new, dt_lev, iteration, time);
185 
186  // **************************************************************************************
187  // Update the land surface model
188  // **************************************************************************************
189  advance_lsm(lev, S_new, dt_lev);
190 
191 #if defined(ERF_USE_RRTMGP)
192  // **************************************************************************************
193  // Update the radiation
194  // **************************************************************************************
195  advance_radiation(lev, S_new, dt_lev);
196 #endif
197 
198 #ifdef ERF_USE_PARTICLES
199  // **************************************************************************************
200  // Update the particle positions
201  // **************************************************************************************
202  evolveTracers( lev, dt_lev, vars_new, z_phys_nd );
203 #endif
204 
205  // ***********************************************************************************************
206  // Impose domain boundary conditions here so that in FillPatching the fine data we won't
207  // need to re-fill these
208  // ***********************************************************************************************
209  if (lev < finest_level) {
210  IntVect ngvect_vels = vars_new[lev][Vars::xvel].nGrowVect();
211  (*physbcs_cons[lev])(vars_new[lev][Vars::cons],0,vars_new[lev][Vars::cons].nComp(),
212  vars_new[lev][Vars::cons].nGrowVect(),time,BCVars::cons_bc,true);
213  (*physbcs_u[lev])(vars_new[lev][Vars::xvel],0,1,ngvect_vels,time,BCVars::xvel_bc,true);
214  (*physbcs_v[lev])(vars_new[lev][Vars::yvel],0,1,ngvect_vels,time,BCVars::yvel_bc,true);
215  (*physbcs_w[lev])(vars_new[lev][Vars::zvel], vars_new[lev][Vars::xvel], vars_new[lev][Vars::yvel],
216  ngvect_vels,time,BCVars::zvel_bc,true);
217  }
218 
219  // **************************************************************************************
220  // Register old and new coarse data if we are at a level less than the finest level
221  // **************************************************************************************
222  if (lev < finest_level)
223  {
224  if (cf_width > 0) {
225  // We must fill the ghost cells of these so that the parallel copy works correctly
226  state_old[IntVars::cons].FillBoundary(geom[lev].periodicity());
227  state_new[IntVars::cons].FillBoundary(geom[lev].periodicity());
228  FPr_c[lev].RegisterCoarseData({&state_old[IntVars::cons], &state_new[IntVars::cons]},
229  {time, time + dt_lev});
230  }
231 
232  if (cf_width >= 0) {
233  // We must fill the ghost cells of these so that the parallel copy works correctly
234  state_old[IntVars::xmom].FillBoundary(geom[lev].periodicity());
235  state_new[IntVars::xmom].FillBoundary(geom[lev].periodicity());
236  FPr_u[lev].RegisterCoarseData({&state_old[IntVars::xmom], &state_new[IntVars::xmom]},
237  {time, time + dt_lev});
238 
239  state_old[IntVars::ymom].FillBoundary(geom[lev].periodicity());
240  state_new[IntVars::ymom].FillBoundary(geom[lev].periodicity());
241  FPr_v[lev].RegisterCoarseData({&state_old[IntVars::ymom], &state_new[IntVars::ymom]},
242  {time, time + dt_lev});
243 
244  state_old[IntVars::zmom].FillBoundary(geom[lev].periodicity());
245  state_new[IntVars::zmom].FillBoundary(geom[lev].periodicity());
246  FPr_w[lev].RegisterCoarseData({&state_old[IntVars::zmom], &state_new[IntVars::zmom]},
247  {time, time + dt_lev});
248  }
249 
250  //
251  // Now create a MultiFab that holds (S_new - S_old) / dt from the coarse level interpolated
252  // on to the coarse/fine boundary at the fine resolution
253  //
254  Interpolater* mapper_f = &face_cons_linear_interp;
255 
256  // PhysBCFunctNoOp null_bc;
257  // MultiFab tempx(vars_new[lev+1][Vars::xvel].boxArray(),vars_new[lev+1][Vars::xvel].DistributionMap(),1,0);
258  // tempx.setVal(0.0);
259  // xmom_crse_rhs[lev+1].setVal(0.0);
260  // FPr_u[lev].FillSet(tempx , time , null_bc, domain_bcs_type);
261  // FPr_u[lev].FillSet(xmom_crse_rhs[lev+1], time+dt_lev, null_bc, domain_bcs_type);
262  // MultiFab::Subtract(xmom_crse_rhs[lev+1],tempx,0,0,1,IntVect{0});
263  // xmom_crse_rhs[lev+1].mult(1.0/dt_lev,0,1,0);
264 
265  // MultiFab tempy(vars_new[lev+1][Vars::yvel].boxArray(),vars_new[lev+1][Vars::yvel].DistributionMap(),1,0);
266  // tempy.setVal(0.0);
267  // ymom_crse_rhs[lev+1].setVal(0.0);
268  // FPr_v[lev].FillSet(tempy , time , null_bc, domain_bcs_type);
269  // FPr_v[lev].FillSet(ymom_crse_rhs[lev+1], time+dt_lev, null_bc, domain_bcs_type);
270  // MultiFab::Subtract(ymom_crse_rhs[lev+1],tempy,0,0,1,IntVect{0});
271  // ymom_crse_rhs[lev+1].mult(1.0/dt_lev,0,1,0);
272 
273  MultiFab temp_state(zmom_crse_rhs[lev+1].boxArray(),zmom_crse_rhs[lev+1].DistributionMap(),1,0);
274  InterpFromCoarseLevel(temp_state, IntVect{0}, IntVect{0}, state_old[IntVars::zmom], 0, 0, 1,
275  geom[lev], geom[lev+1], refRatio(lev), mapper_f, domain_bcs_type, BCVars::zvel_bc);
276  InterpFromCoarseLevel(zmom_crse_rhs[lev+1], IntVect{0}, IntVect{0}, state_new[IntVars::zmom], 0, 0, 1,
277  geom[lev], geom[lev+1], refRatio(lev), mapper_f, domain_bcs_type, BCVars::zvel_bc);
278  MultiFab::Subtract(zmom_crse_rhs[lev+1],temp_state,0,0,1,IntVect{0});
279  zmom_crse_rhs[lev+1].mult(1.0/dt_lev,0,1,0);
280  }
281 
282  // ***********************************************************************************************
283  // Update the time averaged velocities if they are requested
284  // ***********************************************************************************************
286  Time_Avg_Vel_atCC(dt[lev], t_avg_cnt[lev], vel_t_avg[lev].get(), U_new, V_new, W_new);
287  }
288 }
@ nvars
Definition: ERF_DataStruct.H:70
#define Rho_comp
Definition: ERF_IndexDefines.H:36
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:37
#define RhoQ1_comp
Definition: ERF_IndexDefines.H:42
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)
amrex::Vector< amrex::MultiFab > rU_new
Definition: ERF.H:766
std::unique_ptr< ABLMost > m_most
Definition: ERF.H:1170
amrex::Vector< ERFFillPatcher > FPr_u
Definition: ERF.H:811
amrex::Vector< amrex::Vector< amrex::MultiFab > > vars_new
Definition: ERF.H:741
amrex::Vector< ERFFillPatcher > FPr_v
Definition: ERF.H:812
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_cons > > physbcs_cons
Definition: ERF.H:753
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_cc
Definition: ERF.H:838
static SolverChoice solverChoice
Definition: ERF.H:1012
amrex::Vector< ERFFillPatcher > FPr_c
Definition: ERF.H:810
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vel_t_avg
Definition: ERF.H:745
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_w > > physbcs_w
Definition: ERF.H:756
amrex::Vector< amrex::MultiFab > base_state
Definition: ERF.H:870
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Qv_prim
Definition: ERF.H:761
amrex::Vector< amrex::MultiFab > rV_new
Definition: ERF.H:768
amrex::Vector< amrex::BCRec > domain_bcs_type
Definition: ERF.H:886
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Qr_prim
Definition: ERF.H:762
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_u > > physbcs_u
Definition: ERF.H:754
amrex::Vector< amrex::Real > t_avg_cnt
Definition: ERF.H:746
amrex::Vector< amrex::MultiFab > rU_old
Definition: ERF.H:765
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Theta_prim
Definition: ERF.H:760
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_v > > physbcs_v
Definition: ERF.H:755
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_nd
Definition: ERF.H:837
amrex::Vector< amrex::MultiFab > rW_new
Definition: ERF.H:770
amrex::Vector< amrex::MultiFab > zmom_crse_rhs
Definition: ERF.H:774
TurbulentPerturbation turbPert
Definition: ERF.H:1015
amrex::Vector< amrex::MultiFab > rW_old
Definition: ERF.H:769
void advance_lsm(int lev, amrex::MultiFab &, const amrex::Real &dt_advance)
Definition: ERF_AdvanceLSM.cpp:5
amrex::Vector< ERFFillPatcher > FPr_w
Definition: ERF.H:813
amrex::Vector< amrex::Real > dt
Definition: ERF.H:735
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:808
amrex::GpuArray< ERF_BC, AMREX_SPACEDIM *2 > phys_bc_type
Definition: ERF.H:899
amrex::Vector< amrex::MultiFab > rV_old
Definition: ERF.H:767
amrex::Vector< amrex::Vector< amrex::MultiFab > > vars_old
Definition: ERF.H:742
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::Geometry fine_geom, amrex::Real dt, amrex::Real time)
Definition: ERF_AdvanceDycore.cpp:37
void FillPatch(int lev, amrex::Real time, const amrex::Vector< amrex::MultiFab * > &mfs_vel, bool cons_only=false)
@ zvel_bc
Definition: ERF_IndexDefines.H:90
@ yvel_bc
Definition: ERF_IndexDefines.H:89
@ cons_bc
Definition: ERF_IndexDefines.H:76
@ xvel_bc
Definition: ERF_IndexDefines.H:88
@ ymom
Definition: ERF_IndexDefines.H:141
@ cons
Definition: ERF_IndexDefines.H:139
@ zmom
Definition: ERF_IndexDefines.H:142
@ xmom
Definition: ERF_IndexDefines.H:140
@ xvel
Definition: ERF_IndexDefines.H:130
@ cons
Definition: ERF_IndexDefines.H:129
@ zvel
Definition: ERF_IndexDefines.H:132
@ yvel
Definition: ERF_IndexDefines.H:131
int RhoQr_comp
Definition: ERF_DataStruct.H:687
int RhoQc_comp
Definition: ERF_DataStruct.H:681
int RhoQv_comp
Definition: ERF_DataStruct.H:680
MoistureType moisture_type
Definition: ERF_DataStruct.H:664
PerturbationType pert_type
Definition: ERF_DataStruct.H:654
WindFarmType windfarm_type
Definition: ERF_DataStruct.H:665
bool time_avg_vel
Definition: ERF_DataStruct.H:651
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:184
amrex::MultiFab pb_cell
Definition: ERF_TurbPertStruct.H:536
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:245
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::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
46 {
47  BL_PROFILE_VAR("erf_advance_dycore()",erf_advance_dycore);
48 
49  const Box& domain = fine_geom.Domain();
50 
54 
55  MultiFab r_hse (base_state[level], make_alias, BaseState::r0_comp , 1);
56  MultiFab p_hse (base_state[level], make_alias, BaseState::p0_comp , 1);
57  MultiFab pi_hse(base_state[level], make_alias, BaseState::pi0_comp, 1);
58 
59  // These pointers are used in the MRI utility functions
60  MultiFab* r0 = &r_hse;
61  MultiFab* p0 = &p_hse;
62  MultiFab* pi0 = &pi_hse;
63 
64  Real* dptr_rhotheta_src = solverChoice.custom_rhotheta_forcing ? d_rhotheta_src[level].data() : nullptr;
65  Real* dptr_rhoqt_src = solverChoice.custom_moisture_forcing ? d_rhoqt_src[level].data() : nullptr;
66  Real* dptr_wbar_sub = solverChoice.custom_w_subsidence ? d_w_subsid[level].data() : nullptr;
67 
68  // Turbulent Perturbation Pointer
69  //Real* dptr_rhotheta_src = solverChoice.pert_type ? d_rhotheta_src[level].data() : nullptr;
70 
71  Vector<Real*> d_rayleigh_ptrs_at_lev;
72  d_rayleigh_ptrs_at_lev.resize(Rayleigh::nvars);
73  d_rayleigh_ptrs_at_lev[Rayleigh::ubar] = solverChoice.rayleigh_damp_U ? d_rayleigh_ptrs[level][Rayleigh::ubar].data() : nullptr;
74  d_rayleigh_ptrs_at_lev[Rayleigh::vbar] = solverChoice.rayleigh_damp_V ? d_rayleigh_ptrs[level][Rayleigh::vbar].data() : nullptr;
75  d_rayleigh_ptrs_at_lev[Rayleigh::wbar] = solverChoice.rayleigh_damp_W ? d_rayleigh_ptrs[level][Rayleigh::wbar].data() : nullptr;
76  d_rayleigh_ptrs_at_lev[Rayleigh::thetabar] = solverChoice.rayleigh_damp_T ? d_rayleigh_ptrs[level][Rayleigh::thetabar].data() : nullptr;
77 
78  Vector<Real*> d_sponge_ptrs_at_lev;
79  if(sc.sponge_type=="input_sponge")
80  {
81  d_sponge_ptrs_at_lev.resize(Sponge::nvars_sponge);
82  d_sponge_ptrs_at_lev[Sponge::ubar_sponge] = d_sponge_ptrs[level][Sponge::ubar_sponge].data();
83  d_sponge_ptrs_at_lev[Sponge::vbar_sponge] = d_sponge_ptrs[level][Sponge::vbar_sponge].data();
84  }
85 
86  bool l_use_terrain = (SolverChoice::terrain_type != TerrainType::None);
87  bool l_use_diff = ( (dc.molec_diff_type != MolecDiffType::None) ||
88  (tc.les_type != LESType::None) ||
89  (tc.pbl_type != PBLType::None) );
90  bool l_use_kturb = ( (tc.les_type != LESType::None) ||
91  (tc.pbl_type != PBLType::None) );
92  bool l_use_moisture = ( solverChoice.moisture_type != MoistureType::None );
93  bool l_implicit_substepping = ( solverChoice.substepping_type[level] == SubsteppingType::Implicit );
94 
95  const bool use_most = (m_most != nullptr);
96  const bool exp_most = (solverChoice.use_explicit_most);
97  amrex::ignore_unused(use_most);
98 
99  const BoxArray& ba = state_old[IntVars::cons].boxArray();
100  const BoxArray& ba_z = zvel_old.boxArray();
101  const DistributionMapping& dm = state_old[IntVars::cons].DistributionMap();
102 
103  int num_prim = state_old[IntVars::cons].nComp() - 1;
104 
105  MultiFab S_prim (ba , dm, num_prim, state_old[IntVars::cons].nGrowVect());
106  MultiFab pi_stage (ba , dm, 1, state_old[IntVars::cons].nGrowVect());
107  MultiFab fast_coeffs(ba_z, dm, 5, 0);
108  MultiFab* eddyDiffs = eddyDiffs_lev[level].get();
109  MultiFab* SmnSmn = SmnSmn_lev[level].get();
110 
111  // **************************************************************************************
112  // Compute strain for use in slow RHS, Smagorinsky model, and MOST
113  // **************************************************************************************
114  {
115  BL_PROFILE("erf_advance_strain");
116  if (l_use_diff) {
117 
118  const BCRec* bc_ptr_h = domain_bcs_type.data();
119  const GpuArray<Real, AMREX_SPACEDIM> dxInv = fine_geom.InvCellSizeArray();
120 
121 #ifdef _OPENMP
122 #pragma omp parallel if (Gpu::notInLaunchRegion())
123 #endif
124  for ( MFIter mfi(state_new[IntVars::cons],TileNoZ()); mfi.isValid(); ++mfi)
125  {
126  Box bxcc = mfi.growntilebox(IntVect(1,1,0));
127  Box tbxxy = mfi.tilebox(IntVect(1,1,0),IntVect(1,1,0));
128  Box tbxxz = mfi.tilebox(IntVect(1,0,1),IntVect(1,1,0));
129  Box tbxyz = mfi.tilebox(IntVect(0,1,1),IntVect(1,1,0));
130 
131  if (bxcc.smallEnd(2) != domain.smallEnd(2)) {
132  bxcc.growLo(2,1);
133  tbxxy.growLo(2,1);
134  tbxxz.growLo(2,1);
135  tbxyz.growLo(2,1);
136  }
137 
138  if (bxcc.bigEnd(2) != domain.bigEnd(2)) {
139  bxcc.growHi(2,1);
140  tbxxy.growHi(2,1);
141  tbxxz.growHi(2,1);
142  tbxyz.growHi(2,1);
143  }
144 
145  const Array4<const Real> & u = xvel_old.array(mfi);
146  const Array4<const Real> & v = yvel_old.array(mfi);
147  const Array4<const Real> & w = zvel_old.array(mfi);
148 
149  Array4<Real> tau11 = Tau11_lev[level].get()->array(mfi);
150  Array4<Real> tau22 = Tau22_lev[level].get()->array(mfi);
151  Array4<Real> tau33 = Tau33_lev[level].get()->array(mfi);
152  Array4<Real> tau12 = Tau12_lev[level].get()->array(mfi);
153  Array4<Real> tau13 = Tau13_lev[level].get()->array(mfi);
154  Array4<Real> tau23 = Tau23_lev[level].get()->array(mfi);
155 
156  Array4<Real> tau21 = l_use_terrain ? Tau21_lev[level].get()->array(mfi) : Array4<Real>{};
157  Array4<Real> tau31 = l_use_terrain ? Tau31_lev[level].get()->array(mfi) : Array4<Real>{};
158  Array4<Real> tau32 = l_use_terrain ? Tau32_lev[level].get()->array(mfi) : Array4<Real>{};
159  const Array4<const Real>& z_nd = l_use_terrain ? z_phys_nd[level]->const_array(mfi) : Array4<const Real>{};
160 
161  const Array4<const Real> mf_m = mapfac_m[level]->array(mfi);
162  const Array4<const Real> mf_u = mapfac_u[level]->array(mfi);
163  const Array4<const Real> mf_v = mapfac_v[level]->array(mfi);
164 
165  if (l_use_terrain) {
166  ComputeStrain_T(bxcc, tbxxy, tbxxz, tbxyz, domain,
167  u, v, w,
168  tau11, tau22, tau33,
169  tau12, tau13,
170  tau21, tau23,
171  tau31, tau32,
172  z_nd, detJ_cc[level]->const_array(mfi), bc_ptr_h, dxInv,
173  mf_m, mf_u, mf_v);
174  } else {
175  ComputeStrain_N(bxcc, tbxxy, tbxxz, tbxyz, domain,
176  u, v, w,
177  tau11, tau22, tau33,
178  tau12, tau13, tau23,
179  bc_ptr_h, dxInv,
180  mf_m, mf_u, mf_v);
181  }
182  } // mfi
183  } // l_use_diff
184  } // profile
185 
186 #include "ERF_TI_utils.H"
187 
188  // Additional SFS quantities, calculated once per timestep
189  MultiFab* Hfx1 = SFS_hfx1_lev[level].get();
190  MultiFab* Hfx2 = SFS_hfx2_lev[level].get();
191  MultiFab* Hfx3 = SFS_hfx3_lev[level].get();
192  MultiFab* Q1fx1 = SFS_q1fx1_lev[level].get();
193  MultiFab* Q1fx2 = SFS_q1fx2_lev[level].get();
194  MultiFab* Q1fx3 = SFS_q1fx3_lev[level].get();
195  MultiFab* Q2fx3 = SFS_q2fx3_lev[level].get();
196  MultiFab* Diss = SFS_diss_lev[level].get();
197 
198  // *************************************************************************
199  // Calculate cell-centered eddy viscosity & diffusivities
200  //
201  // Notes -- we fill all the data in ghost cells before calling this so
202  // that we can fill the eddy viscosity in the ghost regions and
203  // not have to call a boundary filler on this data itself
204  //
205  // LES - updates both horizontal and vertical eddy viscosity components
206  // PBL - only updates vertical eddy viscosity components so horizontal
207  // components come from the LES model or are left as zero.
208  // *************************************************************************
209  if (l_use_kturb)
210  {
211  // NOTE: state_new transfers to state_old for PBL (due to ptr swap in advance)
212  const BCRec* bc_ptr_h = domain_bcs_type.data();
213  ComputeTurbulentViscosity(xvel_old, yvel_old,
214  *Tau11_lev[level].get(), *Tau22_lev[level].get(), *Tau33_lev[level].get(),
215  *Tau12_lev[level].get(), *Tau13_lev[level].get(), *Tau23_lev[level].get(),
216  state_old[IntVars::cons],
217  *eddyDiffs, *Hfx1, *Hfx2, *Hfx3, *Diss, // to be updated
218  fine_geom, *mapfac_u[level], *mapfac_v[level],
219  z_phys_nd[level], solverChoice,
220  m_most, exp_most, l_use_moisture, level, bc_ptr_h);
221  }
222 
223  // ***********************************************************************************************
224  // Update user-defined source terms -- these are defined once per time step (not per RK stage)
225  // ***********************************************************************************************
227  prob->update_rhotheta_sources(old_time,
228  h_rhotheta_src[level], d_rhotheta_src[level],
229  fine_geom, z_phys_cc[level]);
230  }
231 
233  prob->update_rhoqt_sources(old_time,
234  h_rhoqt_src[level], d_rhoqt_src[level],
235  fine_geom, z_phys_cc[level]);
236  }
237 
239  prob->update_geostrophic_profile(old_time,
240  h_u_geos[level], d_u_geos[level],
241  h_v_geos[level], d_v_geos[level],
242  fine_geom, z_phys_cc[level]);
243  }
244 
245  // ***********************************************************************************************
246  // Convert old velocity available on faces to old momentum on faces to be used in time integration
247  // ***********************************************************************************************
248  MultiFab density(state_old[IntVars::cons], make_alias, Rho_comp, 1);
249 
250  //
251  // This is an optimization since we won't need more than one ghost
252  // cell of momentum in the integrator if not using numerical diffusion
253  //
254  IntVect ngu = (!solverChoice.use_num_diff) ? IntVect(1,1,1) : xvel_old.nGrowVect();
255  IntVect ngv = (!solverChoice.use_num_diff) ? IntVect(1,1,1) : yvel_old.nGrowVect();
256  IntVect ngw = (!solverChoice.use_num_diff) ? IntVect(1,1,0) : zvel_old.nGrowVect();
257 
258  VelocityToMomentum(xvel_old, ngu, yvel_old, ngv, zvel_old, ngw, density,
259  state_old[IntVars::xmom],
260  state_old[IntVars::ymom],
261  state_old[IntVars::zmom],
262  domain, domain_bcs_type);
263 
264  MultiFab::Copy(xvel_new,xvel_old,0,0,1,xvel_old.nGrowVect());
265  MultiFab::Copy(yvel_new,yvel_old,0,0,1,yvel_old.nGrowVect());
266  MultiFab::Copy(zvel_new,zvel_old,0,0,1,zvel_old.nGrowVect());
267 
268  bool fast_only = false;
269  bool vel_and_mom_synced = true;
270 
271  apply_bcs(state_old, old_time,
272  state_old[IntVars::cons].nGrow(), state_old[IntVars::xmom].nGrow(),
273  fast_only, vel_and_mom_synced);
274  cons_to_prim(state_old[IntVars::cons], state_old[IntVars::cons].nGrow());
275 
276 #include "ERF_TI_no_substep_fun.H"
277 #include "ERF_TI_substep_fun.H"
278 #include "ERF_TI_slow_rhs_fun.H"
279 
280  // ***************************************************************************************
281  // Setup the integrator and integrate for a single timestep
282  // **************************************************************************************
283  MRISplitIntegrator<Vector<MultiFab> >& mri_integrator = *mri_integrator_mem[level];
284 
285  // Define rhs and 'post update' utility function that is called after calculating
286  // any state data (e.g. at RK stages or at the end of a timestep)
287  mri_integrator.set_slow_rhs_pre(slow_rhs_fun_pre);
288  mri_integrator.set_slow_rhs_post(slow_rhs_fun_post);
289 
290  if (solverChoice.anelastic[level]) {
291  mri_integrator.set_slow_rhs_inc(slow_rhs_fun_inc);
292  }
293 
294  mri_integrator.set_fast_rhs(fast_rhs_fun);
296  mri_integrator.set_no_substep(no_substep_fun);
297 
298  mri_integrator.advance(state_old, state_new, old_time, dt_advance);
299 
300  if (verbose) Print() << "Done with advance_dycore at level " << level << std::endl;
301 }
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 BCRec *bc_ptr, const GpuArray< Real, AMREX_SPACEDIM > &dxInv, const Array4< const Real > &mf_m, const Array4< const Real > &mf_u, const Array4< const Real > &mf_v)
Definition: ERF_ComputeStrain_N.cpp:28
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 > &tau13, Array4< Real > &tau21, Array4< Real > &tau23, Array4< Real > &tau31, Array4< Real > &tau32, const Array4< const Real > &z_nd, const Array4< const Real > &detJ, const BCRec *bc_ptr, const GpuArray< Real, AMREX_SPACEDIM > &dxInv, const Array4< const Real > &mf_m, const Array4< const Real > &mf_u, const Array4< const Real > &mf_v)
Definition: ERF_ComputeStrain_T.cpp:33
void ComputeTurbulentViscosity(const MultiFab &xvel, const MultiFab &yvel, const MultiFab &Tau11, const MultiFab &Tau22, const MultiFab &Tau33, const MultiFab &Tau12, const MultiFab &Tau13, const MultiFab &Tau23, const MultiFab &cons_in, MultiFab &eddyViscosity, MultiFab &Hfx1, MultiFab &Hfx2, MultiFab &Hfx3, MultiFab &Diss, const Geometry &geom, const MultiFab &mapfac_u, const MultiFab &mapfac_v, const std::unique_ptr< MultiFab > &z_phys_nd, const SolverChoice &solverChoice, std::unique_ptr< ABLMost > &most, const bool &exp_most, const bool &use_moisture, int level, const BCRec *bc_ptr, bool vert_only)
Definition: ERF_ComputeTurbulentViscosity.cpp:436
@ ubar
Definition: ERF_DataStruct.H:70
@ wbar
Definition: ERF_DataStruct.H:70
@ vbar
Definition: ERF_DataStruct.H:70
@ thetabar
Definition: ERF_DataStruct.H:70
@ nvars_sponge
Definition: ERF_DataStruct.H:75
@ vbar_sponge
Definition: ERF_DataStruct.H:75
@ ubar_sponge
Definition: ERF_DataStruct.H:75
auto no_substep_fun
Definition: ERF_TI_no_substep_fun.H:4
auto slow_rhs_fun_inc
Definition: ERF_TI_slow_rhs_fun.H:395
auto slow_rhs_fun_pre
Definition: ERF_TI_slow_rhs_fun.H:6
auto slow_rhs_fun_post
Definition: ERF_TI_slow_rhs_fun.H:301
auto fast_rhs_fun
Definition: ERF_TI_substep_fun.H:4
auto apply_bcs
Definition: ERF_TI_utils.H:50
auto cons_to_prim
Definition: ERF_TI_utils.H:4
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau23_lev
Definition: ERF.H:819
amrex::Vector< std::unique_ptr< MRISplitIntegrator< amrex::Vector< amrex::MultiFab > > > > mri_integrator_mem
Definition: ERF.H:748
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_rhotheta_src
Definition: ERF.H:1119
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q1fx3_lev
Definition: ERF.H:830
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_hfx3_lev
Definition: ERF.H:828
amrex::Vector< std::unique_ptr< amrex::MultiFab > > mapfac_u
Definition: ERF.H:864
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau31_lev
Definition: ERF.H:818
amrex::Vector< std::unique_ptr< amrex::MultiFab > > mapfac_m
Definition: ERF.H:863
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_hfx1_lev
Definition: ERF.H:828
amrex::Vector< std::unique_ptr< amrex::MultiFab > > detJ_cc
Definition: ERF.H:840
amrex::Vector< std::unique_ptr< amrex::MultiFab > > eddyDiffs_lev
Definition: ERF.H:820
amrex::Vector< amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > > d_sponge_ptrs
Definition: ERF.H:1152
amrex::Vector< amrex::Vector< amrex::Real > > h_rhoqt_src
Definition: ERF.H:1121
amrex::Vector< long > dt_mri_ratio
Definition: ERF.H:736
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q2fx3_lev
Definition: ERF.H:831
static int verbose
Definition: ERF.H:1047
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau13_lev
Definition: ERF.H:818
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q1fx2_lev
Definition: ERF.H:830
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau21_lev
Definition: ERF.H:817
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau33_lev
Definition: ERF.H:816
std::unique_ptr< ProblemBase > prob
Definition: ERF.H:723
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_diss_lev
Definition: ERF.H:829
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_v_geos
Definition: ERF.H:1131
amrex::Vector< amrex::Vector< amrex::Real > > h_v_geos
Definition: ERF.H:1130
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_rhoqt_src
Definition: ERF.H:1122
amrex::Vector< amrex::Vector< amrex::Real > > h_rhotheta_src
Definition: ERF.H:1118
amrex::Vector< amrex::Vector< amrex::Real > > h_u_geos
Definition: ERF.H:1127
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SmnSmn_lev
Definition: ERF.H:821
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau32_lev
Definition: ERF.H:819
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_u_geos
Definition: ERF.H:1128
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_w_subsid
Definition: ERF.H:1125
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_hfx2_lev
Definition: ERF.H:828
static int fixed_mri_dt_ratio
Definition: ERF.H:938
amrex::Vector< amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > > d_rayleigh_ptrs
Definition: ERF.H:1149
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau12_lev
Definition: ERF.H:817
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q1fx1_lev
Definition: ERF.H:830
amrex::Vector< std::unique_ptr< amrex::MultiFab > > mapfac_v
Definition: ERF.H:865
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau11_lev
Definition: ERF.H:816
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau22_lev
Definition: ERF.H:816
Definition: ERF_MRI.H:16
void set_slow_rhs_pre(std::function< void(T &, T &, T &, T &, const amrex::Real, const amrex::Real, const amrex::Real, const int)> F)
Definition: ERF_MRI.H:134
void set_no_substep(std::function< void(T &, T &, T &, amrex::Real, amrex::Real, int)> F)
Definition: ERF_MRI.H:164
void set_slow_rhs_inc(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_fast_rhs(std::function< void(int, int, int, T &, const T &, T &, T &, T &, const amrex::Real, const amrex::Real, const amrex::Real, const amrex::Real)> F)
Definition: ERF_MRI.H:147
void set_slow_fast_timestep_ratio(const int timestep_ratio=1)
Definition: ERF_MRI.H:154
amrex::Real advance(T &S_old, T &S_new, amrex::Real time, const amrex::Real time_step)
Definition: ERF_MRI.H:174
void set_slow_rhs_post(std::function< void(T &, T &, T &, T &, T &, const amrex::Real, const amrex::Real, const amrex::Real, const int)> F)
Definition: ERF_MRI.H:142
@ pi0_comp
Definition: ERF_IndexDefines.H:65
@ p0_comp
Definition: ERF_IndexDefines.H:64
@ r0_comp
Definition: ERF_IndexDefines.H:63
Definition: ERF_DiffStruct.H:19
MolecDiffType molec_diff_type
Definition: ERF_DiffStruct.H:84
bool rayleigh_damp_T
Definition: ERF_DataStruct.H:608
bool use_explicit_most
Definition: ERF_DataStruct.H:645
bool rayleigh_damp_V
Definition: ERF_DataStruct.H:606
DiffChoice diffChoice
Definition: ERF_DataStruct.H:579
bool custom_rhotheta_forcing
Definition: ERF_DataStruct.H:634
bool custom_w_subsidence
Definition: ERF_DataStruct.H:636
bool rayleigh_damp_U
Definition: ERF_DataStruct.H:605
bool custom_geostrophic_profile
Definition: ERF_DataStruct.H:637
amrex::Vector< SubsteppingType > substepping_type
Definition: ERF_DataStruct.H:588
bool use_num_diff
Definition: ERF_DataStruct.H:657
bool custom_moisture_forcing
Definition: ERF_DataStruct.H:635
amrex::Vector< TurbChoice > turbChoice
Definition: ERF_DataStruct.H:581
amrex::Vector< int > anelastic
Definition: ERF_DataStruct.H:589
static TerrainType terrain_type
Definition: ERF_DataStruct.H:567
bool rayleigh_damp_W
Definition: ERF_DataStruct.H:607
SpongeChoice spongeChoice
Definition: ERF_DataStruct.H:580
Definition: ERF_SpongeStruct.H:15
std::string sponge_type
Definition: ERF_SpongeStruct.H:61
Definition: ERF_TurbStruct.H:31
PBLType pbl_type
Definition: ERF_TurbStruct.H:201
LESType les_type
Definition: ERF_TurbStruct.H:175
Here is the call graph for this function:

◆ advance_lsm()

void ERF::advance_lsm ( int  lev,
amrex::MultiFab &  ,
const amrex::Real &  dt_advance 
)
8 {
9  if (solverChoice.lsm_type != LandSurfaceType::None) {
10  lsm.Advance(lev, dt_advance);
11  }
12 }
LandSurface lsm
Definition: ERF.H:792
void Advance(const int &lev, const amrex::Real &dt_advance)
Definition: ERF_LandSurface.H:51
LandSurfaceType lsm_type
Definition: ERF_DataStruct.H:667

◆ 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->Update_Micro_Vars_Lev(lev, cons);
13  micro->Advance(lev, dt_advance, iteration, time, solverChoice, vars_new, z_phys_nd, phys_bc_type);
14  micro->Update_State_Vars_Lev(lev, cons);
15  }
16 }
std::unique_ptr< Microphysics > micro
Definition: ERF.H:776

◆ appendPlotVariables()

void ERF::appendPlotVariables ( const std::string &  pp_plot_var_names,
amrex::Vector< std::string > &  plot_var_names 
)
private
129 {
130  ParmParse pp(pp_prefix);
131 
132  Vector<std::string> plot_var_names(0);
133  if (pp.contains(pp_plot_var_names.c_str())) {
134  std::string nm;
135  int nPltVars = pp.countval(pp_plot_var_names.c_str());
136  for (int i = 0; i < nPltVars; i++) {
137  pp.get(pp_plot_var_names.c_str(), nm, i);
138  // Add the named variable to our list of plot variables
139  // if it is not already in the list
140  if (!containerHasElement(plot_var_names, nm)) {
141  plot_var_names.push_back(nm);
142  }
143  }
144  }
145 
146  Vector<std::string> tmp_plot_names(0);
147 #ifdef ERF_USE_PARTICLES
148  Vector<std::string> particle_mesh_plot_names;
149  particleData.GetMeshPlotVarNames( particle_mesh_plot_names );
150  for (int i = 0; i < particle_mesh_plot_names.size(); i++) {
151  std::string tmp(particle_mesh_plot_names[i]);
152  if (containerHasElement(plot_var_names, tmp) ) {
153  tmp_plot_names.push_back(tmp);
154  }
155  }
156 #endif
157 
158  for (int i = 0; i < tmp_plot_names.size(); i++) {
159  a_plot_var_names.push_back( tmp_plot_names[i] );
160  }
161 
162  // Finally, check to see if we found all the requested variables
163  for (const auto& plot_name : plot_var_names) {
164  if (!containerHasElement(a_plot_var_names, plot_name)) {
165  if (amrex::ParallelDescriptor::IOProcessor()) {
166  Warning("\nWARNING: Requested to plot variable '" + plot_name + "' but it is not available");
167  }
168  }
169  }
170 }
bool containerHasElement(const V &iterable, const T &query)
Definition: ERF_Plotfile.cpp:12
std::string pp_prefix
Definition: ERF.H:445
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
CouplingType coupling_type
Definition: ERF_DataStruct.H:663

◆ 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 pre-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> mapfac_arr = mapfac_m[lev]->const_array(mfi);
58  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
59  const Array4<const Real> detJ_arr = detJ_cc[lev]->const_array(mfi);
60  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
61  {
62  cons_arr(i,j,k,scomp+n) *= detJ_arr(i,j,k) / (mapfac_arr(i,j,0)*mapfac_arr(i,j,0));
63  });
64  } else {
65  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
66  {
67  cons_arr(i,j,k,scomp+n) /= (mapfac_arr(i,j,0)*mapfac_arr(i,j,0));
68  });
69  }
70  } // mfi
71  } // lev
72 
73  int fine_lev = crse_lev+1;
74 
75  if (interpolation_type == StateInterpType::Perturbational) {
76  // Make the fine rho and (rho theta) be perturbational
77  MultiFab::Divide(vars_new[fine_lev][Vars::cons],vars_new[fine_lev][Vars::cons],
78  Rho_comp,RhoTheta_comp,1,IntVect{0});
79  MultiFab::Subtract(vars_new[fine_lev][Vars::cons],base_state[fine_lev],
80  BaseState::r0_comp,Rho_comp,1,IntVect{0});
81  MultiFab::Subtract(vars_new[fine_lev][Vars::cons],base_state[fine_lev],
82  BaseState::th0_comp,RhoTheta_comp,1,IntVect{0});
83 
84  // Make the crse rho and (rho theta) be perturbational
85  MultiFab::Divide(vars_new[crse_lev][Vars::cons],vars_new[crse_lev][Vars::cons],
86  Rho_comp,RhoTheta_comp,1,IntVect{0});
87  MultiFab::Subtract(vars_new[crse_lev][Vars::cons],base_state[crse_lev],
88  BaseState::r0_comp,Rho_comp,1,IntVect{0});
89  MultiFab::Subtract(vars_new[crse_lev][Vars::cons],base_state[crse_lev],
90  BaseState::th0_comp,RhoTheta_comp,1,IntVect{0});
91  }
92 
93  average_down(vars_new[crse_lev+1][Vars::cons],vars_new[crse_lev ][Vars::cons],
94  scomp, ncomp, refRatio(crse_lev));
95 
96  if (interpolation_type == StateInterpType::Perturbational) {
97  // Restore the fine data to what it was
98  MultiFab::Add(vars_new[fine_lev][Vars::cons],base_state[fine_lev],
99  BaseState::r0_comp,Rho_comp,1,IntVect{0});
100  MultiFab::Add(vars_new[fine_lev][Vars::cons],base_state[fine_lev],
101  BaseState::th0_comp,RhoTheta_comp,1,IntVect{0});
102  MultiFab::Multiply(vars_new[fine_lev][Vars::cons],vars_new[fine_lev][Vars::cons],
103  Rho_comp,RhoTheta_comp,1,IntVect{0});
104 
105  // Make the crse data be full values not perturbational
106  MultiFab::Add(vars_new[crse_lev][Vars::cons],base_state[crse_lev],
107  BaseState::r0_comp,Rho_comp,1,IntVect{0});
108  MultiFab::Add(vars_new[crse_lev][Vars::cons],base_state[crse_lev],
109  BaseState::th0_comp,RhoTheta_comp,1,IntVect{0});
110  MultiFab::Multiply(vars_new[crse_lev][Vars::cons],vars_new[crse_lev][Vars::cons],
111  Rho_comp,RhoTheta_comp,1,IntVect{0});
112  }
113 
114  vars_new[crse_lev][Vars::cons].FillBoundary(geom[crse_lev].periodicity());
115 
116  // Here we multiply (rho S) by m^2 after average down
117  for (int lev = crse_lev; lev <= crse_lev+1; lev++) {
118  for (MFIter mfi(vars_new[lev][Vars::cons], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
119  const Box& bx = mfi.tilebox();
120  const Array4< Real> cons_arr = vars_new[lev][Vars::cons].array(mfi);
121  const Array4<const Real> mapfac_arr = mapfac_m[lev]->const_array(mfi);
122  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
123  const Array4<const Real> detJ_arr = detJ_cc[lev]->const_array(mfi);
124  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
125  {
126  cons_arr(i,j,k,scomp+n) *= (mapfac_arr(i,j,0)*mapfac_arr(i,j,0)) / detJ_arr(i,j,k);
127  });
128  } else {
129  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
130  {
131  cons_arr(i,j,k,scomp+n) *= (mapfac_arr(i,j,0)*mapfac_arr(i,j,0));
132  });
133  }
134  } // mfi
135  } // lev
136 
137  // ******************************************************************************************
138  // Now average down momenta.
139  // Note that vars_new holds velocities not momenta, but we want to do conservative
140  // averaging so we first convert to momentum, then average down, then convert
141  // back to velocities -- only on the valid region
142  // ******************************************************************************************
143  for (int lev = crse_lev; lev <= crse_lev+1; lev++)
144  {
145  // FillBoundary for density so we can go back and forth between velocity and momentum
146  vars_new[lev][Vars::cons].FillBoundary(geom[lev].periodicity());
147 
148  VelocityToMomentum(vars_new[lev][Vars::xvel], IntVect(0,0,0),
149  vars_new[lev][Vars::yvel], IntVect(0,0,0),
150  vars_new[lev][Vars::zvel], IntVect(0,0,0),
151  vars_new[lev][Vars::cons],
152  rU_new[lev],
153  rV_new[lev],
154  rW_new[lev],
155  Geom(lev).Domain(),
157  }
158 
159  average_down_faces(rU_new[crse_lev+1], rU_new[crse_lev], refRatio(crse_lev), geom[crse_lev]);
160  average_down_faces(rV_new[crse_lev+1], rV_new[crse_lev], refRatio(crse_lev), geom[crse_lev]);
161  average_down_faces(rW_new[crse_lev+1], rW_new[crse_lev], refRatio(crse_lev), geom[crse_lev]);
162 
163  for (int lev = crse_lev; lev <= crse_lev+1; lev++) {
165  vars_new[lev][Vars::yvel],
166  vars_new[lev][Vars::zvel],
167  vars_new[lev][Vars::cons],
168  rU_new[lev],
169  rV_new[lev],
170  rW_new[lev],
171  Geom(lev).Domain(),
173  }
174 }
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)
Definition: ERF_MomentumToVelocity.cpp:25
static StateInterpType interpolation_type
Definition: ERF.H:1061
@ th0_comp
Definition: ERF_IndexDefines.H:66
static MeshType mesh_type
Definition: ERF_DataStruct.H:570
Here is the call graph for this function:

◆ build_fine_mask()

MultiFab & ERF::build_fine_mask ( int  level)

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
430 {
431  // Mask for zeroing covered cells
432  AMREX_ASSERT(level > 0);
433 
434  const BoxArray& cba = grids[level-1];
435  const DistributionMapping& cdm = dmap[level-1];
436 
437  // TODO -- we should make a vector of these a member of ERF class
438  fine_mask.define(cba, cdm, 1, 0, MFInfo());
439  fine_mask.setVal(1.0);
440 
441  BoxArray fba = grids[level];
442  iMultiFab ifine_mask = makeFineMask(cba, cdm, fba, ref_ratio[level-1], 1, 0);
443 
444  const auto fma = fine_mask.arrays();
445  const auto ifma = ifine_mask.arrays();
446  ParallelFor(fine_mask, [=] AMREX_GPU_DEVICE(int bno, int i, int j, int k) noexcept
447  {
448  fma[bno](i,j,k) = ifma[bno](i,j,k);
449  });
450 
451  return fine_mask;
452 }
amrex::MultiFab fine_mask
Definition: ERF.H:1183

◆ ClearLevel()

void ERF::ClearLevel ( int  lev)
override
469 {
470  for (int var_idx = 0; var_idx < Vars::NumTypes; ++var_idx) {
471  vars_new[lev][var_idx].clear();
472  vars_old[lev][var_idx].clear();
473  }
474 
475  base_state[lev].clear();
476 
477  rU_new[lev].clear();
478  rU_old[lev].clear();
479  rV_new[lev].clear();
480  rV_old[lev].clear();
481  rW_new[lev].clear();
482  rW_old[lev].clear();
483 
484  if (lev > 0) {
485  zmom_crse_rhs[lev].clear();
486  }
487 
488  if (solverChoice.anelastic[lev] == 1) {
489  pp_inc[lev].clear();
490  }
491 
492  // Clears the integrator memory
493  mri_integrator_mem[lev].reset();
494 
495  // Clears the physical boundary condition routines
496  physbcs_cons[lev].reset();
497  physbcs_u[lev].reset();
498  physbcs_v[lev].reset();
499  physbcs_w[lev].reset();
500  physbcs_base[lev].reset();
501 
502  // Clears the flux register array
503  advflux_reg[lev]->reset();
504 }
amrex::Vector< amrex::MultiFab > pp_inc
Definition: ERF.H:750
amrex::Vector< amrex::YAFluxRegister * > advflux_reg
Definition: ERF.H:881
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_base > > physbcs_base
Definition: ERF.H:757
@ NumTypes
Definition: ERF_IndexDefines.H:133

◆ cloud_fraction()

Real ERF::cloud_fraction ( amrex::Real  time)
174 {
175  BL_PROFILE("ERF::cloud_fraction()");
176 
177  int lev = 0;
178  // This holds all of qc
179  MultiFab qc(vars_new[lev][Vars::cons],make_alias,RhoQ2_comp,1);
180 
181  int direction = 2; // z-direction
182  Box const& domain = geom[lev].Domain();
183 
184  auto const& qc_arr = qc.const_arrays();
185 
186  // qc_2d is an BaseFab<int> holding the max value over the column
187  auto qc_2d = ReduceToPlane<ReduceOpMax,int>(direction, domain, qc,
188  [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k) -> int
189  {
190  if (qc_arr[box_no](i,j,k) > 0) {
191  return 1;
192  } else {
193  return 0;
194  }
195  });
196 
197  auto* p = qc_2d.dataPtr();
198 
199  Long numpts = qc_2d.numPts();
200 
201  AMREX_ASSERT(numpts < Long(std::numeric_limits<int>::max));
202 
203 #if 1
204  if (ParallelDescriptor::UseGpuAwareMpi()) {
205  ParallelDescriptor::ReduceIntMax(p,static_cast<int>(numpts));
206  } else {
207  Gpu::PinnedVector<int> hv(numpts);
208  Gpu::copyAsync(Gpu::deviceToHost, p, p+numpts, hv.data());
209  Gpu::streamSynchronize();
210  ParallelDescriptor::ReduceIntMax(hv.data(),static_cast<int>(numpts));
211  Gpu::copyAsync(Gpu::hostToDevice, hv.data(), hv.data()+numpts, p);
212  }
213 
214  // Sum over component 0
215  Long num_cloudy = qc_2d.template sum<RunOn::Device>(0);
216 
217 #else
218  //
219  // We need this if we allow domain decomposition in the vertical
220  // but for now we leave it commented out
221  //
222  Long num_cloudy = Reduce::Sum<Long>(numpts,
223  [=] AMREX_GPU_DEVICE (Long i) -> Long {
224  if (p[i] == 1) {
225  return 1;
226  } else {
227  return 0;
228  }
229  });
230  ParallelDescriptor::ReduceLongSum(num_cloudy);
231 #endif
232 
233  Real num_total = qc_2d.box().d_numPts();
234 
235  Real cloud_frac = num_cloudy / num_total;
236 
237  return cloud_frac;
238 }
#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 #ifdef ERF_USE_EB
21  bool already_on_centroids = true;
22  EB_computeDivergence(rhs, rho0_u_const, geom_at_lev, already_on_centroids);
23 #else
24  if (SolverChoice::mesh_type == MeshType::ConstantDz)
25  {
26  computeDivergence(rhs, rho0_u_const, geom_at_lev);
27  }
28  else
29  {
30  for ( MFIter mfi(rhs,TilingIfNotGPU()); mfi.isValid(); ++mfi)
31  {
32  Box bx = mfi.tilebox();
33  const Array4<Real const>& rho0u_arr = rho0_u_const[0]->const_array(mfi);
34  const Array4<Real const>& rho0v_arr = rho0_u_const[1]->const_array(mfi);
35  const Array4<Real const>& rho0w_arr = rho0_u_const[2]->const_array(mfi);
36  const Array4<Real >& rhs_arr = rhs.array(mfi);
37 
38  if (SolverChoice::mesh_type == MeshType::StretchedDz) {
39  Real* stretched_dz_d_ptr = stretched_dz_d[lev].data();
40  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept {
41  Real dz = stretched_dz_d_ptr[k];
42  rhs_arr(i,j,k) = (rho0u_arr(i+1,j,k) - rho0u_arr(i,j,k)) * dxInv[0]
43  +(rho0v_arr(i,j+1,k) - rho0v_arr(i,j,k)) * dxInv[1]
44  +(rho0w_arr(i,j,k+1) - rho0w_arr(i,j,k)) / dz;
45  });
46  } else {
47 
48  //
49  // Note we compute the divergence using "rho0w" == Omega
50  //
51  const Array4<Real const>& ax_arr = ax[lev]->const_array(mfi);
52  const Array4<Real const>& ay_arr = ay[lev]->const_array(mfi);
53  const Array4<Real const>& dJ_arr = detJ_cc[lev]->const_array(mfi);
54  //
55  // az == 1 for terrain-fitted coordinates
56  //
57  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
58  {
59  rhs_arr(i,j,k) = ((ax_arr(i+1,j,k)*rho0u_arr(i+1,j,k) - ax_arr(i,j,k)*rho0u_arr(i,j,k)) * dxInv[0]
60  +(ay_arr(i,j+1,k)*rho0v_arr(i,j+1,k) - ay_arr(i,j,k)*rho0v_arr(i,j,k)) * dxInv[1]
61  +( rho0w_arr(i,j,k+1) - rho0w_arr(i,j,k)) * dxInv[2]) / dJ_arr(i,j,k);
62  });
63  }
64  } // mfi
65  }
66 #endif
67 }
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > stretched_dz_d
Definition: ERF.H:868
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ax
Definition: ERF.H:841
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ay
Definition: ERF.H:842

◆ 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 
36  // Limit dt's by the value of stop_time.
37  const Real eps = 1.e-3*dt_0;
38  if (t_new[0] + dt_0 > stop_time - eps) {
39  dt_0 = stop_time - t_new[0];
40  }
41 
42  dt[0] = dt_0;
43  for (int lev = 1; lev <= finest_level; ++lev) {
44  dt[lev] = dt[lev-1] / nsubsteps[lev];
45  }
46 }
amrex::Real stop_time
Definition: ERF.H:924
amrex::Vector< amrex::Real > t_new
Definition: ERF.H:733
amrex::Real estTimeStep(int lev, long &dt_fast_ratio) const
Definition: ERF_ComputeTimestep.cpp:55
amrex::Vector< int > nsubsteps
Definition: ERF.H:730
static amrex::Real init_shrink
Definition: ERF.H:932
static amrex::Real change_max
Definition: ERF.H:933

◆ ComputeGhostCells()

static AMREX_FORCE_INLINE int ERF::ComputeGhostCells ( const AdvChoice advChoice,
bool  use_num_diff 
)
inlinestaticprivate
1190  {
1191  if (use_num_diff)
1192  {
1193  return 3;
1194  } else {
1195  if (
1201  || (advChoice.dryscal_vert_adv_type == AdvType::Centered_6th) )
1202  { return 3; }
1203  else if (
1205  || (advChoice.dycore_vert_adv_type == AdvType::Upwind_5th)
1209  || (advChoice.dryscal_vert_adv_type == AdvType::Upwind_5th) )
1210  { return 3; }
1211  else if (
1213  || (advChoice.dryscal_vert_adv_type == AdvType::Weno_5)
1214  || (advChoice.moistscal_horiz_adv_type == AdvType::Weno_5)
1215  || (advChoice.moistscal_vert_adv_type == AdvType::Weno_5)
1216  || (advChoice.moistscal_horiz_adv_type == AdvType::Weno_5Z)
1217  || (advChoice.moistscal_vert_adv_type == AdvType::Weno_5Z)
1218  || (advChoice.dryscal_horiz_adv_type == AdvType::Weno_5Z)
1219  || (advChoice.dryscal_vert_adv_type == AdvType::Weno_5Z) )
1220  { return 3; }
1221  else if (
1223  || (advChoice.dryscal_vert_adv_type == AdvType::Weno_7)
1224  || (advChoice.moistscal_horiz_adv_type == AdvType::Weno_7)
1225  || (advChoice.moistscal_vert_adv_type == AdvType::Weno_7)
1226  || (advChoice.moistscal_horiz_adv_type == AdvType::Weno_7Z)
1227  || (advChoice.moistscal_vert_adv_type == AdvType::Weno_7Z)
1228  || (advChoice.dryscal_horiz_adv_type == AdvType::Weno_7Z)
1229  || (advChoice.dryscal_vert_adv_type == AdvType::Weno_7Z) )
1230  { return 4; }
1231  else
1232  { return 2; }
1233  }
1234  }
@ Centered_6th
AdvType moistscal_horiz_adv_type
Definition: ERF_AdvStruct.H:286
AdvType dycore_vert_adv_type
Definition: ERF_AdvStruct.H:283
AdvType moistscal_vert_adv_type
Definition: ERF_AdvStruct.H:287
AdvType dryscal_horiz_adv_type
Definition: ERF_AdvStruct.H:284
AdvType dycore_horiz_adv_type
Definition: ERF_AdvStruct.H:282
AdvType dryscal_vert_adv_type
Definition: ERF_AdvStruct.H:285

◆ Construct_ERFFillPatchers()

void ERF::Construct_ERFFillPatchers ( int  lev)
private
1875 {
1876  auto& fine_new = vars_new[lev];
1877  auto& crse_new = vars_new[lev-1];
1878  auto& ba_fine = fine_new[Vars::cons].boxArray();
1879  auto& ba_crse = crse_new[Vars::cons].boxArray();
1880  auto& dm_fine = fine_new[Vars::cons].DistributionMap();
1881  auto& dm_crse = crse_new[Vars::cons].DistributionMap();
1882 
1883  int ncomp = vars_new[lev][Vars::cons].nComp();
1884 
1885  FPr_c.emplace_back(ba_fine, dm_fine, geom[lev] ,
1886  ba_crse, dm_crse, geom[lev-1],
1887  -cf_width, -cf_set_width, ncomp, &cell_cons_interp);
1888  FPr_u.emplace_back(convert(ba_fine, IntVect(1,0,0)), dm_fine, geom[lev] ,
1889  convert(ba_crse, IntVect(1,0,0)), dm_crse, geom[lev-1],
1890  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
1891  FPr_v.emplace_back(convert(ba_fine, IntVect(0,1,0)), dm_fine, geom[lev] ,
1892  convert(ba_crse, IntVect(0,1,0)), dm_crse, geom[lev-1],
1893  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
1894  FPr_w.emplace_back(convert(ba_fine, IntVect(0,0,1)), dm_fine, geom[lev] ,
1895  convert(ba_crse, IntVect(0,0,1)), dm_crse, geom[lev-1],
1896  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
1897 }
int cf_set_width
Definition: ERF.H:809

◆ DataLog()

AMREX_FORCE_INLINE std::ostream& ERF::DataLog ( int  i)
inlineprivate
1245  {
1246  return *datalog[i];
1247  }
amrex::Vector< std::unique_ptr< std::fstream > > datalog
Definition: ERF.H:1380

◆ DataLogName()

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

The filename of the ith datalog file.

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

◆ Define_ERFFillPatchers()

void ERF::Define_ERFFillPatchers ( int  lev)
private
1901 {
1902  auto& fine_new = vars_new[lev];
1903  auto& crse_new = vars_new[lev-1];
1904  auto& ba_fine = fine_new[Vars::cons].boxArray();
1905  auto& ba_crse = crse_new[Vars::cons].boxArray();
1906  auto& dm_fine = fine_new[Vars::cons].DistributionMap();
1907  auto& dm_crse = crse_new[Vars::cons].DistributionMap();
1908 
1909  int ncomp = fine_new[Vars::cons].nComp();
1910 
1911  FPr_c[lev-1].Define(ba_fine, dm_fine, geom[lev] ,
1912  ba_crse, dm_crse, geom[lev-1],
1913  -cf_width, -cf_set_width, ncomp, &cell_cons_interp);
1914  FPr_u[lev-1].Define(convert(ba_fine, IntVect(1,0,0)), dm_fine, geom[lev] ,
1915  convert(ba_crse, IntVect(1,0,0)), dm_crse, geom[lev-1],
1916  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
1917  FPr_v[lev-1].Define(convert(ba_fine, IntVect(0,1,0)), dm_fine, geom[lev] ,
1918  convert(ba_crse, IntVect(0,1,0)), dm_crse, geom[lev-1],
1919  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
1920  FPr_w[lev-1].Define(convert(ba_fine, IntVect(0,0,1)), dm_fine, geom[lev] ,
1921  convert(ba_crse, IntVect(0,0,1)), dm_crse, geom[lev-1],
1922  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
1923 }

◆ 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
207 {
208  // We assume that this is always called at level 0
209  int lev = 0;
210 
211  bool l_use_kturb = ((solverChoice.turbChoice[lev].les_type != LESType::None) ||
212  (solverChoice.turbChoice[lev].pbl_type != PBLType::None));
213  bool l_use_KE = ( (solverChoice.turbChoice[lev].les_type == LESType::Deardorff) ||
214  (solverChoice.turbChoice[lev].pbl_type == PBLType::MYNN25) );
215 
216  // This will hold rho, theta, ksgs, Kmh, Kmv, uu, uv, uw, vv, vw, ww, uth, vth, wth,
217  // 0 1 2 3 4 5 6 7 8 9 10 11 12 13
218  // thth, uiuiu, uiuiv, uiuiw, p, pu, pv, pw, qv, qc, qr, wqv, wqc, wqr,
219  // 14 15 16 17 18 19 20 21 22 23 24 25 26 27
220  // qi, qs, qg, wthv
221  // 28 29 30 31
222  MultiFab mf_out(grids[lev], dmap[lev], 32, 0);
223 
224  MultiFab mf_vels(grids[lev], dmap[lev], AMREX_SPACEDIM, 0);
225 
226  MultiFab u_cc(mf_vels, make_alias, 0, 1); // u at cell centers
227  MultiFab v_cc(mf_vels, make_alias, 1, 1); // v at cell centers
228  MultiFab w_cc(mf_vels, make_alias, 2, 1); // w at cell centers
229 
230  average_face_to_cellcenter(mf_vels,0,
231  Array<const MultiFab*,3>{&vars_new[lev][Vars::xvel],&vars_new[lev][Vars::yvel],&vars_new[lev][Vars::zvel]});
232 
233  int zdir = 2;
234  auto domain = geom[0].Domain();
235 
236  // Sum in the horizontal plane
237  h_avg_u = sumToLine(mf_vels ,0,1,domain,zdir);
238  h_avg_v = sumToLine(mf_vels ,1,1,domain,zdir);
239  h_avg_w = sumToLine(mf_vels ,2,1,domain,zdir);
240 
241  int hu_size = h_avg_u.size();
242 
243  // Divide by the total number of cells we are averaging over
244  Real area_z = static_cast<Real>(domain.length(0)*domain.length(1));
245  for (int k = 0; k < hu_size; ++k) {
246  h_avg_u[k] /= area_z; h_avg_v[k] /= area_z; h_avg_w[k] /= area_z;
247  }
248 
249  Gpu::DeviceVector<Real> d_avg_u(hu_size, Real(0.0));
250  Gpu::DeviceVector<Real> d_avg_v(hu_size, Real(0.0));
251  Gpu::DeviceVector<Real> d_avg_w(hu_size, Real(0.0));
252 
253 #if 0
254  auto* avg_u_ptr = d_avg_u.data();
255  auto* avg_v_ptr = d_avg_v.data();
256  auto* avg_w_ptr = d_avg_w.data();
257 #endif
258 
259  Gpu::copy(Gpu::hostToDevice, h_avg_u.begin(), h_avg_u.end(), d_avg_u.begin());
260  Gpu::copy(Gpu::hostToDevice, h_avg_v.begin(), h_avg_v.end(), d_avg_v.begin());
261  Gpu::copy(Gpu::hostToDevice, h_avg_w.begin(), h_avg_w.end(), d_avg_w.begin());
262 
263  int nvars = vars_new[lev][Vars::cons].nComp();
264  MultiFab mf_cons(vars_new[lev][Vars::cons], make_alias, 0, nvars);
265 
266  MultiFab p_hse (base_state[lev], make_alias, BaseState::p0_comp, 1);
267 
268  bool use_moisture = (solverChoice.moisture_type != MoistureType::None);
269 
270  for ( MFIter mfi(mf_cons,TilingIfNotGPU()); mfi.isValid(); ++mfi)
271  {
272  const Box& bx = mfi.tilebox();
273  const Array4<Real>& fab_arr = mf_out.array(mfi);
274  const Array4<Real>& u_cc_arr = u_cc.array(mfi);
275  const Array4<Real>& v_cc_arr = v_cc.array(mfi);
276  const Array4<Real>& w_cc_arr = w_cc.array(mfi);
277  const Array4<Real>& cons_arr = mf_cons.array(mfi);
278  const Array4<Real>& p0_arr = p_hse.array(mfi);
279  const Array4<const Real>& eta_arr = (l_use_kturb) ? eddyDiffs_lev[lev]->const_array(mfi) :
280  Array4<const Real>{};
281 
282  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
283  {
284  Real theta = cons_arr(i,j,k,RhoTheta_comp) / cons_arr(i,j,k,Rho_comp);
285  fab_arr(i, j, k, 0) = cons_arr(i,j,k,Rho_comp);
286  fab_arr(i, j, k, 1) = theta;
287  Real ksgs = 0.0;
288  if (l_use_KE) {
289  ksgs = cons_arr(i,j,k,RhoKE_comp) / cons_arr(i,j,k,Rho_comp);
290  }
291  fab_arr(i, j, k, 2) = ksgs;
292 #if 1
293  if (l_use_kturb) {
294  fab_arr(i, j, k, 3) = eta_arr(i,j,k,EddyDiff::Mom_v); // Kmv
295  fab_arr(i, j, k, 4) = eta_arr(i,j,k,EddyDiff::Theta_v); // Khv
296  } else {
297  fab_arr(i, j, k, 3) = 0.0;
298  fab_arr(i, j, k, 4) = 0.0;
299  }
300 #else
301  // Here we hijack the "Kturb" variable name to print out the resolved kinetic energy
302  Real upert = u_cc_arr(i,j,k) - avg_u_ptr[k];
303  Real vpert = v_cc_arr(i,j,k) - avg_v_ptr[k];
304  Real wpert = w_cc_arr(i,j,k) - avg_w_ptr[k];
305  fab_arr(i, j, k, 3) = 0.5 * (upert*upert + vpert*vpert + wpert*wpert);
306 #endif
307  fab_arr(i, j, k, 5) = u_cc_arr(i,j,k) * u_cc_arr(i,j,k); // u*u
308  fab_arr(i, j, k, 6) = u_cc_arr(i,j,k) * v_cc_arr(i,j,k); // u*v
309  fab_arr(i, j, k, 7) = u_cc_arr(i,j,k) * w_cc_arr(i,j,k); // u*w
310  fab_arr(i, j, k, 8) = v_cc_arr(i,j,k) * v_cc_arr(i,j,k); // v*v
311  fab_arr(i, j, k, 9) = v_cc_arr(i,j,k) * w_cc_arr(i,j,k); // v*w
312  fab_arr(i, j, k,10) = w_cc_arr(i,j,k) * w_cc_arr(i,j,k); // w*w
313  fab_arr(i, j, k,11) = u_cc_arr(i,j,k) * theta; // u*th
314  fab_arr(i, j, k,12) = v_cc_arr(i,j,k) * theta; // v*th
315  fab_arr(i, j, k,13) = w_cc_arr(i,j,k) * theta; // w*th
316  fab_arr(i, j, k,14) = theta * theta; // th*th
317 
318  // if the number of fields is changed above, then be sure to update
319  // the following def!
320  Real uiui = fab_arr(i,j,k,5) + fab_arr(i,j,k,8) + fab_arr(i,j,k,10);
321  fab_arr(i, j, k,15) = uiui * u_cc_arr(i,j,k); // (ui*ui)*u
322  fab_arr(i, j, k,16) = uiui * v_cc_arr(i,j,k); // (ui*ui)*v
323  fab_arr(i, j, k,17) = uiui * w_cc_arr(i,j,k); // (ui*ui)*w
324 
325  if (!use_moisture) {
326  Real p = getPgivenRTh(cons_arr(i, j, k, RhoTheta_comp));
327  p -= p0_arr(i,j,k);
328  fab_arr(i, j, k,18) = p; // p
329  fab_arr(i, j, k,19) = p * u_cc_arr(i,j,k); // p*u
330  fab_arr(i, j, k,20) = p * v_cc_arr(i,j,k); // p*v
331  fab_arr(i, j, k,21) = p * w_cc_arr(i,j,k); // p*w
332  fab_arr(i, j, k,22) = 0.; // qv
333  fab_arr(i, j, k,23) = 0.; // qc
334  fab_arr(i, j, k,24) = 0.; // qr
335  fab_arr(i, j, k,25) = 0.; // w*qv
336  fab_arr(i, j, k,26) = 0.; // w*qc
337  fab_arr(i, j, k,27) = 0.; // w*qr
338  fab_arr(i, j, k,28) = 0.; // qi
339  fab_arr(i, j, k,29) = 0.; // qs
340  fab_arr(i, j, k,30) = 0.; // qg
341  fab_arr(i, j, k,31) = 0.; // w*thv
342  }
343  });
344  } // mfi
345 
346  if (use_moisture)
347  {
348  int n_qstate = micro->Get_Qstate_Size();
349 
350  for ( MFIter mfi(mf_cons,TilingIfNotGPU()); mfi.isValid(); ++mfi)
351  {
352  const Box& bx = mfi.tilebox();
353  const Array4<Real>& fab_arr = mf_out.array(mfi);
354  const Array4<Real>& cons_arr = mf_cons.array(mfi);
355  const Array4<Real>& u_cc_arr = u_cc.array(mfi);
356  const Array4<Real>& v_cc_arr = v_cc.array(mfi);
357  const Array4<Real>& w_cc_arr = w_cc.array(mfi);
358  const Array4<Real>& p0_arr = p_hse.array(mfi);
359 
360  int rhoqr_comp = solverChoice.RhoQr_comp;
361 
362  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
363  {
364  Real qv = cons_arr(i,j,k,RhoQ1_comp) / cons_arr(i,j,k,Rho_comp);
365  Real qc = cons_arr(i,j,k,RhoQ2_comp) / cons_arr(i,j,k,Rho_comp);
366  Real qr = (rhoqr_comp > -1) ? cons_arr(i,j,k,rhoqr_comp) / cons_arr(i,j,k,Rho_comp) :
367  Real(0.0);
368  Real p = getPgivenRTh(cons_arr(i, j, k, RhoTheta_comp), qv);
369 
370  p -= p0_arr(i,j,k);
371  fab_arr(i, j, k,18) = p; // p
372  fab_arr(i, j, k,19) = p * u_cc_arr(i,j,k); // p*u
373  fab_arr(i, j, k,20) = p * v_cc_arr(i,j,k); // p*v
374  fab_arr(i, j, k,21) = p * w_cc_arr(i,j,k); // p*w
375  fab_arr(i, j, k,22) = qv; // qv
376  fab_arr(i, j, k,23) = qc; // qc
377  fab_arr(i, j, k,24) = qr; // qr
378  fab_arr(i, j, k,25) = w_cc_arr(i,j,k) * qv; // w*qv
379  fab_arr(i, j, k,26) = w_cc_arr(i,j,k) * qc; // w*qc
380  fab_arr(i, j, k,27) = w_cc_arr(i,j,k) * qr; // w*qr
381  if (n_qstate > 3) {
382  fab_arr(i, j, k,28) = cons_arr(i,j,k,RhoQ3_comp) / cons_arr(i,j,k,Rho_comp); // qi
383  fab_arr(i, j, k,29) = cons_arr(i,j,k,RhoQ5_comp) / cons_arr(i,j,k,Rho_comp); // qs
384  fab_arr(i, j, k,30) = cons_arr(i,j,k,RhoQ6_comp) / cons_arr(i,j,k,Rho_comp); // qg
385  } else {
386  fab_arr(i, j, k,28) = 0.0; // qi
387  fab_arr(i, j, k,29) = 0.0; // qs
388  fab_arr(i, j, k,30) = 0.0; // qg
389  }
390  Real ql = qc + qr;
391  Real theta = cons_arr(i,j,k,RhoTheta_comp) / cons_arr(i,j,k,Rho_comp);
392  Real thv = theta * (1 + 0.61*qv - ql);
393  fab_arr(i, j, k,31) = w_cc_arr(i,j,k) * thv; // w*thv
394  });
395  } // mfi
396  } // use_moisture
397 
398  h_avg_rho = sumToLine(mf_out, 0,1,domain,zdir);
399  h_avg_th = sumToLine(mf_out, 1,1,domain,zdir);
400  h_avg_ksgs = sumToLine(mf_out, 2,1,domain,zdir);
401  h_avg_Kmv = sumToLine(mf_out, 3,1,domain,zdir);
402  h_avg_Khv = sumToLine(mf_out, 4,1,domain,zdir);
403  h_avg_uu = sumToLine(mf_out, 5,1,domain,zdir);
404  h_avg_uv = sumToLine(mf_out, 6,1,domain,zdir);
405  h_avg_uw = sumToLine(mf_out, 7,1,domain,zdir);
406  h_avg_vv = sumToLine(mf_out, 8,1,domain,zdir);
407  h_avg_vw = sumToLine(mf_out, 9,1,domain,zdir);
408  h_avg_ww = sumToLine(mf_out,10,1,domain,zdir);
409  h_avg_uth = sumToLine(mf_out,11,1,domain,zdir);
410  h_avg_vth = sumToLine(mf_out,12,1,domain,zdir);
411  h_avg_wth = sumToLine(mf_out,13,1,domain,zdir);
412  h_avg_thth = sumToLine(mf_out,14,1,domain,zdir);
413  h_avg_uiuiu = sumToLine(mf_out,15,1,domain,zdir);
414  h_avg_uiuiv = sumToLine(mf_out,16,1,domain,zdir);
415  h_avg_uiuiw = sumToLine(mf_out,17,1,domain,zdir);
416  h_avg_p = sumToLine(mf_out,18,1,domain,zdir);
417  h_avg_pu = sumToLine(mf_out,19,1,domain,zdir);
418  h_avg_pv = sumToLine(mf_out,20,1,domain,zdir);
419  h_avg_pw = sumToLine(mf_out,21,1,domain,zdir);
420  h_avg_qv = sumToLine(mf_out,22,1,domain,zdir);
421  h_avg_qc = sumToLine(mf_out,23,1,domain,zdir);
422  h_avg_qr = sumToLine(mf_out,24,1,domain,zdir);
423  h_avg_wqv = sumToLine(mf_out,25,1,domain,zdir);
424  h_avg_wqc = sumToLine(mf_out,26,1,domain,zdir);
425  h_avg_wqr = sumToLine(mf_out,27,1,domain,zdir);
426  h_avg_qi = sumToLine(mf_out,28,1,domain,zdir);
427  h_avg_qs = sumToLine(mf_out,29,1,domain,zdir);
428  h_avg_qg = sumToLine(mf_out,30,1,domain,zdir);
429  h_avg_wthv = sumToLine(mf_out,31,1,domain,zdir);
430 
431  // Divide by the total number of cells we are averaging over
432  int h_avg_u_size = static_cast<int>(h_avg_u.size());
433  for (int k = 0; k < h_avg_u_size; ++k) {
434  h_avg_rho[k] /= area_z;
435  h_avg_ksgs[k] /= area_z;
436  h_avg_Kmv[k] /= area_z;
437  h_avg_Khv[k] /= area_z;
438  h_avg_th[k] /= area_z;
439  h_avg_thth[k] /= area_z;
440  h_avg_uu[k] /= area_z;
441  h_avg_uv[k] /= area_z;
442  h_avg_uw[k] /= area_z;
443  h_avg_vv[k] /= area_z;
444  h_avg_vw[k] /= area_z;
445  h_avg_ww[k] /= area_z;
446  h_avg_uth[k] /= area_z;
447  h_avg_vth[k] /= area_z;
448  h_avg_wth[k] /= area_z;
449  h_avg_uiuiu[k] /= area_z;
450  h_avg_uiuiv[k] /= area_z;
451  h_avg_uiuiw[k] /= area_z;
452  h_avg_p[k] /= area_z;
453  h_avg_pu[k] /= area_z;
454  h_avg_pv[k] /= area_z;
455  h_avg_pw[k] /= area_z;
456  h_avg_qv[k] /= area_z;
457  h_avg_qc[k] /= area_z;
458  h_avg_qr[k] /= area_z;
459  h_avg_wqv[k] /= area_z;
460  h_avg_wqc[k] /= area_z;
461  h_avg_wqr[k] /= area_z;
462  h_avg_qi[k] /= area_z;
463  h_avg_qs[k] /= area_z;
464  h_avg_qg[k] /= area_z;
465  h_avg_wthv[k] /= area_z;
466  }
467 
468 #if 0
469  // Here we print the integrated total kinetic energy as computed in the 1D profile above
470  Real sum = 0.;
471  Real dz = geom[0].ProbHi(2) / static_cast<Real>(h_avg_u_size);
472  for (int k = 0; k < h_avg_u_size; ++k) {
473  sum += h_avg_kturb[k] * h_avg_rho[k] * dz;
474  }
475  amrex::Print() << "ITKE " << time << " " << sum << " using " << h_avg_u_size << " " << dz << std::endl;
476 #endif
477 }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getPgivenRTh(const amrex::Real rhotheta, const amrex::Real qv=0.)
Definition: ERF_EOS.H:84
#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:157
@ Mom_v
Definition: ERF_IndexDefines.H:156
@ theta
Definition: ERF_MM5.H:20
@ qv
Definition: ERF_Kessler.H:36
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
313 {
314  // We assume that this is always called at level 0
315  int lev = 0;
316 
317  bool l_use_kturb = ((solverChoice.turbChoice[lev].les_type != LESType::None) ||
318  (solverChoice.turbChoice[lev].pbl_type != PBLType::None));
319  bool l_use_KE = ( (solverChoice.turbChoice[lev].les_type == LESType::Deardorff) ||
320  (solverChoice.turbChoice[lev].pbl_type == PBLType::MYNN25) );
321 
322  // Note: "uiui" == u_i*u_i = u*u + v*v + w*w
323  // This will hold rho, theta, ksgs, Kmh, Kmv, uu, uv, vv, uth, vth,
324  // indices: 0 1 2 3 4 5 6 7 8 9
325  // thth, uiuiu, uiuiv, p, pu, pv, qv, qc, qr, qi, qs, qg
326  // 10 11 12 13 14 15 16 17 18 19 20 21
327  MultiFab mf_out(grids[lev], dmap[lev], 22, 0);
328 
329  // This will hold uw, vw, ww, wth, uiuiw, pw, wqv, wqc, wqr, wthv
330  // indices: 0 1 2 3 4 5 6 7 8 9
331  MultiFab mf_out_stag(convert(grids[lev], IntVect(0,0,1)), dmap[lev], 10, 0);
332 
333  // This is only used to average u and v; w is not averaged to cell centers
334  MultiFab mf_vels(grids[lev], dmap[lev], 2, 0);
335 
336  MultiFab u_cc(mf_vels, make_alias, 0, 1); // u at cell centers
337  MultiFab v_cc(mf_vels, make_alias, 1, 1); // v at cell centers
338  MultiFab w_fc(vars_new[lev][Vars::zvel], make_alias, 0, 1); // w at face centers (staggered)
339 
340  int zdir = 2;
341  auto domain = geom[0].Domain();
342  Box stag_domain = domain;
343  stag_domain.convert(IntVect(0,0,1));
344 
345  int nvars = vars_new[lev][Vars::cons].nComp();
346  MultiFab mf_cons(vars_new[lev][Vars::cons], make_alias, 0, nvars);
347 
348  MultiFab p_hse (base_state[lev], make_alias, BaseState::p0_comp, 1);
349 
350  bool use_moisture = (solverChoice.moisture_type != MoistureType::None);
351 
352  for ( MFIter mfi(mf_cons,TilingIfNotGPU()); mfi.isValid(); ++mfi)
353  {
354  const Box& bx = mfi.tilebox();
355  const Array4<Real>& fab_arr = mf_out.array(mfi);
356  const Array4<Real>& fab_arr_stag = mf_out_stag.array(mfi);
357  const Array4<Real>& u_arr = vars_new[lev][Vars::xvel].array(mfi);
358  const Array4<Real>& v_arr = vars_new[lev][Vars::yvel].array(mfi);
359  const Array4<Real>& u_cc_arr = u_cc.array(mfi);
360  const Array4<Real>& v_cc_arr = v_cc.array(mfi);
361  const Array4<Real>& w_fc_arr = w_fc.array(mfi);
362  const Array4<Real>& cons_arr = mf_cons.array(mfi);
363  const Array4<Real>& p0_arr = p_hse.array(mfi);
364  const Array4<const Real>& eta_arr = (l_use_kturb) ? eddyDiffs_lev[lev]->const_array(mfi) :
365  Array4<const Real>{};
366 
367  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
368  {
369  u_cc_arr(i,j,k) = 0.5 * (u_arr(i,j,k) + u_arr(i+1,j ,k));
370  v_cc_arr(i,j,k) = 0.5 * (v_arr(i,j,k) + v_arr(i ,j+1,k));
371 
372  Real theta = cons_arr(i,j,k,RhoTheta_comp) / cons_arr(i,j,k,Rho_comp);
373  fab_arr(i, j, k, 0) = cons_arr(i,j,k,Rho_comp);
374  fab_arr(i, j, k, 1) = theta;
375  Real ksgs = 0.0;
376  if (l_use_KE) {
377  ksgs = cons_arr(i,j,k,RhoKE_comp) / cons_arr(i,j,k,Rho_comp);
378  }
379  fab_arr(i, j, k, 2) = ksgs;
380  if (l_use_kturb) {
381  fab_arr(i, j, k, 3) = eta_arr(i,j,k,EddyDiff::Mom_v); // Kmv
382  fab_arr(i, j, k, 4) = eta_arr(i,j,k,EddyDiff::Theta_v); // Khv
383  } else {
384  fab_arr(i, j, k, 3) = 0.0;
385  fab_arr(i, j, k, 4) = 0.0;
386  }
387  fab_arr(i, j, k, 5) = u_cc_arr(i,j,k) * u_cc_arr(i,j,k); // u*u
388  fab_arr(i, j, k, 6) = u_cc_arr(i,j,k) * v_cc_arr(i,j,k); // u*v
389  fab_arr(i, j, k, 7) = v_cc_arr(i,j,k) * v_cc_arr(i,j,k); // v*v
390  fab_arr(i, j, k, 8) = u_cc_arr(i,j,k) * theta; // u*th
391  fab_arr(i, j, k, 9) = v_cc_arr(i,j,k) * theta; // v*th
392  fab_arr(i, j, k,10) = theta * theta; // th*th
393 
394  Real wcc = 0.5 * (w_fc_arr(i,j,k) + w_fc_arr(i,j,k+1));
395 
396  // if the number of fields is changed above, then be sure to update
397  // the following def!
398  Real uiui = fab_arr(i,j,k,5) + fab_arr(i,j,k,7) + wcc*wcc;
399  fab_arr(i, j, k,11) = uiui * u_cc_arr(i,j,k); // (ui*ui)*u
400  fab_arr(i, j, k,12) = uiui * v_cc_arr(i,j,k); // (ui*ui)*v
401 
402  if (!use_moisture) {
403  Real p = getPgivenRTh(cons_arr(i, j, k, RhoTheta_comp));
404  p -= p0_arr(i,j,k);
405  fab_arr(i, j, k,13) = p; // p
406  fab_arr(i, j, k,14) = p * u_cc_arr(i,j,k); // p*u
407  fab_arr(i, j, k,15) = p * v_cc_arr(i,j,k); // p*v
408  fab_arr(i, j, k,16) = 0.; // qv
409  fab_arr(i, j, k,17) = 0.; // qc
410  fab_arr(i, j, k,18) = 0.; // qr
411  fab_arr(i, j, k,19) = 0.; // qi
412  fab_arr(i, j, k,20) = 0.; // qs
413  fab_arr(i, j, k,21) = 0.; // qg
414  }
415  });
416 
417  const Box& zbx = mfi.tilebox(IntVect(0,0,1));
418  ParallelFor(zbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
419  {
420  // average to z faces (first to cell centers, then in z)
421  Real uface = 0.25 * ( u_arr(i ,j,k) + u_arr(i ,j,k-1)
422  + u_arr(i+1,j,k) + u_arr(i+1,j,k-1));
423  Real vface = 0.25 * ( v_arr(i,j ,k) + v_arr(i,j ,k-1)
424  + v_arr(i,j+1,k) + v_arr(i,j+1,k-1));
425  Real theta0 = cons_arr(i,j,k ,RhoTheta_comp) / cons_arr(i,j,k ,Rho_comp);
426  Real theta1 = cons_arr(i,j,k-1,RhoTheta_comp) / cons_arr(i,j,k-1,Rho_comp);
427  Real thface = 0.5*(theta0 + theta1);
428  fab_arr_stag(i,j,k,0) = uface * w_fc_arr(i,j,k); // u*w
429  fab_arr_stag(i,j,k,1) = vface * w_fc_arr(i,j,k); // v*w
430  fab_arr_stag(i,j,k,2) = w_fc_arr(i,j,k) * w_fc_arr(i,j,k); // w*w
431  fab_arr_stag(i,j,k,3) = thface * w_fc_arr(i,j,k); // th*w
432  Real uiui = uface*uface + vface*vface + fab_arr_stag(i,j,k,2);
433  fab_arr_stag(i,j,k,4) = uiui * w_fc_arr(i,j,k); // (ui*ui)*w
434  if (!use_moisture) {
435  Real p0 = getPgivenRTh(cons_arr(i, j, k , RhoTheta_comp)) - p0_arr(i,j,k );
436  Real p1 = getPgivenRTh(cons_arr(i, j, k-1, RhoTheta_comp)) - p0_arr(i,j,k-1);
437  Real pface = 0.5 * (p0 + p1);
438  fab_arr_stag(i,j,k,5) = pface * w_fc_arr(i,j,k); // p*w
439  fab_arr_stag(i,j,k,6) = 0.; // w*qv
440  fab_arr_stag(i,j,k,7) = 0.; // w*qc
441  fab_arr_stag(i,j,k,8) = 0.; // w*qr
442  fab_arr_stag(i,j,k,9) = 0.; // w*thv
443  }
444  });
445 
446  } // mfi
447 
448  if (use_moisture)
449  {
450  int n_qstate = micro->Get_Qstate_Size();
451 
452  for ( MFIter mfi(mf_cons,TilingIfNotGPU()); mfi.isValid(); ++mfi)
453  {
454  const Box& bx = mfi.tilebox();
455  const Array4<Real>& fab_arr = mf_out.array(mfi);
456  const Array4<Real>& fab_arr_stag = mf_out_stag.array(mfi);
457  const Array4<Real>& cons_arr = mf_cons.array(mfi);
458  const Array4<Real>& u_cc_arr = u_cc.array(mfi);
459  const Array4<Real>& v_cc_arr = v_cc.array(mfi);
460  const Array4<Real>& w_fc_arr = w_fc.array(mfi);
461  const Array4<Real>& p0_arr = p_hse.array(mfi);
462 
463  int rhoqr_comp = solverChoice.RhoQr_comp;
464 
465  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
466  {
467  Real qv = cons_arr(i,j,k,RhoQ1_comp) / cons_arr(i,j,k,Rho_comp);
468  Real qc = cons_arr(i,j,k,RhoQ2_comp) / cons_arr(i,j,k,Rho_comp);
469  Real qr = (rhoqr_comp > -1) ? cons_arr(i,j,k,rhoqr_comp) / cons_arr(i,j,k,Rho_comp) :
470  Real(0.0);
471  Real p = getPgivenRTh(cons_arr(i, j, k, RhoTheta_comp), qv);
472 
473  p -= p0_arr(i,j,k);
474  fab_arr(i, j, k,13) = p; // p
475  fab_arr(i, j, k,14) = p * u_cc_arr(i,j,k); // p*u
476  fab_arr(i, j, k,15) = p * v_cc_arr(i,j,k); // p*v
477  fab_arr(i, j, k,16) = qv; // qv
478  fab_arr(i, j, k,17) = qc; // qc
479  fab_arr(i, j, k,18) = qr; // qr
480  if (n_qstate > 3) { // SAM model
481  fab_arr(i, j, k,19) = cons_arr(i,j,k,RhoQ3_comp) / cons_arr(i,j,k,Rho_comp); // qi
482  fab_arr(i, j, k,20) = cons_arr(i,j,k,RhoQ5_comp) / cons_arr(i,j,k,Rho_comp); // qs
483  fab_arr(i, j, k,21) = cons_arr(i,j,k,RhoQ6_comp) / cons_arr(i,j,k,Rho_comp); // qg
484  } else {
485  fab_arr(i, j, k,19) = 0.0; // qi
486  fab_arr(i, j, k,20) = 0.0; // qs
487  fab_arr(i, j, k,21) = 0.0; // qg
488  }
489  });
490 
491  const Box& zbx = mfi.tilebox(IntVect(0,0,1));
492  ParallelFor(zbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
493  {
494  Real qv0 = cons_arr(i,j,k ,RhoQ1_comp) / cons_arr(i,j,k ,Rho_comp);
495  Real qv1 = cons_arr(i,j,k-1,RhoQ1_comp) / cons_arr(i,j,k-1,Rho_comp);
496  Real qc0 = cons_arr(i,j,k ,RhoQ2_comp) / cons_arr(i,j,k ,Rho_comp);
497  Real qc1 = cons_arr(i,j,k-1,RhoQ2_comp) / cons_arr(i,j,k-1,Rho_comp);
498  Real qr0 = (rhoqr_comp > -1) ? cons_arr(i,j,k ,RhoQ3_comp) / cons_arr(i,j,k ,Rho_comp) :
499  Real(0.0);
500  Real qr1 = (rhoqr_comp > -1) ? cons_arr(i,j,k-1,RhoQ3_comp) / cons_arr(i,j,k-1,Rho_comp) :
501  Real(0.0);
502  Real qvface = 0.5 * (qv0 + qv1);
503  Real qcface = 0.5 * (qc0 + qc1);
504  Real qrface = 0.5 * (qr0 + qr1);
505 
506  Real p0 = getPgivenRTh(cons_arr(i, j, k , RhoTheta_comp), qv0) - p0_arr(i,j,k );
507  Real p1 = getPgivenRTh(cons_arr(i, j, k-1, RhoTheta_comp), qv1) - p0_arr(i,j,k-1);
508  Real pface = 0.5 * (p0 + p1);
509 
510  Real theta0 = cons_arr(i,j,k ,RhoTheta_comp) / cons_arr(i,j,k ,Rho_comp);
511  Real theta1 = cons_arr(i,j,k-1,RhoTheta_comp) / cons_arr(i,j,k-1,Rho_comp);
512  Real thface = 0.5*(theta0 + theta1);
513  Real ql = qcface + qrface;
514  Real thv = thface * (1 + 0.61*qvface - ql);
515 
516  fab_arr_stag(i,j,k,5) = pface * w_fc_arr(i,j,k); // p*w
517  fab_arr_stag(i,j,k,6) = qvface * w_fc_arr(i,j,k); // w*qv
518  fab_arr_stag(i,j,k,7) = qcface * w_fc_arr(i,j,k); // w*qc
519  fab_arr_stag(i,j,k,8) = qrface * w_fc_arr(i,j,k); // w*qr
520  fab_arr_stag(i,j,k,9) = thv * w_fc_arr(i,j,k); // w*thv
521  });
522  } // mfi
523  } // use_moisture
524 
525  // Sum in the horizontal plane
526  h_avg_u = sumToLine(u_cc,0,1, domain,zdir);
527  h_avg_v = sumToLine(v_cc,0,1, domain,zdir);
528  h_avg_w = sumToLine(w_fc,0,1,stag_domain,zdir);
529 
530  h_avg_rho = sumToLine(mf_out, 0,1,domain,zdir);
531  h_avg_th = sumToLine(mf_out, 1,1,domain,zdir);
532  h_avg_ksgs = sumToLine(mf_out, 2,1,domain,zdir);
533  h_avg_Kmv = sumToLine(mf_out, 3,1,domain,zdir);
534  h_avg_Khv = sumToLine(mf_out, 4,1,domain,zdir);
535  h_avg_uu = sumToLine(mf_out, 5,1,domain,zdir);
536  h_avg_uv = sumToLine(mf_out, 6,1,domain,zdir);
537  h_avg_vv = sumToLine(mf_out, 7,1,domain,zdir);
538  h_avg_uth = sumToLine(mf_out, 8,1,domain,zdir);
539  h_avg_vth = sumToLine(mf_out, 9,1,domain,zdir);
540  h_avg_thth = sumToLine(mf_out,10,1,domain,zdir);
541  h_avg_uiuiu = sumToLine(mf_out,11,1,domain,zdir);
542  h_avg_uiuiv = sumToLine(mf_out,12,1,domain,zdir);
543  h_avg_p = sumToLine(mf_out,13,1,domain,zdir);
544  h_avg_pu = sumToLine(mf_out,14,1,domain,zdir);
545  h_avg_pv = sumToLine(mf_out,15,1,domain,zdir);
546  h_avg_qv = sumToLine(mf_out,16,1,domain,zdir);
547  h_avg_qc = sumToLine(mf_out,17,1,domain,zdir);
548  h_avg_qr = sumToLine(mf_out,18,1,domain,zdir);
549  h_avg_qi = sumToLine(mf_out,19,1,domain,zdir);
550  h_avg_qs = sumToLine(mf_out,20,1,domain,zdir);
551  h_avg_qg = sumToLine(mf_out,21,1,domain,zdir);
552 
553  h_avg_uw = sumToLine(mf_out_stag,0,1,stag_domain,zdir);
554  h_avg_vw = sumToLine(mf_out_stag,1,1,stag_domain,zdir);
555  h_avg_ww = sumToLine(mf_out_stag,2,1,stag_domain,zdir);
556  h_avg_wth = sumToLine(mf_out_stag,3,1,stag_domain,zdir);
557  h_avg_uiuiw = sumToLine(mf_out_stag,4,1,stag_domain,zdir);
558  h_avg_pw = sumToLine(mf_out_stag,5,1,stag_domain,zdir);
559  h_avg_wqv = sumToLine(mf_out_stag,6,1,stag_domain,zdir);
560  h_avg_wqc = sumToLine(mf_out_stag,7,1,stag_domain,zdir);
561  h_avg_wqr = sumToLine(mf_out_stag,8,1,stag_domain,zdir);
562  h_avg_wthv = sumToLine(mf_out_stag,9,1,stag_domain,zdir);
563 
564  // Divide by the total number of cells we are averaging over
565  Real area_z = static_cast<Real>(domain.length(0)*domain.length(1));
566  int unstag_size = h_avg_w.size() - 1; // _un_staggered heights
567  for (int k = 0; k < unstag_size; ++k) {
568  h_avg_u[k] /= area_z;
569  h_avg_v[k] /= area_z;
570  h_avg_rho[k] /= area_z;
571  h_avg_ksgs[k] /= area_z;
572  h_avg_Kmv[k] /= area_z;
573  h_avg_Khv[k] /= area_z;
574  h_avg_th[k] /= area_z;
575  h_avg_thth[k] /= area_z;
576  h_avg_uu[k] /= area_z;
577  h_avg_uv[k] /= area_z;
578  h_avg_vv[k] /= area_z;
579  h_avg_uth[k] /= area_z;
580  h_avg_vth[k] /= area_z;
581  h_avg_uiuiu[k] /= area_z;
582  h_avg_uiuiv[k] /= area_z;
583  h_avg_p[k] /= area_z;
584  h_avg_pu[k] /= area_z;
585  h_avg_pv[k] /= area_z;
586  h_avg_qv[k] /= area_z;
587  h_avg_qc[k] /= area_z;
588  h_avg_qr[k] /= area_z;
589  h_avg_qi[k] /= area_z;
590  h_avg_qs[k] /= area_z;
591  h_avg_qg[k] /= area_z;
592  }
593 
594  for (int k = 0; k < unstag_size+1; ++k) { // staggered heights
595  h_avg_w[k] /= area_z;
596  h_avg_uw[k] /= area_z;
597  h_avg_vw[k] /= area_z;
598  h_avg_ww[k] /= area_z;
599  h_avg_wth[k] /= area_z;
600  h_avg_uiuiw[k] /= area_z;
601  h_avg_pw[k] /= area_z;
602  h_avg_wqv[k] /= area_z;
603  h_avg_wqc[k] /= area_z;
604  h_avg_wqr[k] /= area_z;
605  h_avg_wthv[k] /= area_z;
606  }
607 }
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 
)
485 {
486  int lev = 0;
487 
488  // This will hold the stress tensor components
489  MultiFab mf_out(grids[lev], dmap[lev], 10, 0);
490 
491  bool l_use_moist = ( solverChoice.moisture_type != MoistureType::None );
492 
493  for ( MFIter mfi(mf_out,TilingIfNotGPU()); mfi.isValid(); ++mfi)
494  {
495  const Box& bx = mfi.tilebox();
496  const Array4<Real>& fab_arr = mf_out.array(mfi);
497 
498  // NOTE: These are from the last RK stage...
499  const Array4<const Real>& tau11_arr = Tau11_lev[lev]->const_array(mfi);
500  const Array4<const Real>& tau12_arr = Tau12_lev[lev]->const_array(mfi);
501  const Array4<const Real>& tau13_arr = Tau13_lev[lev]->const_array(mfi);
502  const Array4<const Real>& tau22_arr = Tau22_lev[lev]->const_array(mfi);
503  const Array4<const Real>& tau23_arr = Tau23_lev[lev]->const_array(mfi);
504  const Array4<const Real>& tau33_arr = Tau33_lev[lev]->const_array(mfi);
505 
506  // These should be re-calculated during ERF_slow_rhs_post
507  // -- just vertical SFS kinematic heat flux for now
508  //const Array4<const Real>& hfx1_arr = SFS_hfx1_lev[lev]->const_array(mfi);
509  //const Array4<const Real>& hfx2_arr = SFS_hfx2_lev[lev]->const_array(mfi);
510  const Array4<const Real>& hfx3_arr = SFS_hfx3_lev[lev]->const_array(mfi);
511  const Array4<const Real>& q1fx3_arr = (l_use_moist) ? SFS_q1fx3_lev[lev]->const_array(mfi) :
512  Array4<const Real>{};
513  const Array4<const Real>& q2fx3_arr = (l_use_moist) ? SFS_q2fx3_lev[lev]->const_array(mfi) :
514  Array4<const Real>{};
515  const Array4<const Real>& diss_arr = SFS_diss_lev[lev]->const_array(mfi);
516 
517  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
518  {
519  fab_arr(i, j, k, 0) = tau11_arr(i,j,k);
520  fab_arr(i, j, k, 1) = 0.25 * ( 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  fab_arr(i, j, k, 2) = 0.25 * ( tau13_arr(i,j,k ) + tau13_arr(i+1,j,k)
523  + tau13_arr(i,j,k+1) + tau13_arr(i+1,j,k+1) );
524  fab_arr(i, j, k, 3) = tau22_arr(i,j,k);
525  fab_arr(i, j, k, 4) = 0.25 * ( tau23_arr(i,j,k ) + tau23_arr(i,j+1,k)
526  + tau23_arr(i,j,k+1) + tau23_arr(i,j+1,k+1) );
527  fab_arr(i, j, k, 5) = tau33_arr(i,j,k);
528  fab_arr(i, j, k, 6) = 0.5 * ( hfx3_arr(i,j,k) + hfx3_arr(i,j,k+1) );
529  fab_arr(i, j, k, 7) = (l_use_moist) ? 0.5 * ( q1fx3_arr(i,j,k) + q1fx3_arr(i,j,k+1) ) : 0.0;
530  fab_arr(i, j, k, 8) = (l_use_moist) ? 0.5 * ( q2fx3_arr(i,j,k) + q2fx3_arr(i,j,k+1) ) : 0.0;
531  fab_arr(i, j, k, 9) = diss_arr(i,j,k);
532  });
533  }
534 
535  int zdir = 2;
536  auto domain = geom[0].Domain();
537 
538  h_avg_tau11 = sumToLine(mf_out,0,1,domain,zdir);
539  h_avg_tau12 = sumToLine(mf_out,1,1,domain,zdir);
540  h_avg_tau13 = sumToLine(mf_out,2,1,domain,zdir);
541  h_avg_tau22 = sumToLine(mf_out,3,1,domain,zdir);
542  h_avg_tau23 = sumToLine(mf_out,4,1,domain,zdir);
543  h_avg_tau33 = sumToLine(mf_out,5,1,domain,zdir);
544  h_avg_hfx3 = sumToLine(mf_out,6,1,domain,zdir);
545  h_avg_q1fx3 = sumToLine(mf_out,7,1,domain,zdir);
546  h_avg_q2fx3 = sumToLine(mf_out,8,1,domain,zdir);
547  h_avg_diss = sumToLine(mf_out,9,1,domain,zdir);
548 
549  int ht_size = h_avg_tau11.size();
550 
551  // Divide by the total number of cells we are averaging over
552  Real area_z = static_cast<Real>(domain.length(0)*domain.length(1));
553  for (int k = 0; k < ht_size; ++k) {
554  h_avg_tau11[k] /= area_z; h_avg_tau12[k] /= area_z; h_avg_tau13[k] /= area_z;
555  h_avg_tau22[k] /= area_z; h_avg_tau23[k] /= area_z;
556  h_avg_tau33[k] /= area_z;
557  h_avg_hfx3[k] /= area_z;
558  h_avg_q1fx3[k] /= area_z; h_avg_q2fx3[k] /= area_z;
559  h_avg_diss[k] /= area_z;
560  }
561 }

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

◆ derive_upwp()

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

◆ erf_enforce_hse()

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

◆ ERF_shared()

void ERF::ERF_shared ( )
103 {
104  if (ParallelDescriptor::IOProcessor()) {
105  const char* erf_hash = buildInfoGetGitHash(1);
106  const char* amrex_hash = buildInfoGetGitHash(2);
107  const char* buildgithash = buildInfoGetBuildGitHash();
108  const char* buildgitname = buildInfoGetBuildGitName();
109 
110  if (strlen(erf_hash) > 0) {
111  Print() << "\n"
112  << "ERF git hash: " << erf_hash << "\n";
113  }
114  if (strlen(amrex_hash) > 0) {
115  Print() << "AMReX git hash: " << amrex_hash << "\n";
116  }
117  if (strlen(buildgithash) > 0) {
118  Print() << buildgitname << " git hash: " << buildgithash << "\n";
119  }
120 
121  Print() << "\n";
122  }
123 
124  int nlevs_max = max_level + 1;
125 
126 #ifdef ERF_USE_WINDFARM
127  Nturb.resize(nlevs_max);
128  vars_windfarm.resize(nlevs_max);
129  SMark.resize(nlevs_max);
130 #endif
131 
132 #if defined(ERF_USE_RRTMGP)
133  qheating_rates.resize(nlevs_max);
134  sw_lw_fluxes.resize(nlevs_max);
135  solar_zenith.resize(nlevs_max);
136 #endif
137 
138  // NOTE: size lsm before readparams (chooses the model at all levels)
139  lsm.ReSize(nlevs_max);
140  lsm_data.resize(nlevs_max);
141  lsm_flux.resize(nlevs_max);
142 
143  // NOTE: size canopy model before readparams (if file exists, we construct)
144  m_forest_drag.resize(nlevs_max);
145  for (int lev = 0; lev < max_level; ++lev) { m_forest_drag[lev] = nullptr;}
146 
147  // Immersed Forcing Representation of Terrain
148  m_terrain_drag.resize(nlevs_max);
149  for (int lev = 0; lev < max_level; ++lev) { m_terrain_drag[lev] = nullptr;}
150 
151 
152  ReadParameters();
153  initializeMicrophysics(nlevs_max);
154 
155 #ifdef ERF_USE_WINDFARM
156  initializeWindFarm(nlevs_max);
157 #endif
158 
159  const std::string& pv1 = "plot_vars_1"; setPlotVariables(pv1,plot_var_names_1);
160  const std::string& pv2 = "plot_vars_2"; setPlotVariables(pv2,plot_var_names_2);
161 
162  // This is only used when we have mesh_type == MeshType::StretchedDz
163  stretched_dz_h.resize(nlevs_max);
164  stretched_dz_d.resize(nlevs_max);
165 
166  // Initialize staggered vertical levels for grid stretching or terrain, and
167  // to simplify Rayleigh damping layer calculations.
168  zlevels_stag.resize(max_level+1);
172  geom,
173  refRatio(),
176  solverChoice.dz0);
177 
178  if (SolverChoice::mesh_type == MeshType::StretchedDz ||
179  SolverChoice::mesh_type == MeshType::VariableDz) {
180  int nz = geom[0].Domain().length(2) + 1; // staggered
181  if (std::fabs(zlevels_stag[0][nz-1]-geom[0].ProbHi(2)) > 1.0e-4) {
182  Print() << "Note: prob_hi[2]=" << geom[0].ProbHi(2)
183  << " does not match highest requested z level " << zlevels_stag[0][nz-1]
184  << std::endl;
185  }
186  if (std::fabs(zlevels_stag[0][0]-geom[0].ProbLo(2)) > 1.0e-4) {
187  Print() << "Note: prob_lo[2]=" << geom[0].ProbLo(2)
188  << " does not match lowest requested level " << zlevels_stag[0][0]
189  << std::endl;
190  }
191 
192  // Redefine the problem domain here?
193  }
194 
195  prob = amrex_probinit(geom[0].ProbLo(),geom[0].ProbHi());
196 
197  // Geometry on all levels has been defined already.
198 
199  // No valid BoxArray and DistributionMapping have been defined.
200  // But the arrays for them have been resized.
201 
202  istep.resize(nlevs_max, 0);
203  nsubsteps.resize(nlevs_max, 1);
204  for (int lev = 1; lev <= max_level; ++lev) {
205  nsubsteps[lev] = MaxRefRatio(lev-1);
206  }
207 
208  t_new.resize(nlevs_max, 0.0);
209  t_old.resize(nlevs_max, -1.e100);
210  dt.resize(nlevs_max, 1.e100);
211  dt_mri_ratio.resize(nlevs_max, 1);
212 
213  vars_new.resize(nlevs_max);
214  vars_old.resize(nlevs_max);
215 
216  // We resize this regardless in order to pass it without error
217  pp_inc.resize(nlevs_max);
218 
219  rU_new.resize(nlevs_max);
220  rV_new.resize(nlevs_max);
221  rW_new.resize(nlevs_max);
222 
223  rU_old.resize(nlevs_max);
224  rV_old.resize(nlevs_max);
225  rW_old.resize(nlevs_max);
226 
227  // xmom_crse_rhs.resize(nlevs_max);
228  // ymom_crse_rhs.resize(nlevs_max);
229  zmom_crse_rhs.resize(nlevs_max);
230 
231  for (int lev = 0; lev < nlevs_max; ++lev) {
232  vars_new[lev].resize(Vars::NumTypes);
233  vars_old[lev].resize(Vars::NumTypes);
234  }
235 
236  // Time integrator
237  mri_integrator_mem.resize(nlevs_max);
238 
239  // Physical boundary conditions
240  physbcs_cons.resize(nlevs_max);
241  physbcs_u.resize(nlevs_max);
242  physbcs_v.resize(nlevs_max);
243  physbcs_w.resize(nlevs_max);
244  physbcs_base.resize(nlevs_max);
245 
246  // Planes to hold Dirichlet values at boundaries
247  xvel_bc_data.resize(nlevs_max);
248  yvel_bc_data.resize(nlevs_max);
249  zvel_bc_data.resize(nlevs_max);
250 
251  advflux_reg.resize(nlevs_max);
252 
253  // Stresses
254  Tau11_lev.resize(nlevs_max); Tau22_lev.resize(nlevs_max); Tau33_lev.resize(nlevs_max);
255  Tau12_lev.resize(nlevs_max); Tau21_lev.resize(nlevs_max);
256  Tau13_lev.resize(nlevs_max); Tau31_lev.resize(nlevs_max);
257  Tau23_lev.resize(nlevs_max); Tau32_lev.resize(nlevs_max);
258  SFS_hfx1_lev.resize(nlevs_max); SFS_hfx2_lev.resize(nlevs_max); SFS_hfx3_lev.resize(nlevs_max);
259  SFS_diss_lev.resize(nlevs_max);
260  SFS_q1fx1_lev.resize(nlevs_max); SFS_q1fx2_lev.resize(nlevs_max); SFS_q1fx3_lev.resize(nlevs_max);
261  SFS_q2fx3_lev.resize(nlevs_max);
262  eddyDiffs_lev.resize(nlevs_max);
263  SmnSmn_lev.resize(nlevs_max);
264 
265  // Sea surface temps
266  sst_lev.resize(nlevs_max);
267  lmask_lev.resize(nlevs_max);
268 
269  // Metric terms
270  z_phys_nd.resize(nlevs_max);
271  z_phys_cc.resize(nlevs_max);
272  detJ_cc.resize(nlevs_max);
273  ax.resize(nlevs_max);
274  ay.resize(nlevs_max);
275  az.resize(nlevs_max);
276 
277  z_phys_nd_new.resize(nlevs_max);
278  detJ_cc_new.resize(nlevs_max);
279  ax_new.resize(nlevs_max);
280  ay_new.resize(nlevs_max);
281  az_new.resize(nlevs_max);
282 
283  z_phys_nd_src.resize(nlevs_max);
284  detJ_cc_src.resize(nlevs_max);
285  ax_src.resize(nlevs_max);
286  ay_src.resize(nlevs_max);
287  az_src.resize(nlevs_max);
288 
289  z_t_rk.resize(nlevs_max);
290 
291  // Wall distance
292  walldist.resize(nlevs_max);
293 
294  // Mapfactors
295  mapfac_m.resize(nlevs_max);
296  mapfac_u.resize(nlevs_max);
297  mapfac_v.resize(nlevs_max);
298 
299  // Thin immersed body
300  xflux_imask.resize(nlevs_max);
301  yflux_imask.resize(nlevs_max);
302  zflux_imask.resize(nlevs_max);
303  //overset_imask.resize(nlevs_max);
304  thin_xforce.resize(nlevs_max);
305  thin_yforce.resize(nlevs_max);
306  thin_zforce.resize(nlevs_max);
307 
308  // Base state
309  base_state.resize(nlevs_max);
310  base_state_new.resize(nlevs_max);
311 
312  // Wave coupling data
313  Hwave.resize(nlevs_max);
314  Lwave.resize(nlevs_max);
315  for (int lev = 0; lev < max_level; ++lev)
316  {
317  Hwave[lev] = nullptr;
318  Lwave[lev] = nullptr;
319  }
320  Hwave_onegrid.resize(nlevs_max);
321  Lwave_onegrid.resize(nlevs_max);
322  for (int lev = 0; lev < max_level; ++lev)
323  {
324  Hwave_onegrid[lev] = nullptr;
325  Lwave_onegrid[lev] = nullptr;
326  }
327 
328  // Theta prim for MOST
329  Theta_prim.resize(nlevs_max);
330 
331  // Qv prim for MOST
332  Qv_prim.resize(nlevs_max);
333 
334  // Qr prim for MOST
335  Qr_prim.resize(nlevs_max);
336 
337  // Time averaged velocity field
338  vel_t_avg.resize(nlevs_max);
339  t_avg_cnt.resize(nlevs_max);
340 
341 #ifdef ERF_USE_NETCDF
342  // Size lat long arrays if using netcdf
343  lat_m.resize(nlevs_max);
344  lon_m.resize(nlevs_max);
345  for (int lev = 0; lev < max_level; ++lev)
346  {
347  lat_m[lev] = nullptr;
348  lon_m[lev] = nullptr;
349  }
350 #endif
351 
352  // Initialize tagging criteria for mesh refinement
354 
355  for (int lev = 0; lev < max_level; ++lev)
356  {
357  Print() << "Refinement ratio at level " << lev+1 << " set to be " <<
358  ref_ratio[lev][0] << " " << ref_ratio[lev][1] << " " << ref_ratio[lev][2] << std::endl;
359  }
360 
361  // We will create each of these in MakeNewLevel.../RemakeLevel
362  m_factory.resize(max_level+1);
363 
364 #ifdef ERF_USE_EB
365  // This is needed before initializing level MultiFabs
366  MakeEBGeometry();
367 #endif
368 }
std::unique_ptr< ProblemBase > amrex_probinit(const amrex_real *problo, const amrex_real *probhi) AMREX_ATTRIBUTE_WEAK
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_TerrainMetrics.cpp:11
amrex::Vector< std::unique_ptr< amrex::MultiFab > > walldist
Definition: ERF.H:860
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Hwave_onegrid
Definition: ERF.H:876
amrex::Vector< std::unique_ptr< amrex::MultiFab > > thin_yforce
Definition: ERF.H:909
void setPlotVariables(const std::string &pp_plot_var_names, amrex::Vector< std::string > &plot_var_names)
Definition: ERF_Plotfile.cpp:17
void ReadParameters()
Definition: ERF.cpp:1366
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ay_new
Definition: ERF.H:854
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_nd_src
Definition: ERF.H:845
amrex::Vector< amrex::MultiFab > base_state_new
Definition: ERF.H:871
amrex::Vector< std::unique_ptr< amrex::MultiFab > > az
Definition: ERF.H:843
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::iMultiFab > > > lmask_lev
Definition: ERF.H:825
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_nd_new
Definition: ERF.H:851
amrex::Vector< std::unique_ptr< amrex::MultiFab > > thin_zforce
Definition: ERF.H:910
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > sst_lev
Definition: ERF.H:824
amrex::Vector< std::unique_ptr< amrex::MultiFab > > thin_xforce
Definition: ERF.H:908
amrex::Vector< std::string > plot_var_names_1
Definition: ERF.H:967
amrex::Vector< amrex::Real > t_old
Definition: ERF.H:734
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_t_rk
Definition: ERF.H:857
amrex::Vector< std::unique_ptr< TerrainDrag > > m_terrain_drag
Definition: ERF.H:1172
amrex::Vector< std::string > plot_var_names_2
Definition: ERF.H:968
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Lwave_onegrid
Definition: ERF.H:877
amrex::Vector< std::unique_ptr< ForestDrag > > m_forest_drag
Definition: ERF.H:1171
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > xvel_bc_data
Definition: ERF.H:698
amrex::Vector< std::unique_ptr< amrex::MultiFab > > detJ_cc_src
Definition: ERF.H:846
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ay_src
Definition: ERF.H:848
amrex::Vector< std::unique_ptr< amrex::iMultiFab > > yflux_imask
Definition: ERF.H:903
amrex::Vector< std::unique_ptr< amrex::MultiFab > > az_new
Definition: ERF.H:855
amrex::Vector< amrex::Vector< amrex::MultiFab * > > lsm_flux
Definition: ERF.H:794
void refinement_criteria_setup()
Definition: ERF_Tagging.cpp:105
amrex::Vector< std::unique_ptr< amrex::FabFactory< amrex::FArrayBox > > > m_factory
Definition: ERF.H:1421
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ax_src
Definition: ERF.H:847
amrex::Vector< amrex::Vector< amrex::Real > > zlevels_stag
Definition: ERF.H:834
amrex::Vector< amrex::Vector< amrex::MultiFab * > > lsm_data
Definition: ERF.H:793
amrex::Vector< amrex::Vector< amrex::Real > > stretched_dz_h
Definition: ERF.H:867
amrex::Vector< std::unique_ptr< amrex::MultiFab > > az_src
Definition: ERF.H:849
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Lwave
Definition: ERF.H:875
amrex::Vector< std::unique_ptr< amrex::iMultiFab > > zflux_imask
Definition: ERF.H:904
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ax_new
Definition: ERF.H:853
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > zvel_bc_data
Definition: ERF.H:700
amrex::Vector< std::unique_ptr< amrex::MultiFab > > detJ_cc_new
Definition: ERF.H:852
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > yvel_bc_data
Definition: ERF.H:699
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Hwave
Definition: ERF.H:874
amrex::Vector< int > istep
Definition: ERF.H:729
amrex::Vector< std::unique_ptr< amrex::iMultiFab > > xflux_imask
Definition: ERF.H:902
void initializeMicrophysics(const int &)
Definition: ERF.cpp:1187
void ReSize(const int &nlev)
Definition: ERF_LandSurface.H:23
const char * buildInfoGetGitHash(int i)
amrex::Real dz0
Definition: ERF_DataStruct.H:624
amrex::Real grid_stretching_ratio
Definition: ERF_DataStruct.H:622
amrex::Real zsurf
Definition: ERF_DataStruct.H:623
Here is the call graph for this function:

◆ ErrorEst()

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

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

Parameters
[in]levclevel of refinement at which we tag cells (0 is coarsest level)
[out]tagsarray of tagged cells
[in]timecurrent time
16 {
17  const int clearval = TagBox::CLEAR;
18  const int tagval = TagBox::SET;
19 
20  for (int j=0; j < ref_tags.size(); ++j)
21  {
22  std::unique_ptr<MultiFab> mf = std::make_unique<MultiFab>(grids[levc], dmap[levc], 1, 0);
23 
24  // This allows dynamic refinement based on the value of the density
25  if (ref_tags[j].Field() == "density")
26  {
27  MultiFab::Copy(*mf,vars_new[levc][Vars::cons],Rho_comp,0,1,0);
28 
29  // This allows dynamic refinement based on the value of qv
30  } else if ( ref_tags[j].Field() == "qv" ) {
31  MultiFab::Copy( *mf, vars_new[levc][Vars::cons], RhoQ1_comp, 0, 1, 0);
32  MultiFab::Divide(*mf, vars_new[levc][Vars::cons], Rho_comp, 0, 1, 0);
33 
34 
35  // This allows dynamic refinement based on the value of qc
36  } else if (ref_tags[j].Field() == "qc" ) {
37  MultiFab::Copy( *mf, vars_new[levc][Vars::cons], RhoQ2_comp, 0, 1, 0);
38  MultiFab::Divide(*mf, vars_new[levc][Vars::cons], Rho_comp, 0, 1, 0);
39 
40 
41  // This allows dynamic refinement based on the value of the scalar/pressure/theta
42  } else if ( (ref_tags[j].Field() == "scalar" ) ||
43  (ref_tags[j].Field() == "pressure") ||
44  (ref_tags[j].Field() == "theta" ) )
45  {
46  for (MFIter mfi(*mf, TilingIfNotGPU()); mfi.isValid(); ++mfi)
47  {
48  const Box& bx = mfi.tilebox();
49  auto& dfab = (*mf)[mfi];
50  auto& sfab = vars_new[levc][Vars::cons][mfi];
51  if (ref_tags[j].Field() == "scalar") {
52  derived::erf_derscalar(bx, dfab, 0, 1, sfab, Geom(levc), time, nullptr, levc);
53  } else if (ref_tags[j].Field() == "theta") {
54  derived::erf_dertheta(bx, dfab, 0, 1, sfab, Geom(levc), time, nullptr, levc);
55  }
56  } // mfi
57 #ifdef ERF_USE_PARTICLES
58  } else {
59  //
60  // This allows dynamic refinement based on the number of particles per cell
61  //
62  // Note that we must count all the particles in levels both at and above the current,
63  // since otherwise, e.g., if the particles are all at level 1, counting particles at
64  // level 0 will not trigger refinement when regridding so level 1 will disappear,
65  // then come back at the next regridding
66  //
67  const auto& particles_namelist( particleData.getNames() );
68  mf->setVal(0.0);
69  for (ParticlesNamesVector::size_type i = 0; i < particles_namelist.size(); i++)
70  {
71  std::string tmp_string(particles_namelist[i]+"_count");
72  IntVect rr = IntVect::TheUnitVector();
73  if (ref_tags[j].Field() == tmp_string) {
74  for (int lev = levc; lev <= finest_level; lev++)
75  {
76  MultiFab temp_dat(grids[lev], dmap[lev], 1, 0); temp_dat.setVal(0);
77  particleData[particles_namelist[i]]->IncrementWithTotal(temp_dat, lev);
78 
79  MultiFab temp_dat_crse(grids[levc], dmap[levc], 1, 0); temp_dat_crse.setVal(0);
80 
81  if (lev == levc) {
82  MultiFab::Copy(*mf, temp_dat, 0, 0, 1, 0);
83  } else {
84  for (int d = 0; d < AMREX_SPACEDIM; d++) {
85  rr[d] *= ref_ratio[levc][d];
86  }
87  average_down(temp_dat, temp_dat_crse, 0, 1, rr);
88  MultiFab::Add(*mf, temp_dat_crse, 0, 0, 1, 0);
89  }
90  }
91  }
92  }
93 #endif
94  }
95 
96  ref_tags[j](tags,mf.get(),clearval,tagval,time,levc,geom[levc]);
97  } // loop over j
98 }
static amrex::Vector< amrex::AMRErrorTag > ref_tags
Definition: ERF.H:1177
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_dertheta(const Box &bx, FArrayBox &derfab, int, int, const FArrayBox &datfab, const Geometry &, Real, const int *, const int)
Definition: ERF_Derive.cpp:144
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
56 {
57  BL_PROFILE("ERF::estTimeStep()");
58 
59  Real estdt_comp = 1.e20;
60  Real estdt_lowM = 1.e20;
61 
62  // We intentionally use the level 0 domain to compute whether to use this direction in the dt calculation
63  const int nxc = geom[0].Domain().length(0);
64  const int nyc = geom[0].Domain().length(1);
65 
66  auto const dxinv = geom[level].InvCellSizeArray();
67  auto const dzinv = 1.0 / dz_min[level];
68 
69  MultiFab const& S_new = vars_new[level][Vars::cons];
70 
71  MultiFab ccvel(grids[level],dmap[level],3,0);
72 
73  average_face_to_cellcenter(ccvel,0,
74  Array<const MultiFab*,3>{&vars_new[level][Vars::xvel],
75  &vars_new[level][Vars::yvel],
76  &vars_new[level][Vars::zvel]});
77 
78  int l_implicit_substepping = (solverChoice.substepping_type[level] == SubsteppingType::Implicit);
79  int l_anelastic = solverChoice.anelastic[level];
80 
81 #ifdef ERF_USE_EB
82  EBFArrayBoxFactory ebfact = EBFactory(level);
83  const MultiFab& detJ = ebfact.getVolFrac();
84 #endif
85 
86 #ifdef ERF_USE_EB
87  Real estdt_comp_inv = ReduceMax(S_new, ccvel, detJ, 0,
88  [=] AMREX_GPU_HOST_DEVICE (Box const& b,
89  Array4<Real const> const& s,
90  Array4<Real const> const& u,
91  Array4<Real const> const& vf) -> Real
92 #else
93  Real estdt_comp_inv = ReduceMax(S_new, ccvel, 0,
94  [=] AMREX_GPU_HOST_DEVICE (Box const& b,
95  Array4<Real const> const& s,
96  Array4<Real const> const& u) -> Real
97 #endif
98  {
99  Real new_comp_dt = -1.e100;
100  amrex::Loop(b, [=,&new_comp_dt] (int i, int j, int k) noexcept
101  {
102 #ifdef ERF_USE_EB
103  if (vf(i,j,k) > 0.)
104 #endif
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_implicit_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 or SCM
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  ParallelDescriptor::ReduceRealMax(estdt_comp_inv);
154  estdt_comp = cfl / estdt_comp_inv;
155 
156  Real estdt_lowM_inv = ReduceMax(ccvel, 0,
157  [=] AMREX_GPU_HOST_DEVICE (Box const& b,
158  Array4<Real const> const& u) -> Real
159  {
160  Real new_lm_dt = -1.e100;
161  Loop(b, [=,&new_lm_dt] (int i, int j, int k) noexcept
162  {
163  new_lm_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0)))*dxinv[0]),
164  ((amrex::Math::abs(u(i,j,k,1)))*dxinv[1]),
165  ((amrex::Math::abs(u(i,j,k,2)))*dxinv[2]), new_lm_dt);
166  });
167  return new_lm_dt;
168  });
169 
170  ParallelDescriptor::ReduceRealMax(estdt_lowM_inv);
171  if (estdt_lowM_inv > 0.0_rt)
172  estdt_lowM = cfl / estdt_lowM_inv;
173 
174  if (verbose) {
175  if (fixed_dt[level] <= 0.0) {
176  Print() << "Using cfl = " << cfl << " and dx/dy/dz_min = " <<
177  1.0/dxinv[0] << " " << 1.0/dxinv[1] << " " << dz_min[level] << std::endl;
178  Print() << "Compressible dt at level " << level << ": " << estdt_comp << std::endl;
179  if (estdt_lowM_inv > 0.0_rt) {
180  Print() << "Anelastic dt at level " << level << ": " << estdt_lowM << std::endl;
181  } else {
182  Print() << "Anelastic dt at level " << level << ": undefined " << std::endl;
183  }
184  }
185 
186  if (fixed_dt[level] > 0.0) {
187  Print() << "Based on cfl of 1.0 " << std::endl;
188  Print() << "Compressible dt at level " << level << " would be: " << estdt_comp/cfl << std::endl;
189  if (estdt_lowM_inv > 0.0_rt) {
190  Print() << "Anelastic dt at level " << level << " would be: " << estdt_lowM/cfl << std::endl;
191  } else {
192  Print() << "Anelastic dt at level " << level << " would be undefined " << std::endl;
193  }
194  Print() << "Fixed dt at level " << level << " is: " << fixed_dt[level] << std::endl;
195  if (fixed_fast_dt[level] > 0.0) {
196  Print() << "Fixed fast dt at level " << level << " is: " << fixed_fast_dt[level] << std::endl;
197  }
198  }
199  }
200 
201  if (solverChoice.substepping_type[level] != SubsteppingType::None) {
202  if (fixed_dt[level] > 0. && fixed_fast_dt[level] > 0.) {
203  dt_fast_ratio = static_cast<long>( fixed_dt[level] / fixed_fast_dt[level] );
204  } else if (fixed_dt[level] > 0.) {
205  // Max CFL_c = 1.0 for substeps by default, but we enforce a min of 4 substeps
206  auto dt_sub_max = (estdt_comp/cfl * sub_cfl);
207  dt_fast_ratio = static_cast<long>( std::max(fixed_dt[level]/dt_sub_max,4.) );
208  }
209 
210  // Force time step ratio to be an even value
212  if ( dt_fast_ratio%2 != 0) dt_fast_ratio += 1;
213  } else {
214  if ( dt_fast_ratio%6 != 0) {
215  Print() << "mri_dt_ratio = " << dt_fast_ratio
216  << " not divisible by 6 for N/3 substeps in stage 1" << std::endl;
217  dt_fast_ratio = static_cast<int>(std::ceil(dt_fast_ratio/6.0) * 6);
218  }
219  }
220 
221  if (verbose) {
222  Print() << "smallest even ratio is: " << dt_fast_ratio << std::endl;
223  }
224  } // if substepping, either explicit or implicit
225 
226  if (fixed_dt[level] > 0.0) {
227  return fixed_dt[level];
228  } else {
229  // Anelastic (substepping is not allowed)
230  if (l_anelastic) {
231  return estdt_lowM;
232 
233  // Compressible with or without substepping
234  } else {
235  return estdt_comp;
236  }
237  }
238 }
constexpr amrex::Real Gamma
Definition: ERF_Constants.H:19
amrex::Vector< amrex::Real > dz_min
Definition: ERF.H:1185
amrex::Vector< amrex::Real > fixed_dt
Definition: ERF.H:936
amrex::Vector< amrex::Real > fixed_fast_dt
Definition: ERF.H:937
static amrex::Real cfl
Definition: ERF.H:930
static amrex::Real sub_cfl
Definition: ERF.H:931
@ rho
Definition: ERF_Kessler.H:30
int force_stage1_single_substep
Definition: ERF_DataStruct.H:586
Here is the call graph for this function:

◆ Evolve()

void ERF::Evolve ( )
375 {
376  BL_PROFILE_VAR("ERF::Evolve()", evolve);
377 
378  Real cur_time = t_new[0];
379 
380  // Take one coarse timestep by calling timeStep -- which recursively calls timeStep
381  // for finer levels (with or without subcycling)
382  for (int step = istep[0]; step < max_step && cur_time < stop_time; ++step)
383  {
384  Print() << "\nCoarse STEP " << step+1 << " starts ..." << std::endl;
385 
386  ComputeDt(step);
387 
388  // Make sure we have read enough of the boundary plane data to make it through this timestep
389  if (input_bndry_planes)
390  {
391  m_r2d->read_input_files(cur_time,dt[0],m_bc_extdir_vals);
392  }
393 
394  int lev = 0;
395  int iteration = 1;
396  timeStep(lev, cur_time, iteration);
397 
398  cur_time += dt[0];
399 
400  Print() << "Coarse STEP " << step+1 << " ends." << " TIME = " << cur_time
401  << " DT = " << dt[0] << std::endl;
402 
403  post_timestep(step, cur_time, dt[0]);
404 
405  if (writeNow(cur_time, dt[0], step+1, m_plot_int_1, m_plot_per_1)) {
406  last_plot_file_step_1 = step+1;
408  }
409  if (writeNow(cur_time, dt[0], step+1, m_plot_int_2, m_plot_per_2)) {
410  last_plot_file_step_2 = step+1;
412  }
413 
414  if (writeNow(cur_time, dt[0], step+1, m_check_int, m_check_per)) {
415  last_check_file_step = step+1;
416 #ifdef ERF_USE_NETCDF
417  if (check_type == "netcdf") {
418  WriteNCCheckpointFile();
419  }
420 #endif
421  if (check_type == "native") {
423  }
424  }
425 
426 #ifdef AMREX_MEM_PROFILING
427  {
428  std::ostringstream ss;
429  ss << "[STEP " << step+1 << "]";
430  MemProfiler::report(ss.str());
431  }
432 #endif
433 
434  if (cur_time >= stop_time - 1.e-6*dt[0]) break;
435  }
436 
437  // Write plotfiles at final time
438  if ( (m_plot_int_1 > 0 || m_plot_per_1 > 0.) && istep[0] > last_plot_file_step_1 ) {
440  }
441  if ( (m_plot_int_2 > 0 || m_plot_per_2 > 0.) && istep[0] > last_plot_file_step_2) {
443  }
444 
445  if ( (m_check_int > 0 || m_check_per > 0.) && istep[0] > last_check_file_step) {
446 #ifdef ERF_USE_NETCDF
447  if (check_type == "netcdf") {
448  WriteNCCheckpointFile();
449  }
450 #endif
451  if (check_type == "native") {
453  }
454  }
455 
456  BL_PROFILE_VAR_STOP(evolve);
457 }
int last_check_file_step
Definition: ERF.H:915
int max_step
Definition: ERF.H:922
int last_plot_file_step_2
Definition: ERF.H:913
static PlotFileType plotfile_type_1
Definition: ERF.H:1057
amrex::Array< amrex::Array< amrex::Real, AMREX_SPACEDIM *2 >, AMREX_SPACEDIM+NBCVAR_max > m_bc_extdir_vals
Definition: ERF.H:893
amrex::Real m_plot_per_1
Definition: ERF.H:950
std::string check_type
Definition: ERF.H:962
int m_plot_int_1
Definition: ERF.H:948
void post_timestep(int nstep, amrex::Real time, amrex::Real dt_lev)
Definition: ERF.cpp:461
amrex::Real m_check_per
Definition: ERF.H:965
int m_check_int
Definition: ERF.H:964
int last_plot_file_step_1
Definition: ERF.H:912
static int input_bndry_planes
Definition: ERF.H:1112
static PlotFileType plotfile_type_2
Definition: ERF.H:1058
void WritePlotFile(int which, PlotFileType plotfile_type, amrex::Vector< std::string > plot_var_names)
Definition: ERF_Plotfile.cpp:186
void ComputeDt(int step=-1)
Definition: ERF_ComputeTimestep.cpp:11
void WriteCheckpointFile() const
Definition: ERF_Checkpoint.cpp:25
int m_plot_int_2
Definition: ERF.H:949
std::unique_ptr< ReadBndryPlanes > m_r2d
Definition: ERF.H:1169
bool writeNow(const amrex::Real cur_time, const amrex::Real dt, const int nstep, const int plot_int, const amrex::Real plot_per)
Definition: ERF.cpp:1951
void timeStep(int lev, amrex::Real time, int iteration)
Definition: ERF_TimeStep.cpp:16
amrex::Real m_plot_per_2
Definition: ERF.H:951

Referenced by main().

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
amrex::Gpu::DeviceVector< amrex::BCRec > domain_bcs_type_d
Definition: ERF.H:887
@ RhoScalar_bc_comp
Definition: ERF_IndexDefines.H:80
@ ext_dir_ingested
Definition: ERF_IndexDefines.H:183

◆ 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)
12 {
13  // Impose bc's at domain boundaries
14  for (int lev = 0; lev <= finest_level; ++lev)
15  {
16  Box domain(Geom(lev).Domain());
17 
18  int ihi = domain.bigEnd(0);
19  int jhi = domain.bigEnd(1);
20  int khi = domain.bigEnd(2);
21 
22  // Impose periodicity first
23  mf_cc_vel[lev].FillBoundary(geom[lev].periodicity());
24 
25  for (MFIter mfi(mf_cc_vel[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi)
26  {
27  // Note that we don't fill corners here -- only the cells that share a face
28  // with interior cells -- this is all that is needed to calculate vorticity
29  const Box& bx = mfi.tilebox();
30  const Array4<Real>& vel_arr = mf_cc_vel[lev].array(mfi);
31 
32  if (!Geom(lev).isPeriodic(0)) {
33  // Low-x side
34  if (bx.smallEnd(0) <= domain.smallEnd(0)) {
35  Real mult = (phys_bc_type[0] == ERF_BC::no_slip_wall) ? -1. : 1.;
36  ParallelFor(makeSlab(bx,0,0), [=] AMREX_GPU_DEVICE(int , int j, int k) noexcept
37  {
38  vel_arr(-1,j,k,1) = mult*vel_arr(0,j,k,1); // v
39  vel_arr(-1,j,k,2) = mult*vel_arr(0,j,k,2); // w
40  });
41  }
42 
43  // High-x side
44  if (bx.bigEnd(0) >= domain.bigEnd(0)) {
45  Real mult = (phys_bc_type[3] == ERF_BC::no_slip_wall) ? -1. : 1.;
46  ParallelFor(makeSlab(bx,0,0), [=] AMREX_GPU_DEVICE(int , int j, int k) noexcept
47  {
48  vel_arr(ihi+1,j,k,1) = mult*vel_arr(ihi,j,k,1); // v
49  vel_arr(ihi+1,j,k,2) = mult*vel_arr(ihi,j,k,2); // w
50  });
51  }
52  } // !periodic
53 
54  if (!Geom(lev).isPeriodic(1)) {
55  // Low-y side
56  if (bx.smallEnd(1) <= domain.smallEnd(1)) {
57  Real mult = (phys_bc_type[1] == ERF_BC::no_slip_wall) ? -1. : 1.;
58  ParallelFor(makeSlab(bx,1,0), [=] AMREX_GPU_DEVICE(int i, int , int k) noexcept
59  {
60  vel_arr(i,-1,k,0) = mult*vel_arr(i,0,k,0); // u
61  vel_arr(i,-1,k,2) = mult*vel_arr(i,0,k,2); // w
62  });
63  }
64 
65  // High-y side
66  if (bx.bigEnd(1) >= domain.bigEnd(1)) {
67  Real mult = (phys_bc_type[4] == ERF_BC::no_slip_wall) ? -1. : 1.;
68  ParallelFor(makeSlab(bx,1,0), [=] AMREX_GPU_DEVICE(int i, int , int k) noexcept
69  {
70  vel_arr(i,jhi+1,k,0) = mult*vel_arr(i,jhi,k,0); // u
71  vel_arr(i,jhi+1,k,2) = mult*-vel_arr(i,jhi,k,2); // w
72  });
73  }
74  } // !periodic
75 
76  if (!Geom(lev).isPeriodic(2)) {
77  // Low-z side
78  if (bx.smallEnd(2) <= domain.smallEnd(2)) {
79  Real mult = (phys_bc_type[2] == ERF_BC::no_slip_wall) ? -1. : 1.;
80  ParallelFor(makeSlab(bx,2,0), [=] AMREX_GPU_DEVICE(int i, int j, int) noexcept
81  {
82  vel_arr(i,j,-1,0) = mult*vel_arr(i,j,0,0); // u
83  vel_arr(i,j,-1,1) = mult*vel_arr(i,j,0,1); // v
84  });
85  }
86 
87  // High-z side
88  if (bx.bigEnd(2) >= domain.bigEnd(2)) {
89  Real mult = (phys_bc_type[5] == ERF_BC::no_slip_wall) ? -1. : 1.;
90  ParallelFor(makeSlab(bx,2,0), [=] AMREX_GPU_DEVICE(int i, int j, int) noexcept
91  {
92  vel_arr(i,j,khi+1,0) = mult*vel_arr(i,j,khi,0); // u
93  vel_arr(i,j,khi+1,1) = mult*vel_arr(i,j,khi,1); // v
94  });
95  }
96  } // !periodic
97  } // MFIter
98 
99  } // lev
100 }
@ 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  FillPatch(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  FillPatch(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  VelocityToMomentum(vars_new[lev-1][Vars::xvel], IntVect{0},
51  vars_new[lev-1][Vars::yvel], IntVect{0},
52  vars_new[lev-1][Vars::zvel], IntVect{0},
53  vars_new[lev-1][Vars::cons],
54  rU_new[lev-1],
55  rV_new[lev-1],
56  rW_new[lev-1],
57  Geom(lev).Domain(),
59  //
60  // *****************************************************************
61  // Interpolate all cell-centered variables from coarse to fine level
62  // *****************************************************************
63  //
64  Interpolater* mapper_c = &cell_cons_interp;
65  Interpolater* mapper_f = &face_cons_linear_interp;
66 
67  //
68  //************************************************************************************************
69  // Interpolate cell-centered data from coarse to fine level
70  // with InterpFromCoarseLevel which ASSUMES that all ghost cells have already been filled
71  // ************************************************************************************************
72  IntVect ngvect_cons = vars_new[lev][Vars::cons].nGrowVect();
73  int ncomp_cons = vars_new[lev][Vars::cons].nComp();
74 
75  InterpFromCoarseLevel(vars_new[lev ][Vars::cons], ngvect_cons, IntVect(0,0,0),
76  vars_new[lev-1][Vars::cons], 0, 0, ncomp_cons,
77  geom[lev-1], geom[lev],
78  refRatio(lev-1), mapper_c, domain_bcs_type, BCVars::cons_bc);
79 
80  //
81  //************************************************************************************************
82  // Interpolate x-momentum from coarse to fine level
83  // with InterpFromCoarseLevel which ASSUMES that all ghost cells have already been filled
84  // ************************************************************************************************
85  //
86  InterpFromCoarseLevel(rU_new[lev], IntVect{0}, IntVect{0}, rU_new[lev-1], 0, 0, 1,
87  geom[lev-1], geom[lev],
88  refRatio(lev-1), mapper_f, domain_bcs_type, BCVars::xvel_bc);
89 
90  //
91  //************************************************************************************************
92  // Interpolate y-momentum from coarse to fine level
93  // with InterpFromCoarseLevel which ASSUMES that all ghost cells have already been filled
94  // ************************************************************************************************
95  //
96  InterpFromCoarseLevel(rV_new[lev], IntVect{0}, IntVect{0}, rV_new[lev-1], 0, 0, 1,
97  geom[lev-1], geom[lev],
98  refRatio(lev-1), mapper_f, domain_bcs_type, BCVars::yvel_bc);
99 
100  //************************************************************************************************
101  // Interpolate z-momentum from coarse to fine level
102  // with InterpFromCoarseLevel which ASSUMES that all ghost cells have already been filled
103  // ************************************************************************************************
104  InterpFromCoarseLevel(rW_new[lev], IntVect{0}, IntVect{0}, rW_new[lev-1], 0, 0, 1,
105  geom[lev-1], geom[lev],
106  refRatio(lev-1), mapper_f, domain_bcs_type, BCVars::zvel_bc);
107  //
108  // *********************************************************
109  // After interpolation of momentum, convert back to velocity
110  // *********************************************************
111  //
112  for (int which_lev = lev-1; which_lev <= lev; which_lev++)
113  {
115  vars_new[which_lev][Vars::yvel],
116  vars_new[which_lev][Vars::zvel],
117  vars_new[which_lev][Vars::cons],
118  rU_new[which_lev],
119  rV_new[which_lev],
120  rW_new[which_lev],
121  Geom(lev).Domain(),
123  }
124 
125  // ***************************************************************************
126  // Physical bc's at domain boundary
127  // ***************************************************************************
128  IntVect ngvect_vels = vars_new[lev][Vars::xvel].nGrowVect();
129 
130  (*physbcs_cons[lev])(vars_new[lev][Vars::cons],0,ncomp_cons,ngvect_cons,time,BCVars::cons_bc,true);
131  ( *physbcs_u[lev])(vars_new[lev][Vars::xvel],0,1 ,ngvect_vels,time,BCVars::xvel_bc,true);
132  ( *physbcs_v[lev])(vars_new[lev][Vars::yvel],0,1 ,ngvect_vels,time,BCVars::yvel_bc,true);
134  ngvect_vels,time,BCVars::zvel_bc,true);
135 
136  // ***************************************************************************
137  // Since lev > 0 here we don't worry about m_r2d or wrfbdy data
138  // ***************************************************************************
139 }
void FillCoarsePatch(int lev, amrex::Real time)
Definition: ERF_FillCoarsePatch.cpp:21
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,
bool  allow_most_bcs = true 
)
private
34 {
35  BL_PROFILE_VAR("FillIntermediatePatch()",FillIntermediatePatch);
36  Interpolater* mapper;
37 
38  PhysBCFunctNoOp null_bc;
39 
40  //
41  // ***************************************************************************
42  // The first thing we do is interpolate the momenta on the "valid" faces of
43  // the fine grids (where the interface is coarse/fine not fine/fine) -- this
44  // will not be over-written by interpolation below because the FillPatch
45  // operators see these as valid faces. But we must have these interpolated
46  // values in the fine data before we call FillPatchTwoLevels.
47  //
48  // Also -- note that we might be filling values by interpolation at physical boundaries
49  // here but that's ok because we will overwrite those values when we impose
50  // the physical bc's below
51  // ***************************************************************************
52  if (lev>0) {
53  if (cf_set_width > 0) {
54  // We note that mfs_vel[Vars::cons] and mfs_mom[Vars::cons] are in fact the same pointer
55  FPr_c[lev-1].FillSet(*mfs_vel[Vars::cons], time, null_bc, domain_bcs_type);
56  }
57  if ( !cons_only && (cf_set_width >= 0) ) {
58  FPr_u[lev-1].FillSet(*mfs_mom[IntVars::xmom], time, null_bc, domain_bcs_type);
59  FPr_v[lev-1].FillSet(*mfs_mom[IntVars::ymom], time, null_bc, domain_bcs_type);
60  FPr_w[lev-1].FillSet(*mfs_mom[IntVars::zmom], time, null_bc, domain_bcs_type);
61  }
62  }
63 
64  // amrex::Print() << "LEVEL " << lev << " CONS ONLY " << cons_only <<
65  // " ICOMP NCOMP " << icomp_cons << " " << ncomp_cons << " NGHOST " << ng_cons << std::endl;
66 
67  if (!cons_only) {
68  AMREX_ALWAYS_ASSERT(mfs_mom.size() == IntVars::NumTypes);
69  AMREX_ALWAYS_ASSERT(mfs_vel.size() == Vars::NumTypes);
70  }
71 
72  // Enforce no penetration for thin immersed body
73  if (!cons_only) {
74  // Enforce no penetration for thin immersed body
75  if (xflux_imask[lev]) {
76  ApplyMask(*mfs_mom[IntVars::xmom], *xflux_imask[lev]);
77  }
78  if (yflux_imask[lev]) {
79  ApplyMask(*mfs_mom[IntVars::ymom], *yflux_imask[lev]);
80  }
81  if (zflux_imask[lev]) {
82  ApplyMask(*mfs_mom[IntVars::zmom], *zflux_imask[lev]);
83  }
84  }
85 
86  //
87  // We now start working on conserved quantities + VELOCITY
88  //
89  if (lev == 0)
90  {
91  // We don't do anything here because we will call the physbcs routines below,
92  // which calls FillBoundary and fills other domain boundary conditions
93  // Physical boundaries will be filled below
94 
95  if (!cons_only)
96  {
97  // ***************************************************************************
98  // We always come in to this call with updated momenta but we need to create updated velocity
99  // in order to impose the rest of the bc's
100  // ***************************************************************************
101  // This only fills VALID region of velocity
102  MomentumToVelocity(*mfs_vel[Vars::xvel], *mfs_vel[Vars::yvel], *mfs_vel[Vars::zvel],
103  *mfs_vel[Vars::cons],
104  *mfs_mom[IntVars::xmom], *mfs_mom[IntVars::ymom], *mfs_mom[IntVars::zmom],
105  Geom(lev).Domain(), domain_bcs_type);
106  }
107  }
108  else
109  {
110  //
111  // We must fill a temporary then copy it back so we don't double add/subtract
112  //
113  MultiFab mf(mfs_vel[Vars::cons]->boxArray(),mfs_vel[Vars::cons]->DistributionMap(),
114  mfs_vel[Vars::cons]->nComp() ,mfs_vel[Vars::cons]->nGrowVect());
115  //
116  // Set all components to 1.789e19, then copy just the density from *mfs_vel[Vars::cons]
117  //
118  mf.setVal(1.789e19);
119  MultiFab::Copy(mf,*mfs_vel[Vars::cons],Rho_comp,Rho_comp,1,mf.nGrowVect());
120 
121  Vector<MultiFab*> fmf = {mfs_vel[Vars::cons],mfs_vel[Vars::cons]};
122  Vector<MultiFab*> cmf = {&vars_old[lev-1][Vars::cons], &vars_new[lev-1][Vars::cons]};
123  Vector<Real> ctime = {t_old[lev-1], t_new[lev-1]};
124  Vector<Real> ftime = {time,time};
125 
126  // Impose physical bc's on fine data (note time and 0 are not used)
127  bool do_fb = true; bool do_terrain_adjustment = false;
128  (*physbcs_cons[lev])(*mfs_vel[Vars::cons],icomp_cons,ncomp_cons,IntVect{ng_cons},time,BCVars::cons_bc,
129  do_fb, do_terrain_adjustment);
130 
131  if ( (icomp_cons+ncomp_cons > 1) && (interpolation_type == StateInterpType::Perturbational) )
132  {
133  // Divide (rho theta) by rho to get theta
134  MultiFab::Divide(*mfs_vel[Vars::cons],*mfs_vel[Vars::cons],Rho_comp,RhoTheta_comp,1,IntVect{0});
135 
136  // Subtract theta_0 from theta
137  MultiFab::Subtract(*mfs_vel[Vars::cons],base_state[lev],BaseState::th0_comp,RhoTheta_comp,1,IntVect{0});
138 
139  if (!amrex::almostEqual(time,ctime[1])) {
140  MultiFab::Divide(vars_old[lev-1][Vars::cons], vars_old[lev-1][Vars::cons],
141  Rho_comp,RhoTheta_comp,1,vars_old[lev-1][Vars::cons].nGrowVect());
142  MultiFab::Subtract(vars_old[lev-1][Vars::cons], base_state[lev-1],
143  BaseState::th0_comp,RhoTheta_comp,1,vars_old[lev-1][Vars::cons].nGrowVect());
144  }
145  if (!amrex::almostEqual(time,ctime[0])) {
146  MultiFab::Divide(vars_new[lev-1][Vars::cons], vars_new[lev-1][Vars::cons],
147  Rho_comp,RhoTheta_comp,1,vars_new[lev-1][Vars::cons].nGrowVect());
148  MultiFab::Subtract(vars_new[lev-1][Vars::cons], base_state[lev-1],
149  BaseState::th0_comp,RhoTheta_comp,1,vars_new[lev-1][Vars::cons].nGrowVect());
150  }
151  }
152 
153  // Subtract rho_0 from rho before we interpolate -- note we only subtract
154  // on valid region of mf since the ghost cells will be filled below
155  if (icomp_cons == 0 && (interpolation_type == StateInterpType::Perturbational))
156  {
157  MultiFab::Subtract(*mfs_vel[Vars::cons],base_state[lev],BaseState::r0_comp,Rho_comp,1,IntVect{0});
158 
159  if (!amrex::almostEqual(time,ctime[1])) {
160  MultiFab::Subtract(vars_old[lev-1][Vars::cons], base_state[lev-1],
161  BaseState::r0_comp,Rho_comp,1,vars_old[lev-1][Vars::cons].nGrowVect());
162  }
163  if (!amrex::almostEqual(time,ctime[0])) {
164  MultiFab::Subtract(vars_new[lev-1][Vars::cons], base_state[lev-1],
165  BaseState::r0_comp,Rho_comp,1,vars_new[lev-1][Vars::cons].nGrowVect());
166  }
167  }
168 
169  // Call FillPatchTwoLevels which ASSUMES that all ghost cells have already been filled
170  mapper = &cell_cons_interp;
171  FillPatchTwoLevels(mf, IntVect{ng_cons}, IntVect(0,0,0),
172  time, cmf, ctime, fmf, ftime,
173  icomp_cons, icomp_cons, ncomp_cons, geom[lev-1], geom[lev],
174  refRatio(lev-1), mapper, domain_bcs_type,
175  icomp_cons);
176 
177  if (icomp_cons == 0 && (interpolation_type == StateInterpType::Perturbational))
178  {
179  // Restore the coarse values to what they were
180  if (!amrex::almostEqual(time,ctime[1])) {
181  MultiFab::Add(vars_old[lev-1][Vars::cons], base_state[lev-1],
182  BaseState::r0_comp,Rho_comp,1,vars_old[lev-1][Vars::cons].nGrowVect());
183  }
184  if (!amrex::almostEqual(time,ctime[0])) {
185  MultiFab::Add(vars_new[lev-1][Vars::cons], base_state[lev-1],
186  BaseState::r0_comp,Rho_comp,1,vars_new[lev-1][Vars::cons].nGrowVect());
187  }
188 
189  // Set values in the cells outside the domain boundary so that we can do the Add
190  // without worrying about uninitialized values outside the domain -- these
191  // will be filled in the physbcs call
192  mf.setDomainBndry(1.234e20,Rho_comp,1,geom[lev]);
193 
194  // Add rho_0 back to rho after we interpolate -- on all the valid + ghost region
195  MultiFab::Add(mf, base_state[lev],BaseState::r0_comp,Rho_comp,1,IntVect{ng_cons});
196  }
197 
198  if ( (icomp_cons+ncomp_cons > 1) && (interpolation_type == StateInterpType::Perturbational) )
199  {
200  // Add theta_0 to theta
201  if (!amrex::almostEqual(time,ctime[1])) {
202  MultiFab::Add(vars_old[lev-1][Vars::cons], base_state[lev-1],
203  BaseState::th0_comp,RhoTheta_comp,1,vars_old[lev-1][Vars::cons].nGrowVect());
204  MultiFab::Multiply(vars_old[lev-1][Vars::cons], vars_old[lev-1][Vars::cons],
205  Rho_comp,RhoTheta_comp,1,vars_old[lev-1][Vars::cons].nGrowVect());
206  }
207  if (!amrex::almostEqual(time,ctime[0])) {
208  MultiFab::Add(vars_new[lev-1][Vars::cons], base_state[lev-1],
209  BaseState::th0_comp,RhoTheta_comp,1,vars_new[lev-1][Vars::cons].nGrowVect());
210  MultiFab::Multiply(vars_new[lev-1][Vars::cons], vars_new[lev-1][Vars::cons],
211  Rho_comp,RhoTheta_comp,1,vars_new[lev-1][Vars::cons].nGrowVect());
212  }
213 
214  // Multiply theta by rho to get (rho theta)
215  MultiFab::Multiply(*mfs_vel[Vars::cons],*mfs_vel[Vars::cons],Rho_comp,RhoTheta_comp,1,IntVect{0});
216 
217  // Add theta_0 to theta
218  MultiFab::Add(*mfs_vel[Vars::cons],base_state[lev],BaseState::th0_comp,RhoTheta_comp,1,IntVect{0});
219 
220  // Add theta_0 back to theta
221  MultiFab::Add(mf,base_state[lev],BaseState::th0_comp,RhoTheta_comp,1,IntVect{ng_cons});
222 
223  // Multiply (theta) by rho to get (rho theta)
224  MultiFab::Multiply(mf,mf,Rho_comp,RhoTheta_comp,1,IntVect{ng_cons});
225  }
226 
227  // Make sure to only copy back the components we worked on
228  MultiFab::Copy(*mfs_vel[Vars::cons],mf,icomp_cons,icomp_cons,ncomp_cons,IntVect{ng_cons});
229 
230  // *****************************************************************************************
231 
232  if (!cons_only)
233  {
234  // ***************************************************************************
235  // We always come in to this call with updated momenta but we need to create updated velocity
236  // in order to impose the rest of the bc's
237  // ***************************************************************************
238  // This only fills VALID region of velocity
239  MomentumToVelocity(*mfs_vel[Vars::xvel], *mfs_vel[Vars::yvel], *mfs_vel[Vars::zvel],
240  *mfs_vel[Vars::cons],
241  *mfs_mom[IntVars::xmom], *mfs_mom[IntVars::ymom], *mfs_mom[IntVars::zmom],
242  Geom(lev).Domain(), domain_bcs_type);
243 
244  mapper = &face_cons_linear_interp;
245 
246  //
247  // NOTE: All interpolation here happens on velocities not momenta;
248  // note we only do the interpolation and FillBoundary here,
249  // physical bc's are imposed later
250  //
251  // NOTE: This will only fill velocity from coarse grid *outside* the fine grids
252  // unlike the FillSet calls above which filled momenta on the coarse/fine bdy
253  //
254 
255  MultiFab& mfu = *mfs_vel[Vars::xvel];
256 
257  fmf = {&mfu,&mfu};
258  cmf = {&vars_old[lev-1][Vars::xvel], &vars_new[lev-1][Vars::xvel]};
259 
260  // Call FillPatchTwoLevels which ASSUMES that all ghost cells have already been filled
261  FillPatchTwoLevels(mfu, IntVect{ng_vel}, IntVect(0,0,0),
262  time, cmf, ctime, fmf, ftime,
263  0, 0, 1, geom[lev-1], geom[lev],
264  refRatio(lev-1), mapper, domain_bcs_type,
266 
267  // *****************************************************************************************
268 
269  MultiFab& mfv = *mfs_vel[Vars::yvel];
270 
271  fmf = {&mfv,&mfv};
272  cmf = {&vars_old[lev-1][Vars::yvel], &vars_new[lev-1][Vars::yvel]};
273 
274  // Call FillPatchTwoLevels which ASSUMES that all ghost cells have already been filled
275  FillPatchTwoLevels(mfv, IntVect{ng_vel}, IntVect(0,0,0),
276  time, cmf, ctime, fmf, ftime,
277  0, 0, 1, geom[lev-1], geom[lev],
278  refRatio(lev-1), mapper, domain_bcs_type,
280 
281  // *****************************************************************************************
282 
283  MultiFab& mfw = *mfs_vel[Vars::zvel];
284 
285  fmf = {&mfw,&mfw};
286  cmf = {&vars_old[lev-1][Vars::zvel], &vars_new[lev-1][Vars::zvel]};
287 
288  // Call FillPatchTwoLevels which ASSUMES that all ghost cells have already been filled
289  FillPatchTwoLevels(mfw, IntVect{ng_vel}, IntVect(0,0,0),
290  time, cmf, ctime, fmf, ftime,
291  0, 0, 1, geom[lev-1], geom[lev],
292  refRatio(lev-1), mapper, domain_bcs_type,
294  } // !cons_only
295  } // lev > 0
296 
297  // ***************************************************************************
298  // Physical bc's at domain boundary
299  // ***************************************************************************
300  IntVect ngvect_cons = IntVect(ng_cons,ng_cons,ng_cons);
301  IntVect ngvect_vels = IntVect(ng_vel ,ng_vel ,ng_vel);
302 
303  bool do_fb = true;
304 
305 #ifdef ERF_USE_NETCDF
306  // We call this here because it is an ERF routine
307  if (use_real_bcs && (lev==0)) {
308  fill_from_realbdy(mfs_vel,time,cons_only,icomp_cons,ncomp_cons,ngvect_cons,ngvect_vels);
309  do_fb = false;
310  }
311 #endif
312 
313  if (m_r2d) fill_from_bndryregs(mfs_vel,time);
314 
315  // We call this even if init_type == InitType::Real because this routine will fill the vertical bcs
316  (*physbcs_cons[lev])(*mfs_vel[Vars::cons],icomp_cons,ncomp_cons,ngvect_cons,time,BCVars::cons_bc, do_fb);
317  if (!cons_only) {
318  (*physbcs_u[lev])(*mfs_vel[Vars::xvel],0,1,ngvect_vels,time,BCVars::xvel_bc, do_fb);
319  (*physbcs_v[lev])(*mfs_vel[Vars::yvel],0,1,ngvect_vels,time,BCVars::yvel_bc, do_fb);
320  (*physbcs_w[lev])(*mfs_vel[Vars::zvel],*mfs_vel[Vars::xvel],*mfs_vel[Vars::yvel],
321  ngvect_vels,time,BCVars::zvel_bc, do_fb);
322  }
323  // ***************************************************************************
324 
325  // MOST boundary conditions
326  if (!(cons_only && ncomp_cons == 1) && m_most && allow_most_bcs) {
327  m_most->impose_most_bcs(lev,mfs_vel,
328  Tau11_lev[lev].get(),
329  Tau22_lev[lev].get(),
330  Tau33_lev[lev].get(),
331  Tau12_lev[lev].get(), Tau21_lev[lev].get(),
332  Tau13_lev[lev].get(), Tau31_lev[lev].get(),
333  Tau23_lev[lev].get(), Tau32_lev[lev].get(),
334  SFS_hfx1_lev[lev].get(),
335  SFS_hfx2_lev[lev].get(),
336  SFS_hfx3_lev[lev].get(),
337  SFS_q1fx1_lev[lev].get(),
338  SFS_q1fx2_lev[lev].get(),
339  SFS_q1fx3_lev[lev].get(),
340  z_phys_nd[lev].get());
341  }
342 
343  // We always come in to this call with momenta so we need to leave with momenta!
344  // We need to make sure we convert back on all ghost cells/faces because this is
345  // how velocity from fine-fine copies (as well as physical and interpolated bcs) will be filled
346  if (!cons_only)
347  {
348  IntVect ngu = (!solverChoice.use_num_diff) ? IntVect(1,1,1) : mfs_vel[Vars::xvel]->nGrowVect();
349  IntVect ngv = (!solverChoice.use_num_diff) ? IntVect(1,1,1) : mfs_vel[Vars::yvel]->nGrowVect();
350  IntVect ngw = (!solverChoice.use_num_diff) ? IntVect(1,1,0) : mfs_vel[Vars::zvel]->nGrowVect();
351 
352  VelocityToMomentum(*mfs_vel[Vars::xvel], ngu,
353  *mfs_vel[Vars::yvel], ngv,
354  *mfs_vel[Vars::zvel], ngw,
355  *mfs_vel[Vars::cons],
356  *mfs_mom[IntVars::xmom], *mfs_mom[IntVars::ymom], *mfs_mom[IntVars::zmom],
357  Geom(lev).Domain(),
359  }
360 
361  mfs_mom[IntVars::cons]->FillBoundary(geom[lev].periodicity());
362  mfs_mom[IntVars::xmom]->FillBoundary(geom[lev].periodicity());
363  mfs_mom[IntVars::ymom]->FillBoundary(geom[lev].periodicity());
364  mfs_mom[IntVars::zmom]->FillBoundary(geom[lev].periodicity());
365 }
AMREX_GPU_HOST AMREX_FORCE_INLINE void ApplyMask(amrex::MultiFab &dst, const amrex::iMultiFab &imask, const int nghost=0)
Definition: ERF_Utils.H:362
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, bool allow_most_bcs=true)
Definition: ERF_FillIntermediatePatch.cpp:28
static bool use_real_bcs
Definition: ERF.H:1068
@ NumTypes
Definition: ERF_IndexDefines.H:143
Here is the call graph for this function:

◆ FillPatch() [1/2]

void ERF::FillPatch ( int  lev,
amrex::Real  time,
const amrex::Vector< amrex::MultiFab * > &  mfs_vel,
bool  cons_only = false 
)
private

◆ FillPatch() [2/2]

void ERF::FillPatch ( 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

◆ get_projection_bc()

Array< LinOpBCType, AMREX_SPACEDIM > ERF::get_projection_bc ( amrex::Orientation::Side  side) const
noexcept
18 {
19  amrex::Array<amrex::LinOpBCType,AMREX_SPACEDIM> r;
20  for (int dir = 0; dir < AMREX_SPACEDIM; ++dir) {
21  if (geom[0].isPeriodic(dir)) {
22  r[dir] = LinOpBCType::Periodic;
23  } else {
24  auto bc_type = domain_bc_type[Orientation(dir,side)];
25  if (bc_type == "Outflow") {
26  r[dir] = LinOpBCType::Dirichlet;
27  } else
28  {
29  r[dir] = LinOpBCType::Neumann;
30  }
31  }
32  }
33  return r;
34 }
amrex::Array< std::string, 2 *AMREX_SPACEDIM > domain_bc_type
Definition: ERF.H:890

◆ getAdvFluxReg()

AMREX_FORCE_INLINE amrex::YAFluxRegister* ERF::getAdvFluxReg ( int  lev)
inlineprivate
1238  {
1239  return advflux_reg[lev];
1240  }

◆ getCPUTime()

static amrex::Real ERF::getCPUTime ( )
inlinestaticprivate
1315  {
1316  int numCores = amrex::ParallelDescriptor::NProcs();
1317 #ifdef _OPENMP
1318  numCores = numCores * omp_get_max_threads();
1319 #endif
1320 
1321  amrex::Real T =
1322  numCores * (amrex::ParallelDescriptor::second() - startCPUTime) +
1324 
1325  return T;
1326  }
static amrex::Real previousCPUTimeUsed
Definition: ERF.H:1311
static amrex::Real startCPUTime
Definition: ERF.H:1310
@ T
Definition: ERF_IndexDefines.H:99

◆ GotoNextLine()

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

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

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

◆ init1DArrays()

void ERF::init1DArrays ( )
private

◆ init_bcs()

void ERF::init_bcs ( )
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, 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  bool rho_read = false;
23  Vector<Real> cons_dir_init(NBCVAR_max,0.0);
24  cons_dir_init[BCVars::Rho_bc_comp] = 1.0;
25  cons_dir_init[BCVars::RhoTheta_bc_comp] = -1.0;
26  auto f = [this,&rho_read] (std::string const& bcid, Orientation ori)
27  {
28  // These are simply defaults for Dirichlet faces -- they should be over-written below
30  m_bc_extdir_vals[BCVars::RhoTheta_bc_comp][ori] = -1.0; // It is important to set this negative
31  // because the sign is tested on below
40 
41  m_bc_extdir_vals[BCVars::xvel_bc][ori] = 0.0; // default
44 
45  // These are simply defaults for Neumann gradients -- they should be over-written below
48 
57 
61 
62  std::string pp_text;
63  if (pp_prefix == "erf") {
64  pp_text = bcid;
65  } else {
66  pp_text = pp_prefix + "." + bcid;
67  }
68  ParmParse pp(pp_text);
69  std::string bc_type_in = "null";
70  pp.query("type", bc_type_in);
71  std::string bc_type = amrex::toLower(bc_type_in);
72 
73  if (bc_type == "symmetry")
74  {
75  // Print() << bcid << " set to symmetry.\n";
77  domain_bc_type[ori] = "Symmetry";
78  }
79  else if (bc_type == "outflow")
80  {
81  // Print() << bcid << " set to outflow.\n";
83  domain_bc_type[ori] = "Outflow";
84  }
85  else if (bc_type == "open")
86  {
87  // Print() << bcid << " set to open.\n";
88  AMREX_ASSERT_WITH_MESSAGE((ori.coordDir() != 2), "Open boundary not valid on zlo or zhi!");
90  domain_bc_type[ori] = "Open";
91  }
92  else if (bc_type == "ho_outflow")
93  {
95  domain_bc_type[ori] = "HO_Outflow";
96  }
97 
98  else if (bc_type == "inflow")
99  {
100  // Print() << bcid << " set to inflow.\n";
102  domain_bc_type[ori] = "Inflow";
103 
104  std::vector<Real> v;
105  if (input_bndry_planes && m_r2d->ingested_velocity()) {
109  } else {
110  // Test for input data file if at xlo face
111  std::string dirichlet_file;
112  auto file_exists = pp.query("dirichlet_file", dirichlet_file);
113  if (file_exists) {
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  Real theta_in = 0.;
133  if (input_bndry_planes && m_r2d->ingested_theta()) {
135  } else {
136  if (rho_in > 0) {
137  pp.get("theta", theta_in);
138  }
139  m_bc_extdir_vals[BCVars::RhoTheta_bc_comp][ori] = rho_in*theta_in;
140  }
141  Real scalar_in = 0.;
142  if (input_bndry_planes && m_r2d->ingested_scalar()) {
144  } else {
145  if (pp.query("scalar", scalar_in))
146  m_bc_extdir_vals[BCVars::RhoScalar_bc_comp][ori] = rho_in*scalar_in;
147  }
148 
149  if (solverChoice.moisture_type != MoistureType::None) {
150  Real qv_in = 0.;
151  if (input_bndry_planes && m_r2d->ingested_q1()) {
153  } else {
154  if (pp.query("qv", qv_in))
155  m_bc_extdir_vals[BCVars::RhoQ1_bc_comp][ori] = rho_in*qv_in;
156  }
157  Real qc_in = 0.;
158  if (input_bndry_planes && m_r2d->ingested_q2()) {
160  } else {
161  if (pp.query("qc", qc_in))
162  m_bc_extdir_vals[BCVars::RhoQ2_bc_comp][ori] = rho_in*qc_in;
163  }
164  }
165 
166  Real KE_in = 0.;
167  if (input_bndry_planes && m_r2d->ingested_KE()) {
169  } else {
170  if (pp.query("KE", KE_in))
171  m_bc_extdir_vals[BCVars::RhoKE_bc_comp][ori] = rho_in*KE_in;
172  }
173  }
174  else if (bc_type == "noslipwall")
175  {
176  // Print() << bcid <<" set to no-slip wall.\n";
178  domain_bc_type[ori] = "NoSlipWall";
179 
180  std::vector<Real> v;
181 
182  // The values of m_bc_extdir_vals default to 0.
183  // But if we find "velocity" in the inputs file, use those values instead.
184  if (pp.queryarr("velocity", v, 0, AMREX_SPACEDIM))
185  {
186  v[ori.coordDir()] = 0.0;
187  m_bc_extdir_vals[BCVars::xvel_bc][ori] = v[0];
188  m_bc_extdir_vals[BCVars::yvel_bc][ori] = v[1];
189  m_bc_extdir_vals[BCVars::zvel_bc][ori] = v[2];
190  }
191 
192  Real rho_in;
193  rho_read = pp.query("density", rho_in);
194  if (rho_read)
195  {
196  m_bc_extdir_vals[BCVars::Rho_bc_comp][ori] = rho_in;
197  }
198 
199  Real theta_in;
200  if (pp.query("theta", theta_in))
201  {
203  }
204 
205  Real theta_grad_in;
206  if (pp.query("theta_grad", theta_grad_in))
207  {
208  m_bc_neumann_vals[BCVars::RhoTheta_bc_comp][ori] = theta_grad_in;
209  }
210 
211  Real qv_in;
212  if (pp.query("qv", qv_in))
213  {
215  }
216  }
217  else if (bc_type == "slipwall")
218  {
219  // Print() << bcid <<" set to slip wall.\n";
220 
222  domain_bc_type[ori] = "SlipWall";
223 
224  Real rho_in;
225  if (pp.query("density", rho_in))
226  {
227  m_bc_extdir_vals[BCVars::Rho_bc_comp][ori] = rho_in;
228  }
229 
230  Real theta_in;
231  if (pp.query("theta", theta_in))
232  {
234  }
235 
236  Real rho_grad_in;
237  if (pp.query("density_grad", rho_grad_in))
238  {
239  m_bc_neumann_vals[BCVars::Rho_bc_comp][ori] = rho_grad_in;
240  }
241 
242  Real theta_grad_in;
243  if (pp.query("theta_grad", theta_grad_in))
244  {
245  m_bc_neumann_vals[BCVars::RhoTheta_bc_comp][ori] = theta_grad_in;
246  }
247  }
248  else if (bc_type == "most")
249  {
250  phys_bc_type[ori] = ERF_BC::MOST;
251  domain_bc_type[ori] = "MOST";
252  }
253  else
254  {
256  }
257 
258  if (geom[0].isPeriodic(ori.coordDir())) {
259  domain_bc_type[ori] = "Periodic";
260  if (phys_bc_type[ori] == ERF_BC::undefined)
261  {
263  } else {
264  Abort("Wrong BC type for periodic boundary");
265  }
266  }
267 
268  if (phys_bc_type[ori] == ERF_BC::undefined)
269  {
270  Print() << "BC Type specified for face " << bcid << " is " << bc_type_in << std::endl;
271  Abort("This BC type is unknown");
272  }
273  };
274 
275  f("xlo", Orientation(Direction::x,Orientation::low));
276  f("xhi", Orientation(Direction::x,Orientation::high));
277  f("ylo", Orientation(Direction::y,Orientation::low));
278  f("yhi", Orientation(Direction::y,Orientation::high));
279  f("zlo", Orientation(Direction::z,Orientation::low));
280  f("zhi", Orientation(Direction::z,Orientation::high));
281 
282  // *****************************************************************************
283  //
284  // Here we translate the physical boundary conditions -- one type per face --
285  // into logical boundary conditions for each velocity component
286  //
287  // *****************************************************************************
288  {
289  domain_bcs_type.resize(AMREX_SPACEDIM+NBCVAR_max);
290  domain_bcs_type_d.resize(AMREX_SPACEDIM+NBCVAR_max);
291 
292  for (OrientationIter oit; oit; ++oit) {
293  Orientation ori = oit();
294  int dir = ori.coordDir();
295  Orientation::Side side = ori.faceDir();
296  auto const bct = phys_bc_type[ori];
297  if ( bct == ERF_BC::symmetry )
298  {
299  if (side == Orientation::low) {
300  for (int i = 0; i < AMREX_SPACEDIM; i++) {
302  }
304  } else {
305  for (int i = 0; i < AMREX_SPACEDIM; i++) {
307  }
309  }
310  }
311  else if (bct == ERF_BC::outflow or bct == ERF_BC::ho_outflow )
312  {
313  if (side == Orientation::low) {
314  for (int i = 0; i < AMREX_SPACEDIM; i++) {
316  }
318  } else {
319  for (int i = 0; i < AMREX_SPACEDIM; i++) {
321  }
323  }
324  }
325  else if (bct == ERF_BC::open)
326  {
327  if (side == Orientation::low) {
328  for (int i = 0; i < AMREX_SPACEDIM; i++)
330  } else {
331  for (int i = 0; i < AMREX_SPACEDIM; i++)
333  }
334  }
335  else if (bct == ERF_BC::inflow)
336  {
337  if (side == Orientation::low) {
338  for (int i = 0; i < AMREX_SPACEDIM; i++) {
340  if (input_bndry_planes && dir < 2 && m_r2d->ingested_velocity()) {
342  }
343  }
344  } else {
345  for (int i = 0; i < AMREX_SPACEDIM; i++) {
347  if (input_bndry_planes && dir < 2 && m_r2d->ingested_velocity()) {
349  }
350  }
351  }
352  }
353  else if (bct == ERF_BC::no_slip_wall)
354  {
355  if (side == Orientation::low) {
356  for (int i = 0; i < AMREX_SPACEDIM; i++) {
358  }
359  } else {
360  for (int i = 0; i < AMREX_SPACEDIM; i++) {
362  }
363  }
364  }
365  else if (bct == ERF_BC::slip_wall)
366  {
367  if (side == Orientation::low) {
368  for (int i = 0; i < AMREX_SPACEDIM; i++) {
370  }
371  // Only normal direction has ext_dir
373 
374  } else {
375  for (int i = 0; i < AMREX_SPACEDIM; i++) {
377  }
378  // Only normal direction has ext_dir
380  }
381  }
382  else if (bct == ERF_BC::periodic)
383  {
384  if (side == Orientation::low) {
385  for (int i = 0; i < AMREX_SPACEDIM; i++) {
387  }
388  } else {
389  for (int i = 0; i < AMREX_SPACEDIM; i++) {
391  }
392  }
393  }
394  else if ( bct == ERF_BC::MOST )
395  {
396  AMREX_ALWAYS_ASSERT(dir == 2 && side == Orientation::low);
400  }
401  }
402  }
403 
404  // *****************************************************************************
405  //
406  // Here we translate the physical boundary conditions -- one type per face --
407  // into logical boundary conditions for each cell-centered variable
408  // (including the base state variables)
409  // NOTE: all "scalars" share the same type of boundary condition
410  //
411  // *****************************************************************************
412  {
413  for (OrientationIter oit; oit; ++oit) {
414  Orientation ori = oit();
415  int dir = ori.coordDir();
416  Orientation::Side side = ori.faceDir();
417  auto const bct = phys_bc_type[ori];
418  if ( bct == ERF_BC::symmetry )
419  {
420  if (side == Orientation::low) {
421  for (int i = 0; i < NBCVAR_max; i++) {
423  }
424  } else {
425  for (int i = 0; i < NBCVAR_max; i++) {
427  }
428  }
429  }
430  else if ( bct == ERF_BC::outflow )
431  {
432  if (side == Orientation::low) {
433  for (int i = 0; i < NBCVAR_max; i++) {
435  }
436  } else {
437  for (int i = 0; i < NBCVAR_max; i++) {
439  }
440  }
441  }
442  else if ( bct == ERF_BC::ho_outflow )
443  {
444  if (side == Orientation::low) {
445  for (int i = 0; i < NBCVAR_max; i++) {
447  }
448  } else {
449  for (int i = 0; i < NBCVAR_max; i++) {
451  }
452  }
453  }
454  else if ( bct == ERF_BC::open )
455  {
456  if (side == Orientation::low) {
457  for (int i = 0; i < NBCVAR_max; i++)
459  } else {
460  for (int i = 0; i < NBCVAR_max; i++)
462  }
463  }
464  else if ( bct == ERF_BC::no_slip_wall )
465  {
466  if (side == Orientation::low) {
467  for (int i = 0; i < NBCVAR_max; i++) {
469  if (m_bc_extdir_vals[BCVars::cons_bc+i][ori] != cons_dir_init[BCVars::cons_bc+i]) {
470  if (rho_read) {
472  } else {
474  }
475  }
476  }
477  if (std::abs(m_bc_neumann_vals[BCVars::RhoTheta_bc_comp][ori]) > 0.) {
479  }
480  } else {
481  for (int i = 0; i < NBCVAR_max; i++) {
483  if (m_bc_extdir_vals[BCVars::cons_bc+i][ori] != cons_dir_init[BCVars::cons_bc+i]) {
484  if (rho_read) {
486  } else {
488  }
489  }
490  }
491  if (std::abs(m_bc_neumann_vals[BCVars::RhoTheta_bc_comp][ori]) > 0.) {
493  }
494  }
495  }
496  else if (bct == ERF_BC::slip_wall)
497  {
498  if (side == Orientation::low) {
499  for (int i = 0; i < NBCVAR_max; i++) {
501  if (m_bc_extdir_vals[BCVars::cons_bc+i][ori] != cons_dir_init[BCVars::cons_bc+i]) {
502  if (rho_read) {
504  } else {
506  }
507  }
508  }
509  if (std::abs(m_bc_neumann_vals[BCVars::RhoTheta_bc_comp][ori]) > 0.) {
511  }
512  if (std::abs(m_bc_neumann_vals[BCVars::Rho_bc_comp][ori]) > 0.) {
514  }
515  } else {
516  for (int i = 0; i < NBCVAR_max; i++) {
518  if (m_bc_extdir_vals[BCVars::cons_bc+i][ori] != cons_dir_init[BCVars::cons_bc+i]) {
519  if (rho_read) {
521  } else {
523  }
524  }
525  }
526  if (std::abs(m_bc_neumann_vals[BCVars::RhoTheta_bc_comp][ori]) > 0.) {
528  }
529  if (std::abs(m_bc_neumann_vals[BCVars::Rho_bc_comp][ori]) > 0.) {
531  }
532  }
533  }
534  else if (bct == ERF_BC::inflow)
535  {
536  if (side == Orientation::low) {
537  for (int i = 0; i < NBCVAR_max; i++) {
539  if (input_bndry_planes && dir < 2 && (
540  ( (BCVars::cons_bc+i == BCVars::Rho_bc_comp) && m_r2d->ingested_density()) ||
541  ( (BCVars::cons_bc+i == BCVars::RhoTheta_bc_comp) && m_r2d->ingested_theta() ) ||
542  ( (BCVars::cons_bc+i == BCVars::RhoKE_bc_comp) && m_r2d->ingested_KE() ) ||
543  ( (BCVars::cons_bc+i == BCVars::RhoScalar_bc_comp) && m_r2d->ingested_scalar() ) ||
544  ( (BCVars::cons_bc+i == BCVars::RhoQ1_bc_comp) && m_r2d->ingested_q1() ) ||
545  ( (BCVars::cons_bc+i == BCVars::RhoQ2_bc_comp) && m_r2d->ingested_q2() )) )
546  {
548  }
549  else if (m_bc_extdir_vals[BCVars::Rho_bc_comp][ori] == 0) {
551  }
552  }
553  } else {
554  for (int i = 0; i < NBCVAR_max; i++) {
556  if (input_bndry_planes && dir < 2 && (
557  ( (BCVars::cons_bc+i == BCVars::Rho_bc_comp) && m_r2d->ingested_density()) ||
558  ( (BCVars::cons_bc+i == BCVars::RhoTheta_bc_comp) && m_r2d->ingested_theta() ) ||
559  ( (BCVars::cons_bc+i == BCVars::RhoKE_bc_comp) && m_r2d->ingested_KE() ) ||
560  ( (BCVars::cons_bc+i == BCVars::RhoScalar_bc_comp) && m_r2d->ingested_scalar() ) ||
561  ( (BCVars::cons_bc+i == BCVars::RhoQ1_bc_comp) && m_r2d->ingested_q1() ) ||
562  ( (BCVars::cons_bc+i == BCVars::RhoQ2_bc_comp) && m_r2d->ingested_q2() )
563  ) )
564  {
566  }
567  else if (m_bc_extdir_vals[BCVars::Rho_bc_comp][ori] == 0) {
569  }
570  }
571  }
572  }
573  else if (bct == ERF_BC::periodic)
574  {
575  if (side == Orientation::low) {
576  for (int i = 0; i < NBCVAR_max; i++) {
578  }
579  } else {
580  for (int i = 0; i < NBCVAR_max; i++) {
582  }
583  }
584  }
585  else if ( bct == ERF_BC::MOST )
586  {
587  AMREX_ALWAYS_ASSERT(dir == 2 && side == Orientation::low);
588  for (int i = 0; i < NBCVAR_max; i++) {
590  }
591  }
592  }
593  }
594 
595  // NOTE: Gpu:copy is a wrapper to htod_memcpy (GPU) or memcpy (CPU) and is a blocking comm
596  Gpu::copy(Gpu::hostToDevice, domain_bcs_type.begin(), domain_bcs_type.end(), domain_bcs_type_d.begin());
597 }
#define NBCVAR_max
Definition: ERF_IndexDefines.H:29
@ ho_outflow
void init_Dirichlet_bc_data(const std::string input_file)
Definition: ERF_InitBCs.cpp:599
amrex::Array< amrex::Array< amrex::Real, AMREX_SPACEDIM *2 >, AMREX_SPACEDIM+NBCVAR_max > m_bc_neumann_vals
Definition: ERF.H:896
@ RhoQ6_bc_comp
Definition: ERF_IndexDefines.H:86
@ RhoQ1_bc_comp
Definition: ERF_IndexDefines.H:81
@ RhoQ4_bc_comp
Definition: ERF_IndexDefines.H:84
@ RhoKE_bc_comp
Definition: ERF_IndexDefines.H:79
@ RhoQ3_bc_comp
Definition: ERF_IndexDefines.H:83
@ RhoTheta_bc_comp
Definition: ERF_IndexDefines.H:78
@ RhoQ2_bc_comp
Definition: ERF_IndexDefines.H:82
@ Rho_bc_comp
Definition: ERF_IndexDefines.H:77
@ RhoQ5_bc_comp
Definition: ERF_IndexDefines.H:85
@ neumann
Definition: ERF_IndexDefines.H:184
@ open
Definition: ERF_IndexDefines.H:186
@ reflect_odd
Definition: ERF_IndexDefines.H:176
@ foextrap
Definition: ERF_IndexDefines.H:179
@ ext_dir
Definition: ERF_IndexDefines.H:180
@ ext_dir_prim
Definition: ERF_IndexDefines.H:182
@ hoextrapcc
Definition: ERF_IndexDefines.H:187
@ int_dir
Definition: ERF_IndexDefines.H:177
@ neumann_int
Definition: ERF_IndexDefines.H:185
@ reflect_even
Definition: ERF_IndexDefines.H:178
Here is the call graph for this function:

◆ init_custom()

void ERF::init_custom ( int  lev)
private

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

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

Parameters
levInteger specifying the current level
27 {
28  auto& lev_new = vars_new[lev];
29 
30  MultiFab r_hse(base_state[lev], make_alias, BaseState::r0_comp, 1);
31  MultiFab p_hse(base_state[lev], make_alias, BaseState::p0_comp, 1);
32 
33  MultiFab cons_pert(lev_new[Vars::cons].boxArray(), lev_new[Vars::cons].DistributionMap(),
34  lev_new[Vars::cons].nComp() , lev_new[Vars::cons].nGrow());
35  MultiFab xvel_pert(lev_new[Vars::xvel].boxArray(), lev_new[Vars::xvel].DistributionMap(), 1, lev_new[Vars::xvel].nGrowVect());
36  MultiFab yvel_pert(lev_new[Vars::yvel].boxArray(), lev_new[Vars::yvel].DistributionMap(), 1, lev_new[Vars::yvel].nGrowVect());
37  MultiFab zvel_pert(lev_new[Vars::zvel].boxArray(), lev_new[Vars::zvel].DistributionMap(), 1, lev_new[Vars::zvel].nGrowVect());
38 
39  // Default all perturbations to zero
40  cons_pert.setVal(0.);
41  xvel_pert.setVal(0.);
42  yvel_pert.setVal(0.);
43  zvel_pert.setVal(0.);
44 
45 #ifdef _OPENMP
46 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
47 #endif
48  for (MFIter mfi(lev_new[Vars::cons], TileNoZ()); mfi.isValid(); ++mfi)
49  {
50  const Box &bx = mfi.tilebox();
51  const Box &xbx = mfi.tilebox(IntVect(1,0,0));
52  const Box &ybx = mfi.tilebox(IntVect(0,1,0));
53  const Box &zbx = mfi.tilebox(IntVect(0,0,1));
54 
55  const auto &cons_pert_arr = cons_pert.array(mfi);
56  const auto &xvel_pert_arr = xvel_pert.array(mfi);
57  const auto &yvel_pert_arr = yvel_pert.array(mfi);
58  const auto &zvel_pert_arr = zvel_pert.array(mfi);
59 
60  Array4<Real const> cons_arr = lev_new[Vars::cons].const_array(mfi);
61  Array4<Real const> z_nd_arr = (solverChoice.terrain_type != TerrainType::None) ? z_phys_nd[lev]->const_array(mfi) : Array4<Real const>{};
62  Array4<Real const> z_cc_arr = (solverChoice.terrain_type != TerrainType::None) ? z_phys_cc[lev]->const_array(mfi) : Array4<Real const>{};
63 
64  Array4<Real const> mf_m = mapfac_m[lev]->array(mfi);
65  Array4<Real const> mf_u = mapfac_m[lev]->array(mfi);
66  Array4<Real const> mf_v = mapfac_m[lev]->array(mfi);
67 
68  Array4<Real> r_hse_arr = r_hse.array(mfi);
69  Array4<Real> p_hse_arr = p_hse.array(mfi);
70 
71  prob->init_custom_pert(bx, xbx, ybx, zbx, cons_arr, cons_pert_arr,
72  xvel_pert_arr, yvel_pert_arr, zvel_pert_arr,
73  r_hse_arr, p_hse_arr, z_nd_arr, z_cc_arr,
74  geom[lev].data(), mf_m, mf_u, mf_v,
75  solverChoice);
76  } //mfi
77 
78  // Add problem-specific perturbation to background flow
79  MultiFab::Add(lev_new[Vars::cons], cons_pert, Rho_comp, Rho_comp, 1, cons_pert.nGrow());
80  MultiFab::Add(lev_new[Vars::cons], cons_pert, RhoTheta_comp, RhoTheta_comp, 1, cons_pert.nGrow());
81  MultiFab::Add(lev_new[Vars::cons], cons_pert, RhoScalar_comp,RhoScalar_comp,NSCALARS, cons_pert.nGrow());
82 
83  // RhoKE is only relevant if using Deardorff with LES or MYNN with PBL
84  if ((solverChoice.turbChoice[lev].les_type == LESType::Deardorff) ||
85  (solverChoice.turbChoice[lev].pbl_type == PBLType::MYNN25)) {
86  MultiFab::Add(lev_new[Vars::cons], cons_pert, RhoKE_comp, RhoKE_comp, 1, cons_pert.nGrow());
87  }
88 
89  if (solverChoice.moisture_type != MoistureType::None) {
90  int qstate_size = micro->Get_Qstate_Size();
91  MultiFab::Add(lev_new[Vars::cons], cons_pert, RhoQ1_comp, RhoQ1_comp, 1, cons_pert.nGrow());
92  MultiFab::Add(lev_new[Vars::cons], cons_pert, RhoQ2_comp, RhoQ2_comp, 1, cons_pert.nGrow());
93  for (int q_offset(2); q_offset<qstate_size; ++q_offset) {
94  int q_idx = RhoQ1_comp+q_offset;
95  MultiFab::Add(lev_new[Vars::cons], cons_pert, q_idx, q_idx, 1, cons_pert.nGrow());
96  }
97  }
98 
99  MultiFab::Add(lev_new[Vars::xvel], xvel_pert, 0, 0, 1, xvel_pert.nGrowVect());
100  MultiFab::Add(lev_new[Vars::yvel], yvel_pert, 0, 0, 1, yvel_pert.nGrowVect());
101  MultiFab::Add(lev_new[Vars::zvel], zvel_pert, 0, 0, 1, zvel_pert.nGrowVect());
102 }
Here is the call graph for this function:

◆ init_Dirichlet_bc_data()

void ERF::init_Dirichlet_bc_data ( const std::string  input_file)
private
600 {
601  const bool use_terrain = (solverChoice.terrain_type != TerrainType::None);
602 
603  // Read the dirichlet_input file
604  Print() << "dirichlet_input file location : " << input_file << std::endl;
605  std::ifstream input_reader(input_file);
606  if (!input_reader.is_open()) {
607  amrex::Abort("Error opening the dirichlet_input file.\n");
608  }
609 
610  Print() << "Successfully opened the dirichlet_input file. Now reading... " << std::endl;
611  std::string line;
612 
613  // Size of Ninp (number of z points in input file)
614  Vector<Real> z_inp_tmp, u_inp_tmp, v_inp_tmp, w_inp_tmp;
615 
616  const int klo = geom[0].Domain().smallEnd()[2];
617  const int khi = geom[0].Domain().bigEnd()[2];
618 
619  const Real zbot = (use_terrain) ? zlevels_stag[0][klo] : geom[0].ProbLo(2);
620  const Real ztop = (use_terrain) ? zlevels_stag[0][khi+1] : geom[0].ProbHi(2);
621 
622  // Add surface
623  z_inp_tmp.push_back(zbot); // height above sea level [m]
624  u_inp_tmp.push_back(0.);
625  v_inp_tmp.push_back(0.);
626  w_inp_tmp.push_back(0.);
627 
628  // Read the vertical profile at each given height
629  Real z, u, v, w;
630  while(std::getline(input_reader, line)) {
631  std::istringstream iss_z(line);
632  iss_z >> z >> u >> v >> w;
633  if (z == zbot) {
634  u_inp_tmp[0] = u;
635  v_inp_tmp[0] = v;
636  w_inp_tmp[0] = w;
637  } else {
638  AMREX_ALWAYS_ASSERT(z > z_inp_tmp[z_inp_tmp.size()-1]); // sounding is increasing in height
639  z_inp_tmp.push_back(z);
640  u_inp_tmp.push_back(u);
641  v_inp_tmp.push_back(v);
642  w_inp_tmp.push_back(w);
643  if (z >= ztop) break;
644  }
645  }
646 
647  amrex::Print() << "Successfully read and interpolated the dirichlet_input file..." << std::endl;
648  input_reader.close();
649 
650  for (int lev = 0; lev <= max_level; lev++) {
651 
652  const int Nz = geom[lev].Domain().size()[2];
653  const Real dz = geom[lev].CellSize()[2];
654 
655  // Size of Nz (domain grid)
656  Vector<Real> zcc_inp(Nz );
657  Vector<Real> znd_inp(Nz+1);
658  Vector<Real> u_inp(Nz ); xvel_bc_data[lev].resize(Nz ,0.0);
659  Vector<Real> v_inp(Nz ); yvel_bc_data[lev].resize(Nz ,0.0);
660  Vector<Real> w_inp(Nz+1); zvel_bc_data[lev].resize(Nz+1,0.0);
661 
662  // At this point, we have an input from zbot up to
663  // z_inp_tmp[N-1] >= ztop. Now, interpolate to grid level 0 heights
664  const int Ninp = z_inp_tmp.size();
665  for (int k(0); k<Nz; ++k) {
666  zcc_inp[k] = (use_terrain) ? 0.5 * (zlevels_stag[0][k] + zlevels_stag[0][k+1])
667  : zbot + (k + 0.5) * dz;
668  znd_inp[k] = (use_terrain) ? zlevels_stag[0][k+1] : zbot + (k) * dz;
669  u_inp[k] = interpolate_1d(z_inp_tmp.dataPtr(), u_inp_tmp.dataPtr(), zcc_inp[k], Ninp);
670  v_inp[k] = interpolate_1d(z_inp_tmp.dataPtr(), v_inp_tmp.dataPtr(), zcc_inp[k], Ninp);
671  w_inp[k] = interpolate_1d(z_inp_tmp.dataPtr(), w_inp_tmp.dataPtr(), znd_inp[k], Ninp);
672  }
673  znd_inp[Nz] = ztop;
674  w_inp[Nz] = interpolate_1d(z_inp_tmp.dataPtr(), w_inp_tmp.dataPtr(), ztop, Ninp);
675 
676  // Copy host data to the device
677  Gpu::copy(Gpu::hostToDevice, u_inp.begin(), u_inp.end(), xvel_bc_data[lev].begin());
678  Gpu::copy(Gpu::hostToDevice, v_inp.begin(), v_inp.end(), yvel_bc_data[lev].begin());
679  Gpu::copy(Gpu::hostToDevice, w_inp.begin(), w_inp.end(), zvel_bc_data[lev].begin());
680 
681  // NOTE: These device vectors are passed to the PhysBC constructors when that
682  // class is instantiated in ERF_MakeNewArrays.cpp.
683  } // lev
684 }
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
51 {
52  // We only want to read the file once -- here we fill one FArrayBox (per variable) that spans the domain
53  if (lev == 0) {
55  Error("input_sounding file name must be provided via input");
56  }
57 
59 
60  // this will interpolate the input profiles to the nominal height levels
61  // (ranging from 0 to the domain top)
62  for (int n = 0; n < input_sounding_data.n_sounding_files; n++) {
64  }
65 
66  // this will calculate the hydrostatically balanced density and pressure
67  // profiles following WRF ideal.exe
69 
70  } else {
71  //
72  // We need to do this interp from coarse level in order to set the values of
73  // the base state inside the domain but outside of the fine region
74  //
75  base_state[lev-1].FillBoundary(geom[lev-1].periodicity());
76  //
77  // NOTE: this interpolater assumes that ALL ghost cells of the coarse MultiFab
78  // have been pre-filled - this includes ghost cells both inside and outside
79  // the domain
80  //
81  InterpFromCoarseLevel(base_state[lev], base_state[lev].nGrowVect(),
82  IntVect(0,0,0), // do not fill ghost cells outside the domain
83  base_state[lev-1], 0, 0, base_state[lev].nComp(),
84  geom[lev-1], geom[lev],
85  refRatio(lev-1), &cell_cons_interp,
87 
88  // We need to do this here because the interpolation above may leave corners unfilled
89  // when the corners need to be filled by, for example, reflection of the fine ghost
90  // cell outside the fine region but inide the domain.
91  (*physbcs_base[lev])(base_state[lev],0,base_state[lev].nComp(),base_state[lev].nGrowVect());
92  }
93 
94  auto& lev_new = vars_new[lev];
95 
96  // update if init_sounding_ideal == true
97  MultiFab r_hse (base_state[lev], make_alias, BaseState::r0_comp, 1);
98  MultiFab p_hse (base_state[lev], make_alias, BaseState::p0_comp, 1);
99  MultiFab pi_hse(base_state[lev], make_alias, BaseState::pi0_comp, 1);
100  MultiFab th_hse(base_state[lev], make_alias, BaseState::th0_comp, 1);
101 
102  const Real l_gravity = solverChoice.gravity;
103  const Real l_rdOcp = solverChoice.rdOcp;
104  const bool l_moist = (solverChoice.moisture_type != MoistureType::None);
105 
106 #ifdef _OPENMP
107 #pragma omp parallel if (Gpu::notInLaunchRegion())
108 #endif
109  for (MFIter mfi(lev_new[Vars::cons], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
110  const Box &bx = mfi.tilebox();
111  const auto &cons_arr = lev_new[Vars::cons].array(mfi);
112  const auto &xvel_arr = lev_new[Vars::xvel].array(mfi);
113  const auto &yvel_arr = lev_new[Vars::yvel].array(mfi);
114  const auto &zvel_arr = lev_new[Vars::zvel].array(mfi);
115  Array4<Real> r_hse_arr = r_hse.array(mfi);
116  Array4<Real> p_hse_arr = p_hse.array(mfi);
117  Array4<Real> pi_hse_arr = pi_hse.array(mfi);
118  Array4<Real> th_hse_arr = th_hse.array(mfi);
119 
120  Array4<Real const> z_cc_arr = (solverChoice.terrain_type != TerrainType::None) ? z_phys_cc[lev]->const_array(mfi) : Array4<Real const>{};
121  Array4<Real const> z_nd_arr = (solverChoice.terrain_type != TerrainType::None) ? z_phys_nd[lev]->const_array(mfi) : Array4<Real const>{};
122 
124  {
125  // HSE will be initialized here, interpolated from values previously
126  // calculated by calc_rho_p()
128  bx, cons_arr,
129  r_hse_arr, p_hse_arr, pi_hse_arr, th_hse_arr,
130  geom[lev].data(), z_cc_arr,
131  l_gravity, l_rdOcp, l_moist, input_sounding_data);
132  }
133  else
134  {
135  // HSE will be calculated later with call to initHSE
137  bx, cons_arr,
138  geom[lev].data(), z_cc_arr,
139  l_moist, input_sounding_data);
140  }
141 
143  bx, xvel_arr, yvel_arr, zvel_arr,
144  geom[lev].data(), z_nd_arr,
146 
147  } //mfi
148 }
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:160
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, 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)
Definition: ERF_InitFromInputSounding.cpp:222
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:323
static bool init_sounding_ideal
Definition: ERF.H:1080
InputSoundingData input_sounding_data
Definition: ERF.H:692
@ base_bc
Definition: ERF_IndexDefines.H:87
void resize_arrays()
Definition: ERF_InputSoundingData.H:60
int n_sounding_files
Definition: ERF_InputSoundingData.H:316
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:314
void calc_rho_p(int itime)
Definition: ERF_InputSoundingData.H:176
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_only()

void ERF::init_only ( int  lev,
amrex::Real  time 
)
1255 {
1256  // Map the words in the inputs file to BC types, then translate
1257  // those types into what they mean for each variable
1258  // This must be called before initHSE (where the base state is initialized)
1259  if (lev == 0 && init_type != InitType::Ideal) {
1260  init_bcs();
1261  }
1262 
1263  t_new[lev] = time;
1264  t_old[lev] = time - 1.e200;
1265 
1266  auto& lev_new = vars_new[lev];
1267  auto& lev_old = vars_old[lev];
1268 
1269  // Loop over grids at this level to initialize our grid data
1270  lev_new[Vars::cons].setVal(0.0); lev_old[Vars::cons].setVal(0.0);
1271  lev_new[Vars::xvel].setVal(0.0); lev_old[Vars::xvel].setVal(0.0);
1272  lev_new[Vars::yvel].setVal(0.0); lev_old[Vars::yvel].setVal(0.0);
1273  lev_new[Vars::zvel].setVal(0.0); lev_old[Vars::zvel].setVal(0.0);
1274 
1275  // Initialize background flow (optional)
1276  if (init_type == InitType::Input_Sounding) {
1277  // The base state is initialized by integrating vertically through the
1278  // input sounding, if the init_sounding_ideal flag is set; otherwise
1279  // it is set by initHSE()
1280 
1281  // The physbc's need the terrain but are needed for initHSE
1282  // We have already made the terrain in the call to init_zphys
1283  // in MakeNewLevelFromScratch
1284  make_physbcs(lev);
1285 
1286  // Now init the base state and the data itself
1288 
1289  if (init_sounding_ideal) {
1290  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(solverChoice.use_gravity,
1291  "Gravity should be on to be consistent with sounding initialization.");
1292  } else {
1293  initHSE();
1294  }
1295 
1296 #ifdef ERF_USE_NETCDF
1297  } else if (init_type == InitType::Ideal || init_type == InitType::Real) {
1298  // The base state is initialized from WRF wrfinput data, output by
1299  // ideal.exe or real.exe
1300  init_from_wrfinput(lev);
1301 
1302  // The physbc's need the terrain but are needed for initHSE
1303  if (init_type == InitType::Ideal) {
1304  make_physbcs(lev);
1305  initHSE(lev);
1306  }
1307 
1308  } else if (init_type == InitType::Metgrid) {
1309  // The base state is initialized from data output by WPS metgrid;
1310  // we will rebalance after interpolation
1311  init_from_metgrid(lev);
1312 #endif
1313  } else if (init_type == InitType::Uniform) {
1314  // Initialize a uniform background field and base state based on the
1315  // problem-specified reference density and temperature
1316 
1317  // The physbc's need the terrain but are needed for initHSE
1318  make_physbcs(lev);
1319 
1320  init_uniform(lev);
1321  initHSE(lev);
1322  } else {
1323  // No background flow initialization specified, initialize the
1324  // background field to be equal to the base state, calculated from the
1325  // problem-specific erf_init_dens_hse
1326 
1327  // The bc's need the terrain but are needed for initHSE
1328  make_physbcs(lev);
1329 
1330  // We will initialize the state from the background state so must set that first
1331  initHSE(lev);
1332  init_from_hse(lev);
1333  }
1334 
1335  // Add problem-specific flow features
1336  //
1337  // Notes:
1338  // - This calls init_custom_pert that is defined for each problem
1339  // - This may modify the base state
1340  // - The fields set by init_custom_pert are **perturbations** to the
1341  // background flow set based on init_type
1342  init_custom(lev);
1343 
1344  // Ensure that the face-based data are the same on both sides of a periodic domain.
1345  // The data associated with the lower grid ID is considered the correct value.
1346  lev_new[Vars::xvel].OverrideSync(geom[lev].periodicity());
1347  lev_new[Vars::yvel].OverrideSync(geom[lev].periodicity());
1348  lev_new[Vars::zvel].OverrideSync(geom[lev].periodicity());
1349 
1350  if(solverChoice.spongeChoice.sponge_type == "input_sponge"){
1351  input_sponge(lev);
1352  }
1353 
1354  // Initialize turbulent perturbation
1355  if (solverChoice.pert_type == PerturbationType::Source ||
1356  solverChoice.pert_type == PerturbationType::Direct) {
1357  if (lev == 0) {
1358  turbPert_update(lev, 0.);
1359  turbPert_amplitude(lev);
1360  }
1361  }
1362 }
void init_from_input_sounding(int lev)
Definition: ERF_InitFromInputSounding.cpp:50
static InitType init_type
Definition: ERF.H:1060
void init_custom(int lev)
Definition: ERF_InitCustom.cpp:26
void init_bcs()
Definition: ERF_InitBCs.cpp:20
void init_from_hse(int lev)
Definition: ERF_InitFromHSE.cpp:32
void initHSE()
Initialize HSE.
Definition: ERF_Init1D.cpp:130
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:563
void init_uniform(int lev)
Definition: ERF_InitUniform.cpp:17
void turbPert_amplitude(const int lev)
Definition: ERF_InitTurbPert.cpp:41
bool use_gravity
Definition: ERF_DataStruct.H:601

◆ 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
27 {
28  // ********************************************************************************************
29  // Base state holds r_0, pres_0, pi_0, th_0 (in that order)
30  //
31  // Here is where we set 3 ghost cells for the base state!
32  //
33  // ********************************************************************************************
34  tmp_base_state.define(ba,dm,BaseState::num_comps,3);
35  tmp_base_state.setVal(0.);
36 
37  if (solverChoice.terrain_type == TerrainType::Moving) {
38  base_state_new[lev].define(ba,dm,BaseState::num_comps,base_state[lev].nGrowVect());
39  base_state_new[lev].setVal(0.);
40  }
41 
42  // ********************************************************************************************
43  // Allocate terrain arrays
44  // ********************************************************************************************
45  if (SolverChoice::mesh_type == MeshType::StretchedDz ||
46  SolverChoice::mesh_type == MeshType::VariableDz) {
47  z_phys_cc[lev] = std::make_unique<MultiFab>(ba,dm,1,1);
48 
49  if (solverChoice.terrain_type == TerrainType::Moving)
50  {
51  detJ_cc_new[lev] = std::make_unique<MultiFab>(ba,dm,1,1);
52  detJ_cc_src[lev] = std::make_unique<MultiFab>(ba,dm,1,1);
53 
54  ax_src[lev] = std::make_unique<MultiFab>(convert(ba,IntVect(1,0,0)),dm,1,1);
55  ay_src[lev] = std::make_unique<MultiFab>(convert(ba,IntVect(0,1,0)),dm,1,1);
56  az_src[lev] = std::make_unique<MultiFab>(convert(ba,IntVect(0,0,1)),dm,1,1);
57 
58  ax_new[lev] = std::make_unique<MultiFab>(convert(ba,IntVect(1,0,0)),dm,1,1);
59  ay_new[lev] = std::make_unique<MultiFab>(convert(ba,IntVect(0,1,0)),dm,1,1);
60  az_new[lev] = std::make_unique<MultiFab>(convert(ba,IntVect(0,0,1)),dm,1,1);
61 
62  z_t_rk[lev] = std::make_unique<MultiFab>( convert(ba, IntVect(0,0,1)), dm, 1, 1 );
63  }
64 
65  BoxArray ba_nd(ba);
66  ba_nd.surroundingNodes();
67 
68  // We need this to be one greater than the ghost cells to handle levels > 0
70  tmp_zphys_nd = std::make_unique<MultiFab>(ba_nd,dm,1,IntVect(ngrow,ngrow,ngrow));
71 
72  if (solverChoice.terrain_type == TerrainType::Moving) {
73  z_phys_nd_new[lev] = std::make_unique<MultiFab>(ba_nd,dm,1,IntVect(ngrow,ngrow,ngrow));
74  z_phys_nd_src[lev] = std::make_unique<MultiFab>(ba_nd,dm,1,IntVect(ngrow,ngrow,ngrow));
75  }
76 
77  } else {
78  z_phys_nd[lev] = nullptr;
79  z_phys_cc[lev] = nullptr;
80 
81  z_phys_nd_new[lev] = nullptr;
82  detJ_cc_new[lev] = nullptr;
83 
84  z_phys_nd_src[lev] = nullptr;
85  detJ_cc_src[lev] = nullptr;
86 
87  z_t_rk[lev] = nullptr;
88  }
89 
90  // We use these area arrays regardless of terrain, EB or none of the above
91  detJ_cc[lev] = std::make_unique<MultiFab>(ba,dm,1,1);
92  ax[lev] = std::make_unique<MultiFab>(convert(ba,IntVect(1,0,0)),dm,1,1);
93  ay[lev] = std::make_unique<MultiFab>(convert(ba,IntVect(0,1,0)),dm,1,1);
94  az[lev] = std::make_unique<MultiFab>(convert(ba,IntVect(0,0,1)),dm,1,1);
95 
96  detJ_cc[lev]->setVal(1.0);
97  ax[lev]->setVal(1.0);
98  ay[lev]->setVal(1.0);
99  az[lev]->setVal(1.0);
100 
101  // ********************************************************************************************
102  // Create wall distance array for RANS modeling
103  // ********************************************************************************************
104  if (solverChoice.turbChoice[lev].rans_type != RANSType::None) {
105  walldist[lev] = std::make_unique<MultiFab>(ba,dm,1,1);
106  walldist[lev]->setVal(1e23);
107  } else {
108  walldist[lev] = nullptr;
109  }
110 
111  // ********************************************************************************************
112  // These are the persistent containers for the old and new data
113  // ********************************************************************************************
114  int ncomp;
115  if (lev > 0) {
116  ncomp = vars_new[lev-1][Vars::cons].nComp();
117  } else {
118  int n_qstate = micro->Get_Qstate_Size();
119  ncomp = NDRY + NSCALARS + n_qstate;
120  }
121 
122  // ********************************************************************************************
123  // The number of ghost cells for density must be 1 greater than that for velocity
124  // so that we can go back in forth between velocity and momentum on all faces
125  // ********************************************************************************************
128 
129  // ********************************************************************************************
130  // New solution data containers
131  // ********************************************************************************************
132  lev_new[Vars::cons].define(ba, dm, ncomp, ngrow_state);
133  lev_old[Vars::cons].define(ba, dm, ncomp, ngrow_state);
134 
135  lev_new[Vars::xvel].define(convert(ba, IntVect(1,0,0)), dm, 1, ngrow_vels);
136  lev_old[Vars::xvel].define(convert(ba, IntVect(1,0,0)), dm, 1, ngrow_vels);
137 
138  lev_new[Vars::yvel].define(convert(ba, IntVect(0,1,0)), dm, 1, ngrow_vels);
139  lev_old[Vars::yvel].define(convert(ba, IntVect(0,1,0)), dm, 1, ngrow_vels);
140 
141  // Note that we need the ghost cells in the z-direction if we are doing any
142  // kind of domain decomposition in the vertical (at level 0 or above)
143  lev_new[Vars::zvel].define(convert(ba, IntVect(0,0,1)), dm, 1, ngrow_vels);
144  lev_old[Vars::zvel].define(convert(ba, IntVect(0,0,1)), dm, 1, ngrow_vels);
145 
146  if (solverChoice.anelastic[lev] == 1) {
147  pp_inc[lev].define(ba, dm, 1, 1);
148  pp_inc[lev].setVal(0.0);
149  }
150 
151  // ********************************************************************************************
152  // These are just used for scratch in the time integrator but we might as well define them here
153  // ********************************************************************************************
154  rU_old[lev].define(convert(ba, IntVect(1,0,0)), dm, 1, ngrow_vels);
155  rU_new[lev].define(convert(ba, IntVect(1,0,0)), dm, 1, ngrow_vels);
156 
157  rV_old[lev].define(convert(ba, IntVect(0,1,0)), dm, 1, ngrow_vels);
158  rV_new[lev].define(convert(ba, IntVect(0,1,0)), dm, 1, ngrow_vels);
159 
160  rW_old[lev].define(convert(ba, IntVect(0,0,1)), dm, 1, ngrow_vels);
161  rW_new[lev].define(convert(ba, IntVect(0,0,1)), dm, 1, ngrow_vels);
162 
163  if (lev > 0) {
164  //xmom_crse_rhs[lev].define(convert(ba, IntVect(1,0,0)), dm, 1, IntVect{0});
165  //ymom_crse_rhs[lev].define(convert(ba, IntVect(0,1,0)), dm, 1, IntVect{0});
166  zmom_crse_rhs[lev].define(convert(ba, IntVect(0,0,1)), dm, 1, IntVect{0});
167  }
168 
169  // We do this here just so they won't be undefined in the initial FillPatch
170  rU_old[lev].setVal(1.2e21);
171  rV_old[lev].setVal(3.4e22);
172  rW_old[lev].setVal(5.6e23);
173  rU_new[lev].setVal(1.2e21);
174  rV_new[lev].setVal(3.4e22);
175  rW_new[lev].setVal(5.6e23);
176 
177  // ********************************************************************************************
178  // These are just time averaged fields for diagnostics
179  // ********************************************************************************************
180 
181  // NOTE: We are not completing a fillpach call on the time averaged data;
182  // which would copy on intersection and interpolate from coarse.
183  // Therefore, we are restarting the averaging when the ba changes,
184  // this may give poor statistics for dynamic mesh refinement.
185  vel_t_avg[lev] = nullptr;
187  vel_t_avg[lev] = std::make_unique<MultiFab>(ba, dm, 4, 0); // Each vel comp and the mag
188  vel_t_avg[lev]->setVal(0.0);
189  t_avg_cnt[lev] = 0.0;
190  }
191 
192  // ********************************************************************************************
193  // Initialize flux registers whenever we create/re-create a level
194  // ********************************************************************************************
195  if (solverChoice.coupling_type == CouplingType::TwoWay) {
196  if (lev == 0) {
197  advflux_reg[0] = nullptr;
198  } else {
199  int ncomp_reflux = vars_new[0][Vars::cons].nComp();
200  advflux_reg[lev] = new YAFluxRegister(ba , grids[lev-1],
201  dm , dmap[lev-1],
202  geom[lev], geom[lev-1],
203  ref_ratio[lev-1], lev, ncomp_reflux);
204  }
205  }
206 
207  // ********************************************************************************************
208  // Define Theta_prim storage if using MOST BC
209  // ********************************************************************************************
210  if (phys_bc_type[Orientation(Direction::z,Orientation::low)] == ERF_BC::MOST) {
211  Theta_prim[lev] = std::make_unique<MultiFab>(ba,dm,1,IntVect(ngrow_state,ngrow_state,0));
212  if (solverChoice.moisture_type != MoistureType::None) {
213  Qv_prim[lev] = std::make_unique<MultiFab>(ba,dm,1,IntVect(ngrow_state,ngrow_state,0));
214  Qr_prim[lev] = std::make_unique<MultiFab>(ba,dm,1,IntVect(ngrow_state,ngrow_state,0));
215  } else {
216  Qv_prim[lev] = nullptr;
217  Qr_prim[lev] = nullptr;
218  }
219  } else {
220  Theta_prim[lev] = nullptr;
221  Qv_prim[lev] = nullptr;
222  Qr_prim[lev] = nullptr;
223  }
224 
225  // ********************************************************************************************
226  // Map factors
227  // ********************************************************************************************
228  BoxList bl2d_mf = ba.boxList();
229  for (auto& b : bl2d_mf) {
230  b.setRange(2,0);
231  }
232  BoxArray ba2d_mf(std::move(bl2d_mf));
233 
234  mapfac_m[lev] = std::make_unique<MultiFab>(ba2d_mf,dm,1,3);
235  mapfac_u[lev] = std::make_unique<MultiFab>(convert(ba2d_mf,IntVect(1,0,0)),dm,1,3);
236  mapfac_v[lev] = std::make_unique<MultiFab>(convert(ba2d_mf,IntVect(0,1,0)),dm,1,3);
238  mapfac_m[lev]->setVal(0.5);
239  mapfac_u[lev]->setVal(0.5);
240  mapfac_v[lev]->setVal(0.5);
241  }
242  else {
243  mapfac_m[lev]->setVal(1.);
244  mapfac_u[lev]->setVal(1.);
245  mapfac_v[lev]->setVal(1.);
246  }
247 
248 #if defined(ERF_USE_WINDFARM)
249  //*********************************************************
250  // Variables for Fitch model for windfarm parametrization
251  //*********************************************************
252  if (solverChoice.windfarm_type == WindFarmType::Fitch){
253  vars_windfarm[lev].define(ba, dm, 5, ngrow_state); // V, dVabsdt, dudt, dvdt, dTKEdt
254  }
255  if (solverChoice.windfarm_type == WindFarmType::EWP){
256  vars_windfarm[lev].define(ba, dm, 3, ngrow_state); // dudt, dvdt, dTKEdt
257  }
258  if (solverChoice.windfarm_type == WindFarmType::SimpleAD) {
259  vars_windfarm[lev].define(ba, dm, 2, ngrow_state);// dudt, dvdt
260  }
261  if (solverChoice.windfarm_type == WindFarmType::GeneralAD) {
262  vars_windfarm[lev].define(ba, dm, 3, ngrow_state);// dudt, dvdt, dwdt
263  }
264  Nturb[lev].define(ba, dm, 1, ngrow_state); // Number of turbines in a cell
265  SMark[lev].define(ba, dm, 2, 1); // Free stream velocity/source term
266  // sampling marker in a cell - 2 components
267 #endif
268 
269 
270 #ifdef ERF_USE_WW3_COUPLING
271  // create a new BoxArray and DistributionMapping for a MultiFab with 1 box
272  BoxArray ba_onegrid(geom[lev].Domain());
273  BoxList bl2d_onegrid = ba_onegrid.boxList();
274  for (auto& b : bl2d_onegrid) {
275  b.setRange(2,0);
276  }
277  BoxArray ba2d_onegrid(std::move(bl2d_onegrid));
278  Vector<int> pmap;
279  pmap.resize(1);
280  pmap[0]=0;
281  DistributionMapping dm_onegrid(ba2d_onegrid);
282  dm_onegrid.define(pmap);
283 
284  Hwave_onegrid[lev] = std::make_unique<MultiFab>(ba2d_onegrid,dm_onegrid,1,IntVect(1,1,0));
285  Lwave_onegrid[lev] = std::make_unique<MultiFab>(ba2d_onegrid,dm_onegrid,1,IntVect(1,1,0));
286 
287  BoxList bl2d_wave = ba.boxList();
288  for (auto& b : bl2d_wave) {
289  b.setRange(2,0);
290  }
291  BoxArray ba2d_wave(std::move(bl2d_wave));
292 
293  Hwave[lev] = std::make_unique<MultiFab>(ba2d_wave,dm,1,IntVect(3,3,0));
294  Lwave[lev] = std::make_unique<MultiFab>(ba2d_wave,dm,1,IntVect(3,3,0));
295 
296  std::cout<<ba_onegrid<<std::endl;
297  std::cout<<ba2d_onegrid<<std::endl;
298  std::cout<<dm_onegrid<<std::endl;
299 #endif
300 
301 
302 #if defined(ERF_USE_RRTMGP)
303  //*********************************************************
304  // Radiation heating source terms
305  //*********************************************************
306  qheating_rates[lev] = std::make_unique<MultiFab>(ba, dm, 2, ngrow_state);
307  qheating_rates[lev]->setVal(0.);
308 
309  //*********************************************************
310  // Radiation fluxes for coupling to LSM
311  //*********************************************************
312 
313  // NOTE: Finer levels do not need to coincide with the bottom domain boundary
314  // at k=0. We make slabs here with the kmin for a given box. Therefore,
315  // care must be taken before applying these fluxes to an LSM model. For
316 
317  // Radiative fluxes for LSM
318  if (solverChoice.lsm_type != LandSurfaceType::None)
319  {
320  BoxList m_bl = ba.boxList();
321  for (auto& b : m_bl) {
322  int kmin = b.smallEnd(2);
323  b.setRange(2,kmin);
324  }
325  BoxArray m_ba(std::move(m_bl));
326 
327  sw_lw_fluxes[lev] = std::make_unique<MultiFab>(m_ba, dm, 5, ngrow_state); // SW direct (2), SW diffuse (2), LW
328  solar_zenith[lev] = std::make_unique<MultiFab>(m_ba, dm, 2, ngrow_state);
329 
330  sw_lw_fluxes[lev]->setVal(0.);
331  solar_zenith[lev]->setVal(0.);
332  }
333 #endif
334 
335  //*********************************************************
336  // Turbulent perturbation region initialization
337  //*********************************************************
338  // TODO: Test perturbation on multiple levels
339  if (solverChoice.pert_type == PerturbationType::Source ||
340  solverChoice.pert_type == PerturbationType::Direct)
341  {
342  if (lev == 0) {
343  turbPert.init_tpi(lev, geom[lev].Domain().bigEnd(), geom[lev].CellSizeArray(), ba, dm, ngrow_state);
344  }
345  }
346 
347  //
348  // Define the land mask here and set it to all land by default
349  // NOTE: the logic below will BREAK if we have any grids not touching the bottom boundary
350  //
351  {
352  lmask_lev[lev].resize(1);
353  auto ngv = lev_new[Vars::cons].nGrowVect(); ngv[2] = 0;
354  BoxList bl2d_mask = ba.boxList();
355  for (auto& b : bl2d_mask) {
356  b.setRange(2,0);
357  }
358  BoxArray ba2d_mask(std::move(bl2d_mask));
359  lmask_lev[lev][0] = std::make_unique<iMultiFab>(ba2d_mask,dm,1,ngv);
360  lmask_lev[lev][0]->setVal(1);
361  lmask_lev[lev][0]->FillBoundary(geom[lev].periodicity());
362  }
363 
364  // Read in tables needed for windfarm simulations
365  // fill in Nturb multifab - number of turbines in each mesh cell
366  // write out the vtk files for wind turbine location and/or
367  // actuator disks
368  #ifdef ERF_USE_WINDFARM
369  //init_windfarm(lev);
370  #endif
371 }
#define NDRY
Definition: ERF_IndexDefines.H:13
static AMREX_FORCE_INLINE int ComputeGhostCells(const AdvChoice &advChoice, bool use_num_diff)
Definition: ERF.H:1189
@ num_comps
Definition: ERF_IndexDefines.H:67
bool test_mapfactor
Definition: ERF_DataStruct.H:596
AdvChoice advChoice
Definition: ERF_DataStruct.H:578
void init_tpi(const int lev, const amrex::IntVect &nx, const amrex::GpuArray< amrex::Real, 3 > dx, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm, const int ngrow_state)
Definition: ERF_TurbPertStruct.H:29

◆ init_thin_body()

void ERF::init_thin_body ( int  lev,
const amrex::BoxArray &  ba,
const amrex::DistributionMapping &  dm 
)
508 {
509  //********************************************************************************************
510  // Thin immersed body
511  // *******************************************************************************************
512 #if 0
513  if ((solverChoice.advChoice.zero_xflux.size() > 0) ||
514  (solverChoice.advChoice.zero_yflux.size() > 0) ||
515  (solverChoice.advChoice.zero_zflux.size() > 0))
516  {
517  overset_imask[lev] = std::make_unique<iMultiFab>(ba,dm,1,0);
518  overset_imask[lev]->setVal(1); // == value is unknown (to be solved)
519  }
520 #endif
521 
522  if (solverChoice.advChoice.zero_xflux.size() > 0) {
523  amrex::Print() << "Setting up thin immersed body for "
524  << solverChoice.advChoice.zero_xflux.size() << " xfaces" << std::endl;
525  BoxArray ba_xf(ba);
526  ba_xf.surroundingNodes(0);
527  thin_xforce[lev] = std::make_unique<MultiFab>(ba_xf,dm,1,0);
528  thin_xforce[lev]->setVal(0.0);
529  xflux_imask[lev] = std::make_unique<iMultiFab>(ba_xf,dm,1,0);
530  xflux_imask[lev]->setVal(1);
531  for ( MFIter mfi(*xflux_imask[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi )
532  {
533  Array4<int> const& imask_arr = xflux_imask[lev]->array(mfi);
534  //Array4<int> const& imask_cell_arr = overset_imask[lev]->array(mfi);
535  Box xbx = mfi.nodaltilebox(0);
536  for (int iv=0; iv < solverChoice.advChoice.zero_xflux.size(); ++iv) {
537  const auto& faceidx = solverChoice.advChoice.zero_xflux[iv];
538  if ((faceidx[0] >= xbx.smallEnd(0)) && (faceidx[0] <= xbx.bigEnd(0)) &&
539  (faceidx[1] >= xbx.smallEnd(1)) && (faceidx[1] <= xbx.bigEnd(1)) &&
540  (faceidx[2] >= xbx.smallEnd(2)) && (faceidx[2] <= xbx.bigEnd(2)))
541  {
542  imask_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
543  //imask_cell_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
544  //imask_cell_arr(faceidx[0]-1,faceidx[1],faceidx[2]) = 0;
545  amrex::AllPrint() << " mask xface at " << faceidx << std::endl;
546  }
547  }
548  }
549  } else {
550  thin_xforce[lev] = nullptr;
551  xflux_imask[lev] = nullptr;
552  }
553 
554  if (solverChoice.advChoice.zero_yflux.size() > 0) {
555  amrex::Print() << "Setting up thin immersed body for "
556  << solverChoice.advChoice.zero_yflux.size() << " yfaces" << std::endl;
557  BoxArray ba_yf(ba);
558  ba_yf.surroundingNodes(1);
559  thin_yforce[lev] = std::make_unique<MultiFab>(ba_yf,dm,1,0);
560  thin_yforce[lev]->setVal(0.0);
561  yflux_imask[lev] = std::make_unique<iMultiFab>(ba_yf,dm,1,0);
562  yflux_imask[lev]->setVal(1);
563  for ( MFIter mfi(*yflux_imask[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi )
564  {
565  Array4<int> const& imask_arr = yflux_imask[lev]->array(mfi);
566  //Array4<int> const& imask_cell_arr = overset_imask[lev]->array(mfi);
567  Box ybx = mfi.nodaltilebox(1);
568  for (int iv=0; iv < solverChoice.advChoice.zero_yflux.size(); ++iv) {
569  const auto& faceidx = solverChoice.advChoice.zero_yflux[iv];
570  if ((faceidx[0] >= ybx.smallEnd(0)) && (faceidx[0] <= ybx.bigEnd(0)) &&
571  (faceidx[1] >= ybx.smallEnd(1)) && (faceidx[1] <= ybx.bigEnd(1)) &&
572  (faceidx[2] >= ybx.smallEnd(2)) && (faceidx[2] <= ybx.bigEnd(2)))
573  {
574  imask_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
575  //imask_cell_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
576  //imask_cell_arr(faceidx[0],faceidx[1]-1,faceidx[2]) = 0;
577  amrex::AllPrint() << " mask yface at " << faceidx << std::endl;
578  }
579  }
580  }
581  } else {
582  thin_yforce[lev] = nullptr;
583  yflux_imask[lev] = nullptr;
584  }
585 
586  if (solverChoice.advChoice.zero_zflux.size() > 0) {
587  amrex::Print() << "Setting up thin immersed body for "
588  << solverChoice.advChoice.zero_zflux.size() << " zfaces" << std::endl;
589  BoxArray ba_zf(ba);
590  ba_zf.surroundingNodes(2);
591  thin_zforce[lev] = std::make_unique<MultiFab>(ba_zf,dm,1,0);
592  thin_zforce[lev]->setVal(0.0);
593  zflux_imask[lev] = std::make_unique<iMultiFab>(ba_zf,dm,1,0);
594  zflux_imask[lev]->setVal(1);
595  for ( MFIter mfi(*zflux_imask[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi )
596  {
597  Array4<int> const& imask_arr = zflux_imask[lev]->array(mfi);
598  //Array4<int> const& imask_cell_arr = overset_imask[lev]->array(mfi);
599  Box zbx = mfi.nodaltilebox(2);
600  for (int iv=0; iv < solverChoice.advChoice.zero_zflux.size(); ++iv) {
601  const auto& faceidx = solverChoice.advChoice.zero_zflux[iv];
602  if ((faceidx[0] >= zbx.smallEnd(0)) && (faceidx[0] <= zbx.bigEnd(0)) &&
603  (faceidx[1] >= zbx.smallEnd(1)) && (faceidx[1] <= zbx.bigEnd(1)) &&
604  (faceidx[2] >= zbx.smallEnd(2)) && (faceidx[2] <= zbx.bigEnd(2)))
605  {
606  imask_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
607  //imask_cell_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
608  //imask_cell_arr(faceidx[0],faceidx[1],faceidx[2]-1) = 0;
609  amrex::AllPrint() << " mask zface at " << faceidx << std::endl;
610  }
611  }
612  }
613  } else {
614  thin_zforce[lev] = nullptr;
615  zflux_imask[lev] = nullptr;
616  }
617 }
amrex::Vector< amrex::IntVect > zero_yflux
Definition: ERF_AdvStruct.H:301
amrex::Vector< amrex::IntVect > zero_xflux
Definition: ERF_AdvStruct.H:300
amrex::Vector< amrex::IntVect > zero_zflux
Definition: ERF_AdvStruct.H:302

◆ 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 
)
private
465 {
466  if (SolverChoice::mesh_type == MeshType::StretchedDz ||
467  SolverChoice::mesh_type == MeshType::VariableDz)
468  {
469  if (init_type != InitType::Real && init_type != InitType::Metgrid)
470  {
471  if (lev > 0) {
472  //
473  // First interpolate from coarser level if there is one
474  // NOTE: this interpolater assumes that ALL ghost cells of the coarse MultiFab
475  // have been pre-filled - this includes ghost cells both inside and outside
476  // the domain
477  //
478  InterpFromCoarseLevel(*z_phys_nd[lev], z_phys_nd[lev]->nGrowVect(),
479  IntVect(0,0,0), // do not fill ghost cells outside the domain
480  *z_phys_nd[lev-1], 0, 0, 1,
481  geom[lev-1], geom[lev],
482  refRatio(lev-1), &node_bilinear_interp,
484  }
485 
486  z_phys_nd[lev]->setVal(-1.e23);
487  prob->init_custom_terrain(geom[lev],*z_phys_nd[lev],time);
488  init_terrain_grid(lev,geom[lev],*z_phys_nd[lev],zlevels_stag[lev],phys_bc_type);
489 
490  if (lev == 0) {
491  Real zmax = z_phys_nd[0]->max(0,0,false);
492  Real rel_diff = (zmax - zlevels_stag[0][zlevels_stag[0].size()-1]) / zmax;
493  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(rel_diff < 1.e-8, "Terrain is taller than domain top!");
494  } // lev == 0
495 
496  z_phys_nd[lev]->FillBoundary(geom[lev].periodicity());
497 
498  } // init_type
499  } // terrain
500 }
void init_terrain_grid(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:118
Here is the call graph for this function:

◆ InitData()

void ERF::InitData ( )
607 {
608  BL_PROFILE_VAR("ERF::InitData()", InitData);
609  InitData_pre();
610  InitData_post();
611  BL_PROFILE_VAR_STOP(InitData);
612 }
void InitData_pre()
Definition: ERF.cpp:615
void InitData_post()
Definition: ERF.cpp:652
void InitData()
Definition: ERF.cpp:606

Referenced by MultiBlockContainer::InitializeBlocks(), and main().

Here is the caller graph for this function:

◆ InitData_post()

void ERF::InitData_post ( )
653 {
654  if (restart_chkfile.empty()) {
655  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
656  if (init_type == InitType::Ideal) {
657  Abort("We do not currently support init_type = ideal with non-constant dz");
658  }
659  }
660 
661  //
662  // Make sure that detJ and z_phys_cc are the average of the data on a finer level if there is one
663  //
664  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
665  for (int crse_lev = finest_level-1; crse_lev >= 0; crse_lev--) {
666  average_down( *detJ_cc[crse_lev+1], *detJ_cc[crse_lev], 0, 1, refRatio(crse_lev));
667  average_down(*z_phys_cc[crse_lev+1], *z_phys_cc[crse_lev], 0, 1, refRatio(crse_lev));
668  }
669  }
670 
671  if (solverChoice.coupling_type == CouplingType::TwoWay) {
672  AverageDown();
673  }
674 
676  {
677  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(finest_level == 0,
678  "Thin immersed body with refinement not currently supported.");
679  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
680  amrex::Print() << "NOTE: Thin immersed body with non-constant dz has not been tested." << std::endl;
681  }
682  }
683 
684 #ifdef ERF_USE_PARTICLES
685  if (Microphysics::modelType(solverChoice.moisture_type) == MoistureModelType::Lagrangian) {
686  for (int lev = 0; lev <= finest_level; lev++) {
687  dynamic_cast<LagrangianMicrophysics&>(*micro).initParticles(z_phys_nd[lev]);
688  }
689  }
690 #endif
691 
692  } else { // Restart from a checkpoint
693 
694  restart();
695 
696  // Create the physbc objects for {cons, u, v, w, base state}
697  // We fill the additional base state ghost cells just in case we have read the old format
698  for (int lev(0); lev <= max_level; ++lev) {
699  make_physbcs(lev);
700  (*physbcs_base[lev])(base_state[lev],0,base_state[lev].nComp(),base_state[lev].nGrowVect());
701  }
702  }
703 
704 #ifdef ERF_USE_PARTICLES
705  /* If using a Lagrangian microphysics model, its particle container has now been
706  constructed and initialized (calls to micro->Init). So, add its pointer to
707  ERF::particleData and remove its name from list of unallocated particle containers. */
708  if (Microphysics::modelType(solverChoice.moisture_type) == MoistureModelType::Lagrangian) {
709  const auto& pc_name( dynamic_cast<LagrangianMicrophysics&>(*micro).getName() );
710  const auto& pc_ptr( dynamic_cast<LagrangianMicrophysics&>(*micro).getParticleContainer() );
711  particleData.pushBack(pc_name, pc_ptr);
712  particleData.getNamesUnalloc().remove(pc_name);
713  }
714 #endif
715 
716  if (input_bndry_planes) {
717  // Read the "time.dat" file to know what data is available
718  m_r2d->read_time_file();
719 
720  // We haven't populated dt yet, set to 0 to ensure assert doesn't crash
721  Real dt_dummy = 0.0;
722  m_r2d->read_input_files(t_new[0],dt_dummy,m_bc_extdir_vals);
723  }
724 
726  {
727  h_rhotheta_src.resize(max_level+1, Vector<Real>(0));
728  d_rhotheta_src.resize(max_level+1, Gpu::DeviceVector<Real>(0));
729  for (int lev = 0; lev <= finest_level; lev++) {
730  const int domlen = geom[lev].Domain().length(2);
731  h_rhotheta_src[lev].resize(domlen, 0.0_rt);
732  d_rhotheta_src[lev].resize(domlen, 0.0_rt);
733  prob->update_rhotheta_sources(t_new[0],
734  h_rhotheta_src[lev], d_rhotheta_src[lev],
735  geom[lev], z_phys_cc[lev]);
736  }
737  }
738 
740  {
741  h_u_geos.resize(max_level+1, Vector<Real>(0));
742  d_u_geos.resize(max_level+1, Gpu::DeviceVector<Real>(0));
743  h_v_geos.resize(max_level+1, Vector<Real>(0));
744  d_v_geos.resize(max_level+1, Gpu::DeviceVector<Real>(0));
745  for (int lev = 0; lev <= finest_level; lev++) {
746  const int domlen = geom[lev].Domain().length(2);
747  h_u_geos[lev].resize(domlen, 0.0_rt);
748  d_u_geos[lev].resize(domlen, 0.0_rt);
749  h_v_geos[lev].resize(domlen, 0.0_rt);
750  d_v_geos[lev].resize(domlen, 0.0_rt);
752  prob->update_geostrophic_profile(t_new[0],
753  h_u_geos[lev], d_u_geos[lev],
754  h_v_geos[lev], d_v_geos[lev],
755  geom[lev], z_phys_cc[lev]);
756  } else {
757  if (SolverChoice::mesh_type == MeshType::VariableDz) {
758  amrex::Print() << "Note: 1-D geostrophic wind profile input is not defined for real terrain" << std::endl;
759  }
761  h_u_geos[lev], d_u_geos[lev],
762  h_v_geos[lev], d_v_geos[lev],
763  geom[lev],
764  zlevels_stag[0]);
765  }
766  }
767  }
768 
770  {
771  h_rhoqt_src.resize(max_level+1, Vector<Real>(0));
772  d_rhoqt_src.resize(max_level+1, Gpu::DeviceVector<Real>(0));
773  for (int lev = 0; lev <= finest_level; lev++) {
774  const int domlen = geom[lev].Domain().length(2);
775  h_rhoqt_src[lev].resize(domlen, 0.0_rt);
776  d_rhoqt_src[lev].resize(domlen, 0.0_rt);
777  prob->update_rhoqt_sources(t_new[0],
778  h_rhoqt_src[lev], d_rhoqt_src[lev],
779  geom[lev], z_phys_cc[lev]);
780  }
781  }
782 
784  {
785  h_w_subsid.resize(max_level+1, Vector<Real>(0));
786  d_w_subsid.resize(max_level+1, Gpu::DeviceVector<Real>(0));
787  for (int lev = 0; lev <= finest_level; lev++) {
788  const int domlen = geom[lev].Domain().length(2) + 1; // lives on z-faces
789  h_w_subsid[lev].resize(domlen, 0.0_rt);
790  d_w_subsid[lev].resize(domlen, 0.0_rt);
791  prob->update_w_subsidence(t_new[0],
792  h_w_subsid[lev], d_w_subsid[lev],
793  geom[lev], z_phys_cc[lev]);
794  }
795  }
796 
799  {
800  initRayleigh();
801  if (init_type == InitType::Input_Sounding)
802  {
803  // Overwrite ubar, vbar, and thetabar with input profiles;
804  // wbar is assumed to be 0. Note: the tau coefficient set by
805  // prob->erf_init_rayleigh() is still used
806  bool restarting = (!restart_chkfile.empty());
807  setRayleighRefFromSounding(restarting);
808  }
809  }
810 
811  // Read in sponge data from input file
812  if(solverChoice.spongeChoice.sponge_type == "input_sponge")
813  {
814  initSponge();
815  bool restarting = (!restart_chkfile.empty());
816  setSpongeRefFromSounding(restarting);
817  }
818 
821  }
822 
823  if (solverChoice.pert_type == PerturbationType::Source ||
824  solverChoice.pert_type == PerturbationType::Direct) {
825  if (is_it_time_for_action(istep[0], t_new[0], dt[0], pert_interval, -1.)) {
826  turbPert.debug(t_new[0]);
827  }
828  }
829 
830  // We only write the file at level 0 for now
832  {
833  // Create the WriteBndryPlanes object so we can handle writing of boundary plane data
834  m_w2d = std::make_unique<WriteBndryPlanes>(grids,geom);
835 
836  Real time = 0.;
837  if (time >= bndry_output_planes_start_time) {
838  bool is_moist = (micro->Get_Qstate_Size() > 0);
839  m_w2d->write_planes(0, time, vars_new, is_moist);
840  }
841  }
842 
843  //
844  // If we are starting from scratch, we have the option to project the initial velocity field
845  // regardless of how we initialized.
846  // pp_inc is used as scratch space here; we zero it out after the projection
847  //
848  if (restart_chkfile == "")
849  {
851  Real dummy_dt = 1.0;
852  for (int lev = 0; lev <= finest_level; ++lev)
853  {
854  project_velocities(lev, dummy_dt, vars_new[lev], pp_inc[lev]);
855  pp_inc[lev].setVal(0.);
856  }
857  }
858  }
859 
860  // Copy from new into old just in case
861  for (int lev = 0; lev <= finest_level; ++lev)
862  {
863  auto& lev_new = vars_new[lev];
864  auto& lev_old = vars_old[lev];
865 
866  int ncomp = lev_new[Vars::cons].nComp();
867 
868  // ***************************************************************************
869  // Physical bc's at domain boundary
870  // ***************************************************************************
871  IntVect ngvect_cons = vars_new[lev][Vars::cons].nGrowVect();
872  IntVect ngvect_vels = vars_new[lev][Vars::xvel].nGrowVect();
873 
874  (*physbcs_cons[lev])(lev_new[Vars::cons],0,ncomp,ngvect_cons,t_new[lev],BCVars::cons_bc,true);
875  ( *physbcs_u[lev])(lev_new[Vars::xvel],0,1 ,ngvect_vels,t_new[lev],BCVars::xvel_bc,true);
876  ( *physbcs_v[lev])(lev_new[Vars::yvel],0,1 ,ngvect_vels,t_new[lev],BCVars::yvel_bc,true);
877  ( *physbcs_w[lev])(lev_new[Vars::zvel],lev_new[Vars::xvel],lev_new[Vars::yvel],
878  ngvect_vels,t_new[lev],BCVars::zvel_bc,true);
879 
880  MultiFab::Copy(lev_old[Vars::cons],lev_new[Vars::cons],0,0,ncomp,lev_new[Vars::cons].nGrowVect());
881  MultiFab::Copy(lev_old[Vars::xvel],lev_new[Vars::xvel],0,0, 1,lev_new[Vars::xvel].nGrowVect());
882  MultiFab::Copy(lev_old[Vars::yvel],lev_new[Vars::yvel],0,0, 1,lev_new[Vars::yvel].nGrowVect());
883  MultiFab::Copy(lev_old[Vars::zvel],lev_new[Vars::zvel],0,0, 1,lev_new[Vars::zvel].nGrowVect());
884  }
885 
886  // Compute the minimum dz in the domain at each level (to be used for setting the timestep)
887  dz_min.resize(max_level+1);
888  for (int lev = 0; lev <= finest_level; ++lev)
889  {
890  dz_min[lev] = geom[lev].CellSize(2);
891  if ( SolverChoice::mesh_type != MeshType::ConstantDz ) {
892  dz_min[lev] *= (*detJ_cc[lev]).min(0);
893  }
894  }
895 
896  ComputeDt();
897 
898  // Fill ghost cells/faces
899  for (int lev = 0; lev <= finest_level; ++lev)
900  {
901  if (lev > 0 && cf_width >= 0) {
903  }
904 
905  auto& lev_new = vars_new[lev];
906 
907  //
908  // Fill boundary conditions -- not sure why we need this here
909  //
910  bool fillset = false;
911  if (lev == 0) {
912  FillPatch(lev, t_new[lev],
913  {&lev_new[Vars::cons],&lev_new[Vars::xvel],&lev_new[Vars::yvel],&lev_new[Vars::zvel]});
914  } else {
915  FillPatch(lev, t_new[lev],
916  {&lev_new[Vars::cons],&lev_new[Vars::xvel],&lev_new[Vars::yvel],&lev_new[Vars::zvel]},
917  {&lev_new[Vars::cons],&rU_new[lev],&rV_new[lev],&rW_new[lev]},
918  base_state[lev], base_state[lev],
919  fillset);
920  }
921 
922  //
923  // We do this here to make sure level (lev-1) boundary conditions are filled
924  // before we interpolate to level (lev) ghost cells
925  //
926  if (lev < finest_level) {
927  auto& lev_old = vars_old[lev];
928  MultiFab::Copy(lev_old[Vars::cons],lev_new[Vars::cons],0,0,lev_old[Vars::cons].nComp(),lev_old[Vars::cons].nGrowVect());
929  MultiFab::Copy(lev_old[Vars::xvel],lev_new[Vars::xvel],0,0,lev_old[Vars::xvel].nComp(),lev_old[Vars::xvel].nGrowVect());
930  MultiFab::Copy(lev_old[Vars::yvel],lev_new[Vars::yvel],0,0,lev_old[Vars::yvel].nComp(),lev_old[Vars::yvel].nGrowVect());
931  MultiFab::Copy(lev_old[Vars::zvel],lev_new[Vars::zvel],0,0,lev_old[Vars::zvel].nComp(),lev_old[Vars::zvel].nGrowVect());
932  }
933 
934  //
935  // We fill the ghost cell values of the base state in case it wasn't done in the initialization
936  //
937  base_state[lev].FillBoundary(geom[lev].periodicity());
938 
939  // For moving terrain only
940  if (solverChoice.terrain_type == TerrainType::Moving) {
941  MultiFab::Copy(base_state_new[lev],base_state[lev],0,0,BaseState::num_comps,base_state[lev].nGrowVect());
942  base_state_new[lev].FillBoundary(geom[lev].periodicity());
943  }
944 
945  }
946 
947  // Allow idealized cases over water, used to set lmask
948  ParmParse pp("erf");
949  int is_land;
950  for (int lev = 0; lev <= finest_level; ++lev)
951  {
952  if (pp.query("is_land", is_land, lev)) {
953  if (is_land == 1) {
954  amrex::Print() << "Level " << lev << " is land" << std::endl;
955  } else if (is_land == 0) {
956  amrex::Print() << "Level " << lev << " is water" << std::endl;
957  } else {
958  Error("is_land should be 0 or 1");
959  }
960  lmask_lev[lev][0]->setVal(is_land);
961  lmask_lev[lev][0]->FillBoundary(geom[lev].periodicity());
962  }
963  }
964 
965 #ifdef ERF_USE_WW3_COUPLING
966  int lev = 0;
967  amrex::Print() << " About to call send_to_ww3 from ERF.cpp" << std::endl;
968  send_to_ww3(lev);
969  amrex::Print() << " About to call read_waves from ERF.cpp" << std::endl;
970  read_waves(lev);
971  // send_to_ww3(lev);
972 #endif
973 
974  // Configure ABLMost params if used MostWall boundary condition
975  // NOTE: we must set up the MOST routine after calling FillPatch
976  // in order to have lateral ghost cells filled (MOST + terrain interp).
977  // FillPatch does not call MOST, FillIntermediatePatch does.
978  if (phys_bc_type[Orientation(Direction::z,Orientation::low)] == ERF_BC::MOST)
979  {
980  bool use_exp_most = solverChoice.use_explicit_most;
981  bool use_rot_most = solverChoice.use_rotate_most;
982  if (use_exp_most) {
983  Print() << "Using MOST with explicitly included surface stresses" << std::endl;
984  if (use_rot_most) {
985  Print() << "Using MOST with surface stress rotations" << std::endl;
986  }
987  }
988 
989  m_most = std::make_unique<ABLMost>(geom, use_exp_most, use_rot_most,
993 #ifdef ERF_USE_NETCDF
994  ,start_bdy_time, bdy_time_interval
995 #endif
996  );
997 
998 
999  if (restart_chkfile != "") {
1000  // Update surface fields if needed
1002  }
1003 
1004  // We now configure ABLMost params here so that we can print the averages at t=0
1005  // Note we don't fill ghost cells here because this is just for diagnostics
1006  for (int lev = 0; lev <= finest_level; ++lev)
1007  {
1008  Real time = t_new[lev];
1009  IntVect ng = Theta_prim[lev]->nGrowVect();
1010 
1011  MultiFab::Copy( *Theta_prim[lev], vars_new[lev][Vars::cons], RhoTheta_comp, 0, 1, ng);
1012  MultiFab::Divide(*Theta_prim[lev], vars_new[lev][Vars::cons], Rho_comp, 0, 1, ng);
1013 
1014  if (solverChoice.moisture_type != MoistureType::None) {
1015  ng = Qv_prim[lev]->nGrowVect();
1016 
1017  MultiFab::Copy( *Qv_prim[lev], vars_new[lev][Vars::cons], RhoQ1_comp, 0, 1, ng);
1018  MultiFab::Divide(*Qv_prim[lev], vars_new[lev][Vars::cons], Rho_comp, 0, 1, ng);
1019 
1020  int rhoqr_comp = solverChoice.RhoQr_comp;
1021  if (rhoqr_comp > -1) {
1022  MultiFab::Copy( *Qr_prim[lev], vars_new[lev][Vars::cons], rhoqr_comp, 0, 1, ng);
1023  MultiFab::Divide(*Qr_prim[lev], vars_new[lev][Vars::cons], Rho_comp, 0, 1, ng);
1024  } else {
1025  Qr_prim[lev]->setVal(0.0);
1026  }
1027  }
1028  m_most->update_mac_ptrs(lev, vars_new, Theta_prim, Qv_prim, Qr_prim);
1029 
1030  if (restart_chkfile == "") {
1031  // Only do this if starting from scratch; if restarting, then
1032  // we don't want to call update_fluxes multiple times because
1033  // it will change u* and theta* from their previous values
1034  m_most->update_pblh(lev, vars_new, z_phys_cc[lev].get(),
1038  m_most->update_fluxes(lev, time);
1039  }
1040  }
1041  }
1042 
1043  // Update micro vars before first plot file
1044  if (solverChoice.moisture_type != MoistureType::None) {
1045  for (int lev = 0; lev <= finest_level; ++lev) micro->Update_Micro_Vars_Lev(lev, vars_new[lev][Vars::cons]);
1046  }
1047 
1048  // Fill time averaged velocities before first plot file
1049  if (solverChoice.time_avg_vel) {
1050  for (int lev = 0; lev <= finest_level; ++lev) {
1051  Time_Avg_Vel_atCC(dt[lev], t_avg_cnt[lev], vel_t_avg[lev].get(),
1052  vars_new[lev][Vars::xvel],
1053  vars_new[lev][Vars::yvel],
1054  vars_new[lev][Vars::zvel]);
1055  }
1056  }
1057 
1058  // check for additional plotting variables that are available after particle containers
1059  // are setup.
1060  const std::string& pv1 = "plot_vars_1"; appendPlotVariables(pv1,plot_var_names_1);
1061  const std::string& pv2 = "plot_vars_2"; appendPlotVariables(pv2,plot_var_names_2);
1062 
1063  if ( restart_chkfile.empty() && (m_check_int > 0 || m_check_per > 0.) )
1064  {
1065 #ifdef ERF_USE_NETCDF
1066  if (check_type == "netcdf") {
1067  WriteNCCheckpointFile();
1068  }
1069 #endif
1070  if (check_type == "native") {
1072  }
1074  }
1075 
1076  if ( (restart_chkfile.empty()) ||
1077  (!restart_chkfile.empty() && plot_file_on_restart) )
1078  {
1079  if (m_plot_int_1 > 0 || m_plot_per_1 > 0.)
1080  {
1083  }
1084  if (m_plot_int_2 > 0 || m_plot_per_2 > 0.)
1085  {
1088  }
1089  }
1090 
1091  // Set these up here because we need to know which MPI rank "cell" is on...
1092  if (pp.contains("data_log"))
1093  {
1094  int num_datalogs = pp.countval("data_log");
1095  datalog.resize(num_datalogs);
1096  datalogname.resize(num_datalogs);
1097  pp.queryarr("data_log",datalogname,0,num_datalogs);
1098  for (int i = 0; i < num_datalogs; i++)
1100  }
1101 
1102  if (restart_chkfile.empty() && profile_int > 0) {
1103  if (destag_profiles) {
1104  // all variables cell-centered
1106  } else {
1107  // some variables staggered
1109  }
1110  }
1111 
1112  if (pp.contains("sample_point_log") && pp.contains("sample_point"))
1113  {
1114  int lev = 0;
1115 
1116  int num_samplepts = pp.countval("sample_point") / AMREX_SPACEDIM;
1117  if (num_samplepts > 0) {
1118  Vector<int> index; index.resize(num_samplepts*AMREX_SPACEDIM);
1119  samplepoint.resize(num_samplepts);
1120 
1121  pp.queryarr("sample_point",index,0,num_samplepts*AMREX_SPACEDIM);
1122  for (int i = 0; i < num_samplepts; i++) {
1123  IntVect iv(index[AMREX_SPACEDIM*i+0],index[AMREX_SPACEDIM*i+1],index[AMREX_SPACEDIM*i+2]);
1124  samplepoint[i] = iv;
1125  }
1126  }
1127 
1128  int num_sampleptlogs = pp.countval("sample_point_log");
1129  AMREX_ALWAYS_ASSERT(num_sampleptlogs == num_samplepts);
1130  if (num_sampleptlogs > 0) {
1131  sampleptlog.resize(num_sampleptlogs);
1132  sampleptlogname.resize(num_sampleptlogs);
1133  pp.queryarr("sample_point_log",sampleptlogname,0,num_sampleptlogs);
1134 
1135  for (int i = 0; i < num_sampleptlogs; i++) {
1137  }
1138  }
1139 
1140  }
1141 
1142  if (pp.contains("sample_line_log") && pp.contains("sample_line"))
1143  {
1144  int lev = 0;
1145 
1146  int num_samplelines = pp.countval("sample_line") / AMREX_SPACEDIM;
1147  if (num_samplelines > 0) {
1148  Vector<int> index; index.resize(num_samplelines*AMREX_SPACEDIM);
1149  sampleline.resize(num_samplelines);
1150 
1151  pp.queryarr("sample_line",index,0,num_samplelines*AMREX_SPACEDIM);
1152  for (int i = 0; i < num_samplelines; i++) {
1153  IntVect iv(index[AMREX_SPACEDIM*i+0],index[AMREX_SPACEDIM*i+1],index[AMREX_SPACEDIM*i+2]);
1154  sampleline[i] = iv;
1155  }
1156  }
1157 
1158  int num_samplelinelogs = pp.countval("sample_line_log");
1159  AMREX_ALWAYS_ASSERT(num_samplelinelogs == num_samplelines);
1160  if (num_samplelinelogs > 0) {
1161  samplelinelog.resize(num_samplelinelogs);
1162  samplelinelogname.resize(num_samplelinelogs);
1163  pp.queryarr("sample_line_log",samplelinelogname,0,num_samplelinelogs);
1164 
1165  for (int i = 0; i < num_samplelinelogs; i++) {
1167  }
1168  }
1169 
1170  }
1171 
1172  // Create object to do line and plane sampling if needed
1173  bool do_line = false; bool do_plane = false;
1174  pp.query("do_line_sampling",do_line); pp.query("do_plane_sampling",do_plane);
1175  if (do_line || do_plane) { data_sampler = std::make_unique<SampleData>(do_line, do_plane); }
1176 
1177 #ifdef ERF_USE_EB
1178  bool write_eb_surface = false;
1179  pp.query("write_eb_surface", write_eb_surface);
1180  if (write_eb_surface) WriteMyEBSurface();
1181 #endif
1182 
1183 }
void initRayleigh()
Initialize Rayleigh damping profiles.
Definition: ERF_InitRayleigh.cpp:14
amrex::Vector< std::string > samplelinelogname
Definition: ERF.H:1388
void setRayleighRefFromSounding(bool restarting)
Set Rayleigh mean profiles from input sounding.
Definition: ERF_InitRayleigh.cpp:55
amrex::Vector< amrex::IntVect > sampleline
Definition: ERF.H:1389
amrex::Vector< amrex::Vector< amrex::Real > > h_w_subsid
Definition: ERF.H:1124
static amrex::Real sum_per
Definition: ERF.H:1054
void setRecordDataInfo(int i, const std::string &filename)
Definition: ERF.H:1328
void write_1D_profiles_stag(amrex::Real time)
Definition: ERF_Write1DProfiles_stag.cpp:23
amrex::Vector< std::unique_ptr< std::fstream > > samplelinelog
Definition: ERF.H:1387
static int sum_interval
Definition: ERF.H:1052
static int pert_interval
Definition: ERF.H:1053
void restart()
Definition: ERF.cpp:1223
void ReadCheckpointFileMOST()
Definition: ERF_Checkpoint.cpp:627
void write_1D_profiles(amrex::Real time)
Definition: ERF_Write1DProfiles.cpp:15
int profile_int
Definition: ERF.H:957
bool destag_profiles
Definition: ERF.H:958
void appendPlotVariables(const std::string &pp_plot_var_names, amrex::Vector< std::string > &plot_var_names)
Definition: ERF_Plotfile.cpp:128
static int output_bndry_planes
Definition: ERF.H:1106
void AverageDown()
Definition: ERF_AverageDown.cpp:16
std::unique_ptr< SampleData > data_sampler
Definition: ERF.H:1378
static amrex::Real bndry_output_planes_start_time
Definition: ERF.H:1109
std::string restart_chkfile
Definition: ERF.H:927
amrex::Vector< std::string > sampleptlogname
Definition: ERF.H:1384
void sum_integrated_quantities(amrex::Real time)
Definition: ERF_WriteScalarProfiles.cpp:14
amrex::Vector< std::unique_ptr< std::fstream > > sampleptlog
Definition: ERF.H:1383
std::unique_ptr< WriteBndryPlanes > m_w2d
Definition: ERF.H:1168
void init_geo_wind_profile(const std::string input_file, amrex::Vector< amrex::Real > &u_geos, amrex::Gpu::DeviceVector< amrex::Real > &u_geos_d, amrex::Vector< amrex::Real > &v_geos, amrex::Gpu::DeviceVector< amrex::Real > &v_geos_d, const amrex::Geometry &lgeom, const amrex::Vector< amrex::Real > &zlev_stag)
Definition: ERF_InitGeowind.cpp:10
void initSponge()
Initialize sponge profiles.
Definition: ERF_InitSponge.cpp:35
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:466
void project_velocities(int lev, amrex::Real dt, amrex::Vector< amrex::MultiFab > &vars, amrex::MultiFab &p)
Definition: ERF_PoissonSolve.cpp:10
int plot_file_on_restart
Definition: ERF.H:916
void Construct_ERFFillPatchers(int lev)
Definition: ERF.cpp:1874
void setRecordSampleLineInfo(int i, int lev, amrex::IntVect &cell, const std::string &filename)
Definition: ERF.H:1358
void setSpongeRefFromSounding(bool restarting)
Set sponge mean profiles from input sounding.
Definition: ERF_InitSponge.cpp:65
amrex::Vector< amrex::IntVect > samplepoint
Definition: ERF.H:1385
void setRecordSamplePointInfo(int i, int lev, amrex::IntVect &cell, const std::string &filename)
Definition: ERF.H:1341
static MoistureModelType modelType(const MoistureType a_moisture_type)
query if a specified moisture model is Eulerian or Lagrangian
Definition: ERF_Microphysics.H:69
bool have_zero_flux_faces
Definition: ERF_AdvStruct.H:303
bool have_geo_wind_profile
Definition: ERF_DataStruct.H:673
bool project_initial_velocity
Definition: ERF_DataStruct.H:626
std::string abl_geo_wind_table
Definition: ERF_DataStruct.H:672
bool use_rotate_most
Definition: ERF_DataStruct.H:648
void debug(amrex::Real)
Definition: ERF_TurbPertStruct.H:508
Here is the call graph for this function:

◆ InitData_pre()

void ERF::InitData_pre ( )
616 {
617  // Initialize the start time for our CPU-time tracker
618  startCPUTime = ParallelDescriptor::second();
619 
620  // Create the ReadBndryPlanes object so we can read boundary plane data
621  // m_r2d is used by init_bcs so we must instantiate this class before
622  if (input_bndry_planes) {
623  Print() << "Defining r2d for the first time " << std::endl;
624  m_r2d = std::make_unique<ReadBndryPlanes>(geom[0], solverChoice.rdOcp);
625  }
626 
630 
631  if (restart_chkfile.empty()) {
632  // start simulation from the beginning
633 
634  const Real time = start_time;
635  InitFromScratch(time);
636  } else {
637  // For initialization this is done in init_only; it is done here for restart
638  init_bcs();
639  }
640 
641  // Verify BCs are compatible with solver choice
642  for (int lev(0); lev <= max_level; ++lev) {
643  if ( ( (solverChoice.turbChoice[lev].pbl_type == PBLType::MYNN25) ||
644  (solverChoice.turbChoice[lev].pbl_type == PBLType::YSU) ) &&
645  phys_bc_type[Orientation(Direction::z,Orientation::low)] != ERF_BC::MOST ) {
646  Abort("MYNN2.5/YSU PBL Model requires MOST at lower boundary");
647  }
648  }
649 }
amrex::Real start_time
Definition: ERF.H:923

◆ initHSE() [1/2]

void ERF::initHSE ( )
private

Initialize HSE.

131 {
132  AMREX_ALWAYS_ASSERT(!init_sounding_ideal);
133  for (int lev = 0; lev <= finest_level; lev++)
134  {
135  initHSE(lev);
136  }
137 }

◆ 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 
30  bool all_boxes_touch_bottom = true;
31  Box domain(geom[lev].Domain());
32 
33  int icomp = 0; int ncomp = BaseState::num_comps;
34 
35  if (lev == 0) {
36  BoxArray ba(base_state[lev].boxArray());
37  for (int i = 0; i < ba.size(); i++) {
38  if (ba[i].smallEnd(2) != domain.smallEnd(2)) {
39  all_boxes_touch_bottom = false;
40  }
41  }
42  }
43  else
44  {
45  //
46  // We need to do this interp from coarse level in order to set the values of
47  // the base state inside the domain but outside of the fine region
48  //
49  base_state[lev-1].FillBoundary(geom[lev-1].periodicity());
50  //
51  // NOTE: this interpolater assumes that ALL ghost cells of the coarse MultiFab
52  // have been pre-filled - this includes ghost cells both inside and outside
53  // the domain
54  //
55  InterpFromCoarseLevel(base_state[lev], base_state[lev].nGrowVect(),
56  IntVect(0,0,0), // do not fill ghost cells outside the domain
57  base_state[lev-1], icomp, icomp, ncomp,
58  geom[lev-1], geom[lev],
59  refRatio(lev-1), &cell_cons_interp,
61 
62  // We need to do this here because the interpolation above may leave corners unfilled
63  // when the corners need to be filled by, for example, reflection of the fine ghost
64  // cell outside the fine region but inide the domain.
65  (*physbcs_base[lev])(base_state[lev],icomp,ncomp,base_state[lev].nGrowVect());
66  }
67 
68  if (all_boxes_touch_bottom || lev > 0) {
69 
70  // Initial r_hse may or may not be in HSE -- defined in ERF_Prob.cpp
72  prob->erf_init_dens_hse_moist(r_hse, z_phys_nd[lev], geom[lev]);
73  } else {
74  prob->erf_init_dens_hse(r_hse, z_phys_nd[lev], z_phys_cc[lev], geom[lev]);
75  }
76 
77  erf_enforce_hse(lev, r_hse, p_hse, pi_hse, th_hse, z_phys_cc[lev]);
78 
79  } else {
80 
81  BoxArray ba_new(domain);
82 
83  ChopGrids2D(ba_new, domain, ParallelDescriptor::NProcs());
84 
85  DistributionMapping dm_new(ba_new);
86 
87  MultiFab new_base_state(ba_new, dm_new, BaseState::num_comps, base_state[lev].nGrowVect());
88  new_base_state.ParallelCopy(base_state[lev],0,0,base_state[lev].nComp(),
89  base_state[lev].nGrowVect(),base_state[lev].nGrowVect());
90 
91  MultiFab new_r_hse (new_base_state, make_alias, BaseState::r0_comp, 1);
92  MultiFab new_p_hse (new_base_state, make_alias, BaseState::p0_comp, 1);
93  MultiFab new_pi_hse(new_base_state, make_alias, BaseState::pi0_comp, 1);
94  MultiFab new_th_hse(new_base_state, make_alias, BaseState::th0_comp, 1);
95 
96  std::unique_ptr<MultiFab> new_z_phys_cc;
97  std::unique_ptr<MultiFab> new_z_phys_nd;
98  if (solverChoice.mesh_type != MeshType::ConstantDz) {
99  new_z_phys_cc = std::make_unique<MultiFab>(ba_new,dm_new,1,1);
100  new_z_phys_cc->ParallelCopy(*z_phys_cc[lev],0,0,1,1,1);
101 
102  BoxArray ba_new_nd(ba_new);
103  ba_new_nd.surroundingNodes();
104  new_z_phys_nd = std::make_unique<MultiFab>(ba_new_nd,dm_new,1,1);
105  new_z_phys_nd->ParallelCopy(*z_phys_nd[lev],0,0,1,1,1);
106  }
107 
108  // Initial r_hse may or may not be in HSE -- defined in ERF_Prob.cpp
110  prob->erf_init_dens_hse_moist(new_r_hse, new_z_phys_nd, geom[lev]);
111  } else {
112  prob->erf_init_dens_hse(new_r_hse, new_z_phys_nd, new_z_phys_cc, geom[lev]);
113  }
114 
115  erf_enforce_hse(lev, new_r_hse, new_p_hse, new_pi_hse, new_th_hse, new_z_phys_cc);
116 
117  // Now copy back into the original arrays
118  base_state[lev].ParallelCopy(new_base_state,0,0,base_state[lev].nComp(),
119  base_state[lev].nGrowVect(),base_state[lev].nGrowVect());
120  }
121 
122  //
123  // Impose physical bc's on the base state -- the values outside the fine region
124  // but inside the domain have already been filled in the call above to InterpFromCoarseLevel
125  //
126  (*physbcs_base[lev])(base_state[lev],0,base_state[lev].nComp(),base_state[lev].nGrowVect());
127 }
void ChopGrids2D(BoxArray &ba, const Box &domain, int target_size)
Definition: ERF_ChopGrids.cpp:21
void erf_enforce_hse(int lev, amrex::MultiFab &dens, amrex::MultiFab &pres, amrex::MultiFab &pi, amrex::MultiFab &th, std::unique_ptr< amrex::MultiFab > &z_cc)
Definition: ERF_Init1D.cpp:149
bool use_moist_background
Definition: ERF_DataStruct.H:679
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
542 {
543  const BoxArray& ba(cons_mf.boxArray());
544  const DistributionMapping& dm(cons_mf.DistributionMap());
545 
546  int ncomp_cons = cons_mf.nComp();
547 
548  // Initialize the integrator memory
549  Vector<MultiFab> int_state; // integration state data structure example
550  int_state.push_back(MultiFab(cons_mf, make_alias, 0, ncomp_cons)); // cons
551  int_state.push_back(MultiFab(convert(ba,IntVect(1,0,0)), dm, 1, vel_mf.nGrow())); // xmom
552  int_state.push_back(MultiFab(convert(ba,IntVect(0,1,0)), dm, 1, vel_mf.nGrow())); // ymom
553  int_state.push_back(MultiFab(convert(ba,IntVect(0,0,1)), dm, 1, vel_mf.nGrow())); // zmom
554 
555  mri_integrator_mem[lev] = std::make_unique<MRISplitIntegrator<Vector<MultiFab> > >(int_state);
556  mri_integrator_mem[lev]->setNoSubstepping((solverChoice.substepping_type[lev] == SubsteppingType::None));
557  mri_integrator_mem[lev]->setAnelastic(solverChoice.anelastic[lev]);
558  mri_integrator_mem[lev]->setNcompCons(ncomp_cons);
559  mri_integrator_mem[lev]->setForceFirstStageSingleSubstep(solverChoice.force_stage1_single_substep);
560 }

◆ 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
1188 {
1189  if (Microphysics::modelType(solverChoice.moisture_type) == MoistureModelType::Eulerian) {
1190 
1191  micro = std::make_unique<EulerianMicrophysics>(a_nlevsmax, solverChoice.moisture_type);
1192 
1193  } else if (Microphysics::modelType(solverChoice.moisture_type) == MoistureModelType::Lagrangian) {
1194 #ifdef ERF_USE_PARTICLES
1195 
1196  micro = std::make_unique<LagrangianMicrophysics>(a_nlevsmax, solverChoice.moisture_type);
1197  /* Lagrangian microphysics models will have a particle container; it needs to be added
1198  to ERF::particleData */
1199  const auto& pc_name( dynamic_cast<LagrangianMicrophysics&>(*micro).getName() );
1200  /* The particle container has not yet been constructed and initialized, so just add
1201  its name here for now (so that functions to set plotting variables can see it). */
1202  particleData.addName( pc_name );
1203 
1204 #else
1205  Abort("Lagrangian microphysics can be used when compiled with ERF_USE_PARTICLES");
1206 #endif
1207  }
1208 
1209  qmoist.resize(a_nlevsmax);
1210  return;
1211 }
amrex::Vector< amrex::Vector< amrex::MultiFab * > > qmoist
Definition: ERF.H:777
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.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  for (int lev = 0; lev <= finest_level; lev++)
23  {
24  // These have 4 components: ubar, vbar, wbar, thetabar
25  h_rayleigh_ptrs[lev].resize(Rayleigh::nvars);
26  d_rayleigh_ptrs[lev].resize(Rayleigh::nvars);
27 
28  const int zlen_rayleigh = geom[lev].Domain().length(2);
29 
30  // Allocate space for these 1D vectors
31  for (int n = 0; n < Rayleigh::nvars; n++) {
32  h_rayleigh_ptrs[lev][n].resize(zlen_rayleigh, 0.0_rt);
33  d_rayleigh_ptrs[lev][n].resize(zlen_rayleigh, 0.0_rt);
34  }
35 
36  // Init the host vectors
37  prob->erf_init_rayleigh(h_rayleigh_ptrs[lev], geom[lev], z_phys_nd[lev], solverChoice.rayleigh_zdamp);
38 
39  // Copy from host vectors to device vectors
40  for (int n = 0; n < Rayleigh::nvars; n++) {
41  Gpu::copy(Gpu::hostToDevice, h_rayleigh_ptrs[lev][n].begin(), h_rayleigh_ptrs[lev][n].end(),
42  d_rayleigh_ptrs[lev][n].begin());
43  }
44  }
45 }
amrex::Vector< amrex::Vector< amrex::Vector< amrex::Real > > > h_rayleigh_ptrs
Definition: ERF.H:1143
amrex::Real rayleigh_zdamp
Definition: ERF_DataStruct.H:610
amrex::Real rayleigh_ztop
Definition: ERF_DataStruct.H:611

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

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

◆ 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
467 {
468  bool int_test = (action_interval > 0 && nstep % action_interval == 0);
469 
470  bool per_test = false;
471  if (action_per > 0.0) {
472  const int num_per_old = static_cast<int>(amrex::Math::floor((time - dtlev) / action_per));
473  const int num_per_new = static_cast<int>(amrex::Math::floor((time) / action_per));
474 
475  if (num_per_old != num_per_new) {
476  per_test = true;
477  }
478  }
479 
480  return int_test || per_test;
481 }

◆ make_physbcs()

void ERF::make_physbcs ( int  lev)
private
564 {
565  if (SolverChoice::mesh_type == MeshType::VariableDz) {
566  AMREX_ALWAYS_ASSERT(z_phys_nd[lev] != nullptr);
567  }
568 
569  physbcs_cons[lev] = std::make_unique<ERFPhysBCFunct_cons> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
571  z_phys_nd[lev], use_real_bcs);
572  physbcs_u[lev] = std::make_unique<ERFPhysBCFunct_u> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
574  z_phys_nd[lev], use_real_bcs, xvel_bc_data[lev].data());
575  physbcs_v[lev] = std::make_unique<ERFPhysBCFunct_v> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
577  z_phys_nd[lev], use_real_bcs, yvel_bc_data[lev].data());
578  physbcs_w[lev] = std::make_unique<ERFPhysBCFunct_w> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
581  use_real_bcs, zvel_bc_data[lev].data());
582  physbcs_base[lev] = std::make_unique<ERFPhysBCFunct_base> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
583  (solverChoice.terrain_type == TerrainType::Moving));
584 }

◆ MakeDiagnosticAverage()

void ERF::MakeDiagnosticAverage ( amrex::Vector< amrex::Real > &  h_havg,
amrex::MultiFab &  S,
int  n 
)
1829 {
1830  // Get the number of cells in z at level 0
1831  int dir_z = AMREX_SPACEDIM-1;
1832  auto domain = geom[0].Domain();
1833  int size_z = domain.length(dir_z);
1834  int start_z = domain.smallEnd()[dir_z];
1835  Real area_z = static_cast<Real>(domain.length(0)*domain.length(1));
1836 
1837  // resize the level 0 horizontal average vectors
1838  h_havg.resize(size_z, 0.0_rt);
1839 
1840  // Get the cell centered data and construct sums
1841 #ifdef _OPENMP
1842 #pragma omp parallel if (Gpu::notInLaunchRegion())
1843 #endif
1844  for (MFIter mfi(S); mfi.isValid(); ++mfi) {
1845  const Box& box = mfi.validbox();
1846  const IntVect& se = box.smallEnd();
1847  const IntVect& be = box.bigEnd();
1848 
1849  auto fab_arr = S[mfi].array();
1850 
1851  FArrayBox fab_reduce(box, 1, The_Async_Arena());
1852  auto arr_reduce = fab_reduce.array();
1853 
1854  ParallelFor(box, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
1855  arr_reduce(i, j, k, 0) = fab_arr(i,j,k,n);
1856  });
1857 
1858  for (int k=se[dir_z]; k <= be[dir_z]; ++k) {
1859  Box kbox(box); kbox.setSmall(dir_z,k); kbox.setBig(dir_z,k);
1860  h_havg[k-start_z] += fab_reduce.sum<RunOn::Device>(kbox,0);
1861  }
1862  }
1863 
1864  // combine sums from different MPI ranks
1865  ParallelDescriptor::ReduceRealSum(h_havg.dataPtr(), h_havg.size());
1866 
1867  // divide by the total number of cells we are averaging over
1868  for (int k = 0; k < size_z; ++k) {
1869  h_havg[k] /= area_z;
1870  }
1871 }

◆ MakeHorizontalAverages()

void ERF::MakeHorizontalAverages ( )
1723 {
1724  int lev = 0;
1725 
1726  // First, average down all levels (if doing two-way coupling)
1727  if (solverChoice.coupling_type == CouplingType::TwoWay) {
1728  AverageDown();
1729  }
1730 
1731  MultiFab mf(grids[lev], dmap[lev], 5, 0);
1732 
1733  int zdir = 2;
1734  auto domain = geom[0].Domain();
1735 
1736  bool use_moisture = (solverChoice.moisture_type != MoistureType::None);
1737  bool is_anelastic = (solverChoice.anelastic[lev] == 1);
1738 
1739  for (MFIter mfi(mf); mfi.isValid(); ++mfi) {
1740  const Box& bx = mfi.validbox();
1741  auto fab_arr = mf.array(mfi);
1742  auto const hse_arr = base_state[lev].const_array(mfi);
1743  auto const cons_arr = vars_new[lev][Vars::cons].const_array(mfi);
1744  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
1745  Real dens = cons_arr(i, j, k, Rho_comp);
1746  fab_arr(i, j, k, 0) = dens;
1747  fab_arr(i, j, k, 1) = cons_arr(i, j, k, RhoTheta_comp) / dens;
1748  if (!use_moisture) {
1749  if (is_anelastic) {
1750  fab_arr(i,j,k,2) = hse_arr(i,j,k,BaseState::p0_comp);
1751  } else {
1752  fab_arr(i,j,k,2) = getPgivenRTh(cons_arr(i,j,k,RhoTheta_comp));
1753  }
1754  }
1755  });
1756  }
1757 
1758  if (use_moisture)
1759  {
1760  for (MFIter mfi(mf); mfi.isValid(); ++mfi) {
1761  const Box& bx = mfi.validbox();
1762  auto fab_arr = mf.array(mfi);
1763  auto const hse_arr = base_state[lev].const_array(mfi);
1764  auto const cons_arr = vars_new[lev][Vars::cons].const_array(mfi);
1765  int ncomp = vars_new[lev][Vars::cons].nComp();
1766 
1767  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
1768  Real dens = cons_arr(i, j, k, Rho_comp);
1769  if (is_anelastic) {
1770  fab_arr(i,j,k,2) = hse_arr(i,j,k,BaseState::p0_comp);
1771  } else {
1772  Real qv = cons_arr(i, j, k, RhoQ1_comp) / dens;
1773  fab_arr(i, j, k, 2) = getPgivenRTh(cons_arr(i, j, k, RhoTheta_comp), qv);
1774  }
1775  fab_arr(i, j, k, 3) = (ncomp > RhoQ1_comp ? cons_arr(i, j, k, RhoQ1_comp) / dens : 0.0);
1776  fab_arr(i, j, k, 4) = (ncomp > RhoQ2_comp ? cons_arr(i, j, k, RhoQ2_comp) / dens : 0.0);
1777  });
1778  }
1779 
1780  Gpu::HostVector<Real> h_avg_qv = sumToLine(mf,3,1,domain,zdir);
1781  Gpu::HostVector<Real> h_avg_qc = sumToLine(mf,4,1,domain,zdir);
1782  }
1783 
1784  // Sum in the horizontal plane
1785  Gpu::HostVector<Real> h_avg_density = sumToLine(mf,0,1,domain,zdir);
1786  Gpu::HostVector<Real> h_avg_temperature = sumToLine(mf,1,1,domain,zdir);
1787  Gpu::HostVector<Real> h_avg_pressure = sumToLine(mf,2,1,domain,zdir);
1788 
1789  // Divide by the total number of cells we are averaging over
1790  int size_z = domain.length(zdir);
1791  Real area_z = static_cast<Real>(domain.length(0)*domain.length(1));
1792  int klen = static_cast<int>(h_avg_density.size());
1793 
1794  for (int k = 0; k < klen; ++k) {
1795  h_havg_density[k] /= area_z;
1796  h_havg_temperature[k] /= area_z;
1797  h_havg_pressure[k] /= area_z;
1798  if (solverChoice.moisture_type != MoistureType::None)
1799  {
1800  h_havg_qc[k] /= area_z;
1801  h_havg_qv[k] /= area_z;
1802  }
1803  } // k
1804 
1805  // resize device vectors
1806  d_havg_density.resize(size_z, 0.0_rt);
1807  d_havg_temperature.resize(size_z, 0.0_rt);
1808  d_havg_pressure.resize(size_z, 0.0_rt);
1809 
1810  // copy host vectors to device vectors
1811  Gpu::copy(Gpu::hostToDevice, h_havg_density.begin(), h_havg_density.end(), d_havg_density.begin());
1812  Gpu::copy(Gpu::hostToDevice, h_havg_temperature.begin(), h_havg_temperature.end(), d_havg_temperature.begin());
1813  Gpu::copy(Gpu::hostToDevice, h_havg_pressure.begin(), h_havg_pressure.end(), d_havg_pressure.begin());
1814 
1815  if (solverChoice.moisture_type != MoistureType::None)
1816  {
1817  d_havg_qv.resize(size_z, 0.0_rt);
1818  d_havg_qc.resize(size_z, 0.0_rt);
1819  Gpu::copy(Gpu::hostToDevice, h_havg_qv.begin(), h_havg_qv.end(), d_havg_qv.begin());
1820  Gpu::copy(Gpu::hostToDevice, h_havg_qc.begin(), h_havg_qc.end(), d_havg_qc.begin());
1821  }
1822 }
amrex::Gpu::DeviceVector< amrex::Real > d_havg_temperature
Definition: ERF.H:1161
amrex::Gpu::DeviceVector< amrex::Real > d_havg_qv
Definition: ERF.H:1163
amrex::Vector< amrex::Real > h_havg_pressure
Definition: ERF.H:1156
amrex::Vector< amrex::Real > h_havg_qc
Definition: ERF.H:1158
amrex::Vector< amrex::Real > h_havg_density
Definition: ERF.H:1154
amrex::Gpu::DeviceVector< amrex::Real > d_havg_qc
Definition: ERF.H:1164
amrex::Gpu::DeviceVector< amrex::Real > d_havg_density
Definition: ERF.H:1160
amrex::Vector< amrex::Real > h_havg_temperature
Definition: ERF.H:1155
amrex::Gpu::DeviceVector< amrex::Real > d_havg_pressure
Definition: ERF.H:1162
amrex::Vector< amrex::Real > h_havg_qv
Definition: ERF.H:1157
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
197 {
198  AMREX_ALWAYS_ASSERT(lev > 0);
199 
200  if (verbose) {
201  amrex::Print() <<" NEW BA FROM COARSE AT LEVEL " << lev << " " << ba << std::endl;
202  }
203 
204  //********************************************************************************************
205  // This allocates all kinds of things, including but not limited to: solution arrays,
206  // terrain arrays, metric terms and base state.
207  // *******************************************************************************************
208  init_stuff(lev, ba, dm, vars_new[lev], vars_old[lev], base_state[lev], z_phys_nd[lev]);
209 
210  t_new[lev] = time;
211  t_old[lev] = time - 1.e200;
212 
213  // ********************************************************************************************
214  // Build the data structures for terrain-related quantities
215  // ********************************************************************************************
216  init_zphys(lev, time);
218 
219  //
220  // Make sure that detJ and z_phys_cc are the average of the data on a finer level if there is one
221  //
222  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
223  for (int crse_lev = lev-1; crse_lev >= 0; crse_lev--) {
224  average_down( *detJ_cc[crse_lev+1], *detJ_cc[crse_lev], 0, 1, refRatio(crse_lev));
225  average_down(*z_phys_cc[crse_lev+1], *z_phys_cc[crse_lev], 0, 1, refRatio(crse_lev));
226  }
227  }
228 
229  // ********************************************************************************************
230  // Build the data structures for canopy model (depends upon z_phys)
231  // ********************************************************************************************
232  if (solverChoice.do_forest_drag) { m_forest_drag[lev]->define_drag_field(ba, dm, geom[lev], z_phys_nd[lev].get()); }
233 
234  if (solverChoice.do_terrain_drag) { m_terrain_drag[lev]->define_terrain_blank_field(ba, dm, geom[lev], z_phys_nd[lev].get()); }
235  //********************************************************************************************
236  // Microphysics
237  // *******************************************************************************************
238  int q_size = micro->Get_Qmoist_Size(lev);
239  qmoist[lev].resize(q_size);
240  micro->Define(lev, solverChoice);
241  if (solverChoice.moisture_type != MoistureType::None)
242  {
243  micro->Init(lev, vars_new[lev][Vars::cons],
244  grids[lev], Geom(lev), 0.0,
245  z_phys_nd[lev], detJ_cc[lev]); // dummy dt value
246  }
247  for (int mvar(0); mvar<qmoist[lev].size(); ++mvar) {
248  qmoist[lev][mvar] = micro->Get_Qmoist_Ptr(lev,mvar);
249  }
250 
251  // ********************************************************************************************
252  // Update the base state at this level by interpolation from coarser level
253  // ********************************************************************************************
254  //
255  // NOTE: this interpolater assumes that ALL ghost cells of the coarse MultiFab
256  // have been pre-filled - this includes ghost cells both inside and outside
257  // the domain
258  //
259  InterpFromCoarseLevel(base_state[lev], base_state[lev].nGrowVect(),
260  IntVect(0,0,0), // do not fill ghost cells outside the domain
261  base_state[lev-1], 0, 0, base_state[lev].nComp(),
262  geom[lev-1], geom[lev],
263  refRatio(lev-1), &cell_cons_interp,
265 
266  initHSE(lev);
267 
268  // ********************************************************************************************
269  // Build the data structures for calculating diffusive/turbulent terms
270  // ********************************************************************************************
271  update_diffusive_arrays(lev, ba, dm);
272 
273  // *****************************************************************************************************
274  // Initialize the boundary conditions (after initializing the terrain but before calling FillCoarsePatch
275  // *****************************************************************************************************
276  make_physbcs(lev);
277 
278  // ********************************************************************************************
279  // Fill data at the new level by interpolation from the coarser level
280  // Note that internal to FillCoarsePatch we will convert velocity to momentum,
281  // then interpolate momentum, then convert momentum back to velocity
282  // Also note that FillCoarsePatch is hard-wired to act only on lev_new at coarse and fine
283  // ********************************************************************************************
284  FillCoarsePatch(lev, time);
285 
286  // ********************************************************************************************
287  // Initialize the integrator class
288  // ********************************************************************************************
289  dt_mri_ratio[lev] = dt_mri_ratio[lev-1];
291 
292  // ********************************************************************************************
293  // If we are making a new level then the FillPatcher for this level hasn't been allocated yet
294  // ********************************************************************************************
295  if (lev > 0 && cf_width >= 0) {
298  }
299 
300 #ifdef ERF_USE_PARTICLES
301  // particleData.Redistribute();
302 #endif
303 }
void update_diffusive_arrays(int lev, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm)
Definition: ERF_MakeNewArrays.cpp:374
void initialize_integrator(int lev, amrex::MultiFab &cons_mf, amrex::MultiFab &vel_mf)
Definition: ERF_MakeNewArrays.cpp:541
void update_terrain_arrays(int lev)
Definition: ERF_MakeNewArrays.cpp:530
void init_zphys(int lev, amrex::Real time)
Definition: ERF_MakeNewArrays.cpp:464
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:23
void Define_ERFFillPatchers(int lev)
Definition: ERF.cpp:1900
bool do_terrain_drag
Definition: ERF_DataStruct.H:700
bool do_forest_drag
Definition: ERF_DataStruct.H:697

◆ MakeNewLevelFromScratch()

void ERF::MakeNewLevelFromScratch ( int  lev,
amrex::Real  time,
const amrex::BoxArray &  ba,
const amrex::DistributionMapping &  dm 
)
override
25 {
26  BoxArray ba;
27  DistributionMapping dm;
28  Box domain(Geom(0).Domain());
29  if (lev == 0 && restart_chkfile.empty() &&
30  (max_grid_size[0][0] >= domain.length(0)) &&
31  (max_grid_size[0][1] >= domain.length(1)) &&
32  ba_in.size() != ParallelDescriptor::NProcs())
33  {
34  // We only decompose in z if max_grid_size_z indicates we should
35  bool decompose_in_z = (max_grid_size[0][2] < domain.length(2));
36 
37  ba = ERFPostProcessBaseGrids(Geom(0).Domain(),decompose_in_z);
38  dm = DistributionMapping(ba);
39  } else {
40  ba = ba_in;
41  dm = dm_in;
42  }
43 
44  // Define grids[lev] to be ba
45  SetBoxArray(lev, ba);
46 
47  // Define dmap[lev] to be dm
48  SetDistributionMap(lev, dm);
49 
50  if (verbose) {
51  amrex::Print() <<" BA FROM SCRATCH AT LEVEL " << lev << " " << ba << std::endl;
52  }
53 
54  if (lev == 0) init_bcs();
55 
56 #ifdef ERF_USE_EB
57  m_factory[lev] = makeEBFabFactory(geom[lev], grids[lev], dmap[lev],
58  {nghost_eb_basic(),
59  nghost_eb_volume(),
60  nghost_eb_full()},
61  EBSupport::full);
62 #else
63  m_factory[lev] = std::make_unique<FArrayBoxFactory>();
64 #endif
65 
66  auto& lev_new = vars_new[lev];
67  auto& lev_old = vars_old[lev];
68 
69  //********************************************************************************************
70  // This allocates all kinds of things, including but not limited to: solution arrays,
71  // terrain arrays, metric terms and base state.
72  // *******************************************************************************************
73  init_stuff(lev, ba, dm, lev_new, lev_old, base_state[lev], z_phys_nd[lev]);
74 
75  //********************************************************************************************
76  // Land Surface Model
77  // *******************************************************************************************
78  int lsm_size = lsm.Get_Data_Size();
79  lsm_data[lev].resize(lsm_size);
80  lsm_flux[lev].resize(lsm_size);
81  lsm.Define(lev, solverChoice);
82  if (solverChoice.lsm_type != LandSurfaceType::None)
83  {
84  lsm.Init(lev, vars_new[lev][Vars::cons], Geom(lev), 0.0); // dummy dt value
85  }
86  for (int mvar(0); mvar<lsm_data[lev].size(); ++mvar) {
87  lsm_data[lev][mvar] = lsm.Get_Data_Ptr(lev,mvar);
88  lsm_flux[lev][mvar] = lsm.Get_Flux_Ptr(lev,mvar);
89  }
90 
91  // ********************************************************************************************
92  // Build the data structures for calculating diffusive/turbulent terms
93  // ********************************************************************************************
94  update_diffusive_arrays(lev, ba, dm);
95 
96  // ********************************************************************************************
97  // Build the data structures for holding sea surface temps
98  // ********************************************************************************************
99  sst_lev[lev].resize(1); sst_lev[lev][0] = nullptr;
100 
101  // ********************************************************************************************
102  // Thin immersed body
103  // *******************************************************************************************
104  init_thin_body(lev, ba, dm);
105 
106  // ********************************************************************************************
107  // Initialize the integrator class
108  // ********************************************************************************************
109  initialize_integrator(lev, lev_new[Vars::cons],lev_new[Vars::xvel]);
110 
111  // ********************************************************************************************
112  // Initialize the data itself
113  // If (init_type == InitType::Real) then we are initializing terrain and the initial data in
114  // the same call so we must call init_only before update_terrain_arrays
115  // If (init_type != InitType::Real) then we want to initialize the terrain before the initial data
116  // since we may need to use the grid information before constructing
117  // initial idealized data
118  // ********************************************************************************************
119  if (restart_chkfile.empty()) {
120  if ((init_type == InitType::Real) || (init_type == InitType::Metgrid)) {
121  init_only(lev, start_time);
122  init_zphys(lev, time);
124  make_physbcs(lev);
125  } else {
126  init_zphys(lev, time);
128  // Note that for init_type != InitType::Real or InitType::Metgrid,
129  // make_physbcs is called inside init_only
130  init_only(lev, start_time);
131  }
132  }
133 
134  // Read in tables needed for windfarm simulations
135  // fill in Nturb multifab - number of turbines in each mesh cell
136  // write out the vtk files for wind turbine location and/or
137  // actuator disks
138  #ifdef ERF_USE_WINDFARM
139  init_windfarm(lev);
140  #endif
141  // ********************************************************************************************
142  // Build the data structures for canopy model (depends upon z_phys)
143  // ********************************************************************************************
144  if (solverChoice.do_forest_drag) { m_forest_drag[lev]->define_drag_field(ba, dm, geom[lev], z_phys_nd[lev].get()); }
145 
146  if (solverChoice.do_terrain_drag) { m_terrain_drag[lev]->define_terrain_blank_field(ba, dm, geom[lev], z_phys_nd[lev].get()); }
147 
148  //********************************************************************************************
149  // Create wall distance field for RANS model (depends upon z_phys)
150  // *******************************************************************************************
151  if (solverChoice.turbChoice[lev].rans_type != RANSType::None) {
152  poisson_wall_dist(lev);
153  }
154 
155  //********************************************************************************************
156  // Microphysics
157  // *******************************************************************************************
158  int q_size = micro->Get_Qmoist_Size(lev);
159  qmoist[lev].resize(q_size);
160  micro->Define(lev, solverChoice);
161  if (solverChoice.moisture_type != MoistureType::None)
162  {
163  micro->Init(lev, vars_new[lev][Vars::cons],
164  grids[lev], Geom(lev), 0.0,
165  z_phys_nd[lev], detJ_cc[lev]); // dummy dt value
166  }
167  for (int mvar(0); mvar<qmoist[lev].size(); ++mvar) {
168  qmoist[lev][mvar] = micro->Get_Qmoist_Ptr(lev,mvar);
169  }
170 
171  // ********************************************************************************************
172  // If we are making a new level then the FillPatcher for this level hasn't been allocated yet
173  // ********************************************************************************************
174  if (lev > 0 && cf_width >= 0) {
177  }
178 
179 #ifdef ERF_USE_PARTICLES
180  if (restart_chkfile.empty()) {
181  if (lev == 0) {
182  initializeTracers((ParGDBBase*)GetParGDB(),z_phys_nd);
183  } else {
184  particleData.Redistribute();
185  }
186  }
187 #endif
188 }
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:1254
void poisson_wall_dist(int lev)
Definition: ERF_PoissonWallDist.cpp:16
void init_thin_body(int lev, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm)
Definition: ERF_MakeNewLevel.cpp:507
int Get_Data_Size()
Definition: ERF_LandSurface.H:78
amrex::MultiFab * Get_Flux_Ptr(const int &lev, const int &varIdx)
Definition: ERF_LandSurface.H:72
void Init(const int &lev, const amrex::MultiFab &cons_in, const amrex::Geometry &geom, const amrex::Real &dt_advance)
Definition: ERF_LandSurface.H:42
void Define(const int &lev, SolverChoice &sc)
Definition: ERF_LandSurface.H:35
amrex::MultiFab * Get_Data_Ptr(const int &lev, const int &varIdx)
Definition: ERF_LandSurface.H:69
Here is the call graph for this function:

◆ NumDataLogs()

AMREX_FORCE_INLINE int ERF::NumDataLogs ( )
inlineprivatenoexcept
1252  {
1253  return datalog.size();
1254  }

◆ NumSampleLineLogs()

AMREX_FORCE_INLINE int ERF::NumSampleLineLogs ( )
inlineprivatenoexcept
1280  {
1281  return samplelinelog.size();
1282  }

◆ NumSampleLines()

AMREX_FORCE_INLINE int ERF::NumSampleLines ( )
inlineprivatenoexcept
1306  {
1307  return sampleline.size();
1308  }

◆ NumSamplePointLogs()

AMREX_FORCE_INLINE int ERF::NumSamplePointLogs ( )
inlineprivatenoexcept
1266  {
1267  return sampleptlog.size();
1268  }

◆ NumSamplePoints()

AMREX_FORCE_INLINE int ERF::NumSamplePoints ( )
inlineprivatenoexcept
1293  {
1294  return samplepoint.size();
1295  }

◆ operator=() [1/2]

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

◆ operator=() [2/2]

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

◆ ParameterSanityChecks()

void ERF::ParameterSanityChecks ( )
private
1657 {
1658  AMREX_ALWAYS_ASSERT(cfl > 0. || fixed_dt[0] > 0.);
1659 
1660  // We don't allow use_real_bcs to be true if init_type is not either InitType::Real or InitType::Metgrid
1661  AMREX_ALWAYS_ASSERT(!use_real_bcs || ((init_type == InitType::Real) || (init_type == InitType::Metgrid)) );
1662 
1663  AMREX_ALWAYS_ASSERT(real_width >= 0);
1664  AMREX_ALWAYS_ASSERT(real_set_width >= 0);
1665  AMREX_ALWAYS_ASSERT(real_width >= real_set_width);
1666 
1667  if (cf_width < 0 || cf_set_width < 0 || cf_width < cf_set_width) {
1668  Abort("You must set cf_width >= cf_set_width >= 0");
1669  }
1670  if (max_level > 0 && cf_set_width > 0) {
1671  for (int lev = 1; lev <= max_level; lev++) {
1672  if (cf_set_width%ref_ratio[lev-1][0] != 0 ||
1673  cf_set_width%ref_ratio[lev-1][1] != 0 ||
1674  cf_set_width%ref_ratio[lev-1][2] != 0 ) {
1675  Abort("You must set cf_width to be a multiple of ref_ratio");
1676  }
1677  }
1678  }
1679 
1680  // If fixed_mri_dt_ratio is set, it must be even
1681  if (fixed_mri_dt_ratio > 0 && (fixed_mri_dt_ratio%2 != 0) )
1682  {
1683  Abort("If you specify fixed_mri_dt_ratio, it must be even");
1684  }
1685 
1686  for (int lev = 0; lev <= max_level; lev++)
1687  {
1688  // We ignore fixed_fast_dt if not substepping
1689  if (solverChoice.substepping_type[lev] == SubsteppingType::None) {
1690  fixed_fast_dt[lev] = -1.0;
1691  }
1692 
1693  // If both fixed_dt and fast_dt are specified, their ratio must be an even integer
1694  if (fixed_dt[lev] > 0. && fixed_fast_dt[lev] > 0. && fixed_mri_dt_ratio <= 0)
1695  {
1696  Real eps = 1.e-12;
1697  int ratio = static_cast<int>( ( (1.0+eps) * fixed_dt[lev] ) / fixed_fast_dt[lev] );
1698  if (fixed_dt[lev] / fixed_fast_dt[lev] != ratio)
1699  {
1700  Abort("Ratio of fixed_dt to fixed_fast_dt must be an even integer");
1701  }
1702  }
1703 
1704  // If all three are specified, they must be consistent
1705  if (fixed_dt[lev] > 0. && fixed_fast_dt[lev] > 0. && fixed_mri_dt_ratio > 0)
1706  {
1707  if (fixed_dt[lev] / fixed_fast_dt[lev] != fixed_mri_dt_ratio)
1708  {
1709  Abort("Dt is over-specfied");
1710  }
1711  }
1712  } // lev
1713 
1714  if (solverChoice.coupling_type == CouplingType::TwoWay && cf_width > 0) {
1715  Abort("For two-way coupling you must set cf_width = 0");
1716  }
1717 }
int real_width
Definition: ERF.H:1075
int real_set_width
Definition: ERF.H:1076

◆ PlotFileName()

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

◆ PlotFileVarNames()

Vector< std::string > ERF::PlotFileVarNames ( amrex::Vector< std::string >  plot_var_names)
staticprivate
175 {
176  Vector<std::string> names;
177 
178  names.insert(names.end(), plot_var_names.begin(), plot_var_names.end());
179 
180  return names;
181 
182 }

◆ poisson_wall_dist()

void ERF::poisson_wall_dist ( int  lev)

Calculate wall distances using the Poisson equation

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

17 {
18  BL_PROFILE("ERF::poisson_wall_dist()");
19 
20  auto const& geomdata = geom[lev];
21 
22  if (solverChoice.mesh_type == MeshType::ConstantDz) {
23 // Comment this out to test the wall dist calc in the trivial case:
24 //#if 0
25  Print() << "Directly calculating direct wall distance for constant dz" << std::endl;
26  const Real* prob_lo = geomdata.ProbLo();
27  const Real* dx = geomdata.CellSize();
28  for (MFIter mfi(*walldist[lev]); mfi.isValid(); ++mfi) {
29  const Box& bx = mfi.validbox();
30  auto dist_arr = walldist[lev]->array(mfi);
31  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
32  dist_arr(i, j, k) = prob_lo[2] + (k + 0.5) * dx[2];
33  });
34  }
35  return;
36 //#endif
37  } else if (solverChoice.mesh_type == MeshType::StretchedDz) {
38  // TODO: Handle this trivial case
39  Error("Wall dist calc not implemented with grid stretching yet");
40  } else {
41  // TODO
42  Error("Wall dist calc not implemented over terrain yet");
43  }
44 
45  Print() << "Calculating Poisson wall distance" << std::endl;
46 
47  // Make sure the solver only sees the levels over which we are solving
48  BoxArray nba = walldist[lev]->boxArray();
49  nba.surroundingNodes();
50  Vector<Geometry> geom_tmp; geom_tmp.push_back(geom[lev]);
51  Vector<BoxArray> ba_tmp; ba_tmp.push_back(nba);
52  Vector<DistributionMapping> dm_tmp; dm_tmp.push_back(walldist[lev]->DistributionMap());
53 
54  Vector<MultiFab> rhs;
55  Vector<MultiFab> phi;
56 
57 #ifdef ERF_USE_EB
58  Error("Wall dist calc not implemented for EB";
59 #else
60  rhs.resize(1); rhs[0].define(ba_tmp[0], dm_tmp[0], 1, 0);
61  phi.resize(1); phi[0].define(ba_tmp[0], dm_tmp[0], 1, 1);
62 #endif
63 
64  rhs[0].setVal(-1.0);
65 
66  // Define an overset mask to set dirichlet nodes on walls
67  iMultiFab mask(ba_tmp[0], dm_tmp[0], 1, 0);
68  Vector<const iMultiFab*> overset_mask = {&mask};
69 
70  auto const dom_lo = lbound(geom[lev].Domain());
71  auto const dom_hi = ubound(geom[lev].Domain());
72 
73  // ****************************************************************************
74  // Initialize phi
75  // (It is essential that we do this in order to fill the corners; this is
76  // used if we include blanking.)
77  // ****************************************************************************
78  phi[0].setVal(0.0);
79 
80  // ****************************************************************************
81  // Interior boundaries are marked with phi=0
82  // ****************************************************************************
83  // Overset mask is 0/1: 1 means the node is an unknown. 0 means it's known.
84  mask.setVal(1);
86  Warning("Poisson distance is inaccurate for bodies in open domains that are small compared to the domain size, skipping...");
87  walldist[lev]->setVal(1e34);
88  return;
89 #if 0
90  Gpu::DeviceVector<IntVect> xfacelist, yfacelist, zfacelist;
91 
92  xfacelist.resize(solverChoice.advChoice.zero_xflux.size());
93  yfacelist.resize(solverChoice.advChoice.zero_yflux.size());
94  zfacelist.resize(solverChoice.advChoice.zero_zflux.size());
95 
96  if (xfacelist.size() > 0) {
97  Gpu::copy(amrex::Gpu::hostToDevice,
100  xfacelist.begin());
101  Print() << " masking interior xfaces" << std::endl;
102  }
103  if (yfacelist.size() > 0) {
104  Gpu::copy(amrex::Gpu::hostToDevice,
107  yfacelist.begin());
108  Print() << " masking interior yfaces" << std::endl;
109  }
110  if (zfacelist.size() > 0) {
111  Gpu::copy(amrex::Gpu::hostToDevice,
114  zfacelist.begin());
115  Print() << " masking interior zfaces" << std::endl;
116  }
117 
118  for (MFIter mfi(phi[0]); mfi.isValid(); ++mfi) {
119  const Box& bx = mfi.validbox();
120 
121  auto phi_arr = phi[0].array(mfi);
122  auto mask_arr = mask.array(mfi);
123 
124  if (xfacelist.size() > 0) {
125  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
126  for (int iface=0; iface < xfacelist.size(); ++iface) {
127  if ((i == xfacelist[iface][0]) &&
128  (j == xfacelist[iface][1]) &&
129  (k == xfacelist[iface][2]))
130  {
131  mask_arr(i, j , k ) = 0;
132  mask_arr(i, j , k+1) = 0;
133  mask_arr(i, j+1, k ) = 0;
134  mask_arr(i, j+1, k+1) = 0;
135  }
136  }
137  });
138  }
139 
140  if (yfacelist.size() > 0) {
141  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
142  for (int iface=0; iface < yfacelist.size(); ++iface) {
143  if ((i == yfacelist[iface][0]) &&
144  (j == yfacelist[iface][1]) &&
145  (k == yfacelist[iface][2]))
146  {
147  mask_arr(i , j, k ) = 0;
148  mask_arr(i , j, k+1) = 0;
149  mask_arr(i+1, j, k ) = 0;
150  mask_arr(i+1, j, k+1) = 0;
151  }
152  }
153  });
154  }
155 
156  if (zfacelist.size() > 0) {
157  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
158  for (int iface=0; iface < zfacelist.size(); ++iface) {
159  if ((i == xfacelist[iface][0]) &&
160  (j == xfacelist[iface][1]) &&
161  (k == xfacelist[iface][2]))
162  {
163  mask_arr(i , j , k) = 0;
164  mask_arr(i , j+1, k) = 0;
165  mask_arr(i+1, j , k) = 0;
166  mask_arr(i+1, j+1, k) = 0;
167  }
168  }
169  });
170  }
171  }
172 #endif
173  }
174 
175  // ****************************************************************************
176  // Setup BCs, with solid domain boundaries being dirichlet
177  // We assume that the zlo boundary corresponds to the land surface
178  // ****************************************************************************
179  amrex::Array<amrex::LinOpBCType,AMREX_SPACEDIM> bc3d_lo, bc3d_hi;
180  Orientation zlo(Direction::z, Orientation::low);
181  bool havewall{false};
182  for (int dir = 0; dir < AMREX_SPACEDIM; ++dir) {
183  if (geom[0].isPeriodic(dir)) {
184  bc3d_lo[dir] = LinOpBCType::Periodic;
185  bc3d_hi[dir] = LinOpBCType::Periodic;
186  } else {
187  bc3d_lo[dir] = LinOpBCType::Neumann;
188  bc3d_hi[dir] = LinOpBCType::Neumann;
189  }
190  }
191  if ( ( phys_bc_type[zlo] == ERF_BC::MOST ) ||
192  ( phys_bc_type[zlo] == ERF_BC::no_slip_wall ) )/*||
193  ((phys_bc_type[zlo] == ERF_BC::slip_wall) && (dom_hi.z > dom_lo.z)) )*/
194  {
195  Print() << " Poisson zlo BC is dirichlet" << std::endl;
196  bc3d_lo[2] = LinOpBCType::Dirichlet;
197  havewall = true;
198  }
199  Print() << " bc lo : " << bc3d_lo << std::endl;
200  Print() << " bc hi : " << bc3d_hi << std::endl;
201 
202  if (!solverChoice.advChoice.have_zero_flux_faces && !havewall) {
203  Error("No solid boundaries in the computational domain");
204  }
205 
206  LPInfo info;
207 /* Nodal solver cannot have hidden dimensions */
208 #if 0
209  // Allow a hidden direction if the domain is one cell wide
210  if (dom_lo.x == dom_hi.x) {
211  info.setHiddenDirection(0);
212  Print() << " domain is 2D in yz" << std::endl;
213  } else if (dom_lo.y == dom_hi.y) {
214  info.setHiddenDirection(1);
215  Print() << " domain is 2D in xz" << std::endl;
216  } else if (dom_lo.z == dom_hi.z) {
217  info.setHiddenDirection(2);
218  Print() << " domain is 2D in xy" << std::endl;
219  }
220 #endif
221 
222  // ****************************************************************************
223  // Solve nodal masked Poisson problem with MLMG
224  // TODO: different solver for terrain?
225  // ****************************************************************************
226  const Real reltol = solverChoice.poisson_reltol;
227  const Real abstol = solverChoice.poisson_abstol;
228 
229  Real sigma = 1.0;
230  MLNodeLaplacian mlpoisson(geom_tmp, ba_tmp, dm_tmp, info, {}, sigma);
231 
232  mlpoisson.setDomainBC(bc3d_lo, bc3d_hi);
233 
234  if (lev > 0) {
235  mlpoisson.setCoarseFineBC(nullptr, ref_ratio[lev-1], LinOpBCType::Neumann);
236  }
237 
238  mlpoisson.setLevelBC(0, nullptr);
239 
240  mlpoisson.setOversetMask(0, mask);
241 
242  // Solve
243  MLMG mlmg(mlpoisson);
244  int max_iter = 100;
245  mlmg.setMaxIter(max_iter);
246 
247  mlmg.setVerbose(mg_verbose);
248  mlmg.setBottomVerbose(0);
249 
250  mlmg.solve(GetVecOfPtrs(phi),
251  GetVecOfConstPtrs(rhs),
252  reltol, abstol);
253 
254  // Now overwrite with periodic fill outside domain and fine-fine fill inside
255  phi[0].FillBoundary(geom[lev].periodicity());
256 
257  // ****************************************************************************
258  // Compute grad(phi) to get distances
259  // - Note that phi is nodal and walldist is cell-centered
260  // - TODO: include terrain metrics for dphi/dz
261  // ****************************************************************************
262  for (MFIter mfi(*walldist[lev]); mfi.isValid(); ++mfi) {
263  const Box& bx = mfi.validbox();
264 
265  const auto invCellSize = geomdata.InvCellSizeArray();
266 
267  auto const& phi_arr = phi[0].const_array(mfi);
268  auto dist_arr = walldist[lev]->array(mfi);
269 
270  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
271  Real dpdx{0}, dpdy{0}, dpdz{0};
272 
273  // dphi/dx
274  if (dom_lo.x != dom_hi.x) {
275  dpdx = 0.25 * invCellSize[0] * (
276  (phi_arr(i+1, j , k ) - phi_arr(i, j , k ))
277  + (phi_arr(i+1, j , k+1) - phi_arr(i, j , k+1))
278  + (phi_arr(i+1, j+1, k ) - phi_arr(i, j+1, k ))
279  + (phi_arr(i+1, j+1, k+1) - phi_arr(i, j+1, k+1)) );
280  }
281 
282  // dphi/dy
283  if (dom_lo.y != dom_hi.y) {
284  dpdy = 0.25 * invCellSize[1] * (
285  (phi_arr(i , j+1, k ) - phi_arr(i , j, k ))
286  + (phi_arr(i , j+1, k+1) - phi_arr(i , j, k+1))
287  + (phi_arr(i+1, j+1, k ) - phi_arr(i+1, j, k ))
288  + (phi_arr(i+1, j+1, k+1) - phi_arr(i+1, j, k+1)) );
289  }
290 
291  // dphi/dz
292  if (dom_lo.z != dom_hi.z) {
293  dpdz = 0.25 * invCellSize[2] * (
294  (phi_arr(i , j , k+1) - phi_arr(i , j , k))
295  + (phi_arr(i , j+1, k+1) - phi_arr(i , j+1, k))
296  + (phi_arr(i+1, j , k+1) - phi_arr(i+1, j , k))
297  + (phi_arr(i+1, j+1, k+1) - phi_arr(i+1, j+1, k)) );
298  }
299 
300  Real dp_dot_dp = dpdx*dpdx + dpdy*dpdy + dpdz*dpdz;
301  Real phi_avg = 0.125 * (
302  phi_arr(i , j , k ) + phi_arr(i , j , k+1) + phi_arr(i , j+1, k ) + phi_arr(i , j+1, k+1)
303  + phi_arr(i+1, j , k ) + phi_arr(i+1, j , k+1) + phi_arr(i+1, j+1, k ) + phi_arr(i+1, j+1, k+1) );
304  dist_arr(i, j, k) = -std::sqrt(dp_dot_dp) + std::sqrt(dp_dot_dp + 2*phi_avg);
305 
306  // DEBUG: output phi instead
307  //dist_arr(i, j, k) = phi_arr(i, j, k);
308  });
309  }
310 }
static int mg_verbose
Definition: ERF.H:1048
amrex::Real poisson_reltol
Definition: ERF_DataStruct.H:594
amrex::Real poisson_abstol
Definition: ERF_DataStruct.H:593

◆ post_timestep()

void ERF::post_timestep ( int  nstep,
amrex::Real  time,
amrex::Real  dt_lev 
)
462 {
463  BL_PROFILE("ERF::post_timestep()");
464 
465 #ifdef ERF_USE_PARTICLES
466  particleData.Redistribute();
467 #endif
468 
469  if (solverChoice.coupling_type == CouplingType::TwoWay)
470  {
471  int ncomp = vars_new[0][Vars::cons].nComp();
472  for (int lev = finest_level-1; lev >= 0; lev--)
473  {
474  // The quantity that is conserved is not (rho S), but rather (rho S / m^2) where
475  // m is the map scale factor at cell centers
476  // Here we pre-divide (rho S) by m^2 before refluxing
477  for (MFIter mfi(vars_new[lev][Vars::cons], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
478  const Box& bx = mfi.tilebox();
479  const Array4< Real> cons_arr = vars_new[lev][Vars::cons].array(mfi);
480  const Array4<const Real> mapfac_arr = mapfac_m[lev]->const_array(mfi);
481  if (solverChoice.mesh_type == MeshType::ConstantDz) {
482  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
483  {
484  cons_arr(i,j,k,n) /= (mapfac_arr(i,j,0)*mapfac_arr(i,j,0));
485  });
486  } else {
487  const Array4<const Real> detJ_arr = detJ_cc[lev]->const_array(mfi);
488  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
489  {
490  cons_arr(i,j,k,n) *= detJ_arr(i,j,k) / (mapfac_arr(i,j,0)*mapfac_arr(i,j,0));
491  });
492  }
493  } // mfi
494 
495  // This call refluxes all "slow" cell-centered variables
496  // (i.e. not density or (rho theta) or velocities) from the lev/lev+1 interface onto lev
497  getAdvFluxReg(lev+1)->Reflux(vars_new[lev][Vars::cons], 2, 2, ncomp-2);
498 
499  // Here we multiply (rho S) by m^2 after refluxing
500  for (MFIter mfi(vars_new[lev][Vars::cons], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
501  const Box& bx = mfi.tilebox();
502  const Array4< Real> cons_arr = vars_new[lev][Vars::cons].array(mfi);
503  const Array4<const Real> mapfac_arr = mapfac_m[lev]->const_array(mfi);
504  if (solverChoice.mesh_type == MeshType::ConstantDz) {
505  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
506  {
507  cons_arr(i,j,k,n) *= (mapfac_arr(i,j,0)*mapfac_arr(i,j,0));
508  });
509  } else {
510  const Array4<const Real> detJ_arr = detJ_cc[lev]->const_array(mfi);
511  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
512  {
513  cons_arr(i,j,k,n) *= (mapfac_arr(i,j,0)*mapfac_arr(i,j,0)) / detJ_arr(i,j,k);
514  });
515  }
516  } // mfi
517 
518  // We need to do this before anything else because refluxing changes the
519  // values of coarse cells underneath fine grids with the assumption they'll
520  // be over-written by averaging down
521  int src_comp;
522  if (solverChoice.anelastic[lev]) {
523  src_comp = 1;
524  } else {
525  src_comp = 0;
526  }
527  int num_comp = ncomp - src_comp;
528  AverageDownTo(lev,src_comp,num_comp);
529  }
530  }
531 
532  if (is_it_time_for_action(nstep, time, dt_lev0, sum_interval, sum_per)) {
534  }
535 
536  if (solverChoice.pert_type == PerturbationType::Source ||
537  solverChoice.pert_type == PerturbationType::Direct) {
538  if (is_it_time_for_action(nstep, time, dt_lev0, pert_interval, -1.)) {
539  turbPert.debug(time);
540  }
541  }
542 
543  if (profile_int > 0 && (nstep+1) % profile_int == 0) {
544  if (destag_profiles) {
545  // all variables cell-centered
546  write_1D_profiles(time);
547  } else {
548  // some variables staggered
550  }
551  }
552 
553  if (output_1d_column) {
554 #ifdef ERF_USE_NETCDF
555  if (is_it_time_for_action(nstep, time, dt_lev0, column_interval, column_per))
556  {
557  int lev_column = 0;
558  for (int lev = finest_level; lev >= 0; lev--)
559  {
560  Real dx_lev = geom[lev].CellSize(0);
561  Real dy_lev = geom[lev].CellSize(1);
562  int i_lev = static_cast<int>(std::floor(column_loc_x / dx_lev));
563  int j_lev = static_cast<int>(std::floor(column_loc_y / dy_lev));
564  if (grids[lev].contains(IntVect(i_lev,j_lev,0))) lev_column = lev;
565  }
566  writeToNCColumnFile(lev_column, column_file_name, column_loc_x, column_loc_y, time);
567  }
568 #else
569  Abort("To output 1D column files ERF must be compiled with NetCDF");
570 #endif
571  }
572 
574  {
577  {
578  bool is_moist = (micro->Get_Qstate_Size() > 0);
579  m_w2d->write_planes(istep[0], time, vars_new, is_moist);
580  }
581  }
582 
583  // Write plane/line sampler data
584  if (is_it_time_for_action(nstep, time, dt_lev0, sampler_interval, sampler_per) && (data_sampler) ) {
585  data_sampler->get_sample_data(geom, vars_new);
586  data_sampler->write_sample_data(t_new, istep, ref_ratio, geom);
587  }
588 
589  // Moving terrain
590  if ( solverChoice.terrain_type == TerrainType::Moving )
591  {
592  for (int lev = finest_level; lev >= 0; lev--)
593  {
594  // Copy z_phs_nd and detJ_cc at end of timestep
595  MultiFab::Copy(*z_phys_nd[lev], *z_phys_nd_new[lev], 0, 0, 1, z_phys_nd[lev]->nGrowVect());
596  MultiFab::Copy( *detJ_cc[lev], *detJ_cc_new[lev], 0, 0, 1, detJ_cc[lev]->nGrowVect());
597  MultiFab::Copy(base_state[lev],base_state_new[lev],0,0,BaseState::num_comps,base_state[lev].nGrowVect());
598 
599  make_zcc(geom[lev],*z_phys_nd[lev],*z_phys_cc[lev]);
600  }
601  }
602 } // post_timestep
void make_zcc(const Geometry &geom, MultiFab &z_phys_nd, MultiFab &z_phys_cc)
Definition: ERF_TerrainMetrics.cpp:716
static amrex::Real column_loc_y
Definition: ERF.H:1102
static std::string column_file_name
Definition: ERF.H:1103
AMREX_FORCE_INLINE amrex::YAFluxRegister * getAdvFluxReg(int lev)
Definition: ERF.H:1237
static amrex::Real bndry_output_planes_per
Definition: ERF.H:1108
static amrex::Real column_per
Definition: ERF.H:1100
amrex::Real sampler_per
Definition: ERF.H:1377
static amrex::Real column_loc_x
Definition: ERF.H:1101
static int bndry_output_planes_interval
Definition: ERF.H:1107
int sampler_interval
Definition: ERF.H:1376
static int output_1d_column
Definition: ERF.H:1098
static int column_interval
Definition: ERF.H:1099
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:87
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_velocities()

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

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::project_velocities()");
13 
14 #ifndef ERF_USE_EB
15  auto const dom_lo = lbound(geom[lev].Domain());
16  auto const dom_hi = ubound(geom[lev].Domain());
17 #endif
18 
19  // Make sure the solver only sees the levels over which we are solving
20  Vector<BoxArray> ba_tmp; ba_tmp.push_back(mom_mf[Vars::cons].boxArray());
21  Vector<DistributionMapping> dm_tmp; dm_tmp.push_back(mom_mf[Vars::cons].DistributionMap());
22  Vector<Geometry> geom_tmp; geom_tmp.push_back(geom[lev]);
23 
24  MultiFab r_hse(base_state[lev], make_alias, BaseState::r0_comp, 1);
25 
26  Vector<MultiFab> rhs;
27  Vector<MultiFab> phi;
28 
29 #ifdef ERF_USE_EB
30  rhs.resize(1); rhs[0].define(ba_tmp[0], dm_tmp[0], 1, 0, MFInfo(), Factory(lev));
31  phi.resize(1); phi[0].define(ba_tmp[0], dm_tmp[0], 1, 1, MFInfo(), Factory(lev));
32 #else
33  rhs.resize(1); rhs[0].define(ba_tmp[0], dm_tmp[0], 1, 0);
34  phi.resize(1); phi[0].define(ba_tmp[0], dm_tmp[0], 1, 1);
35 #endif
36 
37  auto dxInv = geom[lev].InvCellSizeArray();
38 
39  //
40  // ****************************************************************************
41  // Now convert the rho0w MultiFab to hold Omega rather than rhow
42  // ****************************************************************************
43  //
44 #ifndef ERF_USE_EB
45  if (solverChoice.mesh_type == MeshType::VariableDz)
46  {
47  for ( MFIter mfi(rhs[0],TilingIfNotGPU()); mfi.isValid(); ++mfi)
48  {
49  const Array4<Real const>& rho0u_arr = mom_mf[IntVars::xmom].const_array(mfi);
50  const Array4<Real const>& rho0v_arr = mom_mf[IntVars::ymom].const_array(mfi);
51  const Array4<Real >& rho0w_arr = mom_mf[IntVars::zmom].array(mfi);
52 
53  const Array4<Real const>& z_nd = z_phys_nd[lev]->const_array(mfi);
54  //
55  // Define Omega from (rho0 W) but store it in the same array
56  //
57  Box tbz = mfi.nodaltilebox(2);
58  ParallelFor(tbz, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept {
59  if (k > dom_lo.z && k <= dom_hi.z) {
60  Real rho0w = rho0w_arr(i,j,k);
61  rho0w_arr(i,j,k) = OmegaFromW(i,j,k,rho0w,rho0u_arr,rho0v_arr,z_nd,dxInv);
62  } else {
63  rho0w_arr(i,j,k) = Real(0.0);
64  }
65  });
66  } // mfi
67  }
68 #endif
69 
70  // ****************************************************************************
71  // Compute divergence which will form RHS
72  // Note that we replace "rho0w" with the contravariant momentum, Omega
73  // ****************************************************************************
74  Array<MultiFab const*, AMREX_SPACEDIM> rho0_u_const;
75  rho0_u_const[0] = &mom_mf[IntVars::xmom];
76  rho0_u_const[1] = &mom_mf[IntVars::ymom];
77  rho0_u_const[2] = &mom_mf[IntVars::zmom];
78 
79  compute_divergence(lev, rhs[0], rho0_u_const, geom_tmp[0]);
80 
81  Real rhsnorm = rhs[0].norm0();
82 
83  if (mg_verbose > 0) {
84  Print() << "Max/L2 norm of divergence before solve at level " << lev << " : " << rhsnorm << " " << rhs[0].norm2() << std::endl;
85  }
86 
87  // ****************************************************************************
88  //
89  // No need to build the solver if RHS == 0
90  //
91  if (rhsnorm <= solverChoice.poisson_abstol) return;
92  // ****************************************************************************
93 
94  // ****************************************************************************
95  // Initialize phi to 0
96  // (It is essential that we do this in order to fill the corners; these are never
97  // used but the Saxpy requires the values to be initialized.)
98  // ****************************************************************************
99  phi[0].setVal(0.0);
100 
101  Real start_step = static_cast<Real>(ParallelDescriptor::second());
102 
103  // ****************************************************************************
104  // Allocate fluxes
105  // ****************************************************************************
106  Vector<Array<MultiFab,AMREX_SPACEDIM> > fluxes;
107  fluxes.resize(1);
108  for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
109 #ifdef ERF_USE_EB
110  fluxes[0][idim].define(convert(ba_tmp[0], IntVect::TheDimensionVector(idim)), dm_tmp[0], 1, 0, MFInfo(), Factory(lev));
111 #else
112  fluxes[0][idim].define(convert(ba_tmp[0], IntVect::TheDimensionVector(idim)), dm_tmp[0], 1, 0);
113 #endif
114  }
115 
116  // ****************************************************************************
117  // Choose the solver and solve
118  // ****************************************************************************
119 
120  // ****************************************************************************
121  // EB
122  // ****************************************************************************
123 #ifdef ERF_USE_EB
124  solve_with_EB_mlmg(lev, rhs, phi, fluxes);
125 #else
126 
127 #ifdef ERF_USE_FFT
128  Box my_region(ba_tmp[0].minimalBox());
129  bool boxes_make_rectangle = (my_region.numPts() == ba_tmp[0].numPts());
130 #endif
131 
132  // ****************************************************************************
133  // No terrain or grid stretching
134  // ****************************************************************************
135  if (solverChoice.mesh_type == MeshType::ConstantDz) {
136 #ifdef ERF_USE_FFT
137  if (use_fft) {
138  if (boxes_make_rectangle) {
139  solve_with_fft(lev, rhs[0], phi[0], fluxes[0]);
140  } else {
141  amrex::Warning("FFT won't work unless the boxArray covers the domain: defaulting to MLMG");
142  solve_with_mlmg(lev, rhs, phi, fluxes);
143  }
144  } else {
145  solve_with_mlmg(lev, rhs, phi, fluxes);
146  }
147 #else
148  if (use_fft) {
149  amrex::Warning("You set use_fft=true but didn't build with USE_FFT = TRUE; defaulting to MLMG");
150  }
151  solve_with_mlmg(lev, rhs, phi, fluxes);
152 #endif
153  } // No terrain or grid stretching
154 
155  // ****************************************************************************
156  // Grid stretching (flat terrain)
157  // ****************************************************************************
158  else if (solverChoice.mesh_type == MeshType::StretchedDz) {
159 #ifndef ERF_USE_FFT
160  amrex::Abort("Rebuild with USE_FFT = TRUE so you can use the FFT solver");
161 #else
162  if (!boxes_make_rectangle) {
163  amrex::Abort("FFT won't work unless the boxArray covers the domain");
164  } else {
165  if (!use_fft) {
166  amrex::Warning("Using FFT even though you didn't set use_fft to true; it's the best choice");
167  }
168  solve_with_fft(lev, rhs[0], phi[0], fluxes[0]);
169  }
170 #endif
171  } // grid stretching
172 
173  // ****************************************************************************
174  // General terrain
175  // ****************************************************************************
176  else if (solverChoice.mesh_type == MeshType::VariableDz) {
177 #ifdef ERF_USE_FFT
178  if (use_fft)
179  {
180  amrex::Warning("FFT solver does not work for general terrain: switching to FFT-preconditioned GMRES");
181  }
182  if (!boxes_make_rectangle) {
183  amrex::Abort("FFT preconditioner for GMRES won't work unless the boxArray covers the domain");
184  } else {
185  solve_with_gmres(lev, rhs, phi, fluxes);
186  }
187 #else
188  amrex::Abort("Rebuild with USE_FFT = TRUE so you can use the FFT preconditioner for GMRES");
189 #endif
190  } // general terrain
191 
192 #endif // not EB
193 
194  // ****************************************************************************
195  // Print time in solve
196  // ****************************************************************************
197  Real end_step = static_cast<Real>(ParallelDescriptor::second());
198  if (mg_verbose > 0) {
199  amrex::Print() << "Time in solve " << end_step - start_step << std::endl;
200  }
201 
202  // ****************************************************************************
203  // Subtract dt grad(phi) from the momenta (rho0u, rho0v, Omega)
204  // ****************************************************************************
205  MultiFab::Add(mom_mf[IntVars::xmom],fluxes[0][0],0,0,1,0);
206  MultiFab::Add(mom_mf[IntVars::ymom],fluxes[0][1],0,0,1,0);
207  MultiFab::Add(mom_mf[IntVars::zmom],fluxes[0][2],0,0,1,0);
208 
209  //
210  // This call is only to verify the divergence after the solve
211  // It is important we do this before computing the rho0w_arr from Omega back to rho0w
212  //
213  // ****************************************************************************
214  // THIS IS SIMPLY VERIFYING THE DIVERGENCE AFTER THE SOLVE
215  // ****************************************************************************
216  //
217  if (mg_verbose > 0)
218  {
219  compute_divergence(lev, rhs[0], rho0_u_const, geom_tmp[0]);
220 
221  Print() << "Max/L2 norm of divergence after solve at level " << lev << " : " << rhs[0].norm0() << " " << rhs[0].norm2() << std::endl;
222 
223 #if 0
224  // FOR DEBUGGING ONLY
225  for ( MFIter mfi(rhs[0],TilingIfNotGPU()); mfi.isValid(); ++mfi)
226  {
227  const Array4<Real const>& rhs_arr = rhs[0].const_array(mfi);
228  Box bx = mfi.validbox();
229  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept {
230  if (std::abs(rhs_arr(i,j,k)) > 1.e-10) {
231  amrex::Print() << "RHS AT " << IntVect(i,j,k) << " " << rhs_arr(i,j,k) << std::endl;
232  }
233  });
234  } // mfi
235 #endif
236 
237  } // mg_verbose
238 
239 
240  //
241  // ****************************************************************************
242  // Now convert the rho0w MultiFab back to holding (rho0w) rather than Omega
243  // ****************************************************************************
244  //
245  if (solverChoice.mesh_type == MeshType::VariableDz)
246  {
247  for (MFIter mfi(mom_mf[Vars::cons],TilingIfNotGPU()); mfi.isValid(); ++mfi)
248  {
249  Box tbz = mfi.nodaltilebox(2);
250  const Array4<Real >& rho0u_arr = mom_mf[IntVars::xmom].array(mfi);
251  const Array4<Real >& rho0v_arr = mom_mf[IntVars::ymom].array(mfi);
252  const Array4<Real >& rho0w_arr = mom_mf[IntVars::zmom].array(mfi);
253  const Array4<Real const>& z_nd = z_phys_nd[lev]->const_array(mfi);
254  ParallelFor(tbz, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept {
255  Real omega = rho0w_arr(i,j,k);
256  rho0w_arr(i,j,k) = WFromOmega(i,j,k,omega,rho0u_arr,rho0v_arr,z_nd,dxInv);
257  });
258  } // mfi
259  }
260 
261  // ****************************************************************************
262  // Update pressure variable with phi -- note that phi is dt * change in pressure
263  // ****************************************************************************
264  MultiFab::Saxpy(pmf, 1.0/l_dt, phi[0],0,0,1,1);
265  pmf.FillBoundary(geom[lev].periodicity());
266 }
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real WFromOmega(int i, int j, int k, amrex::Real omega, amrex::Real u, amrex::Real v, const amrex::Array4< const amrex::Real > &z_nd, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &dxInv)
Definition: ERF_TerrainMetrics.H:407
static bool use_fft
Definition: ERF.H:1049
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
void solve_with_mlmg(int lev, amrex::Vector< amrex::MultiFab > &rhs, amrex::Vector< amrex::MultiFab > &p, amrex::Vector< amrex::Array< amrex::MultiFab, AMREX_SPACEDIM >> &fluxes)
Definition: ERF_SolveWithMLMG.cpp:40
void solve_with_gmres(int lev, amrex::Vector< amrex::MultiFab > &rhs, amrex::Vector< amrex::MultiFab > &p, amrex::Vector< amrex::Array< amrex::MultiFab, AMREX_SPACEDIM >> &fluxes)
Definition: ERF_SolveWithGMRES.cpp:12
@ omega
Definition: ERF_SAM.H:49
Here is the call graph for this function:

◆ project_velocities_tb()

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

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

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

◆ projection_has_dirichlet()

bool ERF::projection_has_dirichlet ( amrex::Array< amrex::LinOpBCType, AMREX_SPACEDIM >  bcs) const
9 {
10  for (int dir = 0; dir < AMREX_SPACEDIM; ++dir) {
11  if (bcs[dir] == LinOpBCType::Dirichlet) return true;
12  }
13  return false;
14 }

◆ ReadCheckpointFile()

void ERF::ReadCheckpointFile ( )

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

274 {
275  Print() << "Restart from native checkpoint " << restart_chkfile << "\n";
276 
277  // Header
278  std::string File(restart_chkfile + "/Header");
279 
280  VisMF::IO_Buffer io_buffer(VisMF::GetIOBufferSize());
281 
282  Vector<char> fileCharPtr;
283  ParallelDescriptor::ReadAndBcastFile(File, fileCharPtr);
284  std::string fileCharPtrString(fileCharPtr.dataPtr());
285  std::istringstream is(fileCharPtrString, std::istringstream::in);
286 
287  std::string line, word;
288 
289  int chk_ncomp_cons, chk_ncomp;
290 
291  // read in title line
292  std::getline(is, line);
293 
294  // read in finest_level
295  is >> finest_level;
296  GotoNextLine(is);
297 
298  // read the number of components
299  // for each variable we store
300 
301  // conservative, cell-centered vars
302  is >> chk_ncomp_cons;
303  GotoNextLine(is);
304 
305  // x-velocity on faces
306  is >> chk_ncomp;
307  GotoNextLine(is);
308  AMREX_ASSERT(chk_ncomp == 1);
309 
310  // y-velocity on faces
311  is >> chk_ncomp;
312  GotoNextLine(is);
313  AMREX_ASSERT(chk_ncomp == 1);
314 
315  // z-velocity on faces
316  is >> chk_ncomp;
317  GotoNextLine(is);
318  AMREX_ASSERT(chk_ncomp == 1);
319 
320  // read in array of istep
321  std::getline(is, line);
322  {
323  std::istringstream lis(line);
324  int i = 0;
325  while (lis >> word) {
326  istep[i++] = std::stoi(word);
327  }
328  }
329 
330  // read in array of dt
331  std::getline(is, line);
332  {
333  std::istringstream lis(line);
334  int i = 0;
335  while (lis >> word) {
336  dt[i++] = std::stod(word);
337  }
338  }
339 
340  // read in array of t_new
341  std::getline(is, line);
342  {
343  std::istringstream lis(line);
344  int i = 0;
345  while (lis >> word) {
346  t_new[i++] = std::stod(word);
347  }
348  }
349 
350  for (int lev = 0; lev <= finest_level; ++lev) {
351  // read in level 'lev' BoxArray from Header
352  BoxArray ba;
353  ba.readFrom(is);
354  GotoNextLine(is);
355 
356  // create a distribution mapping
357  DistributionMapping dm { ba, ParallelDescriptor::NProcs() };
358 
359  MakeNewLevelFromScratch (lev, t_new[lev], ba, dm);
360  }
361 
362  // ncomp is only valid after we MakeNewLevelFromScratch (asks micro how many vars)
363  // NOTE: Data is written over ncomp, so check that we match the header file
364  int ncomp_cons = vars_new[0][Vars::cons].nComp();
365 
366  // NOTE: QKE was removed so this is for backward compatibility
367  AMREX_ASSERT((chk_ncomp_cons==ncomp_cons) || ((chk_ncomp_cons-1)==ncomp_cons));
368 
369  // read in the MultiFab data
370  for (int lev = 0; lev <= finest_level; ++lev)
371  {
372  // NOTE: For backward compatibility (chk file has QKE)
373  if ((chk_ncomp_cons-1)==ncomp_cons) {
374  MultiFab cons(grids[lev],dmap[lev],chk_ncomp_cons,0);
375  VisMF::Read(cons, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Cell"));
376 
377  // Copy up to RhoKE_comp
378  MultiFab::Copy(vars_new[lev][Vars::cons],cons,0,0,(RhoKE_comp+1),0);
379 
380  // Only if we have a PBL model do we need to copy QKE is src to KE in dst
381  if (solverChoice.turbChoice[lev].pbl_type == PBLType::MYNN25) {
382  MultiFab::Copy(vars_new[lev][Vars::cons],cons,(RhoKE_comp+1),RhoKE_comp,1,0);
383  vars_new[lev][Vars::cons].mult(0.5,RhoKE_comp,1,0);
384  }
385 
386  // Copy other components
387  int ncomp_remainder = ncomp_cons - (RhoKE_comp + 1);
388  MultiFab::Copy(vars_new[lev][Vars::cons],cons,(RhoKE_comp+2),(RhoKE_comp+1),ncomp_remainder,0);
389 
390  vars_new[lev][Vars::cons].setBndry(1.0e34);
391  } else {
392  MultiFab cons(grids[lev],dmap[lev],ncomp_cons,0);
393  VisMF::Read(cons, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Cell"));
394  MultiFab::Copy(vars_new[lev][Vars::cons],cons,0,0,ncomp_cons,0);
395  vars_new[lev][Vars::cons].setBndry(1.0e34);
396  }
397 
398  MultiFab xvel(convert(grids[lev],IntVect(1,0,0)),dmap[lev],1,0);
399  VisMF::Read(xvel, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "XFace"));
400  MultiFab::Copy(vars_new[lev][Vars::xvel],xvel,0,0,1,0);
401  vars_new[lev][Vars::xvel].setBndry(1.0e34);
402 
403  MultiFab yvel(convert(grids[lev],IntVect(0,1,0)),dmap[lev],1,0);
404  VisMF::Read(yvel, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "YFace"));
405  MultiFab::Copy(vars_new[lev][Vars::yvel],yvel,0,0,1,0);
406  vars_new[lev][Vars::yvel].setBndry(1.0e34);
407 
408  MultiFab zvel(convert(grids[lev],IntVect(0,0,1)),dmap[lev],1,0);
409  VisMF::Read(zvel, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "ZFace"));
410  MultiFab::Copy(vars_new[lev][Vars::zvel],zvel,0,0,1,0);
411  vars_new[lev][Vars::zvel].setBndry(1.0e34);
412 
413  // Note that we read the ghost cells of the base state (unlike above)
414 
415  // The original base state only had 3 components and 1 ghost cell -- we read this
416  // here to be consistent with the old style
417  IntVect ng_base; int ncomp_base;
418  bool read_old_base_state = true;
419  if (read_old_base_state) {
420  ng_base = IntVect{1};
421  ncomp_base = 3;
422  } else {
423  ng_base = base_state[lev].nGrowVect();
424  ncomp_base = base_state[lev].nComp();
425  }
426  MultiFab base(grids[lev],dmap[lev],ncomp_base,ng_base);
427  VisMF::Read(base, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "BaseState"));
428 
429  MultiFab::Copy(base_state[lev],base,0,0,ncomp_base,ng_base);
430 
431  if (read_old_base_state) {
432  for (MFIter mfi(base_state[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
433  {
434  // We only compute theta_0 on valid cells since we will impose domain BC's after restart
435  const Box& bx = mfi.tilebox();
436  Array4<Real> const& fab = base_state[lev].array(mfi);
437  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
438  {
440  / fab(i,j,k,BaseState::r0_comp);
441  });
442  }
443  }
444  base_state[lev].FillBoundary(geom[lev].periodicity());
445 
446  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
447  // Note that we also read the ghost cells of z_phys_nd
448  IntVect ng = z_phys_nd[lev]->nGrowVect();
449  MultiFab z_height(convert(grids[lev],IntVect(1,1,1)),dmap[lev],1,ng);
450  VisMF::Read(z_height, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Z_Phys_nd"));
451  MultiFab::Copy(*z_phys_nd[lev],z_height,0,0,1,ng);
453  }
454 
455  // Read in the moisture model restart variables
456  std::vector<int> qmoist_indices(0);
457  std::vector<std::string> qmoist_names(0);
458  micro->Get_Qmoist_Restart_Vars(lev, solverChoice, qmoist_indices, qmoist_names);
459  int qmoist_nvar = qmoist_indices.size();
460  for (int var = 0; var < qmoist_nvar; var++) {
461  IntVect ng_moist = qmoist[lev][qmoist_indices[var]]->nGrowVect();
462  const int ncomp_moist = 1;
463  MultiFab moist_vars(grids[lev],dmap[lev],ncomp_moist,ng_moist);
464  VisMF::Read(moist_vars, amrex::MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", qmoist_names[var]));
465  MultiFab::Copy(*(qmoist[lev][qmoist_indices[var]]),moist_vars,0,0,ncomp_moist,ng_moist);
466  }
467 
468 #if defined(ERF_USE_WINDFARM)
469  if(solverChoice.windfarm_type == WindFarmType::Fitch or
470  solverChoice.windfarm_type == WindFarmType::EWP or
471  solverChoice.windfarm_type == WindFarmType::SimpleAD){
472  IntVect ng = Nturb[lev].nGrowVect();
473  MultiFab mf_Nturb(grids[lev],dmap[lev],1,ng);
474  VisMF::Read(mf_Nturb, amrex::MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "NumTurb"));
475  MultiFab::Copy(Nturb[lev],mf_Nturb,0,0,1,ng);
476  }
477 #endif
478 
479  if (solverChoice.lsm_type != LandSurfaceType::None) {
480  for (int mvar(0); mvar<lsm_data[lev].size(); ++mvar) {
481  BoxArray ba = lsm_data[lev][mvar]->boxArray();
482  DistributionMapping dm = lsm_data[lev][mvar]->DistributionMap();
483  IntVect ng = lsm_data[lev][mvar]->nGrowVect();
484  int nvar = lsm_data[lev][mvar]->nComp();
485  MultiFab lsm_vars(ba,dm,nvar,ng);
486  VisMF::Read(lsm_vars, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "LsmVars"));
487  MultiFab::Copy(*(lsm_data[lev][mvar]),lsm_vars,0,0,nvar,ng);
488  }
489  }
490 
491  // Note that we read the ghost cells of the mapfactors
492  BoxList bl2d = grids[lev].boxList();
493  for (auto& b : bl2d) {
494  b.setRange(2,0);
495  }
496  BoxArray ba2d(std::move(bl2d));
497 
498  {
499  IntVect ng = mapfac_m[lev]->nGrowVect();
500  MultiFab mf_m(ba2d,dmap[lev],1,ng);
501  VisMF::Read(mf_m, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "MapFactor_m"));
502  MultiFab::Copy(*mapfac_m[lev],mf_m,0,0,1,ng);
503 
504  ng = mapfac_u[lev]->nGrowVect();
505  MultiFab mf_u(convert(ba2d,IntVect(1,0,0)),dmap[lev],1,ng);
506  VisMF::Read(mf_u, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "MapFactor_u"));
507  MultiFab::Copy(*mapfac_u[lev],mf_u,0,0,1,ng);
508 
509  ng = mapfac_v[lev]->nGrowVect();
510  MultiFab mf_v(convert(ba2d,IntVect(0,1,0)),dmap[lev],1,ng);
511  VisMF::Read(mf_v, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "MapFactor_v"));
512  MultiFab::Copy(*mapfac_v[lev],mf_v,0,0,1,ng);
513  }
514  }
515 
516 #ifdef ERF_USE_PARTICLES
517  restartTracers((ParGDBBase*)GetParGDB(),restart_chkfile);
518  if (Microphysics::modelType(solverChoice.moisture_type) == MoistureModelType::Lagrangian) {
519  dynamic_cast<LagrangianMicrophysics&>(*micro).restartParticles((ParGDBBase*)GetParGDB(),restart_chkfile);
520  }
521 #endif
522 
523 #ifdef ERF_USE_NETCDF
524  // Read bdy_data files
525  if ((init_type==InitType::Real) || (init_type==InitType::Metgrid)) {
526  int ioproc = ParallelDescriptor::IOProcessorNumber(); // I/O rank
527  int num_time;
528  int num_var;
529  Vector<Box> bx_v;
530  if (ParallelDescriptor::IOProcessor()) {
531  // Open header file and read from it
532  std::ifstream bdy_h_file(MultiFabFileFullPrefix(0, restart_chkfile, "Level_", "bdy_H"));
533  bdy_h_file >> num_time;
534  bdy_h_file >> num_var;
535  bdy_h_file >> start_bdy_time;
536  bdy_h_file >> bdy_time_interval;
537  bdy_h_file >> real_width;
538  bx_v.resize(4*num_var);
539  for (int ivar(0); ivar<num_var; ++ivar) {
540  bdy_h_file >> bx_v[4*ivar ];
541  bdy_h_file >> bx_v[4*ivar+1];
542  bdy_h_file >> bx_v[4*ivar+2];
543  bdy_h_file >> bx_v[4*ivar+3];
544  }
545 
546  // IO size the FABs
547  bdy_data_xlo.resize(num_time);
548  bdy_data_xhi.resize(num_time);
549  bdy_data_ylo.resize(num_time);
550  bdy_data_yhi.resize(num_time);
551  for (int itime(0); itime<num_time; ++itime) {
552  bdy_data_xlo[itime].resize(num_var);
553  bdy_data_xhi[itime].resize(num_var);
554  bdy_data_ylo[itime].resize(num_var);
555  bdy_data_yhi[itime].resize(num_var);
556  for (int ivar(0); ivar<num_var; ++ivar) {
557  bdy_data_xlo[itime][ivar].resize(bx_v[4*ivar ]);
558  bdy_data_xhi[itime][ivar].resize(bx_v[4*ivar+1]);
559  bdy_data_ylo[itime][ivar].resize(bx_v[4*ivar+2]);
560  bdy_data_yhi[itime][ivar].resize(bx_v[4*ivar+3]);
561  }
562  }
563 
564  // Open data file and read from it
565  std::ifstream bdy_d_file(MultiFabFileFullPrefix(0, restart_chkfile, "Level_", "bdy_D"));
566  for (int itime(0); itime<num_time; ++itime) {
567  for (int ivar(0); ivar<num_var; ++ivar) {
568  bdy_data_xlo[itime][ivar].readFrom(bdy_d_file);
569  bdy_data_xhi[itime][ivar].readFrom(bdy_d_file);
570  bdy_data_ylo[itime][ivar].readFrom(bdy_d_file);
571  bdy_data_yhi[itime][ivar].readFrom(bdy_d_file);
572  }
573  }
574  } // IO
575 
576  // Broadcast the data
577  ParallelDescriptor::Barrier();
578  ParallelDescriptor::Bcast(&start_bdy_time,1,ioproc);
579  ParallelDescriptor::Bcast(&bdy_time_interval,1,ioproc);
580  ParallelDescriptor::Bcast(&real_width,1,ioproc);
581  ParallelDescriptor::Bcast(&num_time,1,ioproc);
582  ParallelDescriptor::Bcast(&num_var,1,ioproc);
583 
584  // Everyone size their boxes
585  bx_v.resize(4*num_var);
586 
587  ParallelDescriptor::Bcast(bx_v.dataPtr(),bx_v.size(),ioproc);
588 
589  // Everyone but IO size their FABs
590  if (!ParallelDescriptor::IOProcessor()) {
591  bdy_data_xlo.resize(num_time);
592  bdy_data_xhi.resize(num_time);
593  bdy_data_ylo.resize(num_time);
594  bdy_data_yhi.resize(num_time);
595  for (int itime(0); itime<num_time; ++itime) {
596  bdy_data_xlo[itime].resize(num_var);
597  bdy_data_xhi[itime].resize(num_var);
598  bdy_data_ylo[itime].resize(num_var);
599  bdy_data_yhi[itime].resize(num_var);
600  for (int ivar(0); ivar<num_var; ++ivar) {
601  bdy_data_xlo[itime][ivar].resize(bx_v[4*ivar ]);
602  bdy_data_xhi[itime][ivar].resize(bx_v[4*ivar+1]);
603  bdy_data_ylo[itime][ivar].resize(bx_v[4*ivar+2]);
604  bdy_data_yhi[itime][ivar].resize(bx_v[4*ivar+3]);
605  }
606  }
607  }
608 
609  for (int itime(0); itime<num_time; ++itime) {
610  for (int ivar(0); ivar<num_var; ++ivar) {
611  ParallelDescriptor::Bcast(bdy_data_xlo[itime][ivar].dataPtr(),bdy_data_xlo[itime][ivar].box().numPts(),ioproc);
612  ParallelDescriptor::Bcast(bdy_data_xhi[itime][ivar].dataPtr(),bdy_data_xhi[itime][ivar].box().numPts(),ioproc);
613  ParallelDescriptor::Bcast(bdy_data_ylo[itime][ivar].dataPtr(),bdy_data_ylo[itime][ivar].box().numPts(),ioproc);
614  ParallelDescriptor::Bcast(bdy_data_yhi[itime][ivar].dataPtr(),bdy_data_yhi[itime][ivar].box().numPts(),ioproc);
615  }
616  }
617  } // init real
618 #endif
619 }
static void GotoNextLine(std::istream &is)
Definition: ERF_Checkpoint.cpp:15
void MakeNewLevelFromScratch(int lev, amrex::Real time, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm) override
Definition: ERF_MakeNewLevel.cpp:23
Here is the call graph for this function:

◆ ReadCheckpointFileMOST()

void ERF::ReadCheckpointFileMOST ( )

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

This is called after the ABLMost object is instantiated.

628 {
629  for (int lev = 0; lev <= finest_level; ++lev)
630  {
631  // Note that we read the ghost cells
632  BoxList bl2d = grids[lev].boxList();
633  for (auto& b : bl2d) {
634  b.setRange(2,0);
635  }
636  BoxArray ba2d(std::move(bl2d));
637 
638  if (m_most->have_variable_sea_roughness()) {
639  amrex::Print() << "Reading variable surface roughness" << std::endl;
640  IntVect ng = vars_new[lev][Vars::cons].nGrowVect(); ng[2]=0;
641  MultiFab z0_in(ba2d,dmap[lev],1,ng);
642  VisMF::Read(z0_in, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Z0"));
643  auto z0 = const_cast<FArrayBox*>(m_most->get_z0(lev));
644  for (amrex::MFIter mfi(z0_in); mfi.isValid(); ++mfi) {
645  const Box& bx = mfi.growntilebox();
646  z0->copy<RunOn::Host>(z0_in[mfi], bx);
647  }
648  }
649  }
650 }

◆ ReadParameters()

void ERF::ReadParameters ( )
private
1367 {
1368  {
1369  ParmParse pp; // Traditionally, max_step and stop_time do not have prefix.
1370  pp.query("max_step", max_step);
1371  pp.query("stop_time", stop_time);
1372 
1373  pp.query("start_time", start_time); // This is optional, it defaults to 0
1374  }
1375 
1376  ParmParse pp(pp_prefix);
1377  ParmParse pp_amr("amr");
1378  {
1379  // The type of the file we restart from
1380  pp.query("restart_type", restart_type);
1381 
1382  pp.query("regrid_int", regrid_int);
1383  pp.query("check_file", check_file);
1384  pp.query("check_type", check_type);
1385 
1386  // The regression tests use "amr.restart" and "amr.m_check_int" so we allow
1387  // for those or "erf.restart" / "erf.m_check_int" with the former taking
1388  // precedence if both are specified
1389  pp.query("check_int", m_check_int);
1390  pp.query("check_per", m_check_per);
1391  pp_amr.query("check_int", m_check_int);
1392  pp_amr.query("check_per", m_check_per);
1393 
1394  pp.query("restart", restart_chkfile);
1395  pp_amr.query("restart", restart_chkfile);
1396 
1397  // Verbosity
1398  pp.query("v", verbose);
1399  pp.query("mg_v", mg_verbose);
1400  pp.query("use_fft", use_fft);
1401 #ifndef ERF_USE_FFT
1402  if (use_fft) {
1403  amrex::Abort("You must build with USE_FFT in order to set use_fft = true in your inputs file");
1404  }
1405 #endif
1406 
1407  // Frequency of diagnostic output
1408  pp.query("sum_interval", sum_interval);
1409  pp.query("sum_period" , sum_per);
1410 
1411  pp.query("pert_interval", pert_interval);
1412 
1413  // Time step controls
1414  pp.query("cfl", cfl);
1415  pp.query("substepping_cfl", sub_cfl);
1416  pp.query("init_shrink", init_shrink);
1417  pp.query("change_max", change_max);
1418 
1419  fixed_dt.resize(max_level+1,-1.);
1420  fixed_fast_dt.resize(max_level+1,-1.);
1421 
1422  pp.query("fixed_dt", fixed_dt[0]);
1423  pp.query("fixed_fast_dt", fixed_fast_dt[0]);
1424 
1425  for (int lev = 1; lev <= max_level; lev++)
1426  {
1427  fixed_dt[lev] = fixed_dt[lev-1] / static_cast<Real>(MaxRefRatio(lev-1));
1428  fixed_fast_dt[lev] = fixed_fast_dt[lev-1] / static_cast<Real>(MaxRefRatio(lev-1));
1429  }
1430 
1431  pp.query("fixed_mri_dt_ratio", fixed_mri_dt_ratio);
1432 
1433  // How to initialize
1434  init_type = InitType::None;
1435  pp.query_enum_case_insensitive("init_type",init_type);
1436 
1437  // Should we use the bcs we've read in from wrfbdy or metgrid files?
1438  // We default to yes if we have them, but the user can override that option
1439  use_real_bcs = ( (init_type == InitType::Real) || (init_type == InitType::Metgrid) );
1440  pp.query("use_real_bcs",use_real_bcs);
1441 
1442  // We use this to keep track of how many boxes we read in from WRF initialization
1443  num_files_at_level.resize(max_level+1,0);
1444 
1445  // We use this to keep track of how many boxes are specified thru the refinement indicators
1446  num_boxes_at_level.resize(max_level+1,0);
1447  boxes_at_level.resize(max_level+1);
1448 
1449  // We always have exactly one file at level 0
1450  num_boxes_at_level[0] = 1;
1451  boxes_at_level[0].resize(1);
1452  boxes_at_level[0][0] = geom[0].Domain();
1453 
1454 #ifdef ERF_USE_NETCDF
1455  nc_init_file.resize(max_level+1);
1456 
1457  // NetCDF wrfinput initialization files -- possibly multiple files at each of multiple levels
1458  // but we always have exactly one file at level 0
1459  for (int lev = 0; lev <= max_level; lev++)
1460  {
1461  const std::string nc_file_names = Concatenate("nc_init_file_",lev,1);
1462  if (pp.contains(nc_file_names.c_str()))
1463  {
1464  int num_files = pp.countval(nc_file_names.c_str());
1465  num_files_at_level[lev] = num_files;
1466  nc_init_file[lev].resize(num_files);
1467  pp.queryarr(nc_file_names.c_str(), nc_init_file[lev],0,num_files);
1468  for (int j = 0; j < num_files; j++)
1469  Print() << "Reading NC init file names at level " << lev << " and index " << j << " : " << nc_init_file[lev][j] << std::endl;
1470  }
1471  }
1472 
1473  // NetCDF wrfbdy lateral boundary file
1474  pp.query("nc_bdy_file", nc_bdy_file);
1475 #endif
1476 
1477  // Flag to trigger initialization from input_sounding like WRF's ideal.exe
1478  pp.query("init_sounding_ideal", init_sounding_ideal);
1479 
1480  // Options for vertical interpolation of met_em*.nc data.
1481  pp.query("metgrid_debug_quiescent", metgrid_debug_quiescent);
1482  pp.query("metgrid_debug_isothermal", metgrid_debug_isothermal);
1483  pp.query("metgrid_debug_dry", metgrid_debug_dry);
1484  pp.query("metgrid_debug_psfc", metgrid_debug_psfc);
1485  pp.query("metgrid_debug_msf", metgrid_debug_msf);
1486  pp.query("metgrid_interp_theta", metgrid_interp_theta);
1487  pp.query("metgrid_basic_linear", metgrid_basic_linear);
1488  pp.query("metgrid_use_below_sfc", metgrid_use_below_sfc);
1489  pp.query("metgrid_use_sfc", metgrid_use_sfc);
1490  pp.query("metgrid_retain_sfc", metgrid_retain_sfc);
1491  pp.query("metgrid_proximity", metgrid_proximity);
1492  pp.query("metgrid_order", metgrid_order);
1493  pp.query("metgrid_force_sfc_k", metgrid_force_sfc_k);
1494 
1495  // Set default to FullState for now ... later we will try Perturbation
1496  interpolation_type = StateInterpType::FullState;
1497  pp.query_enum_case_insensitive("interpolation_type" ,interpolation_type);
1498 
1499  PlotFileType plotfile_type_temp = PlotFileType::None;
1500  pp.query_enum_case_insensitive("plotfile_type" ,plotfile_type_temp);
1501  pp.query_enum_case_insensitive("plotfile_type_1",plotfile_type_1);
1502  pp.query_enum_case_insensitive("plotfile_type_2",plotfile_type_2);
1503  //
1504  // This option is for backward consistency -- if only plotfile_type is set,
1505  // then it will be used for both 1 and 2 if and only if they are not set
1506  //
1507  // Default is native amrex if no type is specified
1508  //
1509  if (plotfile_type_temp == PlotFileType::None) {
1510  if (plotfile_type_1 == PlotFileType::None) {
1511  plotfile_type_1 = PlotFileType::Amrex;
1512  }
1513  if (plotfile_type_2 == PlotFileType::None) {
1514  plotfile_type_2 = PlotFileType::Amrex;
1515  }
1516  } else {
1517  if (plotfile_type_1 == PlotFileType::None) {
1518  plotfile_type_1 = plotfile_type_temp;
1519  } else {
1520  amrex::Abort("You must set either plotfile_type or plotfile_type_1, not both");
1521  }
1522  if (plotfile_type_2 == PlotFileType::None) {
1523  plotfile_type_2 = plotfile_type_temp;
1524  } else {
1525  amrex::Abort("You must set either plotfile_type or plotfile_type_2, not both");
1526  }
1527  }
1528 #ifndef ERF_USE_NETCDF
1529  if (plotfile_type_1 == PlotFileType::Netcdf ||
1530  plotfile_type_2 == PlotFileType::Netcdf) {
1531  amrex::Abort("Plotfile type = Netcdf is not allowed without USE_NETCDF = TRUE");
1532  }
1533 #endif
1534 
1535  pp.query("plot_file_1", plot_file_1);
1536  pp.query("plot_file_2", plot_file_2);
1537  pp.query("plot_int_1" , m_plot_int_1);
1538  pp.query("plot_int_2" , m_plot_int_2);
1539  pp.query("plot_per_1", m_plot_per_1);
1540  pp.query("plot_per_2", m_plot_per_2);
1541 
1542  pp.query("expand_plotvars_to_unif_rr",m_expand_plotvars_to_unif_rr);
1543 
1544  pp.query("plot_face_vels",m_plot_face_vels);
1545 
1546  if ( (m_plot_int_1 > 0 && m_plot_per_1 > 0) ||
1547  (m_plot_int_2 > 0 && m_plot_per_2 > 0.) ) {
1548  Abort("Must choose only one of plot_int or plot_per");
1549  }
1550 
1551  pp.query("profile_int", profile_int);
1552  pp.query("destag_profiles", destag_profiles);
1553 
1554  pp.query("plot_lsm", plot_lsm);
1555 #ifdef ERF_USE_RRTMGP
1556  pp.query("plot_rad", plot_rad);
1557 #endif
1558 
1559  pp.query("output_1d_column", output_1d_column);
1560  pp.query("column_per", column_per);
1561  pp.query("column_interval", column_interval);
1562  pp.query("column_loc_x", column_loc_x);
1563  pp.query("column_loc_y", column_loc_y);
1564  pp.query("column_file_name", column_file_name);
1565 
1566  // Sampler output frequency
1567  pp.query("sampler_per", sampler_per);
1568  pp.query("sampler_interval", sampler_interval);
1569 
1570  // Specify information about outputting planes of data
1571  pp.query("output_bndry_planes", output_bndry_planes);
1572  pp.query("bndry_output_planes_interval", bndry_output_planes_interval);
1573  pp.query("bndry_output_planes_per", bndry_output_planes_per);
1574  pp.query("bndry_output_start_time", bndry_output_planes_start_time);
1575 
1576  // Specify whether ingest boundary planes of data
1577  pp.query("input_bndry_planes", input_bndry_planes);
1578 
1579  // Query the set and total widths for wrfbdy interior ghost cells
1580  pp.query("real_width", real_width);
1581  pp.query("real_set_width", real_set_width);
1582 
1583  // Query the set and total widths for crse-fine interior ghost cells
1584  pp.query("cf_width", cf_width);
1585  pp.query("cf_set_width", cf_set_width);
1586 
1587  // Query the canopy model file name
1588  std::string forestfile;
1589  solverChoice.do_forest_drag = pp.query("forest_file", forestfile);
1591  for (int lev = 0; lev <= max_level; ++lev) {
1592  m_forest_drag[lev] = std::make_unique<ForestDrag>(forestfile);
1593  }
1594  }
1595 
1596  //Query the terrain file name
1597  std::string terrainfile;
1598  solverChoice.do_terrain_drag = pp.query("terrain_file", terrainfile);
1600  for (int lev = 0; lev <= max_level; ++lev) {
1601  m_terrain_drag[lev] = std::make_unique<TerrainDrag>(terrainfile);
1602  }
1603  }
1604 
1605  // AmrMesh iterate on grids?
1606  bool iterate(true);
1607  pp_amr.query("iterate_grids",iterate);
1608  if (!iterate) SetIterateToFalse();
1609  }
1610 
1611 #ifdef ERF_USE_PARTICLES
1612  readTracersParams();
1613 #endif
1614 
1615 #ifdef ERF_USE_MULTIBLOCK
1617 #endif
1618 
1619  solverChoice.init_params(max_level);
1620 
1621  // No moving terrain with init real (we must do this after init_params
1622  // because that is where we set terrain_type
1623  if (init_type == InitType::Real && solverChoice.terrain_type == TerrainType::Moving) {
1624  Abort("Moving terrain is not supported with init real");
1625  }
1626 
1627  // What type of land surface model to use
1628  // NOTE: Must be checked after init_params
1629  if (solverChoice.lsm_type == LandSurfaceType::SLM) {
1630  lsm.SetModel<SLM>();
1631  Print() << "SLM land surface model!\n";
1632  } else if (solverChoice.lsm_type == LandSurfaceType::MM5) {
1633  lsm.SetModel<MM5>();
1634  Print() << "MM5 land surface model!\n";
1635 #ifdef ERF_USE_NOAH
1636  } else if (solverChoice.lsm_type == LandSurfaceType::NOAH) {
1637  lsm.SetModel<NOAH>();
1638  Print() << "NOAH land surface model!\n";
1639 #endif
1640  } else if (solverChoice.lsm_type == LandSurfaceType::None) {
1641  lsm.SetModel<NullSurf>();
1642  Print() << "Null land surface model!\n";
1643  } else {
1644  Abort("Dont know this LandSurfaceType!") ;
1645  }
1646 
1647  if (verbose > 0) {
1648  solverChoice.display(max_level);
1649  }
1650 
1652 }
bool metgrid_basic_linear
Definition: ERF.H:1089
amrex::Vector< amrex::Vector< amrex::Box > > boxes_at_level
Definition: ERF.H:727
bool metgrid_debug_msf
Definition: ERF.H:1087
std::string plot_file_2
Definition: ERF.H:946
std::string restart_type
Definition: ERF.H:963
bool m_plot_face_vels
Definition: ERF.H:952
int regrid_int
Definition: ERF.H:942
bool metgrid_retain_sfc
Definition: ERF.H:1092
bool metgrid_use_sfc
Definition: ERF.H:1091
amrex::Vector< int > num_files_at_level
Definition: ERF.H:726
bool metgrid_debug_quiescent
Definition: ERF.H:1083
static std::string nc_bdy_file
Definition: ERF.H:1074
bool metgrid_interp_theta
Definition: ERF.H:1088
static amrex::Vector< amrex::Vector< std::string > > nc_init_file
Definition: ERF.H:1071
int metgrid_force_sfc_k
Definition: ERF.H:1095
bool metgrid_use_below_sfc
Definition: ERF.H:1090
amrex::Real metgrid_proximity
Definition: ERF.H:1093
std::string plot_file_1
Definition: ERF.H:945
bool metgrid_debug_dry
Definition: ERF.H:1085
bool metgrid_debug_isothermal
Definition: ERF.H:1084
bool metgrid_debug_psfc
Definition: ERF.H:1086
void ParameterSanityChecks()
Definition: ERF.cpp:1656
bool m_expand_plotvars_to_unif_rr
Definition: ERF.H:947
amrex::Vector< int > num_boxes_at_level
Definition: ERF.H:725
std::string check_file
Definition: ERF.H:961
int metgrid_order
Definition: ERF.H:1094
bool plot_lsm
Definition: ERF.H:954
void SetModel()
Definition: ERF_LandSurface.H:27
Definition: ERF_MM5.H:26
Definition: ERF_NOAH.H:20
Definition: ERF_NullSurf.H:8
Definition: ERF_SLM.H:26
std::string pp_prefix
Definition: ERF_DataStruct.H:584
void init_params(int max_level)
Definition: ERF_DataStruct.H:84
void display(int max_level)
Definition: ERF_DataStruct.H:434
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

106 {
107  if (max_level > 0)
108  {
109  ParmParse pp(pp_prefix);
110  Vector<std::string> refinement_indicators;
111  pp.queryarr("refinement_indicators",refinement_indicators,0,pp.countval("refinement_indicators"));
112 
113  for (int i=0; i<refinement_indicators.size(); ++i)
114  {
115  std::string ref_prefix = pp_prefix + "." + refinement_indicators[i];
116 
117  ParmParse ppr(ref_prefix);
118  RealBox realbox;
119  int lev_for_box;
120 
121  int num_real_lo = ppr.countval("in_box_lo");
122  int num_indx_lo = ppr.countval("in_box_lo_indices");
123 
124  if ( !((num_real_lo == AMREX_SPACEDIM && num_indx_lo == 0) ||
125  (num_indx_lo == AMREX_SPACEDIM && num_real_lo == 0) ||
126  (num_indx_lo == 0 && num_real_lo == 0)) )
127  {
128  amrex::Abort("Must only specify box for refinement using real OR index space");
129  }
130 
131  if (num_real_lo > 0) {
132  std::vector<Real> rbox_lo(3), rbox_hi(3);
133  ppr.get("max_level",lev_for_box);
134  if (lev_for_box <= max_level)
135  {
136  if (n_error_buf[0] != IntVect::TheZeroVector()) {
137  amrex::Abort("Don't use n_error_buf > 0 when setting the box explicitly");
138  }
139 
140  const Real* plo = geom[lev_for_box].ProbLo();
141  const Real* phi = geom[lev_for_box].ProbHi();
142 
143  ppr.getarr("in_box_lo",rbox_lo,0,AMREX_SPACEDIM);
144  ppr.getarr("in_box_hi",rbox_hi,0,AMREX_SPACEDIM);
145 
146  if (rbox_lo[0] < plo[0]) rbox_lo[0] = plo[0];
147  if (rbox_lo[1] < plo[1]) rbox_lo[1] = plo[1];
148  if (rbox_hi[0] > phi[0]) rbox_hi[0] = phi[0];
149  if (rbox_hi[1] > phi[1]) rbox_hi[1] = phi[1];
150 
151  realbox = RealBox(&(rbox_lo[0]),&(rbox_hi[0]));
152 
153  Print() << "Realbox read in and intersected laterally with domain is " << realbox << std::endl;
154 
155  num_boxes_at_level[lev_for_box] += 1;
156 
157  int ilo, jlo, klo;
158  int ihi, jhi, khi;
159  const auto* dx = geom[lev_for_box].CellSize();
160  ilo = static_cast<int>((rbox_lo[0] - plo[0])/dx[0]);
161  jlo = static_cast<int>((rbox_lo[1] - plo[1])/dx[1]);
162  ihi = static_cast<int>((rbox_hi[0] - plo[0])/dx[0]-1);
163  jhi = static_cast<int>((rbox_hi[1] - plo[1])/dx[1]-1);
164  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
165  // Search for k indices corresponding to nominal grid
166  // AGL heights
167  const Box& domain = geom[lev_for_box].Domain();
168  klo = domain.smallEnd(2) - 1;
169  khi = domain.smallEnd(2) - 1;
170 
171  if (rbox_lo[2] < zlevels_stag[lev_for_box][domain.smallEnd(2)])
172  {
173  klo = domain.smallEnd(2);
174  }
175  else
176  {
177  for (int k=domain.smallEnd(2); k<=domain.bigEnd(2)+1; ++k) {
178  if (zlevels_stag[lev_for_box][k] > rbox_lo[2]) {
179  klo = k-1;
180  break;
181  }
182  }
183  }
184  AMREX_ASSERT(klo >= domain.smallEnd(2));
185 
186  if (rbox_hi[2] > zlevels_stag[lev_for_box][domain.bigEnd(2)+1])
187  {
188  khi = domain.bigEnd(2);
189  }
190  else
191  {
192  for (int k=klo+1; k<=domain.bigEnd(2)+1; ++k) {
193  if (zlevels_stag[lev_for_box][k] > rbox_hi[2]) {
194  khi = k-1;
195  break;
196  }
197  }
198  }
199  AMREX_ASSERT((khi <= domain.bigEnd(2)) && (khi > klo));
200 
201  // Need to update realbox because tagging is based on
202  // the initial _un_deformed grid
203  realbox = RealBox(plo[0]+ ilo *dx[0], plo[1]+ jlo *dx[1], plo[2]+ klo *dx[2],
204  plo[0]+(ihi+1)*dx[0], plo[1]+(jhi+1)*dx[1], plo[2]+(khi+1)*dx[2]);
205  } else {
206  klo = static_cast<int>((rbox_lo[2] - plo[2])/dx[2]);
207  khi = static_cast<int>((rbox_hi[2] - plo[2])/dx[2]-1);
208  }
209 
210  Box bx(IntVect(ilo,jlo,klo),IntVect(ihi,jhi,khi));
211  if ( (ilo%ref_ratio[lev_for_box-1][0] != 0) || ((ihi+1)%ref_ratio[lev_for_box-1][0] != 0) ||
212  (jlo%ref_ratio[lev_for_box-1][1] != 0) || ((jhi+1)%ref_ratio[lev_for_box-1][1] != 0) ||
213  (klo%ref_ratio[lev_for_box-1][2] != 0) || ((khi+1)%ref_ratio[lev_for_box-1][2] != 0) )
214  {
215  amrex::Print() << "Box : " << bx << std::endl;
216  amrex::Print() << "RealBox : " << realbox << std::endl;
217  amrex::Print() << "ilo, ihi+1, jlo, jhi+1, klo, khi+1 by ref_ratio : "
218  << ilo%ref_ratio[lev_for_box-1][0] << " " << (ihi+1)%ref_ratio[lev_for_box-1][0] << " "
219  << jlo%ref_ratio[lev_for_box-1][1] << " " << (jhi+1)%ref_ratio[lev_for_box-1][1] << " "
220  << klo%ref_ratio[lev_for_box-1][2] << " " << (khi+1)%ref_ratio[lev_for_box-1][2] << std::endl;
221  amrex::Error("Fine box is not legit with this ref_ratio");
222  }
223  boxes_at_level[lev_for_box].push_back(bx);
224  Print() << "Saving in 'boxes at level' as " << bx << std::endl;
225  } // lev
226  if (init_type == InitType::Real || init_type == InitType::Metgrid) {
227  if (num_boxes_at_level[lev_for_box] != num_files_at_level[lev_for_box]) {
228  amrex::Error("Number of boxes doesn't match number of input files");
229 
230  }
231  }
232 
233  } else if (num_indx_lo > 0) {
234 
235  std::vector<int> box_lo(3), box_hi(3);
236  ppr.get("max_level",lev_for_box);
237  if (lev_for_box <= max_level)
238  {
239  if (n_error_buf[0] != IntVect::TheZeroVector()) {
240  amrex::Abort("Don't use n_error_buf > 0 when setting the box explicitly");
241  }
242 
243  ppr.getarr("in_box_lo_indices",box_lo,0,AMREX_SPACEDIM);
244  ppr.getarr("in_box_hi_indices",box_hi,0,AMREX_SPACEDIM);
245 
246  Box bx(IntVect(box_lo[0],box_lo[1],box_lo[2]),IntVect(box_hi[0],box_hi[1],box_hi[2]));
247  amrex::Print() << "BOX " << bx << std::endl;
248 
249  const auto* dx = geom[lev_for_box].CellSize();
250  const Real* plo = geom[lev_for_box].ProbLo();
251  realbox = RealBox(plo[0]+ box_lo[0] *dx[0], plo[1]+ box_lo[1] *dx[1], plo[2]+ box_lo[2] *dx[2],
252  plo[0]+(box_hi[0]+1)*dx[0], plo[1]+(box_hi[1]+1)*dx[1], plo[2]+(box_hi[2]+1)*dx[2]);
253 
254  Print() << "Reading " << bx << " at level " << lev_for_box << std::endl;
255  num_boxes_at_level[lev_for_box] += 1;
256 
257  if ( (box_lo[0]%ref_ratio[lev_for_box-1][0] != 0) || ((box_hi[0]+1)%ref_ratio[lev_for_box-1][0] != 0) ||
258  (box_lo[1]%ref_ratio[lev_for_box-1][1] != 0) || ((box_hi[1]+1)%ref_ratio[lev_for_box-1][1] != 0) ||
259  (box_lo[2]%ref_ratio[lev_for_box-1][2] != 0) || ((box_hi[2]+1)%ref_ratio[lev_for_box-1][2] != 0) )
260  amrex::Error("Fine box is not legit with this ref_ratio");
261  boxes_at_level[lev_for_box].push_back(bx);
262  Print() << "Saving in 'boxes at level' as " << bx << std::endl;
263  } // lev
264  if (init_type == InitType::Real || init_type == InitType::Metgrid) {
265  if (num_boxes_at_level[lev_for_box] != num_files_at_level[lev_for_box]) {
266  amrex::Error("Number of boxes doesn't match number of input files");
267 
268  }
269  }
270  }
271 
272  AMRErrorTagInfo info;
273 
274  if (realbox.ok()) {
275  info.SetRealBox(realbox);
276  }
277  if (ppr.countval("start_time") > 0) {
278  Real ref_min_time; ppr.get("start_time",ref_min_time);
279  info.SetMinTime(ref_min_time);
280  }
281  if (ppr.countval("end_time") > 0) {
282  Real ref_max_time; ppr.get("end_time",ref_max_time);
283  info.SetMaxTime(ref_max_time);
284  }
285  if (ppr.countval("max_level") > 0) {
286  int ref_max_level; ppr.get("max_level",ref_max_level);
287  info.SetMaxLevel(ref_max_level);
288  }
289 
290  if (ppr.countval("value_greater")) {
291  int num_val = ppr.countval("value_greater");
292  Vector<Real> value(num_val);
293  ppr.getarr("value_greater",value,0,num_val);
294  std::string field; ppr.get("field_name",field);
295  ref_tags.push_back(AMRErrorTag(value,AMRErrorTag::GREATER,field,info));
296  }
297  else if (ppr.countval("value_less")) {
298  int num_val = ppr.countval("value_less");
299  Vector<Real> value(num_val);
300  ppr.getarr("value_less",value,0,num_val);
301  std::string field; ppr.get("field_name",field);
302  ref_tags.push_back(AMRErrorTag(value,AMRErrorTag::LESS,field,info));
303  }
304  else if (ppr.countval("adjacent_difference_greater")) {
305  int num_val = ppr.countval("adjacent_difference_greater");
306  Vector<Real> value(num_val);
307  ppr.getarr("adjacent_difference_greater",value,0,num_val);
308  std::string field; ppr.get("field_name",field);
309  ref_tags.push_back(AMRErrorTag(value,AMRErrorTag::GRAD,field,info));
310  }
311  else if (realbox.ok())
312  {
313  ref_tags.push_back(AMRErrorTag(info));
314  } else {
315  Abort(std::string("Unrecognized refinement indicator for " + refinement_indicators[i]).c_str());
316  }
317  } // loop over criteria
318  } // if max_level > 0
319 }
Here is the call graph for this function:

◆ remake_zphys()

void ERF::remake_zphys ( int  lev,
std::unique_ptr< amrex::MultiFab > &  temp_zphys_nd 
)
private
504 {
505  if (lev > 0 && SolverChoice::mesh_type == MeshType::VariableDz)
506  {
507  //
508  // First interpolate from coarser level
509  // NOTE: this interpolater assumes that ALL ghost cells of the coarse MultiFab
510  // have been pre-filled - this includes ghost cells both inside and outside
511  // the domain
512  //
513  InterpFromCoarseLevel(*temp_zphys_nd, z_phys_nd[lev]->nGrowVect(),
514  IntVect(0,0,0), // do not fill ghost cells outside the domain
515  *z_phys_nd[lev-1], 0, 0, 1,
516  geom[lev-1], geom[lev],
517  refRatio(lev-1), &node_bilinear_interp,
519 
520  // This recomputes the fine values using the bottom terrain at the fine resolution,
521  // and also fills values of z_phys_nd outside the domain
522  init_terrain_grid(lev,geom[lev],*z_phys_nd[lev],zlevels_stag[lev],phys_bc_type);
523 
524  std::swap(temp_zphys_nd, z_phys_nd[lev]);
525 
526  } // use_terrain && lev > 0
527 }
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
311 {
312  if (verbose) {
313  amrex::Print() <<" REMAKING WITH NEW BA AT LEVEL " << lev << " " << ba << std::endl;
314  }
315 
316  AMREX_ALWAYS_ASSERT(lev > 0);
317  AMREX_ALWAYS_ASSERT(solverChoice.terrain_type != TerrainType::Moving);
318 
319  BoxArray ba_old(vars_new[lev][Vars::cons].boxArray());
320  DistributionMapping dm_old(vars_new[lev][Vars::cons].DistributionMap());
321 
322  if (verbose) {
323  amrex::Print() <<" OLD BA AT LEVEL " << lev << " " << ba_old << std::endl;
324  }
325 
326  int ncomp_cons = vars_new[lev][Vars::cons].nComp();
327  IntVect ngrow_state = vars_new[lev][Vars::cons].nGrowVect();
328 
330 
331  Vector<MultiFab> temp_lev_new(Vars::NumTypes);
332  Vector<MultiFab> temp_lev_old(Vars::NumTypes);
333  MultiFab temp_base_state;
334 
335  std::unique_ptr<MultiFab> temp_zphys_nd;
336 
337  //********************************************************************************************
338  // This allocates all kinds of things, including but not limited to: solution arrays,
339  // terrain arrays and metrics, and base state.
340  // *******************************************************************************************
341  init_stuff(lev, ba, dm, temp_lev_new, temp_lev_old, temp_base_state, temp_zphys_nd);
342 
343  // ********************************************************************************************
344  // Build the data structures for terrain-related quantities
345  // ********************************************************************************************
346  remake_zphys(lev, temp_zphys_nd);
348 
349  //
350  // Make sure that detJ and z_phys_cc are the average of the data on a finer level if there is one
351  //
352  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
353  for (int crse_lev = lev-1; crse_lev >= 0; crse_lev--) {
354  average_down( *detJ_cc[crse_lev+1], *detJ_cc[crse_lev], 0, 1, refRatio(crse_lev));
355  average_down(*z_phys_cc[crse_lev+1], *z_phys_cc[crse_lev], 0, 1, refRatio(crse_lev));
356  }
357  }
358 
359  // ********************************************************************************************
360  // Build the data structures for canopy model (depends upon z_phys)
361  // ********************************************************************************************
362  if (solverChoice.do_forest_drag) { m_forest_drag[lev]->define_drag_field(ba, dm, geom[lev], z_phys_nd[lev].get()); }
363 
364  if (solverChoice.do_terrain_drag) { m_terrain_drag[lev]->define_terrain_blank_field(ba, dm, geom[lev], z_phys_nd[lev].get()); }
365  // *****************************************************************************************************
366  // Create the physbcs objects (after initializing the terrain but before calling FillCoarsePatch
367  // *****************************************************************************************************
368  make_physbcs(lev);
369 
370  // ********************************************************************************************
371  // Update the base state at this level by interpolation from coarser level AND copy
372  // from previous (pre-regrid) base_state array
373  // ********************************************************************************************
374  Interpolater* mapper = &cell_cons_interp;
375 
376  Vector<MultiFab*> fmf = {&base_state[lev ], &base_state[lev ]};
377  Vector<MultiFab*> cmf = {&base_state[lev-1], &base_state[lev-1]};
378  Vector<Real> ftime = {time, time};
379  Vector<Real> ctime = {time, time};
380 
381  // Call FillPatch which ASSUMES that all ghost cells at lev-1 have already been filled
382  FillPatchTwoLevels(temp_base_state, temp_base_state.nGrowVect(), IntVect(0,0,0),
383  time, cmf, ctime, fmf, ftime,
384  0, 0, temp_base_state.nComp(), geom[lev-1], geom[lev],
385  refRatio(lev-1), mapper, domain_bcs_type,
387 
388  // Impose bc's outside the domain
389  (*physbcs_base[lev])(temp_base_state,0,temp_base_state.nComp(),base_state[lev].nGrowVect());
390 
391  // *************************************************************************************************
392  // This will fill the temporary MultiFabs with data from vars_new
393  // NOTE: the momenta here are only used as scratch space, the momenta themselves are not fillpatched
394  // NOTE: we must create the new base state before calling FillPatch because we will
395  // interpolate perturbational quantities
396  // *************************************************************************************************
397  FillPatch(lev, time, {&temp_lev_new[Vars::cons],&temp_lev_new[Vars::xvel],
398  &temp_lev_new[Vars::yvel],&temp_lev_new[Vars::zvel]},
399  {&temp_lev_new[Vars::cons],&rU_new[lev],&rV_new[lev],&rW_new[lev]},
400  base_state[lev], temp_base_state, false);
401 
402  // Now swap the pointers since we needed both old and new in the FillPatch
403  std::swap(temp_base_state, base_state[lev]);
404 
405  // ********************************************************************************************
406  // Copy from new into old just in case
407  // ********************************************************************************************
408  MultiFab::Copy(temp_lev_old[Vars::cons],temp_lev_new[Vars::cons],0,0,ncomp_cons,ngrow_state);
409  MultiFab::Copy(temp_lev_old[Vars::xvel],temp_lev_new[Vars::xvel],0,0, 1,ngrow_vels);
410  MultiFab::Copy(temp_lev_old[Vars::yvel],temp_lev_new[Vars::yvel],0,0, 1,ngrow_vels);
411  MultiFab::Copy(temp_lev_old[Vars::zvel],temp_lev_new[Vars::zvel],0,0, 1,IntVect(ngrow_vels,ngrow_vels,0));
412 
413  // ********************************************************************************************
414  // Now swap the pointers
415  // ********************************************************************************************
416  for (int var_idx = 0; var_idx < Vars::NumTypes; ++var_idx) {
417  std::swap(temp_lev_new[var_idx], vars_new[lev][var_idx]);
418  std::swap(temp_lev_old[var_idx], vars_old[lev][var_idx]);
419  }
420 
421  t_new[lev] = time;
422  t_old[lev] = time - 1.e200;
423 
424  // ********************************************************************************************
425  // Build the data structures for calculating diffusive/turbulent terms
426  // ********************************************************************************************
427  update_diffusive_arrays(lev, ba, dm);
428 
429  //********************************************************************************************
430  // Microphysics
431  // *******************************************************************************************
432  int q_size = micro->Get_Qmoist_Size(lev);
433  qmoist[lev].resize(q_size);
434  micro->Define(lev, solverChoice);
435  if (solverChoice.moisture_type != MoistureType::None)
436  {
437  micro->Init(lev, vars_new[lev][Vars::cons],
438  grids[lev], Geom(lev), 0.0,
439  z_phys_nd[lev], detJ_cc[lev]); // dummy dt value
440  }
441  for (int mvar(0); mvar<qmoist[lev].size(); ++mvar) {
442  qmoist[lev][mvar] = micro->Get_Qmoist_Ptr(lev,mvar);
443  }
444 
445  // ********************************************************************************************
446  // Initialize the integrator class
447  // ********************************************************************************************
449 
450  // We need to re-define the FillPatcher if the grids have changed
451  if (lev > 0 && cf_width >= 0) {
452  bool ba_changed = (ba != ba_old);
453  bool dm_changed = (dm != dm_old);
454  if (ba_changed || dm_changed) {
456  }
457  }
458 
459 #ifdef ERF_USE_PARTICLES
460  particleData.Redistribute();
461 #endif
462 }
void remake_zphys(int lev, std::unique_ptr< amrex::MultiFab > &temp_zphys_nd)
Definition: ERF_MakeNewArrays.cpp:503

◆ restart()

void ERF::restart ( )
1224 {
1225  // TODO: This could be deleted since ba/dm are not created yet?
1226  for (int lev = 0; lev <= finest_level; ++lev)
1227  {
1228  auto& lev_new = vars_new[lev];
1229  auto& lev_old = vars_old[lev];
1230  lev_new[Vars::cons].setVal(0.); lev_old[Vars::cons].setVal(0.);
1231  lev_new[Vars::xvel].setVal(0.); lev_old[Vars::xvel].setVal(0.);
1232  lev_new[Vars::yvel].setVal(0.); lev_old[Vars::yvel].setVal(0.);
1233  lev_new[Vars::zvel].setVal(0.); lev_old[Vars::zvel].setVal(0.);
1234  }
1235 
1236 #ifdef ERF_USE_NETCDF
1237  if (restart_type == "netcdf") {
1238  ReadNCCheckpointFile();
1239  }
1240 #endif
1241  if (restart_type == "native") {
1243  }
1244 
1245  // We set this here so that we don't over-write the checkpoint file we just started from
1247 }
void ReadCheckpointFile()
Definition: ERF_Checkpoint.cpp:273

◆ 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
288 {
289  int datwidth = 14;
290  int datprecision = 6;
291 
292  int ifile = 0;
293 
294  const int ncomp = mf.nComp(); // cell-centered state vars
295 
296  MultiFab mf_vels(grids[lev], dmap[lev], AMREX_SPACEDIM, 0);
297  average_face_to_cellcenter(mf_vels, 0,
298  Array<const MultiFab*,3>{&vars_new[lev][Vars::xvel],&vars_new[lev][Vars::yvel],&vars_new[lev][Vars::zvel]});
299 
300  //
301  // Sample the data at a line (in direction "dir") in space
302  // In this case we sample in the vertical direction so dir = 2
303  // The "k" value of "cell" is ignored
304  //
305  int dir = 2;
306  MultiFab my_line = get_line_data(mf, dir, cell);
307  MultiFab my_line_vels = get_line_data(mf_vels, dir, cell);
308  MultiFab my_line_tau11 = get_line_data(*Tau11_lev[lev], dir, cell);
309  MultiFab my_line_tau12 = get_line_data(*Tau12_lev[lev], dir, cell);
310  MultiFab my_line_tau13 = get_line_data(*Tau13_lev[lev], dir, cell);
311  MultiFab my_line_tau22 = get_line_data(*Tau22_lev[lev], dir, cell);
312  MultiFab my_line_tau23 = get_line_data(*Tau23_lev[lev], dir, cell);
313  MultiFab my_line_tau33 = get_line_data(*Tau33_lev[lev], dir, cell);
314 
315  for (MFIter mfi(my_line, false); mfi.isValid(); ++mfi)
316  {
317  // HERE DO WHATEVER YOU WANT TO THE DATA BEFORE WRITING
318 
319  std::ostream& sample_log = SampleLineLog(ifile);
320  if (sample_log.good()) {
321  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << time;
322  const auto& my_line_arr = my_line[0].const_array();
323  const auto& my_line_vels_arr = my_line_vels[0].const_array();
324  const auto& my_line_tau11_arr = my_line_tau11[0].const_array();
325  const auto& my_line_tau12_arr = my_line_tau12[0].const_array();
326  const auto& my_line_tau13_arr = my_line_tau13[0].const_array();
327  const auto& my_line_tau22_arr = my_line_tau22[0].const_array();
328  const auto& my_line_tau23_arr = my_line_tau23[0].const_array();
329  const auto& my_line_tau33_arr = my_line_tau33[0].const_array();
330  const Box& my_box = my_line[0].box();
331  const int klo = my_box.smallEnd(2);
332  const int khi = my_box.bigEnd(2);
333  int i = cell[0];
334  int j = cell[1];
335  for (int n = 0; n < ncomp; n++) {
336  for (int k = klo; k <= khi; k++) {
337  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << my_line_arr(i,j,k,n);
338  }
339  }
340  for (int n = 0; n < AMREX_SPACEDIM; n++) {
341  for (int k = klo; k <= khi; k++) {
342  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << my_line_vels_arr(i,j,k,n);
343  }
344  }
345  for (int k = klo; k <= khi; k++) {
346  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << my_line_tau11_arr(i,j,k);
347  }
348  for (int k = klo; k <= khi; k++) {
349  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << my_line_tau12_arr(i,j,k);
350  }
351  for (int k = klo; k <= khi; k++) {
352  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << my_line_tau13_arr(i,j,k);
353  }
354  for (int k = klo; k <= khi; k++) {
355  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << my_line_tau22_arr(i,j,k);
356  }
357  for (int k = klo; k <= khi; k++) {
358  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << my_line_tau23_arr(i,j,k);
359  }
360  for (int k = klo; k <= khi; k++) {
361  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << my_line_tau33_arr(i,j,k);
362  }
363  sample_log << std::endl;
364  } // if good
365  } // mfi
366 }
AMREX_FORCE_INLINE std::ostream & SampleLineLog(int i)
Definition: ERF.H:1272

◆ 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
250 {
251  int datwidth = 14;
252 
253  int ifile = 0;
254 
255  //
256  // Sample the data at a single point in space
257  //
258  int ncomp = mf.nComp();
259  Vector<Real> my_point = get_cell_data(mf, cell);
260 
261  if (!my_point.empty()) {
262 
263  // HERE DO WHATEVER YOU WANT TO THE DATA BEFORE WRITING
264 
265  std::ostream& sample_log = SamplePointLog(ifile);
266  if (sample_log.good()) {
267  sample_log << std::setw(datwidth) << time;
268  for (int i = 0; i < ncomp; ++i)
269  {
270  sample_log << std::setw(datwidth) << my_point[i];
271  }
272  sample_log << std::endl;
273  } // if good
274  } // only write from processor that holds the cell
275 }
AMREX_FORCE_INLINE std::ostream & SamplePointLog(int i)
Definition: ERF.H:1258

◆ SampleLine()

amrex::IntVect& ERF::SampleLine ( int  i)
inlineprivate
1299  {
1300  return sampleline[i];
1301  }

◆ SampleLineLog()

AMREX_FORCE_INLINE std::ostream& ERF::SampleLineLog ( int  i)
inlineprivate
1273  {
1274  return *samplelinelog[i];
1275  }

◆ SampleLineLogName()

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

The filename of the ith samplelinelog file.

1398 { return samplelinelogname[i]; }

◆ SamplePoint()

amrex::IntVect& ERF::SamplePoint ( int  i)
inlineprivate
1286  {
1287  return samplepoint[i];
1288  }

◆ SamplePointLog()

AMREX_FORCE_INLINE std::ostream& ERF::SamplePointLog ( int  i)
inlineprivate
1259  {
1260  return *sampleptlog[i];
1261  }

◆ SamplePointLogName()

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

The filename of the ith sampleptlog file.

1395 { return sampleptlogname[i]; }

◆ setPlotVariables()

void ERF::setPlotVariables ( const std::string &  pp_plot_var_names,
amrex::Vector< std::string > &  plot_var_names 
)
private
18 {
19  ParmParse pp(pp_prefix);
20 
21  if (pp.contains(pp_plot_var_names.c_str()))
22  {
23  std::string nm;
24 
25  int nPltVars = pp.countval(pp_plot_var_names.c_str());
26 
27  for (int i = 0; i < nPltVars; i++)
28  {
29  pp.get(pp_plot_var_names.c_str(), nm, i);
30 
31  // Add the named variable to our list of plot variables
32  // if it is not already in the list
33  if (!containerHasElement(plot_var_names, nm)) {
34  plot_var_names.push_back(nm);
35  }
36  }
37  } else {
38  //
39  // The default is to add none of the variables to the list
40  //
41  plot_var_names.clear();
42  }
43 
44  // Get state variables in the same order as we define them,
45  // since they may be in any order in the input list
46  Vector<std::string> tmp_plot_names;
47 
48  for (int i = 0; i < cons_names.size(); ++i) {
49  if ( containerHasElement(plot_var_names, cons_names[i]) ) {
50  if ( (solverChoice.moisture_type == MoistureType::SAM) || (cons_names[i] != "rhoQ4" &&
51  cons_names[i] != "rhoQ5" &&
52  cons_names[i] != "rhoQ6") )
53  {
54  tmp_plot_names.push_back(cons_names[i]);
55  } // moisture_type
56  }
57  }
58 
59  // check for velocity since it's not in cons_names
60  // if we are asked for any velocity component, we will need them all
61  if (containerHasElement(plot_var_names, "x_velocity") ||
62  containerHasElement(plot_var_names, "y_velocity") ||
63  containerHasElement(plot_var_names, "z_velocity")) {
64  tmp_plot_names.push_back("x_velocity");
65  tmp_plot_names.push_back("y_velocity");
66  tmp_plot_names.push_back("z_velocity");
67  }
68 
69  //
70  // If the model we are running doesn't have the variable listed in the inputs file,
71  // just ignore it rather than aborting
72  //
73  for (int i = 0; i < derived_names.size(); ++i) {
74  if ( containerHasElement(plot_var_names, derived_names[i]) ) {
75  if ( SolverChoice::mesh_type != MeshType::ConstantDz ||
76  (derived_names[i] != "z_phys" && derived_names[i] != "detJ") ) {
77  if ( (solverChoice.moisture_type == MoistureType::SAM ||
78  solverChoice.moisture_type == MoistureType::SAM_NoIce) ||
79  (derived_names[i] != "qi" &&
80  derived_names[i] != "qsnow" &&
81  derived_names[i] != "qgraup" &&
82  derived_names[i] != "snow_accum" &&
83  derived_names[i] != "graup_accum") )
84  {
85  if ( (solverChoice.moisture_type != MoistureType::None) ||
86  (derived_names[i] != "qv" && derived_names[i] != "qc" and
87  derived_names[i] != "num_turb" and derived_names[i] != "SMark0" and
88  derived_names[i] != "SMark1") ) {
89  tmp_plot_names.push_back(derived_names[i]);
90  }
91  } // moisture_type
92  } // use_terrain?
93  } // hasElement
94  }
95 
96 #ifdef ERF_USE_WINDFARM
97  for (int i = 0; i < derived_names.size(); ++i) {
98  if ( containerHasElement(plot_var_names, derived_names[i]) ) {
99  if(solverChoice.windfarm_type == WindFarmType::Fitch or solverChoice.windfarm_type == WindFarmType::EWP) {
100  if(derived_names[i] == "num_turb" or derived_names[i] == "SMark0") {
101  tmp_plot_names.push_back(derived_names[i]);
102  }
103  }
104  if( solverChoice.windfarm_type == WindFarmType::SimpleAD or
105  solverChoice.windfarm_type == WindFarmType::GeneralAD ) {
106  if(derived_names[i] == "num_turb" or derived_names[i] == "SMark0" or derived_names[i] == "SMark1") {
107  tmp_plot_names.push_back(derived_names[i]);
108  }
109  }
110  }
111  }
112 #endif
113 
114 #ifdef ERF_USE_PARTICLES
115  const auto& particles_namelist( particleData.getNamesUnalloc() );
116  for (auto it = particles_namelist.cbegin(); it != particles_namelist.cend(); ++it) {
117  std::string tmp( (*it)+"_count" );
118  if (containerHasElement(plot_var_names, tmp) ) {
119  tmp_plot_names.push_back(tmp);
120  }
121  }
122 #endif
123 
124  plot_var_names = tmp_plot_names;
125 }
const amrex::Vector< std::string > derived_names
Definition: ERF.H:974
const amrex::Vector< std::string > cons_names
Definition: ERF.H:969
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.
56 {
57  // If we are restarting then we haven't read the input_sounding file yet
58  // so we need to read it here
59  // TODO: should we store this information in the checkpoint file instead?
60  if (restarting) {
62  for (int n = 0; n < input_sounding_data.n_sounding_files; n++) {
64  }
65  }
66 
67  const Real* z_inp_sound = input_sounding_data.z_inp_sound[0].dataPtr();
68  const Real* U_inp_sound = input_sounding_data.U_inp_sound[0].dataPtr();
69  const Real* V_inp_sound = input_sounding_data.V_inp_sound[0].dataPtr();
70  const Real* theta_inp_sound = input_sounding_data.theta_inp_sound[0].dataPtr();
71  const int inp_sound_size = input_sounding_data.size(0);
72 
73  int refine_fac{1};
74  for (int lev = 0; lev <= finest_level; lev++)
75  {
76  const int klo = geom[lev].Domain().smallEnd(2);
77  const int khi = geom[lev].Domain().bigEnd(2);
78  const int Nz = khi - klo + 1;
79 
80  Vector<Real> zcc(Nz);
81  Vector<Real> zlevels_sub(zlevels_stag[0].begin()+klo/refine_fac,
82  zlevels_stag[0].begin()+khi/refine_fac+2);
83  expand_and_interpolate_1d(zcc, zlevels_sub, refine_fac, true);
84 #if 0
85  amrex::AllPrint() << "lev="<<lev<<" : (refine_fac="<<refine_fac<<",klo="<<klo<<",khi="<<khi<<") ";
86  for (int k = 0; k < zlevels_sub.size(); k++) { amrex::AllPrint() << zlevels_sub[k] << " "; }
87  amrex::AllPrint() << " --> ";
88  for (int k = 0; k < Nz; k++) { amrex::AllPrint() << zcc[k] << " "; }
89  amrex::AllPrint() << std::endl;
90 #endif
91 
92  for (int k = 0; k < Nz; k++)
93  {
94  h_rayleigh_ptrs[lev][Rayleigh::ubar][k] = interpolate_1d(z_inp_sound, U_inp_sound, zcc[k], inp_sound_size);
95  h_rayleigh_ptrs[lev][Rayleigh::vbar][k] = interpolate_1d(z_inp_sound, V_inp_sound, zcc[k], inp_sound_size);
96  h_rayleigh_ptrs[lev][Rayleigh::wbar][k] = Real(0.0);
97  h_rayleigh_ptrs[lev][Rayleigh::thetabar][k] = interpolate_1d(z_inp_sound, theta_inp_sound, zcc[k], inp_sound_size);
98  }
99 
100  // Copy from host version to device version
101  Gpu::copy(Gpu::hostToDevice, h_rayleigh_ptrs[lev][Rayleigh::ubar].begin(), h_rayleigh_ptrs[lev][Rayleigh::ubar].end(),
102  d_rayleigh_ptrs[lev][Rayleigh::ubar].begin());
103  Gpu::copy(Gpu::hostToDevice, h_rayleigh_ptrs[lev][Rayleigh::vbar].begin(), h_rayleigh_ptrs[lev][Rayleigh::vbar].end(),
104  d_rayleigh_ptrs[lev][Rayleigh::vbar].begin());
105  Gpu::copy(Gpu::hostToDevice, h_rayleigh_ptrs[lev][Rayleigh::wbar].begin(), h_rayleigh_ptrs[lev][Rayleigh::wbar].end(),
106  d_rayleigh_ptrs[lev][Rayleigh::wbar].begin());
107  Gpu::copy(Gpu::hostToDevice, h_rayleigh_ptrs[lev][Rayleigh::thetabar].begin(), h_rayleigh_ptrs[lev][Rayleigh::thetabar].end(),
108  d_rayleigh_ptrs[lev][Rayleigh::thetabar].begin());
109 
110  refine_fac *= ref_ratio[lev][2];
111  }
112 }
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:323
amrex::Vector< amrex::Vector< amrex::Real > > z_inp_sound
Definition: ERF_InputSoundingData.H:323
amrex::Vector< amrex::Vector< amrex::Real > > U_inp_sound
Definition: ERF_InputSoundingData.H:323
amrex::Vector< amrex::Vector< amrex::Real > > V_inp_sound
Definition: ERF_InputSoundingData.H:323
int size(int itime) const
Definition: ERF_InputSoundingData.H:300
Here is the call graph for this function:

◆ setRecordDataInfo()

void ERF::setRecordDataInfo ( int  i,
const std::string &  filename 
)
inlineprivate
1329  {
1330  if (amrex::ParallelDescriptor::IOProcessor())
1331  {
1332  datalog[i] = std::make_unique<std::fstream>();
1333  datalog[i]->open(filename.c_str(),std::ios::out|std::ios::app);
1334  if (!datalog[i]->good()) {
1335  amrex::FileOpenFailed(filename);
1336  }
1337  }
1338  amrex::ParallelDescriptor::Barrier("ERF::setRecordDataInfo");
1339  }

◆ setRecordSampleLineInfo()

void ERF::setRecordSampleLineInfo ( int  i,
int  lev,
amrex::IntVect &  cell,
const std::string &  filename 
)
inlineprivate
1359  {
1360  amrex::MultiFab dummy(grids[lev],dmap[lev],1,0);
1361  for (amrex::MFIter mfi(dummy); mfi.isValid(); ++mfi)
1362  {
1363  const amrex::Box& bx = mfi.validbox();
1364  if (bx.contains(cell)) {
1365  samplelinelog[i] = std::make_unique<std::fstream>();
1366  samplelinelog[i]->open(filename.c_str(),std::ios::out|std::ios::app);
1367  if (!samplelinelog[i]->good()) {
1368  amrex::FileOpenFailed(filename);
1369  }
1370  }
1371  }
1372  amrex::ParallelDescriptor::Barrier("ERF::setRecordSampleLineInfo");
1373  }

◆ setRecordSamplePointInfo()

void ERF::setRecordSamplePointInfo ( int  i,
int  lev,
amrex::IntVect &  cell,
const std::string &  filename 
)
inlineprivate
1342  {
1343  amrex::MultiFab dummy(grids[lev],dmap[lev],1,0);
1344  for (amrex::MFIter mfi(dummy); mfi.isValid(); ++mfi)
1345  {
1346  const amrex::Box& bx = mfi.validbox();
1347  if (bx.contains(cell)) {
1348  sampleptlog[i] = std::make_unique<std::fstream>();
1349  sampleptlog[i]->open(filename.c_str(),std::ios::out|std::ios::app);
1350  if (!sampleptlog[i]->good()) {
1351  amrex::FileOpenFailed(filename);
1352  }
1353  }
1354  }
1355  amrex::ParallelDescriptor::Barrier("ERF::setRecordSamplePointInfo");
1356  }

◆ 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:114
amrex::Vector< amrex::Real > z_inp_sponge
Definition: ERF_InputSpongeData.H:114
amrex::Vector< amrex::Real > U_inp_sponge
Definition: ERF_InputSpongeData.H:114
int size() const
Definition: ERF_InputSpongeData.H:102
Here is the call graph for this function:

◆ solve_with_gmres()

void ERF::solve_with_gmres ( int  lev,
amrex::Vector< amrex::MultiFab > &  rhs,
amrex::Vector< amrex::MultiFab > &  p,
amrex::Vector< amrex::Array< amrex::MultiFab, AMREX_SPACEDIM >> &  fluxes 
)

Solve the Poisson equation using FFT-preconditioned GMRES

14 {
15 #ifdef ERF_USE_FFT
16  BL_PROFILE("ERF::solve_with_gmres()");
17 
18  Real reltol = solverChoice.poisson_reltol;
19  Real abstol = solverChoice.poisson_abstol;
20 
21  amrex::GMRES<MultiFab, TerrainPoisson> gmsolver;
22 
23  TerrainPoisson tp(geom[lev], rhs[0].boxArray(), rhs[0].DistributionMap(), stretched_dz_d[lev],
24  z_phys_nd[lev].get(), domain_bc_type);
25 
26  gmsolver.define(tp);
27 
28  gmsolver.setVerbose(mg_verbose);
29 
30  tp.usePrecond(true);
31 
32  gmsolver.solve(phi[0], rhs[0], reltol, abstol);
33 
34  tp.getFluxes(phi[0], fluxes[0]);
35 #else
36  amrex::ignore_unused(lev, rhs, phi, fluxes);
37 #endif
38 }

◆ solve_with_mlmg()

void ERF::solve_with_mlmg ( int  lev,
amrex::Vector< amrex::MultiFab > &  rhs,
amrex::Vector< amrex::MultiFab > &  p,
amrex::Vector< amrex::Array< amrex::MultiFab, AMREX_SPACEDIM >> &  fluxes 
)

Solve the Poisson equation using MLMG Note that the level may or may not be level 0.

41 {
42  BL_PROFILE("ERF::solve_with_mlmg()");
43 
44  auto const dom_lo = lbound(geom[lev].Domain());
45  auto const dom_hi = ubound(geom[lev].Domain());
46 
47  LPInfo info;
48  // Allow a hidden direction if the domain is one cell wide in any lateral direction
49  if (dom_lo.x == dom_hi.x) {
50  info.setHiddenDirection(0);
51  } else if (dom_lo.y == dom_hi.y) {
52  info.setHiddenDirection(1);
53  }
54 
55  // Make sure the solver only sees the levels over which we are solving
56  Vector<BoxArray> ba_tmp; ba_tmp.push_back(rhs[0].boxArray());
57  Vector<DistributionMapping> dm_tmp; dm_tmp.push_back(rhs[0].DistributionMap());
58  Vector<Geometry> geom_tmp; geom_tmp.push_back(geom[lev]);
59 
60  auto bclo = get_projection_bc(Orientation::low);
61  auto bchi = get_projection_bc(Orientation::high);
62 
63  // amrex::Print() << "BCLO " << bclo[0] << " " << bclo[1] << " " << bclo[2] << std::endl;
64  // amrex::Print() << "BCHI " << bchi[0] << " " << bchi[1] << " " << bchi[2] << std::endl;
65 
66  Real reltol = solverChoice.poisson_reltol;
67  Real abstol = solverChoice.poisson_abstol;
68 
69  // ****************************************************************************
70  // Multigrid solve
71  // ****************************************************************************
72 
73  MLPoisson mlpoisson(geom_tmp, ba_tmp, dm_tmp, info);
74  mlpoisson.setDomainBC(bclo, bchi);
75  if (lev > 0) {
76  mlpoisson.setCoarseFineBC(nullptr, ref_ratio[lev-1], LinOpBCType::Neumann);
77  }
78  mlpoisson.setLevelBC(0, nullptr);
79 
80  MLMG mlmg(mlpoisson);
81  int max_iter = 100;
82  mlmg.setMaxIter(max_iter);
83 
84  mlmg.setVerbose(mg_verbose);
85  mlmg.setBottomVerbose(0);
86 
87  mlmg.solve(GetVecOfPtrs(phi),
88  GetVecOfConstPtrs(rhs),
89  reltol, abstol);
90  mlmg.getFluxes(GetVecOfArrOfPtrs(fluxes));
91 
92  phi[0].FillBoundary(geom[lev].periodicity());
93 
94  // ****************************************************************************
95  // Impose bc's on pprime
96  // ****************************************************************************
97 #ifdef _OPENMP
98 #pragma omp parallel if (Gpu::notInLaunchRegion())
99 #endif
100  for (MFIter mfi(phi[0],TilingIfNotGPU()); mfi.isValid(); ++mfi)
101  {
102  Array4<Real> const& pp_arr = phi[0].array(mfi);
103  Box const& bx = mfi.tilebox();
104  auto const bx_lo = lbound(bx);
105  auto const bx_hi = ubound(bx);
106  if (bx_lo.x == dom_lo.x) {
107  auto bc_type = domain_bc_type[Orientation(0,Orientation::low)];
108  if (bc_type == "Outflow" || bc_type == "Open") {
109  ParallelFor(makeSlab(bx,0,dom_lo.x), [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
110  {
111  pp_arr(i-1,j,k) = -pp_arr(i,j,k);
112  });
113  } else {
114  ParallelFor(makeSlab(bx,0,dom_lo.x), [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
115  {
116  pp_arr(i-1,j,k) = pp_arr(i,j,k);
117  });
118  }
119  }
120  if (bx_lo.y == dom_lo.y) {
121  auto bc_type = domain_bc_type[Orientation(1,Orientation::low)];
122  if (bc_type == "Outflow" || bc_type == "Open") {
123  ParallelFor(makeSlab(bx,1,dom_lo.y), [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
124  {
125  pp_arr(i,j-1,k) = -pp_arr(i,j,k);
126  });
127  } else {
128  ParallelFor(makeSlab(bx,1,dom_lo.y), [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
129  {
130  pp_arr(i,j-1,k) = pp_arr(i,j,k);
131  });
132  }
133  }
134  if (bx_lo.z == dom_lo.z) {
135  ParallelFor(makeSlab(bx,2,dom_lo.z), [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
136  {
137  pp_arr(i,j,k-1) = pp_arr(i,j,k);
138  });
139  }
140  if (bx_hi.x == dom_hi.x) {
141  auto bc_type = domain_bc_type[Orientation(0,Orientation::high)];
142  if (bc_type == "Outflow" || bc_type == "Open") {
143  ParallelFor(makeSlab(bx,0,dom_hi.x), [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
144  {
145  pp_arr(i+1,j,k) = -pp_arr(i,j,k);
146  });
147  } else {
148  ParallelFor(makeSlab(bx,0,dom_hi.x), [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
149  {
150  pp_arr(i+1,j,k) = pp_arr(i,j,k);
151  });
152  }
153  }
154  if (bx_hi.y == dom_hi.y) {
155  auto bc_type = domain_bc_type[Orientation(1,Orientation::high)];
156  if (bc_type == "Outflow" || bc_type == "Open") {
157  ParallelFor(makeSlab(bx,1,dom_hi.y), [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
158  {
159  pp_arr(i,j+1,k) = -pp_arr(i,j,k);
160  });
161  } else {
162  ParallelFor(makeSlab(bx,1,dom_hi.y), [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
163  {
164  pp_arr(i,j+1,k) = pp_arr(i,j,k);
165  });
166  }
167  }
168  if (bx_hi.z == dom_hi.z) {
169  ParallelFor(makeSlab(bx,2,dom_hi.z), [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
170  {
171  pp_arr(i,j,k+1) = pp_arr(i,j,k);
172  });
173  }
174  } // mfi
175 
176  // Now overwrite with periodic fill outside domain and fine-fine fill inside
177  phi[0].FillBoundary(geom[lev].periodicity());
178 }

◆ 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
15 {
16  BL_PROFILE("ERF::sum_integrated_quantities()");
17 
18  if (verbose <= 0)
19  return;
20 
21  int datwidth = 14;
22  int datprecision = 6;
23 
24  // Single level sum
25  Real mass_sl;
26 
27  // Multilevel sums
28  Real mass_ml = 0.0;
29  Real rhth_ml = 0.0;
30  Real scal_ml = 0.0;
31 
32 #if 1
33  mass_sl = volWgtSumMF(0,vars_new[0][Vars::cons],Rho_comp,*mapfac_m[0],true,false);
34  for (int lev = 0; lev <= finest_level; lev++) {
35  mass_ml += volWgtSumMF(lev,vars_new[lev][Vars::cons],Rho_comp,*mapfac_m[lev],true,true);
36  }
37 #else
38  for (int lev = 0; lev <= finest_level; lev++) {
39  MultiFab pert_dens(vars_new[lev][Vars::cons].boxArray(),
40  vars_new[lev][Vars::cons].DistributionMap(),
41  1,0);
42  MultiFab r_hse (base_state[lev], make_alias, BaseState::r0_comp, 1);
43  for ( MFIter mfi(pert_dens,TilingIfNotGPU()); mfi.isValid(); ++mfi)
44  {
45  const Box& bx = mfi.tilebox();
46  const Array4<Real >& pert_dens_arr = pert_dens.array(mfi);
47  const Array4<Real const>& S_arr = vars_new[lev][Vars::cons].const_array(mfi);
48  const Array4<Real const>& r0_arr = r_hse.const_array(mfi);
49  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
50  pert_dens_arr(i, j, k, 0) = S_arr(i,j,k,Rho_comp) - r0_arr(i,j,k);
51  });
52  }
53  if (lev == 0) {
54  mass_sl = volWgtSumMF(0,pert_dens,0,*mapfac_m[0],true,false);
55  }
56  mass_ml += volWgtSumMF(lev,pert_dens,0,*mapfac_m[lev],true,true);
57  } // lev
58 #endif
59 
60  Real rhth_sl = volWgtSumMF(0,vars_new[0][Vars::cons], RhoTheta_comp,*mapfac_m[0],true,false);
61  Real scal_sl = volWgtSumMF(0,vars_new[0][Vars::cons],RhoScalar_comp,*mapfac_m[0],true,false);
62 
63  for (int lev = 0; lev <= finest_level; lev++) {
64  rhth_ml += volWgtSumMF(lev,vars_new[lev][Vars::cons], RhoTheta_comp,*mapfac_m[lev],true,true);
65  scal_ml += volWgtSumMF(lev,vars_new[lev][Vars::cons],RhoScalar_comp,*mapfac_m[lev],true,true);
66  }
67 
68  Gpu::HostVector<Real> h_avg_ustar; h_avg_ustar.resize(1);
69  Gpu::HostVector<Real> h_avg_tstar; h_avg_tstar.resize(1);
70  Gpu::HostVector<Real> h_avg_olen; h_avg_olen.resize(1);
71  if ((m_most != nullptr) && (NumDataLogs() > 0)) {
72  Box domain = geom[0].Domain();
73  int zdir = 2;
74  h_avg_ustar = sumToLine(*m_most->get_u_star(0),0,1,domain,zdir);
75  h_avg_tstar = sumToLine(*m_most->get_t_star(0),0,1,domain,zdir);
76  h_avg_olen = sumToLine(*m_most->get_olen(0),0,1,domain,zdir);
77 
78  // Divide by the total number of cells we are averaging over
79  Real area_z = static_cast<Real>(domain.length(0)*domain.length(1));
80  h_avg_ustar[0] /= area_z;
81  h_avg_tstar[0] /= area_z;
82  h_avg_olen[0] /= area_z;
83 
84  } else {
85  h_avg_ustar[0] = 0.;
86  h_avg_tstar[0] = 0.;
87  h_avg_olen[0] = 0.;
88  }
89 
90  const int nfoo = 6;
91  Real foo[nfoo] = {mass_sl,rhth_sl,scal_sl,mass_ml,rhth_ml,scal_ml};
92 #ifdef AMREX_LAZY
93  Lazy::QueueReduction([=]() mutable {
94 #endif
95  ParallelDescriptor::ReduceRealSum(
96  foo, nfoo, ParallelDescriptor::IOProcessorNumber());
97 
98  if (ParallelDescriptor::IOProcessor()) {
99  int i = 0;
100  mass_sl = foo[i++];
101  rhth_sl = foo[i++];
102  scal_sl = foo[i++];
103  mass_ml = foo[i++];
104  rhth_ml = foo[i++];
105  scal_ml = foo[i++];
106 
107  Print() << '\n';
108  if (finest_level == 0) {
109 #if 1
110  Print() << "TIME= " << time << " MASS = " << mass_sl << '\n';
111 #else
112  Print() << "TIME= " << time << " PERT MASS = " << mass_sl << '\n';
113 #endif
114  Print() << "TIME= " << time << " RHO THETA = " << rhth_sl << '\n';
115  Print() << "TIME= " << time << " RHO SCALAR = " << scal_sl << '\n';
116  } else {
117 #if 1
118  Print() << "TIME= " << time << " MASS SL/ML = " << mass_sl << " " << mass_ml << '\n';
119 #else
120  Print() << "TIME= " << time << " PERT MASS SL/ML = " << mass_sl << " " << mass_ml << '\n';
121 #endif
122  Print() << "TIME= " << time << " RHO THETA SL/ML = " << rhth_sl << " " << rhth_ml << '\n';
123  Print() << "TIME= " << time << " RHO SCALAR SL/ML = " << scal_sl << " " << scal_ml << '\n';
124  }
125 
126  // The first data log only holds scalars
127  if (NumDataLogs() > 0)
128  {
129  int n_d = 0;
130  std::ostream& data_log1 = DataLog(n_d);
131  if (data_log1.good()) {
132  if (time == 0.0) {
133  data_log1 << std::setw(datwidth) << " time";
134  data_log1 << std::setw(datwidth) << " u_star";
135  data_log1 << std::setw(datwidth) << " t_star";
136  data_log1 << std::setw(datwidth) << " olen";
137  data_log1 << std::endl;
138  } // time = 0
139 
140  // Write the quantities at this time
141  data_log1 << std::setw(datwidth) << time;
142  data_log1 << std::setw(datwidth) << std::setprecision(datprecision)
143  << h_avg_ustar[0];
144  data_log1 << std::setw(datwidth) << std::setprecision(datprecision)
145  << h_avg_tstar[0];
146  data_log1 << std::setw(datwidth) << std::setprecision(datprecision)
147  << h_avg_olen[0];
148  data_log1 << std::endl;
149  } // if good
150  } // loop over i
151  } // if IOProcessor
152 #ifdef AMREX_LAZY
153  });
154 #endif
155 
156  // This is just an alias for convenience
157  int lev = 0;
158  if (NumSamplePointLogs() > 0 && NumSamplePoints() > 0) {
159  for (int i = 0; i < NumSamplePoints(); ++i)
160  {
161  sample_points(lev, time, SamplePoint(i), vars_new[lev][Vars::cons]);
162  }
163  }
164  if (NumSampleLineLogs() > 0 && NumSampleLines() > 0) {
165  for (int i = 0; i < NumSampleLines(); ++i)
166  {
167  sample_lines(lev, time, SampleLine(i), vars_new[lev][Vars::cons]);
168  }
169  }
170 }
AMREX_FORCE_INLINE int NumSampleLineLogs() noexcept
Definition: ERF.H:1279
AMREX_FORCE_INLINE int NumSamplePointLogs() noexcept
Definition: ERF.H:1265
amrex::IntVect & SampleLine(int i)
Definition: ERF.H:1298
AMREX_FORCE_INLINE int NumSamplePoints() noexcept
Definition: ERF.H:1292
AMREX_FORCE_INLINE int NumSampleLines() noexcept
Definition: ERF.H:1305
amrex::IntVect & SamplePoint(int i)
Definition: ERF.H:1285
void sample_points(int lev, amrex::Real time, amrex::IntVect cell, amrex::MultiFab &mf)
Definition: ERF_WriteScalarProfiles.cpp:249
AMREX_FORCE_INLINE std::ostream & DataLog(int i)
Definition: ERF.H:1244
AMREX_FORCE_INLINE int NumDataLogs() noexcept
Definition: ERF.H:1251
void sample_lines(int lev, amrex::Real time, amrex::IntVect cell, amrex::MultiFab &mf)
Definition: ERF_WriteScalarProfiles.cpp:287

◆ 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
17 {
18  //
19  // We need to FillPatch the coarse level before assessing whether to regrid
20  // We have not done the swap yet so we fill the "new" which will become the "old"
21  //
22  MultiFab& S_new = vars_new[lev][Vars::cons];
23  MultiFab& U_new = vars_new[lev][Vars::xvel];
24  MultiFab& V_new = vars_new[lev][Vars::yvel];
25  MultiFab& W_new = vars_new[lev][Vars::zvel];
26 
27  //
28  // NOTE: the momenta here are not fillpatched (they are only used as scratch space)
29  //
30  if (lev == 0) {
31  FillPatch(lev, time, {&S_new, &U_new, &V_new, &W_new});
32  } else if (lev < finest_level) {
33  FillPatch(lev, time, {&S_new, &U_new, &V_new, &W_new},
34  {&S_new, &rU_new[lev], &rV_new[lev], &rW_new[lev]},
35  base_state[lev], base_state[lev]);
36  }
37 
38  if (regrid_int > 0) // We may need to regrid
39  {
40  // help keep track of whether a level was already regridded
41  // from a coarser level call to regrid
42  static Vector<int> last_regrid_step(max_level+1, 0);
43 
44  // regrid changes level "lev+1" so we don't regrid on max_level
45  // also make sure we don't regrid fine levels again if
46  // it was taken care of during a coarser regrid
47  if (lev < max_level)
48  {
49  if ( (istep[lev] % regrid_int == 0) && (istep[lev] > last_regrid_step[lev]) )
50  {
51  // regrid could add newly refine levels (if finest_level < max_level)
52  // so we save the previous finest level index
53  int old_finest = finest_level;
54 
55  regrid(lev, time);
56 
57 #ifdef ERF_USE_PARTICLES
58  if (finest_level != old_finest) {
59  particleData.Redistribute();
60  }
61 #endif
62 
63  // mark that we have regridded this level already
64  for (int k = lev; k <= finest_level; ++k) {
65  last_regrid_step[k] = istep[k];
66  }
67 
68  // if there are newly created levels, set the time step
69  for (int k = old_finest+1; k <= finest_level; ++k) {
70  dt[k] = dt[k-1] / MaxRefRatio(k-1);
71  }
72  } // if
73  } // lev
74  }
75 
76  // Update what we call "old" and "new" time
77  t_old[lev] = t_new[lev];
78  t_new[lev] += dt[lev];
79 
80  if (Verbose()) {
81  amrex::Print() << "[Level " << lev << " step " << istep[lev]+1 << "] ";
82  amrex::Print() << "ADVANCE from time = " << t_old[lev] << " to " << t_new[lev]
83  << " with dt = " << dt[lev] << std::endl;
84  }
85 
86 #ifdef ERF_USE_WW3_COUPLING
87  amrex::Print() << " About to call send_to_ww3 from ERF_Timestep" << std::endl;
88  send_to_ww3(lev);
89  amrex::Print() << " About to call read_waves from ERF_Timestep" << std::endl;
90  read_waves(lev);
91  //send_to_ww3(lev);
92  //read_waves(lev);
93  //send_to_ww3(lev);
94 #endif
95 
96  // Advance a single level for a single time step
97  Advance(lev, time, dt[lev], istep[lev], nsubsteps[lev]);
98 
99  ++istep[lev];
100 
101  if (Verbose()) {
102  amrex::Print() << "[Level " << lev << " step " << istep[lev] << "] ";
103  amrex::Print() << "Advanced " << CountCells(lev) << " cells" << std::endl;
104  }
105 
106  if (lev < finest_level)
107  {
108  // recursive call for next-finer level
109  for (int i = 1; i <= nsubsteps[lev+1]; ++i)
110  {
111  Real strt_time_for_fine = time + (i-1)*dt[lev+1];
112  timeStep(lev+1, strt_time_for_fine, i);
113  }
114  }
115 
116  if (verbose && lev == 0) {
117  if (solverChoice.moisture_type != MoistureType::None) {
118  amrex::Print() << "Cloud fraction " << time << " " << cloud_fraction(time) << std::endl;
119  }
120  }
121 }
amrex::Real cloud_fraction(amrex::Real time)
Definition: ERF_WriteScalarProfiles.cpp:173
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
42 {
43  // Accessing data
44  auto& lev_new = vars_new[lev];
45 
46  // Creating local data
47  int ncons = lev_new[Vars::cons].nComp();
48  MultiFab cons_data(lev_new[Vars::cons], make_alias, 0, ncons);
49 
50  // Defining BoxArray type
51  auto m_ixtype = cons_data.boxArray().ixType();
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  const Box &bx = mfi.validbox();
58  const auto &cons_pert_arr = cons_data.array(mfi); // Address of perturbation array
59  const amrex::Array4<const amrex::Real> &pert_cell = turbPert.pb_cell.array(mfi); // per-cell perturbation stored in structure
60 
61  turbPert.apply_tpi(lev, bx, RhoTheta_comp, m_ixtype, cons_pert_arr, pert_cell);
62  } // mfi
63 }
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  // This logic is done once then stored within ERF_TurbPertStruct.H
24  turbPert.pt_type = -1;
25  if (solverChoice.pert_type == PerturbationType::Source) {
26  turbPert.pt_type = 0;
27  } else if (solverChoice.pert_type == PerturbationType::Direct) {
28  turbPert.pt_type = 1;
29  }
30  AMREX_ALWAYS_ASSERT(turbPert.pt_type >= 0);
31 
32  // Computing perturbation update time
33  turbPert.calc_tpi_update(lev, local_dt, xvel_data, yvel_data, cons_data);
34 
35  Print() << "Successfully initialized turbulent perturbation update time and amplitude with type: "<< turbPert.pt_type <<"\n";
36 }
int pt_type
Definition: ERF_TurbPertStruct.H:528

◆ update_diffusive_arrays()

void ERF::update_diffusive_arrays ( int  lev,
const amrex::BoxArray &  ba,
const amrex::DistributionMapping &  dm 
)
private
375 {
376  // ********************************************************************************************
377  // Diffusive terms
378  // ********************************************************************************************
379  bool l_use_terrain = (SolverChoice::terrain_type != TerrainType::None);
380  bool l_use_diff = ( (solverChoice.diffChoice.molec_diff_type != MolecDiffType::None) ||
381  (solverChoice.turbChoice[lev].les_type != LESType::None) ||
382  (solverChoice.turbChoice[lev].pbl_type != PBLType::None) );
383  bool l_use_kturb = ( (solverChoice.turbChoice[lev].les_type != LESType::None) ||
384  (solverChoice.turbChoice[lev].pbl_type != PBLType::None) );
385  bool l_use_ddorf = (solverChoice.turbChoice[lev].les_type == LESType::Deardorff);
386  bool l_use_moist = ( solverChoice.moisture_type != MoistureType::None );
387 
388  BoxArray ba12 = convert(ba, IntVect(1,1,0));
389  BoxArray ba13 = convert(ba, IntVect(1,0,1));
390  BoxArray ba23 = convert(ba, IntVect(0,1,1));
391 
392  if (l_use_diff) {
393  //
394  // NOTE: We require ghost cells in the vertical when allowing grids that don't
395  // cover the entire vertical extent of the domain at this level
396  //
397  Tau11_lev[lev] = std::make_unique<MultiFab>( ba , dm, 1, IntVect(1,1,1) );
398  Tau22_lev[lev] = std::make_unique<MultiFab>( ba , dm, 1, IntVect(1,1,1) );
399  Tau33_lev[lev] = std::make_unique<MultiFab>( ba , dm, 1, IntVect(1,1,1) );
400  Tau12_lev[lev] = std::make_unique<MultiFab>( ba12, dm, 1, IntVect(1,1,1) );
401  Tau13_lev[lev] = std::make_unique<MultiFab>( ba13, dm, 1, IntVect(1,1,1) );
402  Tau23_lev[lev] = std::make_unique<MultiFab>( ba23, dm, 1, IntVect(1,1,1) );
403  if (l_use_terrain) {
404  Tau21_lev[lev] = std::make_unique<MultiFab>( ba12, dm, 1, IntVect(1,1,1) );
405  Tau31_lev[lev] = std::make_unique<MultiFab>( ba13, dm, 1, IntVect(1,1,1) );
406  Tau32_lev[lev] = std::make_unique<MultiFab>( ba23, dm, 1, IntVect(1,1,1) );
407  } else {
408  Tau21_lev[lev] = nullptr;
409  Tau31_lev[lev] = nullptr;
410  Tau32_lev[lev] = nullptr;
411  }
412  SFS_hfx1_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(1,0,0)), dm, 1, IntVect(1,1,1) );
413  SFS_hfx2_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(0,1,0)), dm, 1, IntVect(1,1,1) );
414  SFS_hfx3_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(0,0,1)), dm, 1, IntVect(1,1,1) );
415  SFS_diss_lev[lev] = std::make_unique<MultiFab>( ba , dm, 1, IntVect(1,1,1) );
416  SFS_hfx1_lev[lev]->setVal(0.);
417  SFS_hfx2_lev[lev]->setVal(0.);
418  SFS_hfx3_lev[lev]->setVal(0.);
419  SFS_diss_lev[lev]->setVal(0.);
420  if (l_use_moist) {
421  SFS_q1fx3_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(0,0,1)), dm, 1, IntVect(1,1,1) );
422  SFS_q2fx3_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(0,0,1)), dm, 1, IntVect(1,1,1) );
423  SFS_q1fx3_lev[lev]->setVal(0.0);
424  SFS_q2fx3_lev[lev]->setVal(0.0);
426  SFS_q1fx1_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(1,0,0)), dm, 1, IntVect(1,1,1) );
427  SFS_q1fx2_lev[lev] = std::make_unique<MultiFab>( convert(ba,IntVect(0,1,0)), dm, 1, IntVect(1,1,1) );
428  SFS_q1fx1_lev[lev]->setVal(0.0);
429  SFS_q1fx2_lev[lev]->setVal(0.0);
430  } else {
431  SFS_q1fx1_lev[lev] = nullptr;
432  SFS_q1fx2_lev[lev] = nullptr;
433  }
434  } else {
435  SFS_q1fx1_lev[lev] = nullptr;
436  SFS_q1fx2_lev[lev] = nullptr;
437  SFS_q1fx3_lev[lev] = nullptr;
438  SFS_q2fx3_lev[lev] = nullptr;
439  }
440  } else {
441  Tau11_lev[lev] = nullptr; Tau22_lev[lev] = nullptr; Tau33_lev[lev] = nullptr;
442  Tau12_lev[lev] = nullptr; Tau21_lev[lev] = nullptr;
443  Tau13_lev[lev] = nullptr; Tau31_lev[lev] = nullptr;
444  Tau23_lev[lev] = nullptr; Tau32_lev[lev] = nullptr;
445  SFS_hfx1_lev[lev] = nullptr; SFS_hfx2_lev[lev] = nullptr; SFS_hfx3_lev[lev] = nullptr;
446  SFS_diss_lev[lev] = nullptr;
447  }
448 
449  if (l_use_kturb) {
450  eddyDiffs_lev[lev] = std::make_unique<MultiFab>(ba, dm, EddyDiff::NumDiffs, 2);
451  eddyDiffs_lev[lev]->setVal(0.0);
452  if(l_use_ddorf) {
453  SmnSmn_lev[lev] = std::make_unique<MultiFab>( ba, dm, 1, 0 );
454  } else {
455  SmnSmn_lev[lev] = nullptr;
456  }
457  } else {
458  eddyDiffs_lev[lev] = nullptr;
459  SmnSmn_lev[lev] = nullptr;
460  }
461 }
@ NumDiffs
Definition: ERF_IndexDefines.H:162

◆ update_terrain_arrays()

void ERF::update_terrain_arrays ( int  lev)
private
531 {
532  if (SolverChoice::mesh_type == MeshType::StretchedDz ||
533  SolverChoice::mesh_type == MeshType::VariableDz) {
534  make_J(geom[lev],*z_phys_nd[lev],*detJ_cc[lev]);
535  make_areas(geom[lev],*z_phys_nd[lev],*ax[lev],*ay[lev],*az[lev]);
536  make_zcc(geom[lev],*z_phys_nd[lev],*z_phys_cc[lev]);
537  }
538 }
void make_areas(const Geometry &geom, MultiFab &z_phys_nd, MultiFab &ax, MultiFab &ay, MultiFab &az)
Definition: ERF_TerrainMetrics.cpp:651
void make_J(const Geometry &geom, MultiFab &z_phys_nd, MultiFab &detJ_cc)
Definition: ERF_TerrainMetrics.cpp:613
Here is the call graph for this function:

◆ volWgtSumMF()

Real ERF::volWgtSumMF ( int  lev,
const amrex::MultiFab &  mf,
int  comp,
const amrex::MultiFab &  mapfac,
bool  local,
bool  finemask 
)

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

Parameters
levCurrent level
mfMultiFab on which we do the volume weighted sum
compIndex of the component we want to sum
localBoolean sets whether or not to reduce the sum over the domain (false) or compute sums local to each MPI rank (true)
finemaskIf a finer level is available, determines whether we mask fine data
381 {
382  BL_PROFILE("ERF::volWgtSumMF()");
383 
384  Real sum = 0.0;
385  MultiFab tmp(grids[lev], dmap[lev], 1, 0);
386  MultiFab::Copy(tmp, mf, comp, 0, 1, 0);
387 
388  // The quantity that is conserved is not (rho S), but rather (rho S / m^2) where
389  // m is the map scale factor at cell centers
390  for (MFIter mfi(tmp, TilingIfNotGPU()); mfi.isValid(); ++mfi) {
391  const Box& bx = mfi.tilebox();
392  const Array4< Real> tmp_arr = tmp.array(mfi);
393  const Array4<const Real> mapfac_arr = mapfac.const_array(mfi);
394  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
395  {
396  tmp_arr(i,j,k) /= (mapfac_arr(i,j,0)*mapfac_arr(i,j,0));
397  });
398  } // mfi
399 
400  if (lev < finest_level && finemask) {
401  const MultiFab& mask = build_fine_mask(lev+1);
402  MultiFab::Multiply(tmp, mask, 0, 0, 1, 0);
403  }
404 
405  MultiFab volume(grids[lev], dmap[lev], 1, 0);
406  auto const& dx = geom[lev].CellSizeArray();
407  Real cell_vol = dx[0]*dx[1]*dx[2];
408  volume.setVal(cell_vol);
409  if (solverChoice.mesh_type != MeshType::ConstantDz) {
410  MultiFab::Multiply(volume, *detJ_cc[lev], 0, 0, 1, 0);
411  }
412  sum = MultiFab::Dot(tmp, 0, volume, 0, 1, 0, local);
413 
414  if (!local) {
415  ParallelDescriptor::ReduceRealSum(sum);
416  }
417 
418  return sum;
419 }
amrex::MultiFab & build_fine_mask(int lev)
Definition: ERF_WriteScalarProfiles.cpp:429

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

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

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

◆ writeBuildInfo()

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

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.

26 {
27  // chk00010 write a checkpoint file with this root directory
28  // chk00010/Header this contains information you need to save (e.g., finest_level, t_new, etc.) and also
29  // the BoxArrays at each level
30  // chk00010/Level_0/
31  // chk00010/Level_1/
32  // etc. these subdirectories will hold the MultiFab data at each level of refinement
33 
34  // checkpoint file name, e.g., chk00010
35  const std::string& checkpointname = Concatenate(check_file,istep[0],5);
36 
37  Print() << "Writing native checkpoint " << checkpointname << "\n";
38 
39  const int nlevels = finest_level+1;
40 
41  // ---- prebuild a hierarchy of directories
42  // ---- dirName is built first. if dirName exists, it is renamed. then build
43  // ---- dirName/subDirPrefix_0 .. dirName/subDirPrefix_nlevels-1
44  // ---- if callBarrier is true, call ParallelDescriptor::Barrier()
45  // ---- after all directories are built
46  // ---- ParallelDescriptor::IOProcessor() creates the directories
47  PreBuildDirectorHierarchy(checkpointname, "Level_", nlevels, true);
48 
49  int ncomp_cons = vars_new[0][Vars::cons].nComp();
50 
51  // write Header file
52  if (ParallelDescriptor::IOProcessor()) {
53 
54  std::string HeaderFileName(checkpointname + "/Header");
55  VisMF::IO_Buffer io_buffer(VisMF::IO_Buffer_Size);
56  std::ofstream HeaderFile;
57  HeaderFile.rdbuf()->pubsetbuf(io_buffer.dataPtr(), io_buffer.size());
58  HeaderFile.open(HeaderFileName.c_str(), std::ofstream::out |
59  std::ofstream::trunc |
60  std::ofstream::binary);
61  if( ! HeaderFile.good()) {
62  FileOpenFailed(HeaderFileName);
63  }
64 
65  HeaderFile.precision(17);
66 
67  // write out title line
68  HeaderFile << "Checkpoint file for ERF\n";
69 
70  // write out finest_level
71  HeaderFile << finest_level << "\n";
72 
73  // write the number of components
74  // for each variable we store
75 
76  // conservative, cell-centered vars
77  HeaderFile << ncomp_cons << "\n";
78 
79  // x-velocity on faces
80  HeaderFile << 1 << "\n";
81 
82  // y-velocity on faces
83  HeaderFile << 1 << "\n";
84 
85  // z-velocity on faces
86  HeaderFile << 1 << "\n";
87 
88  // write out array of istep
89  for (int i = 0; i < istep.size(); ++i) {
90  HeaderFile << istep[i] << " ";
91  }
92  HeaderFile << "\n";
93 
94  // write out array of dt
95  for (int i = 0; i < dt.size(); ++i) {
96  HeaderFile << dt[i] << " ";
97  }
98  HeaderFile << "\n";
99 
100  // write out array of t_new
101  for (int i = 0; i < t_new.size(); ++i) {
102  HeaderFile << t_new[i] << " ";
103  }
104  HeaderFile << "\n";
105 
106  // write the BoxArray at each level
107  for (int lev = 0; lev <= finest_level; ++lev) {
108  boxArray(lev).writeOn(HeaderFile);
109  HeaderFile << '\n';
110  }
111  }
112 
113  // write the MultiFab data to, e.g., chk00010/Level_0/
114  // Here we make copies of the MultiFab with no ghost cells
115  for (int lev = 0; lev <= finest_level; ++lev)
116  {
117  MultiFab cons(grids[lev],dmap[lev],ncomp_cons,0);
118  MultiFab::Copy(cons,vars_new[lev][Vars::cons],0,0,ncomp_cons,0);
119  VisMF::Write(cons, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Cell"));
120 
121  MultiFab xvel(convert(grids[lev],IntVect(1,0,0)),dmap[lev],1,0);
122  MultiFab::Copy(xvel,vars_new[lev][Vars::xvel],0,0,1,0);
123  VisMF::Write(xvel, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "XFace"));
124 
125  MultiFab yvel(convert(grids[lev],IntVect(0,1,0)),dmap[lev],1,0);
126  MultiFab::Copy(yvel,vars_new[lev][Vars::yvel],0,0,1,0);
127  VisMF::Write(yvel, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "YFace"));
128 
129  MultiFab zvel(convert(grids[lev],IntVect(0,0,1)),dmap[lev],1,0);
130  MultiFab::Copy(zvel,vars_new[lev][Vars::zvel],0,0,1,0);
131  VisMF::Write(zvel, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "ZFace"));
132 
133  // Note that we write the ghost cells of the base state (unlike above)
134  // For backward compatibility we only write the first components and 1 ghost cell
135  IntVect ng_base; int ncomp_base;
136  bool write_old_base_state = true;
137  if (write_old_base_state) {
138  ng_base = IntVect{1};
139  ncomp_base = 3;
140  } else {
141  ng_base = base_state[lev].nGrowVect();
142  ncomp_base = base_state[lev].nComp();
143  }
144  MultiFab base(grids[lev],dmap[lev],ncomp_base,ng_base);
145  MultiFab::Copy(base,base_state[lev],0,0,ncomp_base,ng_base);
146  VisMF::Write(base, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "BaseState"));
147 
148  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
149  // Note that we also write the ghost cells of z_phys_nd
150  IntVect ng = z_phys_nd[lev]->nGrowVect();
151  MultiFab z_height(convert(grids[lev],IntVect(1,1,1)),dmap[lev],1,ng);
152  MultiFab::Copy(z_height,*z_phys_nd[lev],0,0,1,ng);
153  VisMF::Write(z_height, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Z_Phys_nd"));
154  }
155 
156  // We must read and write qmoist with ghost cells because we don't directly impose BCs on these vars
157  // Write the moisture model restart variables
158  std::vector<int> qmoist_indices(0);
159  std::vector<std::string> qmoist_names(0);
160  micro->Get_Qmoist_Restart_Vars(lev, solverChoice, qmoist_indices, qmoist_names);
161  int qmoist_nvar = qmoist_indices.size();
162  for (int var = 0; var < qmoist_nvar; var++) {
163  IntVect ng_moist = qmoist[lev][qmoist_indices[var]]->nGrowVect();
164  const int ncomp = 1;
165  MultiFab moist_vars(grids[lev],dmap[lev],ncomp,ng_moist);
166  MultiFab::Copy(moist_vars,*(qmoist[lev][qmoist_indices[var]]),0,0,ncomp,ng_moist);
167  VisMF::Write(moist_vars, amrex::MultiFabFileFullPrefix(lev, checkpointname, "Level_", qmoist_names[var]));
168  }
169 
170 #if defined(ERF_USE_WINDFARM)
171  if(solverChoice.windfarm_type == WindFarmType::Fitch or
172  solverChoice.windfarm_type == WindFarmType::EWP or
173  solverChoice.windfarm_type == WindFarmType::SimpleAD){
174  IntVect ng_turb = Nturb[lev].nGrowVect();
175  MultiFab mf_Nturb(grids[lev],dmap[lev],1,ng_turb);
176  MultiFab::Copy(mf_Nturb,Nturb[lev],0,0,1,ng_turb);
177  VisMF::Write(mf_Nturb, amrex::MultiFabFileFullPrefix(lev, checkpointname, "Level_", "NumTurb"));
178  }
179 #endif
180 
181  if (solverChoice.lsm_type != LandSurfaceType::None) {
182  for (int mvar(0); mvar<lsm_data[lev].size(); ++mvar) {
183  BoxArray ba = lsm_data[lev][mvar]->boxArray();
184  DistributionMapping dm = lsm_data[lev][mvar]->DistributionMap();
185  IntVect ng = lsm_data[lev][mvar]->nGrowVect();
186  int nvar = lsm_data[lev][mvar]->nComp();
187  MultiFab lsm_vars(ba,dm,nvar,ng);
188  MultiFab::Copy(lsm_vars,*(lsm_data[lev][mvar]),0,0,nvar,ng);
189  VisMF::Write(lsm_vars, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "LsmVars"));
190  }
191  }
192 
193  // Note that we also write the ghost cells of the mapfactors (2D)
194  BoxList bl2d = grids[lev].boxList();
195  for (auto& b : bl2d) {
196  b.setRange(2,0);
197  }
198  BoxArray ba2d(std::move(bl2d));
199 
200  IntVect ng = mapfac_m[lev]->nGrowVect();
201  MultiFab mf_m(ba2d,dmap[lev],1,ng);
202  MultiFab::Copy(mf_m,*mapfac_m[lev],0,0,1,ng);
203  VisMF::Write(mf_m, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "MapFactor_m"));
204 
205  ng = mapfac_u[lev]->nGrowVect();
206  MultiFab mf_u(convert(ba2d,IntVect(1,0,0)),dmap[lev],1,ng);
207  MultiFab::Copy(mf_u,*mapfac_u[lev],0,0,1,ng);
208  VisMF::Write(mf_u, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "MapFactor_u"));
209 
210  ng = mapfac_v[lev]->nGrowVect();
211  MultiFab mf_v(convert(ba2d,IntVect(0,1,0)),dmap[lev],1,ng);
212  MultiFab::Copy(mf_v,*mapfac_v[lev],0,0,1,ng);
213  VisMF::Write(mf_v, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "MapFactor_v"));
214 
215  if (m_most && m_most->have_variable_sea_roughness()) {
216  amrex::Print() << "Writing variable surface roughness" << std::endl;
217  ng = vars_new[lev][Vars::cons].nGrowVect(); ng[2]=0;
218  MultiFab z0(ba2d,dmap[lev],1,ng);
219  for (amrex::MFIter mfi(z0); mfi.isValid(); ++mfi) {
220  const Box& bx = mfi.growntilebox();
221  z0[mfi].copy<RunOn::Host>(*(m_most->get_z0(lev)), bx);
222  }
223  VisMF::Write(z0, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Z0"));
224  }
225  }
226 
227 #ifdef ERF_USE_PARTICLES
228  particleData.Checkpoint(checkpointname);
229 #endif
230 
231 #ifdef ERF_USE_NETCDF
232  // Write bdy_data files
233  if (ParallelDescriptor::IOProcessor() && ((init_type==InitType::Real) || (init_type==InitType::Metgrid))) {
234 
235  // Vector dimensions
236  int num_time = bdy_data_xlo.size();
237  int num_var = bdy_data_xlo[0].size();
238 
239  // Open header file and write to it
240  std::ofstream bdy_h_file(MultiFabFileFullPrefix(0, checkpointname, "Level_", "bdy_H"));
241  bdy_h_file << std::setprecision(1) << std::fixed;
242  bdy_h_file << num_time << "\n";
243  bdy_h_file << num_var << "\n";
244  bdy_h_file << start_bdy_time << "\n";
245  bdy_h_file << bdy_time_interval << "\n";
246  bdy_h_file << real_width << "\n";
247  for (int ivar(0); ivar<num_var; ++ivar) {
248  bdy_h_file << bdy_data_xlo[0][ivar].box() << "\n";
249  bdy_h_file << bdy_data_xhi[0][ivar].box() << "\n";
250  bdy_h_file << bdy_data_ylo[0][ivar].box() << "\n";
251  bdy_h_file << bdy_data_yhi[0][ivar].box() << "\n";
252  }
253 
254  // Open data file and write to it
255  std::ofstream bdy_d_file(MultiFabFileFullPrefix(0, checkpointname, "Level_", "bdy_D"));
256  for (int itime(0); itime<num_time; ++itime) {
257  for (int ivar(0); ivar<num_var; ++ivar) {
258  bdy_data_xlo[itime][ivar].writeOn(bdy_d_file,0,1);
259  bdy_data_xhi[itime][ivar].writeOn(bdy_d_file,0,1);
260  bdy_data_ylo[itime][ivar].writeOn(bdy_d_file,0,1);
261  bdy_data_yhi[itime][ivar].writeOn(bdy_d_file,0,1);
262  }
263  }
264  }
265 #endif
266 
267 }

◆ 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
1717 {
1718  AMREX_ALWAYS_ASSERT(nlevels <= bArray.size());
1719  AMREX_ALWAYS_ASSERT(nlevels <= my_ref_ratio.size()+1);
1720  AMREX_ALWAYS_ASSERT(nlevels <= level_steps.size());
1721 
1722  HeaderFile.precision(17);
1723 
1724  // ---- this is the generic plot file type name
1725  HeaderFile << versionName << '\n';
1726 
1727  HeaderFile << varnames.size() << '\n';
1728 
1729  for (int ivar = 0; ivar < varnames.size(); ++ivar) {
1730  HeaderFile << varnames[ivar] << "\n";
1731  }
1732  HeaderFile << AMREX_SPACEDIM << '\n';
1733  HeaderFile << my_time << '\n';
1734  HeaderFile << finest_level << '\n';
1735  for (int i = 0; i < AMREX_SPACEDIM; ++i) {
1736  HeaderFile << my_geom[0].ProbLo(i) << ' ';
1737  }
1738  HeaderFile << '\n';
1739  for (int i = 0; i < AMREX_SPACEDIM; ++i) {
1740  HeaderFile << my_geom[0].ProbHi(i) << ' ';
1741  }
1742  HeaderFile << '\n';
1743  for (int i = 0; i < finest_level; ++i) {
1744  HeaderFile << my_ref_ratio[i][0] << ' ';
1745  }
1746  HeaderFile << '\n';
1747  for (int i = 0; i <= finest_level; ++i) {
1748  HeaderFile << my_geom[i].Domain() << ' ';
1749  }
1750  HeaderFile << '\n';
1751  for (int i = 0; i <= finest_level; ++i) {
1752  HeaderFile << level_steps[i] << ' ';
1753  }
1754  HeaderFile << '\n';
1755  for (int i = 0; i <= finest_level; ++i) {
1756  for (int k = 0; k < AMREX_SPACEDIM; ++k) {
1757  HeaderFile << my_geom[i].CellSize()[k] << ' ';
1758  }
1759  HeaderFile << '\n';
1760  }
1761  HeaderFile << (int) my_geom[0].Coord() << '\n';
1762  HeaderFile << "0\n";
1763 
1764  for (int level = 0; level <= finest_level; ++level) {
1765  HeaderFile << level << ' ' << bArray[level].size() << ' ' << my_time << '\n';
1766  HeaderFile << level_steps[level] << '\n';
1767 
1768  const IntVect& domain_lo = my_geom[level].Domain().smallEnd();
1769  for (int i = 0; i < bArray[level].size(); ++i)
1770  {
1771  // Need to shift because the RealBox ctor we call takes the
1772  // physical location of index (0,0,0). This does not affect
1773  // the usual cases where the domain index starts with 0.
1774  const Box& b = shift(bArray[level][i], -domain_lo);
1775  RealBox loc = RealBox(b, my_geom[level].CellSize(), my_geom[level].ProbLo());
1776  for (int n = 0; n < AMREX_SPACEDIM; ++n) {
1777  HeaderFile << loc.lo(n) << ' ' << loc.hi(n) << '\n';
1778  }
1779  }
1780 
1781  HeaderFile << MultiFabHeaderPath(level, levelPrefix, mfPrefix) << '\n';
1782  }
1783  HeaderFile << "1" << "\n";
1784  HeaderFile << "3" << "\n";
1785  HeaderFile << "amrexvec_nu_x" << "\n";
1786  HeaderFile << "amrexvec_nu_y" << "\n";
1787  HeaderFile << "amrexvec_nu_z" << "\n";
1788  std::string mf_nodal_prefix = "Nu_nd";
1789  for (int level = 0; level <= finest_level; ++level) {
1790  HeaderFile << MultiFabHeaderPath(level, levelPrefix, mf_nodal_prefix) << '\n';
1791  }
1792 }
Coord
Definition: ERF_DataStruct.H:64

◆ writeJobInfo()

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

◆ 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
1631 {
1632  BL_PROFILE("WriteMultiLevelPlotfileWithTerrain()");
1633 
1634  AMREX_ALWAYS_ASSERT(nlevels <= mf.size());
1635  AMREX_ALWAYS_ASSERT(nlevels <= rr.size()+1);
1636  AMREX_ALWAYS_ASSERT(nlevels <= level_steps.size());
1637  AMREX_ALWAYS_ASSERT(mf[0]->nComp() == varnames.size());
1638 
1639  bool callBarrier(false);
1640  PreBuildDirectorHierarchy(plotfilename, levelPrefix, nlevels, callBarrier);
1641  if (!extra_dirs.empty()) {
1642  for (const auto& d : extra_dirs) {
1643  const std::string ed = plotfilename+"/"+d;
1644  PreBuildDirectorHierarchy(ed, levelPrefix, nlevels, callBarrier);
1645  }
1646  }
1647  ParallelDescriptor::Barrier();
1648 
1649  if (ParallelDescriptor::MyProc() == ParallelDescriptor::NProcs()-1) {
1650  Vector<BoxArray> boxArrays(nlevels);
1651  for(int level(0); level < boxArrays.size(); ++level) {
1652  boxArrays[level] = mf[level]->boxArray();
1653  }
1654 
1655  auto f = [=]() {
1656  VisMF::IO_Buffer io_buffer(VisMF::IO_Buffer_Size);
1657  std::string HeaderFileName(plotfilename + "/Header");
1658  std::ofstream HeaderFile;
1659  HeaderFile.rdbuf()->pubsetbuf(io_buffer.dataPtr(), io_buffer.size());
1660  HeaderFile.open(HeaderFileName.c_str(), std::ofstream::out |
1661  std::ofstream::trunc |
1662  std::ofstream::binary);
1663  if( ! HeaderFile.good()) FileOpenFailed(HeaderFileName);
1664  WriteGenericPlotfileHeaderWithTerrain(HeaderFile, nlevels, boxArrays, varnames,
1665  my_geom, time, level_steps, rr, versionName,
1666  levelPrefix, mfPrefix);
1667  };
1668 
1669  if (AsyncOut::UseAsyncOut()) {
1670  AsyncOut::Submit(std::move(f));
1671  } else {
1672  f();
1673  }
1674  }
1675 
1676  std::string mf_nodal_prefix = "Nu_nd";
1677  for (int level = 0; level <= finest_level; ++level)
1678  {
1679  if (AsyncOut::UseAsyncOut()) {
1680  VisMF::AsyncWrite(*mf[level],
1681  MultiFabFileFullPrefix(level, plotfilename, levelPrefix, mfPrefix),
1682  true);
1683  VisMF::AsyncWrite(*mf_nd[level],
1684  MultiFabFileFullPrefix(level, plotfilename, levelPrefix, mf_nodal_prefix),
1685  true);
1686  } else {
1687  const MultiFab* data;
1688  std::unique_ptr<MultiFab> mf_tmp;
1689  if (mf[level]->nGrowVect() != 0) {
1690  mf_tmp = std::make_unique<MultiFab>(mf[level]->boxArray(),
1691  mf[level]->DistributionMap(),
1692  mf[level]->nComp(), 0, MFInfo(),
1693  mf[level]->Factory());
1694  MultiFab::Copy(*mf_tmp, *mf[level], 0, 0, mf[level]->nComp(), 0);
1695  data = mf_tmp.get();
1696  } else {
1697  data = mf[level];
1698  }
1699  VisMF::Write(*data , MultiFabFileFullPrefix(level, plotfilename, levelPrefix, mfPrefix));
1700  VisMF::Write(*mf_nd[level], MultiFabFileFullPrefix(level, plotfilename, levelPrefix, mf_nodal_prefix));
1701  }
1702  }
1703 }
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:1706

◆ writeNow()

bool ERF::writeNow ( const amrex::Real  cur_time,
const amrex::Real  dt,
const int  nstep,
const int  plot_int,
const amrex::Real  plot_per 
)
1952 {
1953  bool write_now = false;
1954 
1955  if ( plot_int > 0 && (nstep % plot_int == 0) ) {
1956  write_now = true;
1957 
1958  } else if (plot_per > 0.0) {
1959 
1960  // Check to see if we've crossed a plot_per interval by comparing
1961  // the number of intervals that have elapsed for both the current
1962  // time and the time at the beginning of this timestep.
1963 
1964  const Real eps = std::numeric_limits<Real>::epsilon() * Real(10.0) * std::abs(cur_time);
1965 
1966  int num_per_old = static_cast<int>(std::floor((cur_time-eps-dt_lev) / plot_per));
1967  int num_per_new = static_cast<int>(std::floor((cur_time-eps ) / plot_per));
1968 
1969  // Before using these, however, we must test for the case where we're
1970  // within machine epsilon of the next interval. In that case, increment
1971  // the counter, because we have indeed reached the next plot_per interval
1972  // at this point.
1973 
1974  const Real next_plot_time = (num_per_old + 1) * plot_per;
1975 
1976  if ((num_per_new == num_per_old) && std::abs(cur_time - next_plot_time) <= eps)
1977  {
1978  num_per_new += 1;
1979  }
1980 
1981  // Similarly, we have to account for the case where the old time is within
1982  // machine epsilon of the beginning of this interval, so that we don't double
1983  // count that time threshold -- we already plotted at that time on the last timestep.
1984 
1985  if ((num_per_new != num_per_old) && std::abs((cur_time - dt_lev) - next_plot_time) <= eps)
1986  num_per_old += 1;
1987 
1988  if (num_per_old != num_per_new)
1989  write_now = true;
1990  }
1991  return write_now;
1992 }

◆ WritePlotFile()

void ERF::WritePlotFile ( int  which,
PlotFileType  plotfile_type,
amrex::Vector< std::string >  plot_var_names 
)
187 {
188  const Vector<std::string> varnames = PlotFileVarNames(plot_var_names);
189  const int ncomp_mf = varnames.size();
190 
191  int ncomp_cons = vars_new[0][Vars::cons].nComp();
192 
193  if (ncomp_mf == 0) return;
194 
195  // We Fillpatch here because some of the derived quantities require derivatives
196  // which require ghost cells to be filled. We do not need to call FillPatcher
197  // because we don't need to set interior fine points.
198  // NOTE: the momenta here are only used as scratch space, the momenta themselves are not fillpatched
199 
200  // Level 0 FilLPatch
202  &vars_new[0][Vars::yvel], &vars_new[0][Vars::zvel]});
203 
204  for (int lev = 1; lev <= finest_level; ++lev) {
205  bool fillset = false;
206  FillPatch(lev, t_new[lev], {&vars_new[lev][Vars::cons], &vars_new[lev][Vars::xvel],
207  &vars_new[lev][Vars::yvel], &vars_new[lev][Vars::zvel]},
208  {&vars_new[lev][Vars::cons],
209  &rU_new[lev], &rV_new[lev], &rW_new[lev]},
210  base_state[lev], base_state[lev], fillset);
211  }
212 
213  // Get qmoist pointers if using moisture
214  bool use_moisture = (solverChoice.moisture_type != MoistureType::None);
215  for (int lev = 0; lev <= finest_level; ++lev) {
216  for (int mvar(0); mvar<qmoist[lev].size(); ++mvar) {
217  qmoist[lev][mvar] = micro->Get_Qmoist_Ptr(lev,mvar);
218  }
219  }
220 
221  // Vector of MultiFabs for cell-centered data
222  Vector<MultiFab> mf(finest_level+1);
223  for (int lev = 0; lev <= finest_level; ++lev) {
224  mf[lev].define(grids[lev], dmap[lev], ncomp_mf, 0);
225  }
226 
227  // Vector of MultiFabs for nodal data
228  Vector<MultiFab> mf_nd(finest_level+1);
229  if ( SolverChoice::mesh_type != MeshType::ConstantDz) {
230  for (int lev = 0; lev <= finest_level; ++lev) {
231  BoxArray nodal_grids(grids[lev]); nodal_grids.surroundingNodes();
232  mf_nd[lev].define(nodal_grids, dmap[lev], 3, 0);
233  mf_nd[lev].setVal(0.);
234  }
235  }
236 
237  // Vector of MultiFabs for face-centered velocity
238  Vector<MultiFab> mf_u(finest_level+1);
239  Vector<MultiFab> mf_v(finest_level+1);
240  Vector<MultiFab> mf_w(finest_level+1);
241  if (m_plot_face_vels) {
242  for (int lev = 0; lev <= finest_level; ++lev) {
243  BoxArray grid_stag_u(grids[lev]); grid_stag_u.surroundingNodes(0);
244  BoxArray grid_stag_v(grids[lev]); grid_stag_v.surroundingNodes(1);
245  BoxArray grid_stag_w(grids[lev]); grid_stag_w.surroundingNodes(2);
246  mf_u[lev].define(grid_stag_u, dmap[lev], 1, 0);
247  mf_v[lev].define(grid_stag_v, dmap[lev], 1, 0);
248  mf_w[lev].define(grid_stag_w, dmap[lev], 1, 0);
249  MultiFab::Copy(mf_u[lev],vars_new[lev][Vars::xvel],0,0,1,0);
250  MultiFab::Copy(mf_v[lev],vars_new[lev][Vars::yvel],0,0,1,0);
251  MultiFab::Copy(mf_w[lev],vars_new[lev][Vars::zvel],0,0,1,0);
252  }
253  }
254 
255  // Array of MultiFabs for cell-centered velocity
256  Vector<MultiFab> mf_cc_vel(finest_level+1);
257 
258  if (containerHasElement(plot_var_names, "x_velocity" ) ||
259  containerHasElement(plot_var_names, "y_velocity" ) ||
260  containerHasElement(plot_var_names, "z_velocity" ) ||
261  containerHasElement(plot_var_names, "magvel" ) ||
262  containerHasElement(plot_var_names, "vorticity_x") ||
263  containerHasElement(plot_var_names, "vorticity_y") ||
264  containerHasElement(plot_var_names, "vorticity_z") ) {
265 
266  for (int lev = 0; lev <= finest_level; ++lev) {
267  mf_cc_vel[lev].define(grids[lev], dmap[lev], AMREX_SPACEDIM, IntVect(1,1,1));
268  average_face_to_cellcenter(mf_cc_vel[lev],0,
269  Array<const MultiFab*,3>{&vars_new[lev][Vars::xvel],
270  &vars_new[lev][Vars::yvel],
271  &vars_new[lev][Vars::zvel]});
272  } // lev
273  } // if (vel or vort)
274 
275  // We need ghost cells if computing vorticity
276  if ( containerHasElement(plot_var_names, "vorticity_x")||
277  containerHasElement(plot_var_names, "vorticity_y") ||
278  containerHasElement(plot_var_names, "vorticity_z") )
279  {
280  amrex::Interpolater* mapper = &cell_cons_interp;
281  for (int lev = 1; lev <= finest_level; ++lev)
282  {
283  Vector<MultiFab*> fmf = {&(mf_cc_vel[lev]), &(mf_cc_vel[lev])};
284  Vector<Real> ftime = {t_new[lev], t_new[lev]};
285  Vector<MultiFab*> cmf = {&mf_cc_vel[lev-1], &mf_cc_vel[lev-1]};
286  Vector<Real> ctime = {t_new[lev], t_new[lev]};
287 
288  amrex::FillPatchTwoLevels(mf_cc_vel[lev], t_new[lev], cmf, ctime, fmf, ftime,
289  0, 0, AMREX_SPACEDIM, geom[lev-1], geom[lev],
290  null_bc_for_fill, 0, null_bc_for_fill, 0, refRatio(lev-1),
291  mapper, domain_bcs_type, 0);
292  } // lev
293 
294  // Impose bc's at domain boundaries at all levels
295  FillBdyCCVels(mf_cc_vel);
296  } // if (vort)
297 
298  for (int lev = 0; lev <= finest_level; ++lev)
299  {
300  int mf_comp = 0;
301 
302  // First, copy any of the conserved state variables into the output plotfile
303  for (int i = 0; i < cons_names.size(); ++i) {
304  if (containerHasElement(plot_var_names, cons_names[i])) {
305  MultiFab::Copy(mf[lev],vars_new[lev][Vars::cons],i,mf_comp,1,0);
306  mf_comp++;
307  }
308  }
309 
310  // Next, check for velocities
311  if (containerHasElement(plot_var_names, "x_velocity")) {
312  MultiFab::Copy(mf[lev], mf_cc_vel[lev], 0, mf_comp, 1, 0);
313  mf_comp += 1;
314  }
315  if (containerHasElement(plot_var_names, "y_velocity")) {
316  MultiFab::Copy(mf[lev], mf_cc_vel[lev], 1, mf_comp, 1, 0);
317  mf_comp += 1;
318  }
319  if (containerHasElement(plot_var_names, "z_velocity")) {
320  MultiFab::Copy(mf[lev], mf_cc_vel[lev], 2, mf_comp, 1, 0);
321  mf_comp += 1;
322  }
323 
324  // Finally, check for any derived quantities and compute them, inserting
325  // them into our output multifab
326  auto calculate_derived = [&](const std::string& der_name,
327  MultiFab& src_mf,
328  decltype(derived::erf_dernull)& der_function)
329  {
330  if (containerHasElement(plot_var_names, der_name)) {
331  MultiFab dmf(mf[lev], make_alias, mf_comp, 1);
332 #ifdef _OPENMP
333 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
334 #endif
335  for (MFIter mfi(dmf, TilingIfNotGPU()); mfi.isValid(); ++mfi)
336  {
337  const Box& bx = mfi.tilebox();
338  auto& dfab = dmf[mfi];
339  auto& sfab = src_mf[mfi];
340  der_function(bx, dfab, 0, 1, sfab, Geom(lev), t_new[0], nullptr, lev);
341  }
342 
343  mf_comp++;
344  }
345  };
346 
347  bool ismoist = (solverChoice.moisture_type != MoistureType::None);
348 
349  // Note: All derived variables must be computed in order of "derived_names" defined in ERF.H
350  calculate_derived("soundspeed", vars_new[lev][Vars::cons], derived::erf_dersoundspeed);
351  if (ismoist) {
352  calculate_derived("temp", vars_new[lev][Vars::cons], derived::erf_dermoisttemp);
353  } else {
354  calculate_derived("temp", vars_new[lev][Vars::cons], derived::erf_dertemp);
355  }
356  calculate_derived("theta", vars_new[lev][Vars::cons], derived::erf_dertheta);
357  calculate_derived("KE", vars_new[lev][Vars::cons], derived::erf_derKE);
358  calculate_derived("scalar", vars_new[lev][Vars::cons], derived::erf_derscalar);
359  calculate_derived("vorticity_x", mf_cc_vel[lev] , derived::erf_dervortx);
360  calculate_derived("vorticity_y", mf_cc_vel[lev] , derived::erf_dervorty);
361  calculate_derived("vorticity_z", mf_cc_vel[lev] , derived::erf_dervortz);
362  calculate_derived("magvel" , mf_cc_vel[lev] , derived::erf_dermagvel);
363 
364  if (containerHasElement(plot_var_names, "divU"))
365  {
366  MultiFab dmf(mf[lev], make_alias, mf_comp, 1);
367  Array<MultiFab const*, AMREX_SPACEDIM> u;
368  u[0] = &(vars_new[lev][Vars::xvel]);
369  u[1] = &(vars_new[lev][Vars::yvel]);
370  u[2] = &(vars_new[lev][Vars::zvel]);
371  compute_divergence (lev, dmf, u, geom[lev]);
372  mf_comp += 1;
373  }
374 
375  MultiFab r_hse(base_state[lev], make_alias, BaseState::r0_comp , 1);
376  MultiFab p_hse(base_state[lev], make_alias, BaseState::p0_comp , 1);
377  MultiFab th_hse(base_state[lev], make_alias, BaseState::th0_comp, 1);
378  if (containerHasElement(plot_var_names, "pres_hse"))
379  {
380  MultiFab::Copy(mf[lev],p_hse,0,mf_comp,1,0);
381  mf_comp += 1;
382  }
383  if (containerHasElement(plot_var_names, "dens_hse"))
384  {
385  MultiFab::Copy(mf[lev],r_hse,0,mf_comp,1,0);
386  mf_comp += 1;
387  }
388  if (containerHasElement(plot_var_names, "theta_hse"))
389  {
390  MultiFab::Copy(mf[lev],th_hse,0,mf_comp,1,0);
391  mf_comp += 1;
392  }
393 
394  if (containerHasElement(plot_var_names, "pressure"))
395  {
396  if (solverChoice.anelastic[lev] == 1) {
397  MultiFab::Copy(mf[lev], p_hse, 0, mf_comp, 1, 0);
398  } else
399 #ifdef _OPENMP
400 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
401 #endif
402  {
403  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
404  {
405  const Box& bx = mfi.tilebox();
406  const Array4<Real >& derdat = mf[lev].array(mfi);
407  const Array4<Real const>& S_arr = vars_new[lev][Vars::cons].const_array(mfi);
408  const int ncomp = vars_new[lev][Vars::cons].nComp();
409 
410  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
411  {
412  Real qv_for_p = (use_moisture && (ncomp > RhoQ1_comp)) ? S_arr(i,j,k,RhoQ1_comp)/S_arr(i,j,k,Rho_comp) : 0;
413  const Real rhotheta = S_arr(i,j,k,RhoTheta_comp);
414  derdat(i, j, k, mf_comp) = getPgivenRTh(rhotheta,qv_for_p);
415  });
416  }
417  } // not anelastic
418  mf_comp += 1;
419  } // pressure
420 
421  if (containerHasElement(plot_var_names, "pert_pres"))
422  {
423  if (solverChoice.anelastic[lev] == 1) {
424  MultiFab::Copy(mf[lev], pp_inc[lev], 0, mf_comp, 1, 0);
425  } else
426 #ifdef _OPENMP
427 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
428 #endif
429  {
430  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
431  {
432  const Box& bx = mfi.tilebox();
433  const Array4<Real>& derdat = mf[lev].array(mfi);
434  const Array4<Real const>& p0_arr = p_hse.const_array(mfi);
435  const Array4<Real const>& S_arr = vars_new[lev][Vars::cons].const_array(mfi);
436  const int ncomp = vars_new[lev][Vars::cons].nComp();
437 
438  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
439  {
440  Real qv_for_p = (use_moisture && (ncomp > RhoQ1_comp)) ? S_arr(i,j,k,RhoQ1_comp)/S_arr(i,j,k,Rho_comp) : 0;
441  const Real rhotheta = S_arr(i,j,k,RhoTheta_comp);
442  derdat(i, j, k, mf_comp) = getPgivenRTh(rhotheta,qv_for_p) - p0_arr(i,j,k);
443  });
444  }
445  } // not anelastic
446  mf_comp += 1;
447  }
448 
449  if (containerHasElement(plot_var_names, "pert_dens"))
450  {
451 #ifdef _OPENMP
452 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
453 #endif
454  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
455  {
456  const Box& bx = mfi.tilebox();
457  const Array4<Real>& derdat = mf[lev].array(mfi);
458  const Array4<Real const>& S_arr = vars_new[lev][Vars::cons].const_array(mfi);
459  const Array4<Real const>& r0_arr = r_hse.const_array(mfi);
460  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
461  derdat(i, j, k, mf_comp) = S_arr(i,j,k,Rho_comp) - r0_arr(i,j,k);
462  });
463  }
464  mf_comp ++;
465  }
466 
467  if (containerHasElement(plot_var_names, "eq_pot_temp"))
468  {
469 #ifdef _OPENMP
470 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
471 #endif
472  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
473  {
474  const Box& bx = mfi.tilebox();
475  const Array4<Real>& derdat = mf[lev].array(mfi);
476  const Array4<Real const>& S_arr = vars_new[lev][Vars::cons].const_array(mfi);
477  const int ncomp = vars_new[lev][Vars::cons].nComp();
478  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
479  Real qv = (use_moisture && (ncomp > RhoQ1_comp)) ? S_arr(i,j,k,RhoQ1_comp)/S_arr(i,j,k,Rho_comp) : 0.0;
480  Real qc = (use_moisture && (ncomp > RhoQ2_comp)) ? S_arr(i,j,k,RhoQ2_comp)/S_arr(i,j,k,Rho_comp) : 0.0;
481  Real T = getTgivenRandRTh(S_arr(i,j,k,Rho_comp), S_arr(i,j,k,RhoTheta_comp), qv);
482  Real pressure = getPgivenRTh(S_arr(i,j,k,RhoTheta_comp), qv);
483  Real fac = Cp_d + Cp_l*(qv + qc);
484  Real pv = erf_esatw(T)*100.0;
485 
486  derdat(i, j, k, mf_comp) = T*std::pow((pressure - pv)/p_0, -R_d/fac)*std::exp(L_v*qv/(fac*T)) ;
487  });
488  }
489  mf_comp ++;
490  }
491 
492  if (containerHasElement(plot_var_names, "terrain_IB_mask"))
493  {
494  MultiFab* terrain_blank = m_terrain_drag[lev]->get_terrain_blank_field();
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& bx = mfi.tilebox();
501  const Array4<Real>& derdat = mf[lev].array(mfi);
502  const Array4<Real const>& src = terrain_blank->const_array(mfi);
503  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
504  derdat(i, j, k, mf_comp) = src(i,j,k);
505  });
506  }
507  mf_comp ++;
508  }
509 
510 #ifdef ERF_USE_WINDFARM
511  if (containerHasElement(plot_var_names, "num_turb") and
512  (solverChoice.windfarm_type == WindFarmType::Fitch or solverChoice.windfarm_type == WindFarmType::EWP or
513  solverChoice.windfarm_type == WindFarmType::SimpleAD or solverChoice.windfarm_type == WindFarmType::GeneralAD))
514  {
515 #ifdef _OPENMP
516 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
517 #endif
518  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
519  {
520  const Box& bx = mfi.tilebox();
521  const Array4<Real>& derdat = mf[lev].array(mfi);
522  const Array4<Real const>& Nturb_array = Nturb[lev].const_array(mfi);
523  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
524  derdat(i, j, k, mf_comp) = Nturb_array(i,j,k,0);
525  });
526  }
527  mf_comp ++;
528  }
529 
530  if( containerHasElement(plot_var_names, "SMark0") and
531  (solverChoice.windfarm_type == WindFarmType::Fitch or solverChoice.windfarm_type == WindFarmType::EWP or
532  solverChoice.windfarm_type == WindFarmType::SimpleAD or solverChoice.windfarm_type == WindFarmType::GeneralAD) ) {
533  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
534  {
535  const Box& bx = mfi.tilebox();
536  const Array4<Real>& derdat = mf[lev].array(mfi);
537  const Array4<Real const>& SMark_array = SMark[lev].const_array(mfi);
538  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
539  derdat(i, j, k, mf_comp) = SMark_array(i,j,k,0);
540  });
541  }
542  mf_comp ++;
543  }
544 
545  if(containerHasElement(plot_var_names, "SMark1") and
546  (solverChoice.windfarm_type == WindFarmType::SimpleAD or solverChoice.windfarm_type == WindFarmType::GeneralAD)) {
547  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
548  {
549  const Box& bx = mfi.tilebox();
550  const Array4<Real>& derdat = mf[lev].array(mfi);
551  const Array4<Real const>& SMark_array = SMark[lev].const_array(mfi);
552  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
553  derdat(i, j, k, mf_comp) = SMark_array(i,j,k,1);
554  });
555  }
556  mf_comp ++;
557  }
558 
559 #endif
560 
561  int klo = geom[lev].Domain().smallEnd(2);
562  int khi = geom[lev].Domain().bigEnd(2);
563 
564  if (containerHasElement(plot_var_names, "dpdx"))
565  {
566  auto dxInv = geom[lev].InvCellSizeArray();
567  MultiFab pres(vars_new[lev][Vars::cons].boxArray(), vars_new[lev][Vars::cons].DistributionMap(), 1, 1);
568 #ifdef _OPENMP
569 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
570 #endif
571  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
572  {
573  // First define pressure on grown box
574  const Box& gbx = mfi.growntilebox(1);
575  const Array4<Real > & p_arr = pres.array(mfi);
576  const Array4<Real const> & hse_arr = base_state[lev].const_array(mfi);
577  const Array4<Real const>& S_arr = vars_new[lev][Vars::cons].const_array(mfi);
578  if (solverChoice.anelastic[lev] == 1) {
579  ParallelFor(gbx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept {
580  p_arr(i,j,k) = hse_arr(i,j,k,1);
581  });
582  } else {
583  ParallelFor(gbx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept {
584  p_arr(i,j,k) = getPgivenRTh(S_arr(i,j,k,RhoTheta_comp));
585  });
586  }
587  }
588  pres.FillBoundary(geom[lev].periodicity());
589 
590 #ifdef _OPENMP
591 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
592 #endif
593  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
594  {
595  // Now compute pressure gradient on valid box
596  const Box& bx = mfi.tilebox();
597  const Array4<Real>& derdat = mf[lev].array(mfi);
598  const Array4<Real> & p_arr = pres.array(mfi);
599 
600  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
601  const Array4<Real const>& z_nd = z_phys_nd[lev]->const_array(mfi);
602 
603  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
604 
605  // Pgrad at lower I face
606  Real met_h_xi_lo = Compute_h_xi_AtIface (i, j, k, dxInv, z_nd);
607  Real met_h_zeta_lo = Compute_h_zeta_AtIface(i, j, k, dxInv, z_nd);
608  Real gp_xi_lo = dxInv[0] * (p_arr(i,j,k) - p_arr(i-1,j,k));
609  Real gp_zeta_on_iface_lo;
610  if(k == klo) {
611  gp_zeta_on_iface_lo = 0.5 * dxInv[2] * (
612  p_arr(i-1,j,k+1) + p_arr(i,j,k+1)
613  - p_arr(i-1,j,k ) - p_arr(i,j,k ) );
614  } else if (k == khi) {
615  gp_zeta_on_iface_lo = 0.5 * dxInv[2] * (
616  p_arr(i-1,j,k ) + p_arr(i,j,k )
617  - p_arr(i-1,j,k-1) - p_arr(i,j,k-1) );
618  } else {
619  gp_zeta_on_iface_lo = 0.25 * dxInv[2] * (
620  p_arr(i-1,j,k+1) + p_arr(i,j,k+1)
621  - p_arr(i-1,j,k-1) - p_arr(i,j,k-1) );
622  }
623  Real gpx_lo = gp_xi_lo - (met_h_xi_lo/ met_h_zeta_lo) * gp_zeta_on_iface_lo;
624 
625  // Pgrad at higher I face
626  Real met_h_xi_hi = Compute_h_xi_AtIface (i+1, j, k, dxInv, z_nd);
627  Real met_h_zeta_hi = Compute_h_zeta_AtIface(i+1, j, k, dxInv, z_nd);
628  Real gp_xi_hi = dxInv[0] * (p_arr(i+1,j,k) - p_arr(i,j,k));
629  Real gp_zeta_on_iface_hi;
630  if(k == klo) {
631  gp_zeta_on_iface_hi = 0.5 * dxInv[2] * (
632  p_arr(i+1,j,k+1) + p_arr(i,j,k+1)
633  - p_arr(i+1,j,k ) - p_arr(i,j,k ) );
634  } else if (k == khi) {
635  gp_zeta_on_iface_hi = 0.5 * dxInv[2] * (
636  p_arr(i+1,j,k ) + p_arr(i,j,k )
637  - p_arr(i+1,j,k-1) - p_arr(i,j,k-1) );
638  } else {
639  gp_zeta_on_iface_hi = 0.25 * dxInv[2] * (
640  p_arr(i+1,j,k+1) + p_arr(i,j,k+1)
641  - p_arr(i+1,j,k-1) - p_arr(i,j,k-1) );
642  }
643  Real gpx_hi = gp_xi_hi - (met_h_xi_hi/ met_h_zeta_hi) * gp_zeta_on_iface_hi;
644 
645  // Average P grad to CC
646  derdat(i ,j ,k, mf_comp) = 0.5 * (gpx_lo + gpx_hi);
647  });
648  } else {
649  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
650  derdat(i ,j ,k, mf_comp) = 0.5 * (p_arr(i+1,j,k) - p_arr(i-1,j,k)) * dxInv[0];
651  });
652  }
653  } // mfi
654  mf_comp ++;
655  } // dpdx
656 
657  if (containerHasElement(plot_var_names, "dpdy"))
658  {
659  auto dxInv = geom[lev].InvCellSizeArray();
660 
661  MultiFab pres(vars_new[lev][Vars::cons].boxArray(), vars_new[lev][Vars::cons].DistributionMap(), 1, 1);
662 #ifdef _OPENMP
663 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
664 #endif
665  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
666  {
667  // First define pressure on grown box
668  const Box& gbx = mfi.growntilebox(1);
669  const Array4<Real > & p_arr = pres.array(mfi);
670  const Array4<Real const> & hse_arr = base_state[lev].const_array(mfi);
671  const Array4<Real const>& S_arr = vars_new[lev][Vars::cons].const_array(mfi);
672  if (solverChoice.anelastic[lev] == 1) {
673  ParallelFor(gbx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept {
674  p_arr(i,j,k) = hse_arr(i,j,k,1);
675  });
676  } else {
677  ParallelFor(gbx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept {
678  p_arr(i,j,k) = getPgivenRTh(S_arr(i,j,k,RhoTheta_comp));
679  });
680  }
681  }
682  pres.FillBoundary(geom[lev].periodicity());
683 
684 #ifdef _OPENMP
685 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
686 #endif
687  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
688  {
689  // Now compute pressure gradient on valid box
690  const Box& bx = mfi.tilebox();
691  const Array4<Real>& derdat = mf[lev].array(mfi);
692  const Array4<Real> & p_arr = pres.array(mfi);
693 
694  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
695  const Array4<Real const>& z_nd = z_phys_nd[lev]->const_array(mfi);
696 
697  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
698 
699  Real met_h_eta_lo = Compute_h_eta_AtJface (i, j, k, dxInv, z_nd);
700  Real met_h_zeta_lo = Compute_h_zeta_AtJface(i, j, k, dxInv, z_nd);
701  Real gp_eta_lo = dxInv[1] * (p_arr(i,j,k) - p_arr(i,j-1,k));
702  Real gp_zeta_on_jface_lo;
703  if (k == klo) {
704  gp_zeta_on_jface_lo = 0.5 * dxInv[2] * (
705  p_arr(i,j,k+1) + p_arr(i,j-1,k+1)
706  - p_arr(i,j,k ) - p_arr(i,j-1,k ) );
707  } else if (k == khi) {
708  gp_zeta_on_jface_lo = 0.5 * dxInv[2] * (
709  p_arr(i,j,k ) + p_arr(i,j-1,k )
710  - p_arr(i,j,k-1) - p_arr(i,j-1,k-1) );
711  } else {
712  gp_zeta_on_jface_lo = 0.25 * dxInv[2] * (
713  p_arr(i,j,k+1) + p_arr(i,j-1,k+1)
714  - p_arr(i,j,k-1) - p_arr(i,j-1,k-1) );
715  }
716  Real gpy_lo = gp_eta_lo - (met_h_eta_lo / met_h_zeta_lo) * gp_zeta_on_jface_lo;
717 
718  Real met_h_eta_hi = Compute_h_eta_AtJface (i, j+1, k, dxInv, z_nd);
719  Real met_h_zeta_hi = Compute_h_zeta_AtJface(i, j+1, k, dxInv, z_nd);
720  Real gp_eta_hi = dxInv[1] * (p_arr(i,j+1,k) - p_arr(i,j,k));
721  Real gp_zeta_on_jface_hi;
722  if (k == klo) {
723  gp_zeta_on_jface_hi = 0.5 * dxInv[2] * (
724  p_arr(i,j+1,k+1) + p_arr(i,j,k+1)
725  - p_arr(i,j+1,k ) - p_arr(i,j,k ) );
726  } else if (k == khi) {
727  gp_zeta_on_jface_hi = 0.5 * dxInv[2] * (
728  p_arr(i,j+1,k ) + p_arr(i,j,k )
729  - p_arr(i,j+1,k-1) - p_arr(i,j,k-1) );
730  } else {
731  gp_zeta_on_jface_hi = 0.25 * dxInv[2] * (
732  p_arr(i,j+1,k+1) + p_arr(i,j,k+1)
733  - p_arr(i,j+1,k-1) - p_arr(i,j,k-1) );
734  }
735  Real gpy_hi = gp_eta_hi - (met_h_eta_hi / met_h_zeta_hi) * gp_zeta_on_jface_hi;
736 
737  derdat(i ,j ,k, mf_comp) = 0.5 * (gpy_lo + gpy_hi);
738  });
739  } else {
740  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
741  derdat(i ,j ,k, mf_comp) = 0.5 * (p_arr(i,j+1,k) - p_arr(i,j-1,k)) * dxInv[1];
742  });
743  }
744  } // mf
745  mf_comp ++;
746  } // dpdy
747 
748  if (containerHasElement(plot_var_names, "pres_hse_x"))
749  {
750  auto dxInv = geom[lev].InvCellSizeArray();
751 #ifdef _OPENMP
752 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
753 #endif
754  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
755  {
756  const Box& bx = mfi.tilebox();
757  const Array4<Real >& derdat = mf[lev].array(mfi);
758  const Array4<Real const>& p_arr = p_hse.const_array(mfi);
759 
760  //USE_TERRAIN POSSIBLE ISSUE HERE
761  const Array4<Real const>& z_nd = z_phys_nd[lev]->const_array(mfi);
762 
763  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
764  Real met_h_xi_lo = Compute_h_xi_AtIface (i, j, k, dxInv, z_nd);
765  Real met_h_zeta_lo = Compute_h_zeta_AtIface(i, j, k, dxInv, z_nd);
766  Real gp_xi_lo = dxInv[0] * (p_arr(i,j,k) - p_arr(i-1,j,k));
767  Real gp_zeta_on_iface_lo;
768  if (k == klo) {
769  gp_zeta_on_iface_lo = 0.5 * dxInv[2] * (
770  p_arr(i-1,j,k+1) + p_arr(i,j,k+1)
771  - p_arr(i-1,j,k ) - p_arr(i,j,k ) );
772  } else if (k == khi) {
773  gp_zeta_on_iface_lo = 0.5 * dxInv[2] * (
774  p_arr(i-1,j,k ) + p_arr(i,j,k )
775  - p_arr(i-1,j,k-1) - p_arr(i,j,k-1) );
776  } else {
777  gp_zeta_on_iface_lo = 0.25 * dxInv[2] * (
778  p_arr(i-1,j,k+1) + p_arr(i,j,k+1)
779  - p_arr(i-1,j,k-1) - p_arr(i,j,k-1) );
780  }
781  Real gpx_lo = gp_xi_lo - (met_h_xi_lo/ met_h_zeta_lo) * gp_zeta_on_iface_lo;
782 
783  Real met_h_xi_hi = Compute_h_xi_AtIface (i+1, j, k, dxInv, z_nd);
784  Real met_h_zeta_hi = Compute_h_zeta_AtIface(i+1, j, k, dxInv, z_nd);
785  Real gp_xi_hi = dxInv[0] * (p_arr(i+1,j,k) - p_arr(i,j,k));
786  Real gp_zeta_on_iface_hi;
787  if (k == klo) {
788  gp_zeta_on_iface_hi = 0.5 * dxInv[2] * (
789  p_arr(i+1,j,k+1) + p_arr(i,j,k+1)
790  - p_arr(i+1,j,k ) - p_arr(i,j,k ) );
791  } else if (k == khi) {
792  gp_zeta_on_iface_hi = 0.5 * dxInv[2] * (
793  p_arr(i+1,j,k ) + p_arr(i,j,k )
794  - p_arr(i+1,j,k-1) - p_arr(i,j,k-1) );
795  } else {
796  gp_zeta_on_iface_hi = 0.25 * dxInv[2] * (
797  p_arr(i+1,j,k+1) + p_arr(i,j,k+1)
798  - p_arr(i+1,j,k-1) - p_arr(i,j,k-1) );
799  }
800  Real gpx_hi = gp_xi_hi - (met_h_xi_hi/ met_h_zeta_hi) * gp_zeta_on_iface_hi;
801 
802  derdat(i ,j ,k, mf_comp) = 0.5 * (gpx_lo + gpx_hi);
803  });
804  }
805  mf_comp += 1;
806  } // pres_hse_x
807 
808  if (containerHasElement(plot_var_names, "pres_hse_y"))
809  {
810  auto dxInv = geom[lev].InvCellSizeArray();
811 #ifdef _OPENMP
812 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
813 #endif
814  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
815  {
816  const Box& bx = mfi.tilebox();
817  const Array4<Real >& derdat = mf[lev].array(mfi);
818  const Array4<Real const>& p_arr = p_hse.const_array(mfi);
819  const Array4<Real const>& z_nd = z_phys_nd[lev]->const_array(mfi);
820  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
821  Real met_h_eta_lo = Compute_h_eta_AtJface (i, j, k, dxInv, z_nd);
822  Real met_h_zeta_lo = Compute_h_zeta_AtJface(i, j, k, dxInv, z_nd);
823  Real gp_eta_lo = dxInv[1] * (p_arr(i,j,k) - p_arr(i,j-1,k));
824  Real gp_zeta_on_jface_lo;
825  if (k == klo) {
826  gp_zeta_on_jface_lo = 0.5 * dxInv[2] * (
827  p_arr(i,j,k+1) + p_arr(i,j-1,k+1)
828  - p_arr(i,j,k ) - p_arr(i,j-1,k ) );
829  } else if (k == khi) {
830  gp_zeta_on_jface_lo = 0.5 * dxInv[2] * (
831  p_arr(i,j,k ) + p_arr(i,j-1,k )
832  - p_arr(i,j,k-1) - p_arr(i,j-1,k-1) );
833  } else {
834  gp_zeta_on_jface_lo = 0.25 * dxInv[2] * (
835  p_arr(i,j,k+1) + p_arr(i,j-1,k+1)
836  - p_arr(i,j,k-1) - p_arr(i,j-1,k-1) );
837  }
838  Real gpy_lo = gp_eta_lo - (met_h_eta_lo / met_h_zeta_lo) * gp_zeta_on_jface_lo;
839 
840  Real met_h_eta_hi = Compute_h_eta_AtJface (i, j+1, k, dxInv, z_nd);
841  Real met_h_zeta_hi = Compute_h_zeta_AtJface(i, j+1, k, dxInv, z_nd);
842  Real gp_eta_hi = dxInv[1] * (p_arr(i,j+1,k) - p_arr(i,j,k));
843  Real gp_zeta_on_jface_hi;
844  if (k == klo) {
845  gp_zeta_on_jface_hi = 0.5 * dxInv[2] * (
846  p_arr(i,j+1,k+1) + p_arr(i,j,k+1)
847  - p_arr(i,j+1,k ) - p_arr(i,j,k ) );
848  } else if (k == khi) {
849  gp_zeta_on_jface_hi = 0.5 * dxInv[2] * (
850  p_arr(i,j+1,k ) + p_arr(i,j,k )
851  - p_arr(i,j+1,k-1) - p_arr(i,j,k-1) );
852  } else {
853  gp_zeta_on_jface_hi = 0.25 * dxInv[2] * (
854  p_arr(i,j+1,k+1) + p_arr(i,j,k+1)
855  - p_arr(i,j+1,k-1) - p_arr(i,j,k-1) );
856  }
857  Real gpy_hi = gp_eta_hi - (met_h_eta_hi / met_h_zeta_hi) * gp_zeta_on_jface_hi;
858 
859  derdat(i ,j ,k, mf_comp) = 0.5 * (gpy_lo + gpy_hi);
860  });
861  }
862  mf_comp += 1;
863  } // pres_hse_y
864 
865  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
866  if (containerHasElement(plot_var_names, "z_phys"))
867  {
868  MultiFab::Copy(mf[lev],*z_phys_cc[lev],0,mf_comp,1,0);
869  mf_comp ++;
870  }
871 
872  if (containerHasElement(plot_var_names, "detJ"))
873  {
874  MultiFab::Copy(mf[lev],*detJ_cc[lev],0,mf_comp,1,0);
875  mf_comp ++;
876  }
877  } // use_terrain
878 
879  if (containerHasElement(plot_var_names, "mapfac")) {
880 #ifdef _OPENMP
881 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
882 #endif
883  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
884  {
885  const Box& bx = mfi.tilebox();
886  const Array4<Real>& derdat = mf[lev].array(mfi);
887  const Array4<Real>& mf_m = mapfac_m[lev]->array(mfi);
888  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
889  derdat(i ,j ,k, mf_comp) = mf_m(i,j,0);
890  });
891  }
892  mf_comp ++;
893  }
894 
895 #ifdef ERF_USE_NETCDF
896  if (use_real_bcs) {
897  if (containerHasElement(plot_var_names, "lat_m")) {
898 #ifdef _OPENMP
899 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
900 #endif
901  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
902  {
903  const Box& bx = mfi.tilebox();
904  const Array4<Real>& derdat = mf[lev].array(mfi);
905  const Array4<Real>& data = lat_m[lev]->array(mfi);
906  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
907  derdat(i, j, k, mf_comp) = data(i,j,0);
908  });
909  }
910  mf_comp ++;
911  } // lat_m
912  if (containerHasElement(plot_var_names, "lon_m")) {
913 #ifdef _OPENMP
914 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
915 #endif
916  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
917  {
918  const Box& bx = mfi.tilebox();
919  const Array4<Real>& derdat = mf[lev].array(mfi);
920  const Array4<Real>& data = lon_m[lev]->array(mfi);
921  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
922  derdat(i, j, k, mf_comp) = data(i,j,0);
923  });
924  }
925  mf_comp ++;
926  } // lon_m
927  } // use_real_bcs
928 #endif
929 
930 
932  if (containerHasElement(plot_var_names, "u_t_avg")) {
933 #ifdef _OPENMP
934 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
935 #endif
936  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
937  {
938  const Box& bx = mfi.tilebox();
939  const Array4<Real>& derdat = mf[lev].array(mfi);
940  const Array4<Real>& data = vel_t_avg[lev]->array(mfi);
941  const Real norm = t_avg_cnt[lev];
942  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
943  {
944  derdat(i ,j ,k, mf_comp) = data(i,j,k,0) / norm;
945  });
946  }
947  mf_comp ++;
948  }
949 
950  if (containerHasElement(plot_var_names, "v_t_avg")) {
951 #ifdef _OPENMP
952 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
953 #endif
954  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
955  {
956  const Box& bx = mfi.tilebox();
957  const Array4<Real>& derdat = mf[lev].array(mfi);
958  const Array4<Real>& data = vel_t_avg[lev]->array(mfi);
959  const Real norm = t_avg_cnt[lev];
960  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
961  {
962  derdat(i ,j ,k, mf_comp) = data(i,j,k,1) / norm;
963  });
964  }
965  mf_comp ++;
966  }
967 
968  if (containerHasElement(plot_var_names, "w_t_avg")) {
969 #ifdef _OPENMP
970 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
971 #endif
972  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
973  {
974  const Box& bx = mfi.tilebox();
975  const Array4<Real>& derdat = mf[lev].array(mfi);
976  const Array4<Real>& data = vel_t_avg[lev]->array(mfi);
977  const Real norm = t_avg_cnt[lev];
978  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
979  {
980  derdat(i ,j ,k, mf_comp) = data(i,j,k,2) / norm;
981  });
982  }
983  mf_comp ++;
984  }
985 
986  if (containerHasElement(plot_var_names, "umag_t_avg")) {
987 #ifdef _OPENMP
988 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
989 #endif
990  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
991  {
992  const Box& bx = mfi.tilebox();
993  const Array4<Real>& derdat = mf[lev].array(mfi);
994  const Array4<Real>& data = vel_t_avg[lev]->array(mfi);
995  const Real norm = t_avg_cnt[lev];
996  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
997  {
998  derdat(i ,j ,k, mf_comp) = data(i,j,k,3) / norm;
999  });
1000  }
1001  mf_comp ++;
1002  }
1003  }
1004 
1005  if (containerHasElement(plot_var_names, "nut")) {
1006  MultiFab dmf(mf[lev], make_alias, mf_comp, 1);
1007  MultiFab cmf(vars_new[lev][Vars::cons], make_alias, 0, 1); // to provide rho only
1008 #ifdef _OPENMP
1009 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
1010 #endif
1011  for (MFIter mfi(dmf, TilingIfNotGPU()); mfi.isValid(); ++mfi)
1012  {
1013  const Box& bx = mfi.tilebox();
1014  auto prim = dmf[mfi].array();
1015  auto const cons = cmf[mfi].const_array();
1016  auto const diff = (*eddyDiffs_lev[lev])[mfi].const_array();
1017  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
1018  {
1019  const Real rho = cons(i, j, k, Rho_comp);
1020  const Real Kmv = diff(i, j, k, EddyDiff::Mom_v);
1021  prim(i,j,k) = Kmv / rho;
1022  });
1023  }
1024 
1025  mf_comp++;
1026  }
1027 
1028  if (containerHasElement(plot_var_names, "Kmv")) {
1029  MultiFab::Copy(mf[lev],*eddyDiffs_lev[lev],EddyDiff::Mom_v,mf_comp,1,0);
1030  mf_comp ++;
1031  }
1032  if (containerHasElement(plot_var_names, "Kmh")) {
1033  MultiFab::Copy(mf[lev],*eddyDiffs_lev[lev],EddyDiff::Mom_h,mf_comp,1,0);
1034  mf_comp ++;
1035  }
1036  if (containerHasElement(plot_var_names, "Khv")) {
1037  MultiFab::Copy(mf[lev],*eddyDiffs_lev[lev],EddyDiff::Theta_v,mf_comp,1,0);
1038  mf_comp ++;
1039  }
1040  if (containerHasElement(plot_var_names, "Khh")) {
1041  MultiFab::Copy(mf[lev],*eddyDiffs_lev[lev],EddyDiff::Theta_h,mf_comp,1,0);
1042  mf_comp ++;
1043  }
1044  if (containerHasElement(plot_var_names, "Lturb")) {
1045  MultiFab::Copy(mf[lev],*eddyDiffs_lev[lev],EddyDiff::Turb_lengthscale,mf_comp,1,0);
1046  mf_comp ++;
1047  }
1048  if (containerHasElement(plot_var_names, "walldist")) {
1049  MultiFab::Copy(mf[lev],*walldist[lev],0,mf_comp,1,0);
1050  mf_comp ++;
1051  }
1052 
1053  // TODO: The size of the q variables can vary with different
1054  // moisture models. Therefore, certain components may
1055  // reside at different indices. For example, Kessler is
1056  // warm but precipitating. This puts qp at index 3.
1057  // However, SAM is cold and precipitating so qp is index 4.
1058  // Need to built an external enum struct or a better pathway.
1059 
1060  // NOTE: Protect against accessing non-existent data
1061  if (use_moisture) {
1062  int n_qstate = micro->Get_Qstate_Size();
1063 
1064  // Non-precipitating components
1065  //--------------------------------------------------------------------------
1066  if(containerHasElement(plot_var_names, "qt"))
1067  {
1068  int n_start = RhoQ1_comp; // qv
1069  int n_end = RhoQ2_comp; // qc
1070  if (n_qstate > 3) n_end = RhoQ3_comp; // qi
1071  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], n_start, mf_comp, 1, 0);
1072  for (int n_comp(n_start+1); n_comp <= n_end; ++n_comp) {
1073  MultiFab::Add(mf[lev], vars_new[lev][Vars::cons], n_comp, mf_comp, 1, 0);
1074  }
1075  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp , mf_comp, 1, 0);
1076  mf_comp += 1;
1077  }
1078 
1079  if(containerHasElement(plot_var_names, "qv") && (n_qstate >= 1))
1080  {
1081  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], RhoQ1_comp, mf_comp, 1, 0);
1082  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp , mf_comp, 1, 0);
1083  mf_comp += 1;
1084  }
1085 
1086  if(containerHasElement(plot_var_names, "qc") && (n_qstate >= 2))
1087  {
1088  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], RhoQ2_comp, mf_comp, 1, 0);
1089  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp , mf_comp, 1, 0);
1090  mf_comp += 1;
1091  }
1092 
1093  if(containerHasElement(plot_var_names, "qi") && (n_qstate >= 4))
1094  {
1095  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], RhoQ3_comp, mf_comp, 1, 0);
1096  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp , mf_comp, 1, 0);
1097  mf_comp += 1;
1098  }
1099 
1100  // Precipitating components
1101  //--------------------------------------------------------------------------
1102  if(containerHasElement(plot_var_names, "qp") && (n_qstate >= 3))
1103  {
1104  int n_start = (n_qstate > 3) ? RhoQ4_comp : RhoQ3_comp;
1105  int n_end = ncomp_cons - 1;
1106  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], n_start, mf_comp, 1, 0);
1107  for (int n_comp(n_start+1); n_comp <= n_end; ++n_comp) {
1108  MultiFab::Add( mf[lev], vars_new[lev][Vars::cons], n_comp, mf_comp, 1, 0);
1109  }
1110  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp , mf_comp, 1, 0);
1111  mf_comp += 1;
1112  }
1113 
1114  if(containerHasElement(plot_var_names, "qrain") && (n_qstate >= 3))
1115  {
1116  int n_start = (n_qstate > 3) ? RhoQ4_comp : RhoQ3_comp;
1117  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], n_start , mf_comp, 1, 0);
1118  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp, mf_comp, 1, 0);
1119  mf_comp += 1;
1120  }
1121 
1122  if(containerHasElement(plot_var_names, "qsnow") && (n_qstate >= 5))
1123  {
1124  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], RhoQ5_comp, mf_comp, 1, 0);
1125  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp, mf_comp, 1, 0);
1126  mf_comp += 1;
1127  }
1128 
1129  if(containerHasElement(plot_var_names, "qgraup") && (n_qstate >= 6))
1130  {
1131  MultiFab::Copy( mf[lev], vars_new[lev][Vars::cons], RhoQ6_comp, mf_comp, 1, 0);
1132  MultiFab::Divide(mf[lev], vars_new[lev][Vars::cons], Rho_comp, mf_comp, 1, 0);
1133  mf_comp += 1;
1134  }
1135 
1136  if (containerHasElement(plot_var_names, "qsat"))
1137  {
1138 #ifdef _OPENMP
1139 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
1140 #endif
1141  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
1142  {
1143  const Box& bx = mfi.tilebox();
1144  const Array4<Real>& derdat = mf[lev].array(mfi);
1145  const Array4<Real const>& S_arr = vars_new[lev][Vars::cons].const_array(mfi);
1146  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
1147  {
1148  Real qv = S_arr(i,j,k,RhoQ1_comp) / S_arr(i,j,k,Rho_comp);
1149  Real T = getTgivenRandRTh(S_arr(i,j,k,Rho_comp), S_arr(i,j,k,RhoTheta_comp), qv);
1150  Real pressure = getPgivenRTh(S_arr(i,j,k,RhoTheta_comp), qv) * Real(0.01);
1151  erf_qsatw(T, pressure, derdat(i,j,k,mf_comp));
1152  });
1153  }
1154  mf_comp ++;
1155  }
1156 
1157  if(solverChoice.moisture_type == MoistureType::Kessler){
1158  if (containerHasElement(plot_var_names, "rain_accum"))
1159  {
1160  MultiFab::Copy(mf[lev],*(qmoist[lev][4]),0,mf_comp,1,0);
1161  mf_comp += 1;
1162  }
1163  }
1164  else if(solverChoice.moisture_type == MoistureType::SAM)
1165  {
1166  if (containerHasElement(plot_var_names, "rain_accum"))
1167  {
1168  MultiFab::Copy(mf[lev],*(qmoist[lev][8]),0,mf_comp,1,0);
1169  mf_comp += 1;
1170  }
1171  if (containerHasElement(plot_var_names, "snow_accum"))
1172  {
1173  MultiFab::Copy(mf[lev],*(qmoist[lev][9]),0,mf_comp,1,0);
1174  mf_comp += 1;
1175  }
1176  if (containerHasElement(plot_var_names, "graup_accum"))
1177  {
1178  MultiFab::Copy(mf[lev],*(qmoist[lev][10]),0,mf_comp,1,0);
1179  mf_comp += 1;
1180  }
1181  }
1182  }
1183 
1184 #ifdef ERF_USE_PARTICLES
1185  const auto& particles_namelist( particleData.getNames() );
1186  for (ParticlesNamesVector::size_type i = 0; i < particles_namelist.size(); i++) {
1187  if (containerHasElement(plot_var_names, std::string(particles_namelist[i]+"_count"))) {
1188  MultiFab temp_dat(mf[lev].boxArray(), mf[lev].DistributionMap(), 1, 0);
1189  temp_dat.setVal(0);
1190  particleData[particles_namelist[i]]->Increment(temp_dat, lev);
1191  MultiFab::Copy(mf[lev], temp_dat, 0, mf_comp, 1, 0);
1192  mf_comp += 1;
1193  }
1194  }
1195 
1196  Vector<std::string> particle_mesh_plot_names(0);
1197  particleData.GetMeshPlotVarNames( particle_mesh_plot_names );
1198  for (int i = 0; i < particle_mesh_plot_names.size(); i++) {
1199  std::string plot_var_name(particle_mesh_plot_names[i]);
1200  if (containerHasElement(plot_var_names, plot_var_name) ) {
1201  MultiFab temp_dat(mf[lev].boxArray(), mf[lev].DistributionMap(), 1, 1);
1202  temp_dat.setVal(0);
1203  particleData.GetMeshPlotVar(plot_var_name, temp_dat, lev);
1204  MultiFab::Copy(mf[lev], temp_dat, 0, mf_comp, 1, 0);
1205  mf_comp += 1;
1206  }
1207  }
1208 #endif
1209 
1210 #ifdef ERF_USE_EB
1211  if (containerHasElement(plot_var_names, "volfrac")) {
1212  MultiFab::Copy(mf[lev], EBFactory(lev).getVolFrac(), 0, mf_comp, 1, 0);
1213  mf_comp += 1;
1214  }
1215 #endif
1216 
1217 #ifdef ERF_COMPUTE_ERROR
1218  // Next, check for error in velocities and if desired, output them -- note we output none or all, not just some
1219  if (containerHasElement(plot_var_names, "xvel_err") ||
1220  containerHasElement(plot_var_names, "yvel_err") ||
1221  containerHasElement(plot_var_names, "zvel_err"))
1222  {
1223  //
1224  // Moving terrain ANALYTICAL
1225  //
1226  Real H = geom[lev].ProbHi()[2];
1227  Real Ampl = 0.16;
1228  Real wavelength = 100.;
1229  Real kp = 2. * PI / wavelength;
1230  Real g = CONST_GRAV;
1231  Real omega = std::sqrt(g * kp);
1232  Real omega_t = omega * t_new[lev];
1233 
1234  const auto dx = geom[lev].CellSizeArray();
1235 
1236 #ifdef _OPENMP
1237 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
1238 #endif
1239  for (MFIter mfi(mf[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi)
1240  {
1241  const Box& bx = mfi.validbox();
1242  Box xbx(bx); xbx.surroundingNodes(0);
1243  const Array4<Real> xvel_arr = vars_new[lev][Vars::xvel].array(mfi);
1244  const Array4<Real> zvel_arr = vars_new[lev][Vars::zvel].array(mfi);
1245 
1246  const Array4<Real const>& z_nd = z_phys_nd[lev]->const_array(mfi);
1247 
1248  ParallelFor(xbx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
1249  {
1250  Real x = i * dx[0];
1251  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));
1252 
1253  Real z_base = Ampl * std::sin(kp * x - omega_t);
1254  z -= z_base;
1255 
1256  Real fac = std::cosh( kp * (z - H) ) / std::sinh(kp * H);
1257 
1258  xvel_arr(i,j,k) -= -Ampl * omega * fac * std::sin(kp * x - omega_t);
1259  });
1260 
1261  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
1262  {
1263  Real x = (i + 0.5) * dx[0];
1264  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));
1265 
1266  Real z_base = Ampl * std::sin(kp * x - omega_t);
1267  z -= z_base;
1268 
1269  Real fac = std::sinh( kp * (z - H) ) / std::sinh(kp * H);
1270 
1271  zvel_arr(i,j,k) -= Ampl * omega * fac * std::cos(kp * x - omega_t);
1272  });
1273  }
1274 
1275  MultiFab temp_mf(mf[lev].boxArray(), mf[lev].DistributionMap(), AMREX_SPACEDIM, 0);
1276  average_face_to_cellcenter(temp_mf,0,
1277  Array<const MultiFab*,3>{&vars_new[lev][Vars::xvel],&vars_new[lev][Vars::yvel],&vars_new[lev][Vars::zvel]});
1278 
1279  if (containerHasElement(plot_var_names, "xvel_err")) {
1280  MultiFab::Copy(mf[lev],temp_mf,0,mf_comp,1,0);
1281  mf_comp += 1;
1282  }
1283  if (containerHasElement(plot_var_names, "yvel_err")) {
1284  MultiFab::Copy(mf[lev],temp_mf,1,mf_comp,1,0);
1285  mf_comp += 1;
1286  }
1287  if (containerHasElement(plot_var_names, "zvel_err")) {
1288  MultiFab::Copy(mf[lev],temp_mf,2,mf_comp,1,0);
1289  mf_comp += 1;
1290  }
1291 
1292  // Now restore the velocities to what they were
1293 #ifdef _OPENMP
1294 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
1295 #endif
1296  for (MFIter mfi(mf[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi)
1297  {
1298  const Box& bx = mfi.validbox();
1299  Box xbx(bx); xbx.surroundingNodes(0);
1300 
1301  const Array4<Real> xvel_arr = vars_new[lev][Vars::xvel].array(mfi);
1302  const Array4<Real> zvel_arr = vars_new[lev][Vars::zvel].array(mfi);
1303 
1304  const Array4<Real const>& z_nd = z_phys_nd[lev]->const_array(mfi);
1305 
1306  ParallelFor(xbx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
1307  {
1308  Real x = i * dx[0];
1309  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));
1310  Real z_base = Ampl * std::sin(kp * x - omega_t);
1311 
1312  z -= z_base;
1313 
1314  Real fac = std::cosh( kp * (z - H) ) / std::sinh(kp * H);
1315  xvel_arr(i,j,k) += -Ampl * omega * fac * std::sin(kp * x - omega_t);
1316  });
1317  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
1318  {
1319  Real x = (i + 0.5) * dx[0];
1320  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));
1321  Real z_base = Ampl * std::sin(kp * x - omega_t);
1322 
1323  z -= z_base;
1324  Real fac = std::sinh( kp * (z - H) ) / std::sinh(kp * H);
1325 
1326  zvel_arr(i,j,k) += Ampl * omega * fac * std::cos(kp * x - omega_t);
1327  });
1328  }
1329  } // end xvel_err, yvel_err, zvel_err
1330 
1331  if (containerHasElement(plot_var_names, "pp_err"))
1332  {
1333  // Moving terrain ANALYTICAL
1334 #ifdef _OPENMP
1335 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
1336 #endif
1337  for ( MFIter mfi(mf[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
1338  {
1339  const Box& bx = mfi.tilebox();
1340  const Array4<Real>& derdat = mf[lev].array(mfi);
1341  const Array4<Real const>& p0_arr = p_hse.const_array(mfi);
1342  const Array4<Real const>& S_arr = vars_new[lev][Vars::cons].const_array(mfi);
1343 
1344  const auto dx = geom[lev].CellSizeArray();
1345  const Array4<Real const>& z_nd = z_phys_nd[lev]->const_array(mfi);
1346  const Array4<Real const>& r0_arr = r_hse.const_array(mfi);
1347 
1348  Real H = geom[lev].ProbHi()[2];
1349  Real Ampl = 0.16;
1350  Real wavelength = 100.;
1351  Real kp = 2. * PI / wavelength;
1352  Real g = CONST_GRAV;
1353  Real omega = std::sqrt(g * kp);
1354  Real omega_t = omega * t_new[lev];
1355 
1356  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
1357  {
1358  const Real rhotheta = S_arr(i,j,k,RhoTheta_comp);
1359  derdat(i, j, k, mf_comp) = getPgivenRTh(rhotheta) - p0_arr(i,j,k);
1360 
1361  Real rho_hse = r0_arr(i,j,k);
1362 
1363  Real x = (i + 0.5) * dx[0];
1364  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 )
1365  +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) );
1366  Real z_base = Ampl * std::sin(kp * x - omega_t);
1367 
1368  z -= z_base;
1369  Real fac = std::cosh( kp * (z - H) ) / std::sinh(kp * H);
1370  Real pprime_exact = -(Ampl * omega * omega / kp) * fac *
1371  std::sin(kp * x - omega_t) * r0_arr(i,j,k);
1372 
1373  derdat(i,j,k,mf_comp) -= pprime_exact;
1374  });
1375  }
1376  mf_comp += 1;
1377  }
1378 #endif
1379 
1380 #ifdef ERF_USE_RRTMGP
1381  if (containerHasElement(plot_var_names, "qsrc_sw")) {
1382  MultiFab::Copy(mf[lev], *(qheating_rates[lev]), 0, mf_comp, 1, 0);
1383  mf_comp += 1;
1384  }
1385  if (containerHasElement(plot_var_names, "qsrc_lw")) {
1386  MultiFab::Copy(mf[lev], *(qheating_rates[lev]), 1, mf_comp, 1, 0);
1387  mf_comp += 1;
1388  }
1389 #endif
1390  }
1391 
1392 #ifdef ERF_USE_EB
1393  for (int lev = 0; lev <= finest_level; ++lev) {
1394  EB_set_covered(mf[lev], 0.0);
1395  }
1396 #endif
1397 
1398  // Fill terrain distortion MF
1399  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
1400  for (int lev(0); lev <= finest_level; ++lev) {
1401  MultiFab::Copy(mf_nd[lev],*z_phys_nd[lev],0,2,1,0);
1402  Real dz = Geom()[lev].CellSizeArray()[2];
1403  for (MFIter mfi(mf_nd[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
1404  const Box& bx = mfi.tilebox();
1405  Array4< Real> mf_arr = mf_nd[lev].array(mfi);
1406  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
1407  mf_arr(i,j,k,2) -= k * dz;
1408  });
1409  }
1410  }
1411  }
1412 
1413  std::string plotfilename;
1414  std::string plotfilenameU;
1415  std::string plotfilenameV;
1416  std::string plotfilenameW;
1417  if (which == 1) {
1418  plotfilename = Concatenate(plot_file_1, istep[0], 5);
1419  plotfilenameU = Concatenate(plot_file_1+"U", istep[0], 5);
1420  plotfilenameV = Concatenate(plot_file_1+"V", istep[0], 5);
1421  plotfilenameW = Concatenate(plot_file_1+"W", istep[0], 5);
1422  } else if (which == 2) {
1423  plotfilename = Concatenate(plot_file_2, istep[0], 5);
1424  plotfilenameU = Concatenate(plot_file_2+"U", istep[0], 5);
1425  plotfilenameV = Concatenate(plot_file_2+"V", istep[0], 5);
1426  plotfilenameW = Concatenate(plot_file_2+"W", istep[0], 5);
1427  }
1428 
1429  // LSM writes it's own data
1430  if (which==1 && plot_lsm) {
1431  lsm.Plot_Lsm_Data(t_new[0], istep, refRatio());
1432  }
1433 
1434 #ifdef ERF_USE_RRTMGP
1435  // write additional RRTMGP data
1436  // TODO: currently single level only
1437  if (which==1 && plot_rad) {
1438  rad.writePlotfile(plot_file_1, t_new[0], istep[0]);
1439  }
1440 #endif
1441 
1442  // Single level
1443  if (finest_level == 0)
1444  {
1445  if (plotfile_type == PlotFileType::Amrex)
1446  {
1447  Print() << "Writing native plotfile " << plotfilename << "\n";
1448  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
1449  WriteMultiLevelPlotfileWithTerrain(plotfilename, finest_level+1,
1450  GetVecOfConstPtrs(mf),
1451  GetVecOfConstPtrs(mf_nd),
1452  varnames,
1453  Geom(), t_new[0], istep, refRatio());
1454  } else {
1455  WriteMultiLevelPlotfile(plotfilename, finest_level+1,
1456  GetVecOfConstPtrs(mf),
1457  varnames,
1458  Geom(), t_new[0], istep, refRatio());
1459  }
1460  writeJobInfo(plotfilename);
1461 
1462  if (m_plot_face_vels) {
1463  Print() << "Writing face velocities" << std::endl;
1464  WriteMultiLevelPlotfile(plotfilenameU, finest_level+1,
1465  GetVecOfConstPtrs(mf_u),
1466  {"x_velocity_stag"},
1467  Geom(), t_new[0], istep, refRatio());
1468  WriteMultiLevelPlotfile(plotfilenameV, finest_level+1,
1469  GetVecOfConstPtrs(mf_v),
1470  {"y_velocity_stag"},
1471  Geom(), t_new[0], istep, refRatio());
1472  WriteMultiLevelPlotfile(plotfilenameW, finest_level+1,
1473  GetVecOfConstPtrs(mf_w),
1474  {"z_velocity_stag"},
1475  Geom(), t_new[0], istep, refRatio());
1476  }
1477 
1478 #ifdef ERF_USE_PARTICLES
1479  particleData.writePlotFile(plotfilename);
1480 #endif
1481 #ifdef ERF_USE_NETCDF
1482  } else if (plotfile_type == PlotFileType::Netcdf) {
1483  int lev = 0;
1484  int l_which = 0;
1485  writeNCPlotFile(lev, l_which, plotfilename, GetVecOfConstPtrs(mf), varnames, istep, t_new[0]);
1486 #endif
1487  } else {
1488  // Here we assume the plotfile_type is PlotFileType::None
1489  Print() << "Writing no plotfile since plotfile_type is none" << std::endl;
1490  }
1491 
1492  } else { // Multilevel
1493 
1494  if (plotfile_type == PlotFileType::Amrex) {
1495 
1496  int lev0 = 0;
1497  int desired_ratio = std::max(std::max(ref_ratio[lev0][0],ref_ratio[lev0][1]),ref_ratio[lev0][2]);
1498  bool any_ratio_one = ( ( (ref_ratio[lev0][0] == 1) || (ref_ratio[lev0][1] == 1) ) ||
1499  (ref_ratio[lev0][2] == 1) );
1500  for (int lev = 1; lev < finest_level; lev++) {
1501  any_ratio_one = any_ratio_one ||
1502  ( ( (ref_ratio[lev][0] == 1) || (ref_ratio[lev][1] == 1) ) ||
1503  (ref_ratio[lev][2] == 1) );
1504  }
1505 
1506  if (any_ratio_one && m_expand_plotvars_to_unif_rr)
1507  {
1508  Vector<IntVect> r2(finest_level);
1509  Vector<Geometry> g2(finest_level+1);
1510  Vector<MultiFab> mf2(finest_level+1);
1511 
1512  mf2[0].define(grids[0], dmap[0], ncomp_mf, 0);
1513 
1514  // Copy level 0 as is
1515  MultiFab::Copy(mf2[0],mf[0],0,0,mf[0].nComp(),0);
1516 
1517  // Define a new multi-level array of Geometry's so that we pass the new "domain" at lev > 0
1518  Array<int,AMREX_SPACEDIM> periodicity =
1519  {Geom()[lev0].isPeriodic(0),Geom()[lev0].isPeriodic(1),Geom()[lev0].isPeriodic(2)};
1520  g2[lev0].define(Geom()[lev0].Domain(),&(Geom()[lev0].ProbDomain()),0,periodicity.data());
1521 
1522  r2[0] = IntVect(desired_ratio/ref_ratio[lev0][0],
1523  desired_ratio/ref_ratio[lev0][1],
1524  desired_ratio/ref_ratio[lev0][2]);
1525 
1526  for (int lev = 1; lev <= finest_level; ++lev) {
1527  if (lev > 1) {
1528  r2[lev-1][0] = r2[lev-2][0] * desired_ratio / ref_ratio[lev-1][0];
1529  r2[lev-1][1] = r2[lev-2][1] * desired_ratio / ref_ratio[lev-1][1];
1530  r2[lev-1][2] = r2[lev-2][2] * desired_ratio / ref_ratio[lev-1][2];
1531  }
1532 
1533  mf2[lev].define(refine(grids[lev],r2[lev-1]), dmap[lev], ncomp_mf, 0);
1534 
1535  // Set the new problem domain
1536  Box d2(Geom()[lev].Domain());
1537  d2.refine(r2[lev-1]);
1538 
1539  g2[lev].define(d2,&(Geom()[lev].ProbDomain()),0,periodicity.data());
1540  }
1541 
1542  // Do piecewise interpolation of mf into mf2
1543  for (int lev = 1; lev <= finest_level; ++lev) {
1544  Interpolater* mapper_c = &pc_interp;
1545  InterpFromCoarseLevel(mf2[lev], t_new[lev], mf[lev],
1546  0, 0, ncomp_mf,
1547  geom[lev], g2[lev],
1549  r2[lev-1], mapper_c, domain_bcs_type, 0);
1550  }
1551 
1552  // Define an effective ref_ratio which is isotropic to be passed into WriteMultiLevelPlotfile
1553  Vector<IntVect> rr(finest_level);
1554  for (int lev = 0; lev < finest_level; ++lev) {
1555  rr[lev] = IntVect(desired_ratio);
1556  }
1557 
1558  Print() << "Writing plotfile " << plotfilename << "\n";
1559  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
1560  WriteMultiLevelPlotfileWithTerrain(plotfilename, finest_level+1,
1561  GetVecOfConstPtrs(mf2),
1562  GetVecOfConstPtrs(mf_nd),
1563  varnames,
1564  g2, t_new[0], istep, rr);
1565  } else {
1566  WriteMultiLevelPlotfile(plotfilename, finest_level+1,
1567  GetVecOfConstPtrs(mf2), varnames,
1568  g2, t_new[0], istep, rr);
1569  }
1570 
1571  } else {
1572  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
1573  WriteMultiLevelPlotfileWithTerrain(plotfilename, finest_level+1,
1574  GetVecOfConstPtrs(mf),
1575  GetVecOfConstPtrs(mf_nd),
1576  varnames,
1577  geom, t_new[0], istep, ref_ratio);
1578  } else {
1579  WriteMultiLevelPlotfile(plotfilename, finest_level+1,
1580  GetVecOfConstPtrs(mf), varnames,
1581  geom, t_new[0], istep, ref_ratio);
1582  }
1583  if (m_plot_face_vels) {
1584  Print() << "Writing face velocities" << std::endl;
1585  WriteMultiLevelPlotfile(plotfilenameU, finest_level+1,
1586  GetVecOfConstPtrs(mf_u),
1587  {"x_velocity_stag"},
1588  geom, t_new[0], istep, ref_ratio);
1589  WriteMultiLevelPlotfile(plotfilenameV, finest_level+1,
1590  GetVecOfConstPtrs(mf_v),
1591  {"y_velocity_stag"},
1592  geom, t_new[0], istep, ref_ratio);
1593  WriteMultiLevelPlotfile(plotfilenameW, finest_level+1,
1594  GetVecOfConstPtrs(mf_w),
1595  {"z_velocity_stag"},
1596  geom, t_new[0], istep, ref_ratio);
1597  }
1598  } // ref_ratio test
1599 
1600  writeJobInfo(plotfilename);
1601 
1602 #ifdef ERF_USE_PARTICLES
1603  particleData.writePlotFile(plotfilename);
1604 #endif
1605 
1606 #ifdef ERF_USE_NETCDF
1607  } else if (plotfile_type == PlotFileType::Netcdf) {
1608  for (int lev = 0; lev <= finest_level; ++lev) {
1609  for (int which_box = 0; which_box < num_boxes_at_level[lev]; which_box++) {
1610  writeNCPlotFile(lev, which_box, plotfilename, GetVecOfConstPtrs(mf), varnames, istep, t_new[0]);
1611  }
1612  }
1613 #endif
1614  }
1615  } // end multi-level
1616 }
constexpr amrex::Real Cp_d
Definition: ERF_Constants.H:12
constexpr amrex::Real PI
Definition: ERF_Constants.H:6
constexpr amrex::Real CONST_GRAV
Definition: ERF_Constants.H:21
constexpr amrex::Real Cp_l
Definition: ERF_Constants.H:14
constexpr amrex::Real R_d
Definition: ERF_Constants.H:10
constexpr amrex::Real L_v
Definition: ERF_Constants.H:16
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
#define RhoQ4_comp
Definition: ERF_IndexDefines.H:45
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_esatw(amrex::Real t)
Definition: ERF_MicrophysicsUtils.H:64
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void erf_qsatw(amrex::Real t, amrex::Real p, amrex::Real &qsatw)
Definition: ERF_MicrophysicsUtils.H:158
PhysBCFunctNoOp null_bc_for_fill
Definition: ERF_Plotfile.cpp:9
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:101
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:87
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:130
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:158
void FillBdyCCVels(amrex::Vector< amrex::MultiFab > &mf_cc_vel)
Definition: ERF_FillBdyCCVels.cpp:11
static amrex::Vector< std::string > PlotFileVarNames(amrex::Vector< std::string > plot_var_names)
Definition: ERF_Plotfile.cpp:174
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:1619
void writeJobInfo(const std::string &dir) const
Definition: ERF_WriteJobInfo.cpp:9
void Plot_Lsm_Data(amrex::Real time, const amrex::Vector< int > &level_steps, const amrex::Vector< amrex::IntVect > &ref_ratio)
Definition: ERF_LandSurface.H:84
@ Turb_lengthscale
Definition: ERF_IndexDefines.H:161
@ Mom_h
Definition: ERF_IndexDefines.H:151
@ Theta_h
Definition: ERF_IndexDefines.H:152
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_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:284
void erf_dernull(const Box &, FArrayBox &, int, int, const FArrayBox &, const Geometry &, Real, const int *, const int)
Definition: ERF_Derive.cpp:39
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_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
Here is the call graph for this function:

Member Data Documentation

◆ advflux_reg

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

Referenced by getAdvFluxReg().

◆ ax

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

◆ ax_new

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

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

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

◆ az_src

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

std::string ERF::check_type {"native"}
private

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

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

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

◆ d_rhotheta_src

amrex::Vector<amrex::Gpu::DeviceVector<amrex::Real> > ERF::d_rhotheta_src
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

◆ data_sampler

std::unique_ptr<SampleData> ERF::data_sampler = nullptr
private

◆ datalog

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

◆ datalogname

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

Referenced by DataLogName().

◆ derived_names

const amrex::Vector<std::string> ERF::derived_names
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_mri_ratio

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

◆ dz_min

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

◆ eddyDiffs_lev

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

◆ fine_mask

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

◆ 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

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

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

◆ h_rhotheta_src

amrex::Vector< amrex::Vector<amrex::Real> > ERF::h_rhotheta_src
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

◆ 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

◆ init_sounding_ideal

bool ERF::init_sounding_ideal = false
staticprivate

◆ init_type

InitType ERF::init_type
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

◆ last_check_file_step

int ERF::last_check_file_step
private

◆ last_plot_file_step_1

int ERF::last_plot_file_step_1
private

◆ last_plot_file_step_2

int ERF::last_plot_file_step_2
private

◆ lmask_lev

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

◆ lsm

LandSurface ERF::lsm
private

◆ lsm_data

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

◆ lsm_flux

amrex::Vector<amrex::Vector<amrex::MultiFab*> > ERF::lsm_flux
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_factory

amrex::Vector<std::unique_ptr<amrex::FabFactory<amrex::FArrayBox> > > ERF::m_factory
private

◆ m_forest_drag

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

◆ m_most

std::unique_ptr<ABLMost> ERF::m_most = nullptr
private

◆ m_plot_face_vels

bool ERF::m_plot_face_vels = false
private

◆ m_plot_int_1

int ERF::m_plot_int_1 = -1
private

◆ m_plot_int_2

int ERF::m_plot_int_2 = -1
private

◆ m_plot_per_1

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

◆ m_plot_per_2

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

◆ m_r2d

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

◆ m_terrain_drag

amrex::Vector<std::unique_ptr<TerrainDrag> > ERF::m_terrain_drag
private

◆ m_w2d

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

◆ mapfac_m

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

◆ mapfac_u

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

◆ mapfac_v

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

◆ max_step

int ERF::max_step = std::numeric_limits<int>::max()
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 {0}
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 {1000.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

◆ 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

◆ 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

◆ plot_file_1

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

◆ plot_file_2

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

◆ plot_file_on_restart

int ERF::plot_file_on_restart = 1
private

◆ plot_lsm

bool ERF::plot_lsm = false
private

◆ plot_var_names_1

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

◆ plot_var_names_2

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

◆ plotfile_type_1

PlotFileType ERF::plotfile_type_1 = PlotFileType::None
staticprivate

◆ plotfile_type_2

PlotFileType ERF::plotfile_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

◆ 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

◆ 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

◆ restart_chkfile

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

◆ restart_type

std::string ERF::restart_type {"native"}
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().

◆ sampler_interval

int ERF::sampler_interval = -1
private

◆ sampler_per

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

◆ 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

◆ SmnSmn_lev

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

◆ solverChoice

SolverChoice ERF::solverChoice
staticprivate

◆ sponge_type

std::string ERF::sponge_type
staticprivate

◆ sst_lev

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

◆ start_time

amrex::Real ERF::start_time = 0.0
private

◆ startCPUTime

Real ERF::startCPUTime = 0.0
staticprivate

Referenced by getCPUTime().

◆ stop_time

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

◆ 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

◆ sum_interval

int ERF::sum_interval = -1
staticprivate

◆ sum_per

Real ERF::sum_per = -1.0
staticprivate

◆ 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

◆ Tau11_lev

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

◆ Tau12_lev

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

◆ Tau13_lev

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

◆ Tau21_lev

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

◆ Tau22_lev

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

◆ Tau23_lev

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

◆ Tau31_lev

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

◆ Tau32_lev

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

◆ Tau33_lev

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

◆ turbPert

TurbulentPerturbation ERF::turbPert
private

◆ use_fft

bool ERF::use_fft = false
staticprivate

◆ use_real_bcs

bool ERF::use_real_bcs
staticprivate

◆ 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

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