ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 WriteMyEBSurface ()
 
void compute_divergence (int lev, amrex::MultiFab &rhs, amrex::Array< amrex::MultiFab const *, AMREX_SPACEDIM > rho0_u_const, amrex::Geometry const &geom_at_lev)
 
void project_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_EB_mlmg (int lev, amrex::Vector< amrex::MultiFab > &rhs, amrex::Vector< amrex::MultiFab > &p, amrex::Vector< amrex::Array< amrex::MultiFab, AMREX_SPACEDIM >> &fluxes)
 
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 sum_derived_quantities (amrex::Real time)
 
void write_1D_profiles (amrex::Real time)
 
void write_1D_profiles_stag (amrex::Real time)
 
amrex::Real cloud_fraction (amrex::Real time)
 
void FillBdyCCVels (amrex::Vector< amrex::MultiFab > &mf_cc_vel, int levc=0)
 
void sample_points (int lev, amrex::Real time, amrex::IntVect cell, amrex::MultiFab &mf)
 
void sample_lines (int lev, amrex::Real time, amrex::IntVect cell, amrex::MultiFab &mf)
 
void derive_diag_profiles (amrex::Real time, amrex::Gpu::HostVector< amrex::Real > &h_avg_u, amrex::Gpu::HostVector< amrex::Real > &h_avg_v, amrex::Gpu::HostVector< amrex::Real > &h_avg_w, amrex::Gpu::HostVector< amrex::Real > &h_avg_rho, amrex::Gpu::HostVector< amrex::Real > &h_avg_th, amrex::Gpu::HostVector< amrex::Real > &h_avg_ksgs, amrex::Gpu::HostVector< amrex::Real > &h_avg_Kmv, amrex::Gpu::HostVector< amrex::Real > &h_avg_Khv, amrex::Gpu::HostVector< amrex::Real > &h_avg_qv, amrex::Gpu::HostVector< amrex::Real > &h_avg_qc, amrex::Gpu::HostVector< amrex::Real > &h_avg_qr, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqv, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqc, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqr, amrex::Gpu::HostVector< amrex::Real > &h_avg_qi, amrex::Gpu::HostVector< amrex::Real > &h_avg_qs, amrex::Gpu::HostVector< amrex::Real > &h_avg_qg, amrex::Gpu::HostVector< amrex::Real > &h_avg_uu, amrex::Gpu::HostVector< amrex::Real > &h_avg_uv, amrex::Gpu::HostVector< amrex::Real > &h_avg_uw, amrex::Gpu::HostVector< amrex::Real > &h_avg_vv, amrex::Gpu::HostVector< amrex::Real > &h_avg_vw, amrex::Gpu::HostVector< amrex::Real > &h_avg_ww, amrex::Gpu::HostVector< amrex::Real > &h_avg_uth, amrex::Gpu::HostVector< amrex::Real > &h_avg_vth, amrex::Gpu::HostVector< amrex::Real > &h_avg_wth, amrex::Gpu::HostVector< amrex::Real > &h_avg_thth, amrex::Gpu::HostVector< amrex::Real > &h_avg_ku, amrex::Gpu::HostVector< amrex::Real > &h_avg_kv, amrex::Gpu::HostVector< amrex::Real > &h_avg_kw, amrex::Gpu::HostVector< amrex::Real > &h_avg_p, amrex::Gpu::HostVector< amrex::Real > &h_avg_pu, amrex::Gpu::HostVector< amrex::Real > &h_avg_pv, amrex::Gpu::HostVector< amrex::Real > &h_avg_pw, amrex::Gpu::HostVector< amrex::Real > &h_avg_wthv)
 
void derive_diag_profiles_stag (amrex::Real time, amrex::Gpu::HostVector< amrex::Real > &h_avg_u, amrex::Gpu::HostVector< amrex::Real > &h_avg_v, amrex::Gpu::HostVector< amrex::Real > &h_avg_w, amrex::Gpu::HostVector< amrex::Real > &h_avg_rho, amrex::Gpu::HostVector< amrex::Real > &h_avg_th, amrex::Gpu::HostVector< amrex::Real > &h_avg_ksgs, amrex::Gpu::HostVector< amrex::Real > &h_avg_Kmv, amrex::Gpu::HostVector< amrex::Real > &h_avg_Khv, amrex::Gpu::HostVector< amrex::Real > &h_avg_qv, amrex::Gpu::HostVector< amrex::Real > &h_avg_qc, amrex::Gpu::HostVector< amrex::Real > &h_avg_qr, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqv, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqc, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqr, amrex::Gpu::HostVector< amrex::Real > &h_avg_qi, amrex::Gpu::HostVector< amrex::Real > &h_avg_qs, amrex::Gpu::HostVector< amrex::Real > &h_avg_qg, amrex::Gpu::HostVector< amrex::Real > &h_avg_uu, amrex::Gpu::HostVector< amrex::Real > &h_avg_uv, amrex::Gpu::HostVector< amrex::Real > &h_avg_uw, amrex::Gpu::HostVector< amrex::Real > &h_avg_vv, amrex::Gpu::HostVector< amrex::Real > &h_avg_vw, amrex::Gpu::HostVector< amrex::Real > &h_avg_ww, amrex::Gpu::HostVector< amrex::Real > &h_avg_uth, amrex::Gpu::HostVector< amrex::Real > &h_avg_vth, amrex::Gpu::HostVector< amrex::Real > &h_avg_wth, amrex::Gpu::HostVector< amrex::Real > &h_avg_thth, amrex::Gpu::HostVector< amrex::Real > &h_avg_ku, amrex::Gpu::HostVector< amrex::Real > &h_avg_kv, amrex::Gpu::HostVector< amrex::Real > &h_avg_kw, amrex::Gpu::HostVector< amrex::Real > &h_avg_p, amrex::Gpu::HostVector< amrex::Real > &h_avg_pu, amrex::Gpu::HostVector< amrex::Real > &h_avg_pv, amrex::Gpu::HostVector< amrex::Real > &h_avg_pw, amrex::Gpu::HostVector< amrex::Real > &h_avg_wthv)
 
void derive_stress_profiles (amrex::Gpu::HostVector< amrex::Real > &h_avg_tau11, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau12, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau13, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau22, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau23, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau33, amrex::Gpu::HostVector< amrex::Real > &h_avg_hfx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_q1fx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_q2fx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_diss)
 
void derive_stress_profiles_stag (amrex::Gpu::HostVector< amrex::Real > &h_avg_tau11, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau12, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau13, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau22, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau23, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau33, amrex::Gpu::HostVector< amrex::Real > &h_avg_hfx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_q1fx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_q2fx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_diss)
 
amrex::Real volWgtSumMF (int lev, const amrex::MultiFab &mf, int comp, const amrex::MultiFab &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 &cons_in, amrex::MultiFab &xvel_in, amrex::MultiFab &yvel_in, 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 WriteSubvolume ()
 
void WriteMultiLevelPlotfileWithTerrain (const std::string &plotfilename, int nlevels, const amrex::Vector< const amrex::MultiFab * > &mf, const amrex::Vector< const amrex::MultiFab * > &mf_nd, const amrex::Vector< std::string > &varnames, const amrex::Vector< amrex::Geometry > &my_geom, amrex::Real time, const amrex::Vector< int > &level_steps, const amrex::Vector< amrex::IntVect > &my_ref_ratio, const std::string &versionName="HyperCLaw-V1.1", const std::string &levelPrefix="Level_", const std::string &mfPrefix="Cell", const amrex::Vector< std::string > &extra_dirs=amrex::Vector< std::string >()) const
 
void WriteGenericPlotfileHeaderWithTerrain (std::ostream &HeaderFile, int nlevels, const amrex::Vector< amrex::BoxArray > &bArray, const amrex::Vector< std::string > &varnames, const amrex::Vector< amrex::Geometry > &my_geom, amrex::Real time, const amrex::Vector< int > &level_steps, const amrex::Vector< amrex::IntVect > &my_ref_ratio, const std::string &versionName, const std::string &levelPrefix, const std::string &mfPrefix) const
 
void erf_enforce_hse (int lev, amrex::MultiFab &dens, amrex::MultiFab &pres, amrex::MultiFab &pi, amrex::MultiFab &th, amrex::MultiFab &qv, std::unique_ptr< amrex::MultiFab > &z_cc)
 
void init_from_input_sounding (int lev)
 
void 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 MakeEBGeometry ()
 
void make_eb_box ()
 
void make_eb_regular ()
 
void AverageDownTo (int crse_lev, int scomp, int ncomp)
 
void WriteCheckpointFile () const
 
void ReadCheckpointFile ()
 
void ReadCheckpointFileMOST ()
 
void init_zphys (int lev, amrex::Real time)
 
void remake_zphys (int lev, amrex::Real time, std::unique_ptr< amrex::MultiFab > &temp_zphys_nd)
 
void update_terrain_arrays (int lev)
 
void writeJobInfo (const std::string &dir) const
 

Static Public Member Functions

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

Public Attributes

std::string pp_prefix {"erf"}
 

Private Member Functions

void ReadParameters ()
 
void ParameterSanityChecks ()
 
void AverageDown ()
 
void update_diffusive_arrays (int lev, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm)
 
void Construct_ERFFillPatchers (int lev)
 
void Define_ERFFillPatchers (int lev)
 
void init1DArrays ()
 
void init_bcs ()
 
void init_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 std::ostream & DerDataLog (int i)
 
AMREX_FORCE_INLINE int NumDataLogs () noexcept
 
AMREX_FORCE_INLINE int NumDerDataLogs () noexcept
 
AMREX_FORCE_INLINE std::ostream & SamplePointLog (int i)
 
AMREX_FORCE_INLINE int NumSamplePointLogs () noexcept
 
AMREX_FORCE_INLINE std::ostream & SampleLineLog (int i)
 
AMREX_FORCE_INLINE int NumSampleLineLogs () noexcept
 
amrex::IntVect & SamplePoint (int i)
 
AMREX_FORCE_INLINE int NumSamplePoints () noexcept
 
amrex::IntVect & SampleLine (int i)
 
AMREX_FORCE_INLINE int NumSampleLines () noexcept
 
void setRecordDataInfo (int i, const std::string &filename)
 
void setRecordDerDataInfo (int i, const std::string &filename)
 
void setRecordSamplePointInfo (int i, int lev, amrex::IntVect &cell, const std::string &filename)
 
void setRecordSampleLineInfo (int i, int lev, amrex::IntVect &cell, const std::string &filename)
 
std::string DataLogName (int i) const noexcept
 The filename of the ith datalog file. More...
 
std::string DerDataLogName (int i) const noexcept
 
std::string SamplePointLogName (int i) const noexcept
 The filename of the ith sampleptlog file. More...
 
std::string SampleLineLogName (int i) const noexcept
 The filename of the ith samplelinelog file. More...
 
eb_ const & get_eb (int lev) const noexcept
 
amrex::EBFArrayBoxFactory const & EBFactory (int lev) const noexcept
 

Static Private Member Functions

static amrex::Vector< std::string > PlotFileVarNames (amrex::Vector< std::string > plot_var_names)
 
static void GotoNextLine (std::istream &is)
 
static AMREX_FORCE_INLINE int ComputeGhostCells (const AdvChoice &advChoice, bool use_num_diff)
 
static amrex::Real getCPUTime ()
 
static int nghost_eb_basic ()
 
static int nghost_eb_volume ()
 
static int nghost_eb_full ()
 

Private Attributes

amrex::Vector< std::unique_ptr< amrex::MultiFab > > sinPhi_m
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > cosPhi_m
 
InputSoundingData input_sounding_data
 
InputSpongeData input_sponge_data
 
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > xvel_bc_data
 
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > yvel_bc_data
 
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > zvel_bc_data
 
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > th_bc_data
 
std::unique_ptr< ProblemBaseprob = nullptr
 
amrex::Vector< int > num_boxes_at_level
 
amrex::Vector< int > num_files_at_level
 
amrex::Vector< amrex::Vector< amrex::Box > > boxes_at_level
 
amrex::Vector< int > istep
 
amrex::Vector< int > nsubsteps
 
amrex::Vector< amrex::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 > > terrain_blanking
 
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_subvol
 
int last_check_file_step
 
int plot_file_on_restart = 1
 
const int datwidth = 14
 
const int datprecision = 6
 
const int timeprecision = 13
 
int max_step = std::numeric_limits<int>::max()
 
amrex::Real start_time = 0.0
 
amrex::Real stop_time = std::numeric_limits<amrex::Real>::max()
 
bool use_datetime = false
 
const std::string datetime_format = "%Y-%m-%d %H:%M:%S"
 
std::string restart_chkfile = ""
 
amrex::Vector< amrex::Real > fixed_dt
 
amrex::Vector< amrex::Real > fixed_fast_dt
 
int regrid_int = -1
 
bool regrid_level_0_on_restart = false
 
std::string plot_file_1 {"plt_1_"}
 
std::string plot_file_2 {"plt_2_"}
 
std::string subvol_file {"subvol"}
 
bool m_expand_plotvars_to_unif_rr = false
 
int m_plot_int_1 = -1
 
int m_plot_int_2 = -1
 
int m_subvol_int = -1
 
amrex::Real m_plot_per_1 = -1.0
 
amrex::Real m_plot_per_2 = -1.0
 
amrex::Real m_subvol_per = -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 {500.0}
 
int metgrid_order {2}
 
int metgrid_force_sfc_k {6}
 
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::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::unique_ptr< std::fstream > > der_datalog
 
amrex::Vector< std::string > datalogname
 
amrex::Vector< std::string > der_datalogname
 
amrex::Vector< std::unique_ptr< std::fstream > > sampleptlog
 
amrex::Vector< std::string > sampleptlogname
 
amrex::Vector< amrex::IntVect > samplepoint
 
amrex::Vector< std::unique_ptr< std::fstream > > samplelinelog
 
amrex::Vector< std::string > samplelinelogname
 
amrex::Vector< amrex::IntVect > sampleline
 
amrex::Vector< std::unique_ptr< eb_ > > eb
 

Static Private Attributes

static amrex::Real cfl = 0.8
 
static amrex::Real sub_cfl = 1.0
 
static amrex::Real init_shrink = 1.0
 
static amrex::Real change_max = 1.1
 
static amrex::Real dt_max_initial = 2.0e100
 
static amrex::Real dt_max = 1e9
 
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 StateInterpType interpolation_type
 
static std::string sponge_type
 
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 ( )
87 {
88  int fix_random_seed = 0;
89  ParmParse pp("erf"); pp.query("fix_random_seed", fix_random_seed);
90  // Note that the value of 1024UL is not significant -- the point here is just to set the
91  // same seed for all MPI processes for the purpose of regression testing
92  if (fix_random_seed) {
93  Print() << "Fixing the random seed" << std::endl;
94  InitRandom(1024UL);
95  }
96 
97  ERF_shared();
98 }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real pp(amrex::Real y)
Definition: ERF_MicrophysicsUtils.H:219
void ERF_shared()
Definition: ERF.cpp:101
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  // Update the inflow perturbation update time and amplitude
68  if (solverChoice.pert_type == PerturbationType::Source ||
69  solverChoice.pert_type == PerturbationType::Direct)
70  {
71  turbPert.calc_tpi_update(lev, dt_lev, U_old, V_old, S_old);
72  }
73 
74  // If PerturbationType::Direct is selected, directly add the computed perturbation
75  // on the conserved field
76  if (solverChoice.pert_type == PerturbationType::Direct)
77  {
78  auto m_ixtype = S_old.boxArray().ixType(); // Conserved term
79  for (MFIter mfi(S_old,TileNoZ()); mfi.isValid(); ++mfi) {
80  Box bx = mfi.tilebox();
81  const Array4<Real> &cell_data = S_old.array(mfi);
82  const Array4<const Real> &pert_cell = turbPert.pb_cell[lev].array(mfi);
83  turbPert.apply_tpi(lev, bx, RhoTheta_comp, m_ixtype, cell_data, pert_cell);
84  }
85  }
86 
87  // configure ABLMost params if used MostWall boundary condition
88  if (phys_bc_type[Orientation(Direction::z,Orientation::low)] == ERF_BC::MOST) {
89  if (m_most) {
90  IntVect ng = Theta_prim[lev]->nGrowVect();
91  MultiFab::Copy( *Theta_prim[lev], S_old, RhoTheta_comp, 0, 1, ng);
92  MultiFab::Divide(*Theta_prim[lev], S_old, Rho_comp , 0, 1, ng);
93  if (solverChoice.moisture_type != MoistureType::None) {
94  ng = Qv_prim[lev]->nGrowVect();
95 
96  MultiFab::Copy( *Qv_prim[lev], S_old, RhoQ1_comp, 0, 1, ng);
97  MultiFab::Divide(*Qv_prim[lev], S_old, Rho_comp , 0, 1, ng);
98 
99  if (solverChoice.RhoQr_comp > -1) {
100  MultiFab::Copy( *Qr_prim[lev], S_old, solverChoice.RhoQr_comp, 0, 1, ng);
101  MultiFab::Divide(*Qr_prim[lev], S_old, Rho_comp , 0, 1, ng);
102  } else {
103  Qr_prim[lev]->setVal(0.0);
104  }
105  }
106  // NOTE: std::swap above causes the field ptrs to be out of date.
107  // Reassign the field ptrs for MAC avg computation.
108  m_most->update_mac_ptrs(lev, vars_old, Theta_prim, Qv_prim, Qr_prim);
109  m_most->update_pblh(lev, vars_old, z_phys_cc[lev].get(),
113  m_most->update_fluxes(lev, time);
114  }
115  }
116 
117 #if defined(ERF_USE_WINDFARM)
118  if (solverChoice.windfarm_type != WindFarmType::None) {
119  advance_windfarm(Geom(lev), dt_lev, S_old,
120  U_old, V_old, W_old, vars_windfarm[lev], Nturb[lev], SMark[lev], time);
121  }
122 
123 #endif
124 
125  const BoxArray& ba = S_old.boxArray();
126  const DistributionMapping& dm = S_old.DistributionMap();
127 
128  int nvars = S_old.nComp();
129 
130  // Source array for conserved cell-centered quantities -- this will be filled
131  // in the call to make_sources in ERF_TI_slow_rhs_fun.H
132  MultiFab cc_source(ba,dm,nvars,1); cc_source.setVal(0.0);
133 
134  // Source arrays for momenta -- these will be filled
135  // in the call to make_mom_sources in ERF_TI_slow_rhs_fun.H
136  BoxArray ba_x(ba); ba_x.surroundingNodes(0);
137  MultiFab xmom_source(ba_x,dm,nvars,1); xmom_source.setVal(0.0);
138 
139  BoxArray ba_y(ba); ba_y.surroundingNodes(1);
140  MultiFab ymom_source(ba_y,dm,nvars,1); ymom_source.setVal(0.0);
141 
142  BoxArray ba_z(ba); ba_z.surroundingNodes(2);
143  MultiFab zmom_source(ba_z,dm,nvars,1); zmom_source.setVal(0.0);
144 
145  // We don't need to call FillPatch on cons_mf because we have fillpatch'ed S_old above
146  MultiFab cons_mf(ba,dm,nvars,S_old.nGrowVect());
147  MultiFab::Copy(cons_mf,S_old,0,0,S_old.nComp(),S_old.nGrowVect());
148 
149  amrex::Vector<MultiFab> state_old;
150  amrex::Vector<MultiFab> state_new;
151 
152  // **************************************************************************************
153  // Here we define state_old and state_new which are to be advanced
154  // **************************************************************************************
155  // Initial solution
156  // Note that "old" and "new" here are relative to each RK stage.
157  state_old.push_back(MultiFab(cons_mf , amrex::make_alias, 0, nvars)); // cons
158  state_old.push_back(MultiFab(rU_old[lev], amrex::make_alias, 0, 1)); // xmom
159  state_old.push_back(MultiFab(rV_old[lev], amrex::make_alias, 0, 1)); // ymom
160  state_old.push_back(MultiFab(rW_old[lev], amrex::make_alias, 0, 1)); // zmom
161 
162  // Final solution
163  // state_new at the end of the last RK stage holds the t^{n+1} data
164  state_new.push_back(MultiFab(S_new , amrex::make_alias, 0, nvars)); // cons
165  state_new.push_back(MultiFab(rU_new[lev], amrex::make_alias, 0, 1)); // xmom
166  state_new.push_back(MultiFab(rV_new[lev], amrex::make_alias, 0, 1)); // ymom
167  state_new.push_back(MultiFab(rW_new[lev], amrex::make_alias, 0, 1)); // zmom
168 
169  // **************************************************************************************
170  // Update the dycore
171  // **************************************************************************************
172  advance_dycore(lev, state_old, state_new,
173  U_old, V_old, W_old,
174  U_new, V_new, W_new,
175  cc_source, xmom_source, ymom_source, zmom_source,
176  Geom(lev), dt_lev, time);
177 
178  // **************************************************************************************
179  // Update the microphysics (moisture)
180  // **************************************************************************************
181  advance_microphysics(lev, S_new, dt_lev, iteration, time);
182 
183  // **************************************************************************************
184  // Update the land surface model
185  // **************************************************************************************
186  advance_lsm(lev, S_new, U_new, V_new, dt_lev);
187 
188 #if defined(ERF_USE_RRTMGP)
189  // **************************************************************************************
190  // Update the radiation
191  // **************************************************************************************
192  advance_radiation(lev, S_new, dt_lev);
193 #endif
194 
195 #ifdef ERF_USE_PARTICLES
196  // **************************************************************************************
197  // Update the particle positions
198  // **************************************************************************************
199  evolveTracers( lev, dt_lev, vars_new, z_phys_nd );
200 #endif
201 
202  // ***********************************************************************************************
203  // Impose domain boundary conditions here so that in FillPatching the fine data we won't
204  // need to re-fill these
205  // ***********************************************************************************************
206  if (lev < finest_level) {
207  IntVect ngvect_vels = vars_new[lev][Vars::xvel].nGrowVect();
209  0,vars_new[lev][Vars::cons].nComp(),
210  vars_new[lev][Vars::cons].nGrowVect(),time,BCVars::cons_bc,true);
211  (*physbcs_u[lev])(vars_new[lev][Vars::xvel], vars_new[lev][Vars::xvel], vars_new[lev][Vars::yvel],
212  ngvect_vels,time,BCVars::xvel_bc,true);
213  (*physbcs_v[lev])(vars_new[lev][Vars::yvel], vars_new[lev][Vars::xvel], vars_new[lev][Vars::yvel],
214  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:74
#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:752
std::unique_ptr< ABLMost > m_most
Definition: ERF.H:1173
amrex::Vector< ERFFillPatcher > FPr_u
Definition: ERF.H:797
amrex::Vector< amrex::Vector< amrex::MultiFab > > vars_new
Definition: ERF.H:727
amrex::Vector< ERFFillPatcher > FPr_v
Definition: ERF.H:798
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_cons > > physbcs_cons
Definition: ERF.H:739
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_cc
Definition: ERF.H:824
static SolverChoice solverChoice
Definition: ERF.H:1020
amrex::Vector< ERFFillPatcher > FPr_c
Definition: ERF.H:796
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vel_t_avg
Definition: ERF.H:731
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_w > > physbcs_w
Definition: ERF.H:742
amrex::Vector< amrex::MultiFab > base_state
Definition: ERF.H:859
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Qv_prim
Definition: ERF.H:747
amrex::Vector< amrex::MultiFab > rV_new
Definition: ERF.H:754
amrex::Vector< amrex::BCRec > domain_bcs_type
Definition: ERF.H:875
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Qr_prim
Definition: ERF.H:748
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_u > > physbcs_u
Definition: ERF.H:740
amrex::Vector< amrex::Real > t_avg_cnt
Definition: ERF.H:732
amrex::Vector< amrex::MultiFab > rU_old
Definition: ERF.H:751
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Theta_prim
Definition: ERF.H:746
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_v > > physbcs_v
Definition: ERF.H:741
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_nd
Definition: ERF.H:823
amrex::Vector< amrex::MultiFab > rW_new
Definition: ERF.H:756
amrex::Vector< amrex::MultiFab > zmom_crse_rhs
Definition: ERF.H:760
void advance_lsm(int lev, amrex::MultiFab &cons_in, amrex::MultiFab &xvel_in, amrex::MultiFab &yvel_in, const amrex::Real &dt_advance)
Definition: ERF_AdvanceLSM.cpp:5
TurbulentPerturbation turbPert
Definition: ERF.H:1023
amrex::Vector< amrex::MultiFab > rW_old
Definition: ERF.H:755
amrex::Vector< ERFFillPatcher > FPr_w
Definition: ERF.H:799
amrex::Vector< amrex::Real > dt
Definition: ERF.H:721
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:794
amrex::GpuArray< ERF_BC, AMREX_SPACEDIM *2 > phys_bc_type
Definition: ERF.H:888
amrex::Vector< amrex::MultiFab > rV_old
Definition: ERF.H:753
amrex::Vector< amrex::Vector< amrex::MultiFab > > vars_old
Definition: ERF.H:728
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:38
void FillPatch(int lev, amrex::Real time, const amrex::Vector< amrex::MultiFab * > &mfs_vel, bool cons_only=false)
@ zvel_bc
Definition: ERF_IndexDefines.H:89
@ yvel_bc
Definition: ERF_IndexDefines.H:88
@ cons_bc
Definition: ERF_IndexDefines.H:76
@ xvel_bc
Definition: ERF_IndexDefines.H:87
@ ymom
Definition: ERF_IndexDefines.H:152
@ cons
Definition: ERF_IndexDefines.H:150
@ zmom
Definition: ERF_IndexDefines.H:153
@ xmom
Definition: ERF_IndexDefines.H:151
@ xvel
Definition: ERF_IndexDefines.H:141
@ cons
Definition: ERF_IndexDefines.H:140
@ zvel
Definition: ERF_IndexDefines.H:143
@ yvel
Definition: ERF_IndexDefines.H:142
int RhoQr_comp
Definition: ERF_DataStruct.H:783
int RhoQc_comp
Definition: ERF_DataStruct.H:777
int RhoQv_comp
Definition: ERF_DataStruct.H:776
MoistureType moisture_type
Definition: ERF_DataStruct.H:759
PerturbationType pert_type
Definition: ERF_DataStruct.H:746
WindFarmType windfarm_type
Definition: ERF_DataStruct.H:760
bool time_avg_vel
Definition: ERF_DataStruct.H:743
amrex::Vector< amrex::MultiFab > pb_cell
Definition: ERF_TurbPertStruct.H:554
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:201
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:262
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
47 {
48  BL_PROFILE_VAR("erf_advance_dycore()",erf_advance_dycore);
49 
50  const Box& domain = fine_geom.Domain();
51 
55 
56  MultiFab r_hse (base_state[level], make_alias, BaseState::r0_comp , 1);
57  MultiFab p_hse (base_state[level], make_alias, BaseState::p0_comp , 1);
58  MultiFab pi_hse(base_state[level], make_alias, BaseState::pi0_comp, 1);
59 
60  // These pointers are used in the MRI utility functions
61  MultiFab* r0 = &r_hse;
62  MultiFab* p0 = &p_hse;
63  MultiFab* pi0 = &pi_hse;
64 
65  Real* dptr_rhotheta_src = solverChoice.custom_rhotheta_forcing ? d_rhotheta_src[level].data() : nullptr;
66  Real* dptr_rhoqt_src = solverChoice.custom_moisture_forcing ? d_rhoqt_src[level].data() : nullptr;
67  Real* dptr_wbar_sub = solverChoice.custom_w_subsidence ? d_w_subsid[level].data() : nullptr;
68 
69  // Turbulent Perturbation Pointer
70  //Real* dptr_rhotheta_src = solverChoice.pert_type ? d_rhotheta_src[level].data() : nullptr;
71 
72  Vector<Real*> d_rayleigh_ptrs_at_lev;
73  d_rayleigh_ptrs_at_lev.resize(Rayleigh::nvars);
74  d_rayleigh_ptrs_at_lev[Rayleigh::ubar] = solverChoice.rayleigh_damp_U ? d_rayleigh_ptrs[level][Rayleigh::ubar].data() : nullptr;
75  d_rayleigh_ptrs_at_lev[Rayleigh::vbar] = solverChoice.rayleigh_damp_V ? d_rayleigh_ptrs[level][Rayleigh::vbar].data() : nullptr;
76  d_rayleigh_ptrs_at_lev[Rayleigh::wbar] = solverChoice.rayleigh_damp_W ? d_rayleigh_ptrs[level][Rayleigh::wbar].data() : nullptr;
77  d_rayleigh_ptrs_at_lev[Rayleigh::thetabar] = solverChoice.rayleigh_damp_T ? d_rayleigh_ptrs[level][Rayleigh::thetabar].data() : nullptr;
78 
79  Vector<Real*> d_sponge_ptrs_at_lev;
80  if(sc.sponge_type=="input_sponge")
81  {
82  d_sponge_ptrs_at_lev.resize(Sponge::nvars_sponge);
83  d_sponge_ptrs_at_lev[Sponge::ubar_sponge] = d_sponge_ptrs[level][Sponge::ubar_sponge].data();
84  d_sponge_ptrs_at_lev[Sponge::vbar_sponge] = d_sponge_ptrs[level][Sponge::vbar_sponge].data();
85  }
86 
87  bool l_use_terrain_fitted_coords = (solverChoice.mesh_type != MeshType::ConstantDz);
88  bool l_use_kturb = ( (tc.les_type != LESType::None) ||
89  (tc.rans_type != RANSType::None) ||
90  (tc.pbl_type != PBLType::None) );
91  bool l_use_diff = ( (dc.molec_diff_type != MolecDiffType::None) ||
92  l_use_kturb );
93  bool l_use_moisture = ( solverChoice.moisture_type != MoistureType::None );
94  bool l_implicit_substepping = ( solverChoice.substepping_type[level] == SubsteppingType::Implicit );
95 
96  const bool use_most = (m_most != nullptr);
97  const bool exp_most = (solverChoice.use_explicit_most);
98  const FArrayBox* z_0 = (use_most) ? m_most->get_z0(level) : nullptr;
99 
100  const BoxArray& ba = state_old[IntVars::cons].boxArray();
101  const BoxArray& ba_z = zvel_old.boxArray();
102  const DistributionMapping& dm = state_old[IntVars::cons].DistributionMap();
103 
104  int num_prim = state_old[IntVars::cons].nComp() - 1;
105 
106  MultiFab S_prim (ba , dm, num_prim, state_old[IntVars::cons].nGrowVect());
107  MultiFab pi_stage (ba , dm, 1, state_old[IntVars::cons].nGrowVect());
108  MultiFab fast_coeffs(ba_z, dm, 5, 0);
109  MultiFab* eddyDiffs = eddyDiffs_lev[level].get();
110  MultiFab* SmnSmn = SmnSmn_lev[level].get();
111 
112  // **************************************************************************************
113  // Compute strain for use in slow RHS, Smagorinsky model, and MOST
114  // **************************************************************************************
115  {
116  BL_PROFILE("erf_advance_strain");
117  if (l_use_diff) {
118 
119  const BCRec* bc_ptr_h = domain_bcs_type.data();
120  const GpuArray<Real, AMREX_SPACEDIM> dxInv = fine_geom.InvCellSizeArray();
121 
122 #ifdef _OPENMP
123 #pragma omp parallel if (Gpu::notInLaunchRegion())
124 #endif
125  for ( MFIter mfi(state_new[IntVars::cons],TileNoZ()); mfi.isValid(); ++mfi)
126  {
127  Box bxcc = mfi.growntilebox(IntVect(1,1,0));
128  Box tbxxy = mfi.tilebox(IntVect(1,1,0),IntVect(1,1,0));
129  Box tbxxz = mfi.tilebox(IntVect(1,0,1),IntVect(1,1,0));
130  Box tbxyz = mfi.tilebox(IntVect(0,1,1),IntVect(1,1,0));
131 
132  if (bxcc.smallEnd(2) != domain.smallEnd(2)) {
133  bxcc.growLo(2,1);
134  tbxxy.growLo(2,1);
135  tbxxz.growLo(2,1);
136  tbxyz.growLo(2,1);
137  }
138 
139  if (bxcc.bigEnd(2) != domain.bigEnd(2)) {
140  bxcc.growHi(2,1);
141  tbxxy.growHi(2,1);
142  tbxxz.growHi(2,1);
143  tbxyz.growHi(2,1);
144  }
145 
146  const Array4<const Real> & u = xvel_old.array(mfi);
147  const Array4<const Real> & v = yvel_old.array(mfi);
148  const Array4<const Real> & w = zvel_old.array(mfi);
149 
150  Array4<Real> tau11 = Tau11_lev[level].get()->array(mfi);
151  Array4<Real> tau22 = Tau22_lev[level].get()->array(mfi);
152  Array4<Real> tau33 = Tau33_lev[level].get()->array(mfi);
153  Array4<Real> tau12 = Tau12_lev[level].get()->array(mfi);
154  Array4<Real> tau13 = Tau13_lev[level].get()->array(mfi);
155  Array4<Real> tau23 = Tau23_lev[level].get()->array(mfi);
156 
157  Array4<Real> tau21 = l_use_terrain_fitted_coords ? Tau21_lev[level].get()->array(mfi) : Array4<Real>{};
158  Array4<Real> tau31 = l_use_terrain_fitted_coords ? Tau31_lev[level].get()->array(mfi) : Array4<Real>{};
159  Array4<Real> tau32 = l_use_terrain_fitted_coords ? Tau32_lev[level].get()->array(mfi) : Array4<Real>{};
160  const Array4<const Real>& z_nd = z_phys_nd[level]->const_array(mfi);
161 
162  const Array4<const Real> mf_m = mapfac_m[level]->array(mfi);
163  const Array4<const Real> mf_u = mapfac_u[level]->array(mfi);
164  const Array4<const Real> mf_v = mapfac_v[level]->array(mfi);
165 
166  if (l_use_terrain_fitted_coords) {
167  ComputeStrain_T(bxcc, tbxxy, tbxxz, tbxyz, domain,
168  u, v, w,
169  tau11, tau22, tau33,
170  tau12, tau13,
171  tau21, tau23,
172  tau31, tau32,
173  z_nd, detJ_cc[level]->const_array(mfi), bc_ptr_h, dxInv,
174  mf_m, mf_u, mf_v);
175  } else {
176  ComputeStrain_N(bxcc, tbxxy, tbxxz, tbxyz, domain,
177  u, v, w,
178  tau11, tau22, tau33,
179  tau12, tau13, tau23,
180  bc_ptr_h, dxInv,
181  mf_m, mf_u, mf_v);
182  }
183  } // mfi
184  } // l_use_diff
185  } // profile
186 
187 #include "ERF_TI_utils.H"
188 
189  // Additional SFS quantities, calculated once per timestep
190  MultiFab* Hfx1 = SFS_hfx1_lev[level].get();
191  MultiFab* Hfx2 = SFS_hfx2_lev[level].get();
192  MultiFab* Hfx3 = SFS_hfx3_lev[level].get();
193  MultiFab* Q1fx1 = SFS_q1fx1_lev[level].get();
194  MultiFab* Q1fx2 = SFS_q1fx2_lev[level].get();
195  MultiFab* Q1fx3 = SFS_q1fx3_lev[level].get();
196  MultiFab* Q2fx3 = SFS_q2fx3_lev[level].get();
197  MultiFab* Diss = SFS_diss_lev[level].get();
198 
199  // *************************************************************************
200  // Calculate cell-centered eddy viscosity & diffusivities
201  //
202  // Notes -- we fill all the data in ghost cells before calling this so
203  // that we can fill the eddy viscosity in the ghost regions and
204  // not have to call a boundary filler on this data itself
205  //
206  // LES - updates both horizontal and vertical eddy viscosity components
207  // PBL - only updates vertical eddy viscosity components so horizontal
208  // components come from the LES model or are left as zero.
209  // *************************************************************************
210  if (l_use_kturb)
211  {
212  // NOTE: state_new transfers to state_old for PBL (due to ptr swap in advance)
213  const BCRec* bc_ptr_h = domain_bcs_type.data();
214  ComputeTurbulentViscosity(xvel_old, yvel_old,
215  *Tau11_lev[level].get(), *Tau22_lev[level].get(), *Tau33_lev[level].get(),
216  *Tau12_lev[level].get(), *Tau13_lev[level].get(), *Tau23_lev[level].get(),
217  state_old[IntVars::cons],
218  *walldist[level].get(),
219  *eddyDiffs, *Hfx1, *Hfx2, *Hfx3, *Diss, // to be updated
220  fine_geom, *mapfac_u[level], *mapfac_v[level],
221  z_phys_nd[level], solverChoice,
222  m_most, z_0, exp_most,
223  l_use_terrain_fitted_coords, l_use_moisture, level, bc_ptr_h);
224  }
225 
226  // ***********************************************************************************************
227  // Update user-defined source terms -- these are defined once per time step (not per RK stage)
228  // ***********************************************************************************************
230  prob->update_rhotheta_sources(old_time,
231  h_rhotheta_src[level], d_rhotheta_src[level],
232  fine_geom, z_phys_cc[level]);
233  }
234 
236  prob->update_rhoqt_sources(old_time,
237  h_rhoqt_src[level], d_rhoqt_src[level],
238  fine_geom, z_phys_cc[level]);
239  }
240 
242  prob->update_geostrophic_profile(old_time,
243  h_u_geos[level], d_u_geos[level],
244  h_v_geos[level], d_v_geos[level],
245  fine_geom, z_phys_cc[level]);
246  }
247 
249  prob->update_w_subsidence(old_time,
250  h_w_subsid[level], d_w_subsid[level],
251  fine_geom, z_phys_nd[level]);
252  }
253 
254  // ***********************************************************************************************
255  // Convert old velocity available on faces to old momentum on faces to be used in time integration
256  // ***********************************************************************************************
257  MultiFab density(state_old[IntVars::cons], make_alias, Rho_comp, 1);
258 
259  //
260  // This is an optimization since we won't need more than one ghost
261  // cell of momentum in the integrator if not using numerical diffusion
262  //
263  IntVect ngu = (!solverChoice.use_num_diff) ? IntVect(1,1,1) : xvel_old.nGrowVect();
264  IntVect ngv = (!solverChoice.use_num_diff) ? IntVect(1,1,1) : yvel_old.nGrowVect();
265  IntVect ngw = (!solverChoice.use_num_diff) ? IntVect(1,1,0) : zvel_old.nGrowVect();
266 
267  VelocityToMomentum(xvel_old, ngu, yvel_old, ngv, zvel_old, ngw, density,
268  state_old[IntVars::xmom],
269  state_old[IntVars::ymom],
270  state_old[IntVars::zmom],
271  domain, domain_bcs_type);
272 
273  MultiFab::Copy(xvel_new,xvel_old,0,0,1,xvel_old.nGrowVect());
274  MultiFab::Copy(yvel_new,yvel_old,0,0,1,yvel_old.nGrowVect());
275  MultiFab::Copy(zvel_new,zvel_old,0,0,1,zvel_old.nGrowVect());
276 
277  bool fast_only = false;
278  bool vel_and_mom_synced = true;
279 
280  apply_bcs(state_old, old_time,
281  state_old[IntVars::cons].nGrow(), state_old[IntVars::xmom].nGrow(),
282  fast_only, vel_and_mom_synced);
283  cons_to_prim(state_old[IntVars::cons], state_old[IntVars::cons].nGrow());
284 
285 #include "ERF_TI_no_substep_fun.H"
286 #include "ERF_TI_substep_fun.H"
287 #include "ERF_TI_slow_rhs_fun.H"
288 
289  // ***************************************************************************************
290  // Setup the integrator and integrate for a single timestep
291  // **************************************************************************************
292  MRISplitIntegrator<Vector<MultiFab> >& mri_integrator = *mri_integrator_mem[level];
293 
294  // Define rhs and 'post update' utility function that is called after calculating
295  // any state data (e.g. at RK stages or at the end of a timestep)
296  mri_integrator.set_slow_rhs_pre(slow_rhs_fun_pre);
297  mri_integrator.set_slow_rhs_post(slow_rhs_fun_post);
298 
299  if (solverChoice.anelastic[level]) {
300  mri_integrator.set_slow_rhs_inc(slow_rhs_fun_inc);
301  }
302 
303  mri_integrator.set_fast_rhs(fast_rhs_fun);
305  mri_integrator.set_no_substep(no_substep_fun);
306 
307  mri_integrator.advance(state_old, state_new, old_time, dt_advance);
308 
309  if (verbose) Print() << "Done with advance_dycore at level " << level << std::endl;
310 }
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, const MultiFab &wdist, 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 amrex::FArrayBox *z_0, const bool &exp_most, const bool &use_terrain_fitted_coords, const bool &use_moisture, int level, const BCRec *bc_ptr, bool vert_only)
Definition: ERF_ComputeTurbulentViscosity.cpp:542
@ ubar
Definition: ERF_DataStruct.H:74
@ wbar
Definition: ERF_DataStruct.H:74
@ vbar
Definition: ERF_DataStruct.H:74
@ thetabar
Definition: ERF_DataStruct.H:74
@ nvars_sponge
Definition: ERF_DataStruct.H:79
@ vbar_sponge
Definition: ERF_DataStruct.H:79
@ ubar_sponge
Definition: ERF_DataStruct.H:79
auto no_substep_fun
Definition: ERF_TI_no_substep_fun.H:4
auto slow_rhs_fun_inc
Definition: ERF_TI_slow_rhs_fun.H:416
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:325
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 > > walldist
Definition: ERF.H:849
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau23_lev
Definition: ERF.H:805
amrex::Vector< std::unique_ptr< MRISplitIntegrator< amrex::Vector< amrex::MultiFab > > > > mri_integrator_mem
Definition: ERF.H:734
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_rhotheta_src
Definition: ERF.H:1122
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q1fx3_lev
Definition: ERF.H:816
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_hfx3_lev
Definition: ERF.H:814
amrex::Vector< amrex::Vector< amrex::Real > > h_w_subsid
Definition: ERF.H:1127
amrex::Vector< std::unique_ptr< amrex::MultiFab > > mapfac_u
Definition: ERF.H:853
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau31_lev
Definition: ERF.H:804
amrex::Vector< std::unique_ptr< amrex::MultiFab > > mapfac_m
Definition: ERF.H:852
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_hfx1_lev
Definition: ERF.H:814
amrex::Vector< std::unique_ptr< amrex::MultiFab > > detJ_cc
Definition: ERF.H:826
amrex::Vector< std::unique_ptr< amrex::MultiFab > > eddyDiffs_lev
Definition: ERF.H:806
amrex::Vector< amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > > d_sponge_ptrs
Definition: ERF.H:1155
amrex::Vector< amrex::Vector< amrex::Real > > h_rhoqt_src
Definition: ERF.H:1124
amrex::Vector< long > dt_mri_ratio
Definition: ERF.H:722
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q2fx3_lev
Definition: ERF.H:817
static int verbose
Definition: ERF.H:1055
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau13_lev
Definition: ERF.H:804
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q1fx2_lev
Definition: ERF.H:816
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau21_lev
Definition: ERF.H:803
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau33_lev
Definition: ERF.H:802
std::unique_ptr< ProblemBase > prob
Definition: ERF.H:709
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_diss_lev
Definition: ERF.H:815
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_v_geos
Definition: ERF.H:1134
amrex::Vector< amrex::Vector< amrex::Real > > h_v_geos
Definition: ERF.H:1133
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_rhoqt_src
Definition: ERF.H:1125
amrex::Vector< amrex::Vector< amrex::Real > > h_rhotheta_src
Definition: ERF.H:1121
amrex::Vector< amrex::Vector< amrex::Real > > h_u_geos
Definition: ERF.H:1130
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SmnSmn_lev
Definition: ERF.H:807
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau32_lev
Definition: ERF.H:805
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_u_geos
Definition: ERF.H:1131
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_w_subsid
Definition: ERF.H:1128
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_hfx2_lev
Definition: ERF.H:814
static int fixed_mri_dt_ratio
Definition: ERF.H:939
amrex::Vector< amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > > d_rayleigh_ptrs
Definition: ERF.H:1152
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau12_lev
Definition: ERF.H:803
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q1fx1_lev
Definition: ERF.H:816
amrex::Vector< std::unique_ptr< amrex::MultiFab > > mapfac_v
Definition: ERF.H:854
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau11_lev
Definition: ERF.H:802
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau22_lev
Definition: ERF.H:802
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:81
bool rayleigh_damp_T
Definition: ERF_DataStruct.H:700
bool use_explicit_most
Definition: ERF_DataStruct.H:737
static MeshType mesh_type
Definition: ERF_DataStruct.H:665
bool rayleigh_damp_V
Definition: ERF_DataStruct.H:698
DiffChoice diffChoice
Definition: ERF_DataStruct.H:674
bool custom_rhotheta_forcing
Definition: ERF_DataStruct.H:726
bool custom_w_subsidence
Definition: ERF_DataStruct.H:728
bool rayleigh_damp_U
Definition: ERF_DataStruct.H:697
bool custom_geostrophic_profile
Definition: ERF_DataStruct.H:729
amrex::Vector< SubsteppingType > substepping_type
Definition: ERF_DataStruct.H:680
bool use_num_diff
Definition: ERF_DataStruct.H:749
bool custom_moisture_forcing
Definition: ERF_DataStruct.H:727
amrex::Vector< TurbChoice > turbChoice
Definition: ERF_DataStruct.H:676
amrex::Vector< int > anelastic
Definition: ERF_DataStruct.H:681
bool rayleigh_damp_W
Definition: ERF_DataStruct.H:699
SpongeChoice spongeChoice
Definition: ERF_DataStruct.H:675
Definition: ERF_SpongeStruct.H:15
std::string sponge_type
Definition: ERF_SpongeStruct.H:58
Definition: ERF_TurbStruct.H:31
PBLType pbl_type
Definition: ERF_TurbStruct.H:240
RANSType rans_type
Definition: ERF_TurbStruct.H:237
LESType les_type
Definition: ERF_TurbStruct.H:204
Here is the call graph for this function:

◆ advance_lsm()

void ERF::advance_lsm ( int  lev,
amrex::MultiFab &  cons_in,
amrex::MultiFab &  xvel_in,
amrex::MultiFab &  yvel_in,
const amrex::Real &  dt_advance 
)
10 {
11  if (solverChoice.lsm_type != LandSurfaceType::None) {
12  if (solverChoice.lsm_type == LandSurfaceType::NOAH) {
13  lsm.Advance(lev, cons_in, xvel_in, yvel_in, SFS_hfx3_lev[lev].get(), SFS_q1fx3_lev[lev].get(), dt_advance, istep[lev]);
14  } else {
15  lsm.Advance(lev, dt_advance);
16  }
17  }
18 }
LandSurface lsm
Definition: ERF.H:778
amrex::Vector< int > istep
Definition: ERF.H:715
void Advance(const int &lev, amrex::MultiFab &cons_in, amrex::MultiFab &xvel_in, amrex::MultiFab &yvel_in, amrex::MultiFab *hfx3_out, amrex::MultiFab *qfx3_out, const amrex::Real &dt_advance, const int &nstep)
Definition: ERF_LandSurface.H:52
LandSurfaceType lsm_type
Definition: ERF_DataStruct.H:762

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

◆ appendPlotVariables()

void ERF::appendPlotVariables ( const std::string &  pp_plot_var_names,
amrex::Vector< std::string > &  plot_var_names 
)
private
168 {
169  ParmParse pp(pp_prefix);
170 
171  Vector<std::string> plot_var_names(0);
172  if (pp.contains(pp_plot_var_names.c_str())) {
173  std::string nm;
174  int nPltVars = pp.countval(pp_plot_var_names.c_str());
175  for (int i = 0; i < nPltVars; i++) {
176  pp.get(pp_plot_var_names.c_str(), nm, i);
177  // Add the named variable to our list of plot variables
178  // if it is not already in the list
179  if (!containerHasElement(plot_var_names, nm)) {
180  plot_var_names.push_back(nm);
181  }
182  }
183  }
184 
185  Vector<std::string> tmp_plot_names(0);
186 #ifdef ERF_USE_PARTICLES
187  Vector<std::string> particle_mesh_plot_names;
188  particleData.GetMeshPlotVarNames( particle_mesh_plot_names );
189  for (int i = 0; i < particle_mesh_plot_names.size(); i++) {
190  std::string tmp(particle_mesh_plot_names[i]);
191  if (containerHasElement(plot_var_names, tmp) ) {
192  tmp_plot_names.push_back(tmp);
193  }
194  }
195 #endif
196 
197  for (int i = 0; i < tmp_plot_names.size(); i++) {
198  a_plot_var_names.push_back( tmp_plot_names[i] );
199  }
200 
201  // Finally, check to see if we found all the requested variables
202  for (const auto& plot_name : plot_var_names) {
203  if (!containerHasElement(a_plot_var_names, plot_name)) {
204  if (amrex::ParallelDescriptor::IOProcessor()) {
205  Warning("\nWARNING: Requested to plot variable '" + plot_name + "' but it is not available");
206  }
207  }
208  }
209 }
bool containerHasElement(const V &iterable, const T &query)
Definition: ERF_Container.H:5
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:758

◆ 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:1068
@ th0_comp
Definition: ERF_IndexDefines.H:66
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
502 {
503  // Mask for zeroing covered cells
504  AMREX_ASSERT(level > 0);
505 
506  const BoxArray& cba = grids[level-1];
507  const DistributionMapping& cdm = dmap[level-1];
508 
509  // TODO -- we should make a vector of these a member of ERF class
510  fine_mask.define(cba, cdm, 1, 0, MFInfo());
511  fine_mask.setVal(1.0);
512 
513  BoxArray fba = grids[level];
514  iMultiFab ifine_mask = makeFineMask(cba, cdm, fba, ref_ratio[level-1], 1, 0);
515 
516  const auto fma = fine_mask.arrays();
517  const auto ifma = ifine_mask.arrays();
518  ParallelFor(fine_mask, [=] AMREX_GPU_DEVICE(int bno, int i, int j, int k) noexcept
519  {
520  fma[bno](i,j,k) = ifma[bno](i,j,k);
521  });
522 
523  return fine_mask;
524 }
amrex::MultiFab fine_mask
Definition: ERF.H:1185

◆ ClearLevel()

void ERF::ClearLevel ( int  lev)
override
545 {
546  for (int var_idx = 0; var_idx < Vars::NumTypes; ++var_idx) {
547  vars_new[lev][var_idx].clear();
548  vars_old[lev][var_idx].clear();
549  }
550 
551  base_state[lev].clear();
552 
553  rU_new[lev].clear();
554  rU_old[lev].clear();
555  rV_new[lev].clear();
556  rV_old[lev].clear();
557  rW_new[lev].clear();
558  rW_old[lev].clear();
559 
560  if (lev > 0) {
561  zmom_crse_rhs[lev].clear();
562  }
563 
564  if (solverChoice.anelastic[lev] == 1) {
565  pp_inc[lev].clear();
566  }
567 
568  // Clears the integrator memory
569  mri_integrator_mem[lev].reset();
570 
571  // Clears the physical boundary condition routines
572  physbcs_cons[lev].reset();
573  physbcs_u[lev].reset();
574  physbcs_v[lev].reset();
575  physbcs_w[lev].reset();
576  physbcs_base[lev].reset();
577 
578  // Clears the flux register array
579  advflux_reg[lev]->reset();
580 }
amrex::Vector< amrex::MultiFab > pp_inc
Definition: ERF.H:736
amrex::Vector< amrex::YAFluxRegister * > advflux_reg
Definition: ERF.H:870
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_base > > physbcs_base
Definition: ERF.H:743
@ NumTypes
Definition: ERF_IndexDefines.H:144

◆ cloud_fraction()

Real ERF::cloud_fraction ( amrex::Real  time)
251 {
252  BL_PROFILE("ERF::cloud_fraction()");
253 
254  int lev = 0;
255  // This holds all of qc
256  MultiFab qc(vars_new[lev][Vars::cons],make_alias,RhoQ2_comp,1);
257 
258  int direction = 2; // z-direction
259  Box const& domain = geom[lev].Domain();
260 
261  auto const& qc_arr = qc.const_arrays();
262 
263  // qc_2d is an BaseFab<int> holding the max value over the column
264  auto qc_2d = ReduceToPlane<ReduceOpMax,int>(direction, domain, qc,
265  [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k) -> int
266  {
267  if (qc_arr[box_no](i,j,k) > 0) {
268  return 1;
269  } else {
270  return 0;
271  }
272  });
273 
274  auto* p = qc_2d.dataPtr();
275 
276  Long numpts = qc_2d.numPts();
277 
278  AMREX_ASSERT(numpts < Long(std::numeric_limits<int>::max));
279 
280 #if 1
281  if (ParallelDescriptor::UseGpuAwareMpi()) {
282  ParallelDescriptor::ReduceIntMax(p,static_cast<int>(numpts));
283  } else {
284  Gpu::PinnedVector<int> hv(numpts);
285  Gpu::copyAsync(Gpu::deviceToHost, p, p+numpts, hv.data());
286  Gpu::streamSynchronize();
287  ParallelDescriptor::ReduceIntMax(hv.data(),static_cast<int>(numpts));
288  Gpu::copyAsync(Gpu::hostToDevice, hv.data(), hv.data()+numpts, p);
289  }
290 
291  // Sum over component 0
292  Long num_cloudy = qc_2d.template sum<RunOn::Device>(0);
293 
294 #else
295  //
296  // We need this if we allow domain decomposition in the vertical
297  // but for now we leave it commented out
298  //
299  Long num_cloudy = Reduce::Sum<Long>(numpts,
300  [=] AMREX_GPU_DEVICE (Long i) -> Long {
301  if (p[i] == 1) {
302  return 1;
303  } else {
304  return 0;
305  }
306  });
307  ParallelDescriptor::ReduceLongSum(num_cloudy);
308 #endif
309 
310  Real num_total = qc_2d.box().d_numPts();
311 
312  Real cloud_frac = num_cloudy / num_total;
313 
314  return cloud_frac;
315 }
#define RhoQ2_comp
Definition: ERF_IndexDefines.H:43
@ qc
Definition: ERF_SatAdj.H:36

◆ compute_divergence()

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

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

11 {
12  BL_PROFILE("ERF::compute_divergence()");
13 
14  auto dxInv = geom_at_lev.InvCellSizeArray();
15 
16  // ****************************************************************************
17  // Compute divergence which will form RHS
18  // Note that we replace "rho0w" with the contravariant momentum, Omega
19  // ****************************************************************************
20  if (solverChoice.terrain_type == TerrainType::EB)
21  {
22  bool already_on_centroids = true;
23  EB_computeDivergence(rhs, rho0_u_const, geom_at_lev, already_on_centroids);
24  }
25  else if (SolverChoice::mesh_type == MeshType::ConstantDz)
26  {
27  computeDivergence(rhs, rho0_u_const, geom_at_lev);
28  }
29  else
30  {
31  for ( MFIter mfi(rhs,TilingIfNotGPU()); mfi.isValid(); ++mfi)
32  {
33  Box bx = mfi.tilebox();
34  const Array4<Real const>& rho0u_arr = rho0_u_const[0]->const_array(mfi);
35  const Array4<Real const>& rho0v_arr = rho0_u_const[1]->const_array(mfi);
36  const Array4<Real const>& rho0w_arr = rho0_u_const[2]->const_array(mfi);
37  const Array4<Real >& rhs_arr = rhs.array(mfi);
38 
39  if (SolverChoice::mesh_type == MeshType::StretchedDz) {
40  Real* stretched_dz_d_ptr = stretched_dz_d[lev].data();
41  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept {
42  Real dz = stretched_dz_d_ptr[k];
43  rhs_arr(i,j,k) = (rho0u_arr(i+1,j,k) - rho0u_arr(i,j,k)) * dxInv[0]
44  +(rho0v_arr(i,j+1,k) - rho0v_arr(i,j,k)) * dxInv[1]
45  +(rho0w_arr(i,j,k+1) - rho0w_arr(i,j,k)) / dz;
46  });
47  } else {
48 
49  //
50  // Note we compute the divergence using "rho0w" == Omega
51  //
52  const Array4<Real const>& ax_arr = ax[lev]->const_array(mfi);
53  const Array4<Real const>& ay_arr = ay[lev]->const_array(mfi);
54  const Array4<Real const>& dJ_arr = detJ_cc[lev]->const_array(mfi);
55  //
56  // az == 1 for terrain-fitted coordinates
57  //
58  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
59  {
60  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]
61  +(ay_arr(i,j+1,k)*rho0v_arr(i,j+1,k) - ay_arr(i,j,k)*rho0v_arr(i,j,k)) * dxInv[1]
62  +( rho0w_arr(i,j,k+1) - rho0w_arr(i,j,k)) * dxInv[2]) / dJ_arr(i,j,k);
63  });
64  }
65  } // mfi
66  }
67 }
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > stretched_dz_d
Definition: ERF.H:857
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ax
Definition: ERF.H:827
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ay
Definition: ERF.H:828
static TerrainType terrain_type
Definition: ERF_DataStruct.H:659

◆ ComputeDt()

void ERF::ComputeDt ( int  step = -1)
private

Function that calls estTimeStep for each level

12 {
13  Vector<Real> dt_tmp(finest_level+1);
14 
15  for (int lev = 0; lev <= finest_level; ++lev)
16  {
17  dt_tmp[lev] = estTimeStep(lev, dt_mri_ratio[lev]);
18  }
19 
20  ParallelDescriptor::ReduceRealMin(&dt_tmp[0], dt_tmp.size());
21 
22  Real dt_0 = dt_tmp[0];
23  int n_factor = 1;
24  for (int lev = 0; lev <= finest_level; ++lev) {
25  dt_tmp[lev] = amrex::min(dt_tmp[lev], change_max*dt[lev]);
26  n_factor *= nsubsteps[lev];
27  dt_0 = amrex::min(dt_0, n_factor*dt_tmp[lev]);
28  if (step == 0){
29  dt_0 *= init_shrink;
30  if (verbose && init_shrink != 1.0) {
31  Print() << "Timestep 0: shrink initial dt at level " << lev << " by " << init_shrink << std::endl;
32  }
33  }
34  }
35  // Limit dt's by the value of stop_time.
36  const Real eps = 1.e-3*dt_0;
37  if (t_new[0] + dt_0 > stop_time - eps) {
38  dt_0 = stop_time - t_new[0];
39  }
40 
41  dt[0] = dt_0;
42  for (int lev = 1; lev <= finest_level; ++lev) {
43  dt[lev] = dt[lev-1] / nsubsteps[lev];
44  }
45 }
amrex::Real stop_time
Definition: ERF.H:920
amrex::Vector< amrex::Real > t_new
Definition: ERF.H:719
amrex::Real estTimeStep(int lev, long &dt_fast_ratio) const
Definition: ERF_ComputeTimestep.cpp:54
amrex::Vector< int > nsubsteps
Definition: ERF.H:716
static amrex::Real init_shrink
Definition: ERF.H:931
static amrex::Real change_max
Definition: ERF.H:932

◆ ComputeGhostCells()

static AMREX_FORCE_INLINE int ERF::ComputeGhostCells ( const AdvChoice advChoice,
bool  use_num_diff 
)
inlinestaticprivate
1192  {
1193  if (use_num_diff)
1194  {
1195  return 3;
1196  } else {
1197  if (
1203  || (advChoice.dryscal_vert_adv_type == AdvType::Centered_6th) )
1204  { return 3; }
1205  else if (
1207  || (advChoice.dycore_vert_adv_type == AdvType::Upwind_5th)
1211  || (advChoice.dryscal_vert_adv_type == AdvType::Upwind_5th) )
1212  { return 3; }
1213  else if (
1215  || (advChoice.dryscal_vert_adv_type == AdvType::Weno_5)
1216  || (advChoice.moistscal_horiz_adv_type == AdvType::Weno_5)
1217  || (advChoice.moistscal_vert_adv_type == AdvType::Weno_5)
1218  || (advChoice.moistscal_horiz_adv_type == AdvType::Weno_5Z)
1219  || (advChoice.moistscal_vert_adv_type == AdvType::Weno_5Z)
1220  || (advChoice.dryscal_horiz_adv_type == AdvType::Weno_5Z)
1221  || (advChoice.dryscal_vert_adv_type == AdvType::Weno_5Z) )
1222  { return 3; }
1223  else if (
1225  || (advChoice.dryscal_vert_adv_type == AdvType::Weno_7)
1226  || (advChoice.moistscal_horiz_adv_type == AdvType::Weno_7)
1227  || (advChoice.moistscal_vert_adv_type == AdvType::Weno_7)
1228  || (advChoice.moistscal_horiz_adv_type == AdvType::Weno_7Z)
1229  || (advChoice.moistscal_vert_adv_type == AdvType::Weno_7Z)
1230  || (advChoice.dryscal_horiz_adv_type == AdvType::Weno_7Z)
1231  || (advChoice.dryscal_vert_adv_type == AdvType::Weno_7Z) )
1232  { return 4; }
1233  else
1234  { return 2; }
1235  }
1236  }
@ Centered_6th
AdvType moistscal_horiz_adv_type
Definition: ERF_AdvStruct.H:343
AdvType dycore_vert_adv_type
Definition: ERF_AdvStruct.H:340
AdvType moistscal_vert_adv_type
Definition: ERF_AdvStruct.H:344
AdvType dryscal_horiz_adv_type
Definition: ERF_AdvStruct.H:341
AdvType dycore_horiz_adv_type
Definition: ERF_AdvStruct.H:339
AdvType dryscal_vert_adv_type
Definition: ERF_AdvStruct.H:342

◆ Construct_ERFFillPatchers()

void ERF::Construct_ERFFillPatchers ( int  lev)
private
1996 {
1997  auto& fine_new = vars_new[lev];
1998  auto& crse_new = vars_new[lev-1];
1999  auto& ba_fine = fine_new[Vars::cons].boxArray();
2000  auto& ba_crse = crse_new[Vars::cons].boxArray();
2001  auto& dm_fine = fine_new[Vars::cons].DistributionMap();
2002  auto& dm_crse = crse_new[Vars::cons].DistributionMap();
2003 
2004  int ncomp = vars_new[lev][Vars::cons].nComp();
2005 
2006  FPr_c.emplace_back(ba_fine, dm_fine, geom[lev] ,
2007  ba_crse, dm_crse, geom[lev-1],
2008  -cf_width, -cf_set_width, ncomp, &cell_cons_interp);
2009  FPr_u.emplace_back(convert(ba_fine, IntVect(1,0,0)), dm_fine, geom[lev] ,
2010  convert(ba_crse, IntVect(1,0,0)), dm_crse, geom[lev-1],
2011  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
2012  FPr_v.emplace_back(convert(ba_fine, IntVect(0,1,0)), dm_fine, geom[lev] ,
2013  convert(ba_crse, IntVect(0,1,0)), dm_crse, geom[lev-1],
2014  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
2015  FPr_w.emplace_back(convert(ba_fine, IntVect(0,0,1)), dm_fine, geom[lev] ,
2016  convert(ba_crse, IntVect(0,0,1)), dm_crse, geom[lev-1],
2017  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
2018 }
int cf_set_width
Definition: ERF.H:795

◆ DataLog()

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

◆ DataLogName()

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

The filename of the ith datalog file.

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

◆ Define_ERFFillPatchers()

void ERF::Define_ERFFillPatchers ( int  lev)
private
2022 {
2023  auto& fine_new = vars_new[lev];
2024  auto& crse_new = vars_new[lev-1];
2025  auto& ba_fine = fine_new[Vars::cons].boxArray();
2026  auto& ba_crse = crse_new[Vars::cons].boxArray();
2027  auto& dm_fine = fine_new[Vars::cons].DistributionMap();
2028  auto& dm_crse = crse_new[Vars::cons].DistributionMap();
2029 
2030  int ncomp = fine_new[Vars::cons].nComp();
2031 
2032  FPr_c[lev-1].Define(ba_fine, dm_fine, geom[lev] ,
2033  ba_crse, dm_crse, geom[lev-1],
2034  -cf_width, -cf_set_width, ncomp, &cell_cons_interp);
2035  FPr_u[lev-1].Define(convert(ba_fine, IntVect(1,0,0)), dm_fine, geom[lev] ,
2036  convert(ba_crse, IntVect(1,0,0)), dm_crse, geom[lev-1],
2037  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
2038  FPr_v[lev-1].Define(convert(ba_fine, IntVect(0,1,0)), dm_fine, geom[lev] ,
2039  convert(ba_crse, IntVect(0,1,0)), dm_crse, geom[lev-1],
2040  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
2041  FPr_w[lev-1].Define(convert(ba_fine, IntVect(0,0,1)), dm_fine, geom[lev] ,
2042  convert(ba_crse, IntVect(0,0,1)), dm_crse, geom[lev-1],
2043  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
2044 }

◆ DerDataLog()

AMREX_FORCE_INLINE std::ostream& ERF::DerDataLog ( int  i)
inlineprivate
1254  {
1255  return *der_datalog[i];
1256  }
amrex::Vector< std::unique_ptr< std::fstream > > der_datalog
Definition: ERF.H:1411

◆ DerDataLogName()

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

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

◆ derive_diag_profiles_stag()

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

Computes the profiles for diagnostic quantities at staggered heights.

Parameters
h_avg_uProfile for x-velocity on Host
h_avg_vProfile for y-velocity on Host
h_avg_wProfile for z-velocity on Host
h_avg_rhoProfile for density on Host
h_avg_thProfile for potential temperature on Host
h_avg_ksgsProfile for Kinetic Energy on Host
h_avg_uuProfile for x-velocity squared on Host
h_avg_uvProfile for x-velocity * y-velocity on Host
h_avg_uwProfile for x-velocity * z-velocity on Host
h_avg_vvProfile for y-velocity squared on Host
h_avg_vwProfile for y-velocity * z-velocity on Host
h_avg_wwProfile for z-velocity squared on Host
h_avg_uthProfile for x-velocity * potential temperature on Host
h_avg_uiuiuProfile for u_i*u_i*u triple product on Host
h_avg_uiuivProfile for u_i*u_i*v triple product on Host
h_avg_uiuiwProfile for u_i*u_i*w triple product on Host
h_avg_pProfile for pressure perturbation on Host
h_avg_puProfile for pressure perturbation * x-velocity on Host
h_avg_pvProfile for pressure perturbation * y-velocity on Host
h_avg_pwProfile for pressure perturbation * z-velocity on Host
311 {
312  // We assume that this is always called at level 0
313  int lev = 0;
314 
315  bool l_use_kturb = ((solverChoice.turbChoice[lev].les_type != LESType::None) ||
316  (solverChoice.turbChoice[lev].rans_type != RANSType::None) ||
317  (solverChoice.turbChoice[lev].pbl_type != PBLType::None));
318  bool l_use_KE = ( (solverChoice.turbChoice[lev].les_type == LESType::Deardorff) ||
319  (solverChoice.turbChoice[lev].rans_type == RANSType::kEqn) ||
320  (solverChoice.turbChoice[lev].pbl_type == PBLType::MYNN25) ||
321  (solverChoice.turbChoice[lev].pbl_type == PBLType::MYNNEDMF) );
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 
)
483 {
484  int lev = 0;
485 
486  // This will hold the stress tensor components
487  MultiFab mf_out(grids[lev], dmap[lev], 10, 0);
488 
489  MultiFab mf_rho(vars_new[lev][Vars::cons], make_alias, 0, 1);
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  const Array4<const Real>& rho_arr = mf_rho.const_array(mfi);
499 
500  // NOTE: These are from the last RK stage...
501  const Array4<const Real>& tau11_arr = Tau11_lev[lev]->const_array(mfi);
502  const Array4<const Real>& tau12_arr = Tau12_lev[lev]->const_array(mfi);
503  const Array4<const Real>& tau13_arr = Tau13_lev[lev]->const_array(mfi);
504  const Array4<const Real>& tau22_arr = Tau22_lev[lev]->const_array(mfi);
505  const Array4<const Real>& tau23_arr = Tau23_lev[lev]->const_array(mfi);
506  const Array4<const Real>& tau33_arr = Tau33_lev[lev]->const_array(mfi);
507 
508  // These should be re-calculated during ERF_slow_rhs_post
509  // -- just vertical SFS kinematic heat flux for now
510  //const Array4<const Real>& hfx1_arr = SFS_hfx1_lev[lev]->const_array(mfi);
511  //const Array4<const Real>& hfx2_arr = SFS_hfx2_lev[lev]->const_array(mfi);
512  const Array4<const Real>& hfx3_arr = SFS_hfx3_lev[lev]->const_array(mfi);
513  const Array4<const Real>& q1fx3_arr = (l_use_moist) ? SFS_q1fx3_lev[lev]->const_array(mfi) :
514  Array4<const Real>{};
515  const Array4<const Real>& q2fx3_arr = (l_use_moist) ? SFS_q2fx3_lev[lev]->const_array(mfi) :
516  Array4<const Real>{};
517  const Array4<const Real>& diss_arr = SFS_diss_lev[lev]->const_array(mfi);
518 
519  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
520  {
521  // rho averaging should follow Diffusion/ERF_ComputeStress_*.cpp
522  fab_arr(i, j, k, 0) = tau11_arr(i,j,k) / rho_arr(i,j,k);
523  fab_arr(i, j, k, 1) = ( tau12_arr(i,j ,k) + tau12_arr(i+1,j ,k)
524  + tau12_arr(i,j+1,k) + tau12_arr(i+1,j+1,k) )
525  / ( rho_arr(i,j ,k) + rho_arr(i+1,j ,k)
526  + rho_arr(i,j+1,k) + rho_arr(i+1,j+1,k) );
527  fab_arr(i, j, k, 2) = ( tau13_arr(i,j,k ) + tau13_arr(i+1,j,k )
528  + tau13_arr(i,j,k+1) + tau13_arr(i+1,j,k+1) )
529  / ( rho_arr(i,j,k ) + rho_arr(i+1,j,k )
530  + rho_arr(i,j,k+1) + rho_arr(i+1,j,k+1) );
531  fab_arr(i, j, k, 3) = tau22_arr(i,j,k) / rho_arr(i,j,k);
532  fab_arr(i, j, k, 4) = ( tau23_arr(i,j,k ) + tau23_arr(i,j+1,k )
533  + tau23_arr(i,j,k+1) + tau23_arr(i,j+1,k+1) )
534  / ( rho_arr(i,j,k ) + rho_arr(i,j+1,k )
535  + rho_arr(i,j,k+1) + rho_arr(i,j+1,k+1) );
536  fab_arr(i, j, k, 5) = tau33_arr(i,j,k) / rho_arr(i,j,k);
537  fab_arr(i, j, k, 6) = 0.5 * ( hfx3_arr(i,j,k) + hfx3_arr(i,j,k+1) ) / rho_arr(i,j,k);
538  fab_arr(i, j, k, 7) = (l_use_moist) ? 0.5 * ( q1fx3_arr(i,j,k) + q1fx3_arr(i,j,k+1) ) / rho_arr(i,j,k) : 0.0;
539  fab_arr(i, j, k, 8) = (l_use_moist) ? 0.5 * ( q2fx3_arr(i,j,k) + q2fx3_arr(i,j,k+1) ) / rho_arr(i,j,k) : 0.0;
540  fab_arr(i, j, k, 9) = diss_arr(i,j,k) / rho_arr(i,j,k);
541  });
542  }
543 
544  int zdir = 2;
545  auto domain = geom[0].Domain();
546 
547  h_avg_tau11 = sumToLine(mf_out,0,1,domain,zdir);
548  h_avg_tau12 = sumToLine(mf_out,1,1,domain,zdir);
549  h_avg_tau13 = sumToLine(mf_out,2,1,domain,zdir);
550  h_avg_tau22 = sumToLine(mf_out,3,1,domain,zdir);
551  h_avg_tau23 = sumToLine(mf_out,4,1,domain,zdir);
552  h_avg_tau33 = sumToLine(mf_out,5,1,domain,zdir);
553  h_avg_hfx3 = sumToLine(mf_out,6,1,domain,zdir);
554  h_avg_q1fx3 = sumToLine(mf_out,7,1,domain,zdir);
555  h_avg_q2fx3 = sumToLine(mf_out,8,1,domain,zdir);
556  h_avg_diss = sumToLine(mf_out,9,1,domain,zdir);
557 
558  int ht_size = h_avg_tau11.size();
559 
560  // Divide by the total number of cells we are averaging over
561  Real area_z = static_cast<Real>(domain.length(0)*domain.length(1));
562  for (int k = 0; k < ht_size; ++k) {
563  h_avg_tau11[k] /= area_z;
564  h_avg_tau12[k] /= area_z;
565  h_avg_tau13[k] /= area_z;
566  h_avg_tau22[k] /= area_z;
567  h_avg_tau23[k] /= area_z;
568  h_avg_tau33[k] /= area_z;
569  h_avg_hfx3[k] /= area_z;
570  h_avg_q1fx3[k] /= area_z;
571  h_avg_q2fx3[k] /= area_z;
572  h_avg_diss[k] /= area_z;
573  }
574 }

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

◆ derive_upwp()

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

◆ EBFactory()

amrex::EBFArrayBoxFactory const& ERF::EBFactory ( int  lev) const
inlineprivatenoexcept
1442  {
1443  return *(eb[lev]->get_const_factory());
1444  }
amrex::Vector< std::unique_ptr< eb_ > > eb
Definition: ERF.H:1434

Referenced by WriteMyEBSurface().

Here is the caller graph for this function:

◆ erf_enforce_hse()

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

Enforces hydrostatic equilibrium when using terrain.

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

◆ ERF_shared()

void ERF::ERF_shared ( )
102 {
103  if (ParallelDescriptor::IOProcessor()) {
104  const char* erf_hash = buildInfoGetGitHash(1);
105  const char* amrex_hash = buildInfoGetGitHash(2);
106  const char* buildgithash = buildInfoGetBuildGitHash();
107  const char* buildgitname = buildInfoGetBuildGitName();
108 
109  if (strlen(erf_hash) > 0) {
110  Print() << "\n"
111  << "ERF git hash: " << erf_hash << "\n";
112  }
113  if (strlen(amrex_hash) > 0) {
114  Print() << "AMReX git hash: " << amrex_hash << "\n";
115  }
116  if (strlen(buildgithash) > 0) {
117  Print() << buildgitname << " git hash: " << buildgithash << "\n";
118  }
119 
120  Print() << "\n";
121  }
122 
123  int nlevs_max = max_level + 1;
124 
125 #ifdef ERF_USE_WINDFARM
126  Nturb.resize(nlevs_max);
127  vars_windfarm.resize(nlevs_max);
128  SMark.resize(nlevs_max);
129 #endif
130 
131 #if defined(ERF_USE_RRTMGP)
132  qheating_rates.resize(nlevs_max);
133  sw_lw_fluxes.resize(nlevs_max);
134  solar_zenith.resize(nlevs_max);
135 #endif
136 
137  // NOTE: size lsm before readparams (chooses the model at all levels)
138  lsm.ReSize(nlevs_max);
139  lsm_data.resize(nlevs_max);
140  lsm_flux.resize(nlevs_max);
141 
142  // NOTE: size canopy model before readparams (if file exists, we construct)
143  m_forest_drag.resize(nlevs_max);
144  for (int lev = 0; lev <= max_level; ++lev) { m_forest_drag[lev] = nullptr;}
145 
146  ReadParameters();
147  initializeMicrophysics(nlevs_max);
148 
149 #ifdef ERF_USE_WINDFARM
150  initializeWindFarm(nlevs_max);
151 #endif
152 
153 #ifdef ERF_USE_RRTMGP
154  rad.resize(nlevs_max);
155  for (int lev = 0; lev <= max_level; ++lev) { rad[lev] = std::make_unique<Radiation>(lev,solverChoice); }
156 #endif
157 
158  const std::string& pv1 = "plot_vars_1"; setPlotVariables(pv1,plot_var_names_1);
159  const std::string& pv2 = "plot_vars_2"; setPlotVariables(pv2,plot_var_names_2);
160 
161  // This is only used when we have mesh_type == MeshType::StretchedDz
162  stretched_dz_h.resize(nlevs_max);
163  stretched_dz_d.resize(nlevs_max);
164 
165  // Initialize staggered vertical levels for grid stretching or terrain, and
166  // to simplify Rayleigh damping layer calculations.
167  zlevels_stag.resize(max_level+1);
171  geom,
172  refRatio(),
175  solverChoice.dz0);
176 
177  if (SolverChoice::mesh_type == MeshType::StretchedDz ||
178  SolverChoice::mesh_type == MeshType::VariableDz) {
179  int nz = geom[0].Domain().length(2) + 1; // staggered
180  if (std::fabs(zlevels_stag[0][nz-1]-geom[0].ProbHi(2)) > 1.0e-4) {
181  Print() << "Note: prob_hi[2]=" << geom[0].ProbHi(2)
182  << " does not match highest requested z level " << zlevels_stag[0][nz-1]
183  << std::endl;
184  }
185  if (std::fabs(zlevels_stag[0][0]-geom[0].ProbLo(2)) > 1.0e-4) {
186  Print() << "Note: prob_lo[2]=" << geom[0].ProbLo(2)
187  << " does not match lowest requested level " << zlevels_stag[0][0]
188  << std::endl;
189  }
190 
191  // Redefine the problem domain here?
192  }
193 
194  prob = amrex_probinit(geom[0].ProbLo(),geom[0].ProbHi());
195 
196  // Geometry on all levels has been defined already.
197 
198  // No valid BoxArray and DistributionMapping have been defined.
199  // But the arrays for them have been resized.
200 
201  istep.resize(nlevs_max, 0);
202  nsubsteps.resize(nlevs_max, 1);
203  for (int lev = 1; lev <= max_level; ++lev) {
204  nsubsteps[lev] = MaxRefRatio(lev-1);
205  }
206 
207  t_new.resize(nlevs_max, 0.0);
208  t_old.resize(nlevs_max, -1.e100);
209  dt.resize(nlevs_max, std::min(1.e100,dt_max_initial));
210  dt_mri_ratio.resize(nlevs_max, 1);
211 
212  vars_new.resize(nlevs_max);
213  vars_old.resize(nlevs_max);
214 
215  // We resize this regardless in order to pass it without error
216  pp_inc.resize(nlevs_max);
217 
218  rU_new.resize(nlevs_max);
219  rV_new.resize(nlevs_max);
220  rW_new.resize(nlevs_max);
221 
222  rU_old.resize(nlevs_max);
223  rV_old.resize(nlevs_max);
224  rW_old.resize(nlevs_max);
225 
226  // xmom_crse_rhs.resize(nlevs_max);
227  // ymom_crse_rhs.resize(nlevs_max);
228  zmom_crse_rhs.resize(nlevs_max);
229 
230  for (int lev = 0; lev < nlevs_max; ++lev) {
231  vars_new[lev].resize(Vars::NumTypes);
232  vars_old[lev].resize(Vars::NumTypes);
233  }
234 
235  // Time integrator
236  mri_integrator_mem.resize(nlevs_max);
237 
238  // Physical boundary conditions
239  physbcs_cons.resize(nlevs_max);
240  physbcs_u.resize(nlevs_max);
241  physbcs_v.resize(nlevs_max);
242  physbcs_w.resize(nlevs_max);
243  physbcs_base.resize(nlevs_max);
244 
245  // Planes to hold Dirichlet values at boundaries
246  xvel_bc_data.resize(nlevs_max);
247  yvel_bc_data.resize(nlevs_max);
248  zvel_bc_data.resize(nlevs_max);
249  th_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  terrain_blanking.resize(nlevs_max);
292 
293  // Wall distance
294  walldist.resize(nlevs_max);
295 
296  // Mapfactors
297  mapfac_m.resize(nlevs_max);
298  mapfac_u.resize(nlevs_max);
299  mapfac_v.resize(nlevs_max);
300 
301  // Thin immersed body
302  xflux_imask.resize(nlevs_max);
303  yflux_imask.resize(nlevs_max);
304  zflux_imask.resize(nlevs_max);
305  //overset_imask.resize(nlevs_max);
306  thin_xforce.resize(nlevs_max);
307  thin_yforce.resize(nlevs_max);
308  thin_zforce.resize(nlevs_max);
309 
310  // Base state
311  base_state.resize(nlevs_max);
312  base_state_new.resize(nlevs_max);
313 
314  // Wave coupling data
315  Hwave.resize(nlevs_max);
316  Lwave.resize(nlevs_max);
317  for (int lev = 0; lev < max_level; ++lev)
318  {
319  Hwave[lev] = nullptr;
320  Lwave[lev] = nullptr;
321  }
322  Hwave_onegrid.resize(nlevs_max);
323  Lwave_onegrid.resize(nlevs_max);
324  for (int lev = 0; lev < max_level; ++lev)
325  {
326  Hwave_onegrid[lev] = nullptr;
327  Lwave_onegrid[lev] = nullptr;
328  }
329 
330  // Theta prim for MOST
331  Theta_prim.resize(nlevs_max);
332 
333  // Qv prim for MOST
334  Qv_prim.resize(nlevs_max);
335 
336  // Qr prim for MOST
337  Qr_prim.resize(nlevs_max);
338 
339  // Time averaged velocity field
340  vel_t_avg.resize(nlevs_max);
341  t_avg_cnt.resize(nlevs_max);
342 
343 #ifdef ERF_USE_NETCDF
344  // Size lat long arrays if using netcdf
345  lat_m.resize(nlevs_max);
346  lon_m.resize(nlevs_max);
347  for (int lev = 0; lev < max_level; ++lev) {
348  lat_m[lev] = nullptr;
349  lon_m[lev] = nullptr;
350  }
351 #endif
352 
353  // Variable coriolis
354  sinPhi_m.resize(nlevs_max);
355  cosPhi_m.resize(nlevs_max);
356  for (int lev = 0; lev < max_level; ++lev) {
357  sinPhi_m[lev] = nullptr;
358  cosPhi_m[lev] = nullptr;
359  }
360 
361  // Initialize tagging criteria for mesh refinement
363 
364  for (int lev = 0; lev < max_level; ++lev)
365  {
366  Print() << "Refinement ratio at level " << lev+1 << " set to be " <<
367  ref_ratio[lev][0] << " " << ref_ratio[lev][1] << " " << ref_ratio[lev][2] << std::endl;
368  }
369 
370  // We will create each of these in MakeNewLevelFromScratch
371  eb.resize(max_level+1);
372  for (int lev = 0; lev < max_level + 1; lev++){
373  eb[lev] = std::make_unique<eb_>();
374  }
375 
376  //
377  // Construct the EB data structures and store in a separate class
378  //
379  // This is needed before initializing level MultiFabs
380  if ( solverChoice.terrain_type == TerrainType::EB ||
381  solverChoice.terrain_type == TerrainType::ImmersedForcing)
382  {
383  Box terrain_bx(surroundingNodes(geom[max_level].Domain())); terrain_bx.grow(3);
384  FArrayBox terrain_fab(makeSlab(terrain_bx,2,0),1);
385  Real dummy_time = 0.0;
386  prob->init_terrain_surface(geom[max_level], terrain_fab, dummy_time);
387  TerrainIF ebterrain(terrain_fab, geom[max_level], stretched_dz_d[max_level]);
388  auto gshop = EB2::makeShop(ebterrain);
389  bool build_coarse_level_by_coarsening(false);
390  amrex::EB2::Build(gshop, geom[max_level], max_level, max_level, build_coarse_level_by_coarsening);
391  }
392 }
void init_zlevels(Vector< Vector< Real >> &zlevels_stag, Vector< Vector< Real >> &stretched_dz_h, Vector< Gpu::DeviceVector< Real >> &stretched_dz_d, Vector< Geometry > const &geom, Vector< IntVect > const &ref_ratio, const Real grid_stretching_ratio, const Real zsurf, const Real dz0)
Definition: ERF_InitZLevels.cpp:11
std::unique_ptr< ProblemBase > amrex_probinit(const amrex_real *problo, const amrex_real *probhi) AMREX_ATTRIBUTE_WEAK
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Hwave_onegrid
Definition: ERF.H:865
amrex::Vector< std::unique_ptr< amrex::MultiFab > > thin_yforce
Definition: ERF.H:898
void setPlotVariables(const std::string &pp_plot_var_names, amrex::Vector< std::string > &plot_var_names)
Definition: ERF_Plotfile.cpp:13
void ReadParameters()
Definition: ERF.cpp:1487
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ay_new
Definition: ERF.H:840
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_nd_src
Definition: ERF.H:831
amrex::Vector< amrex::MultiFab > base_state_new
Definition: ERF.H:860
amrex::Vector< std::unique_ptr< amrex::MultiFab > > az
Definition: ERF.H:829
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::iMultiFab > > > lmask_lev
Definition: ERF.H:811
amrex::Vector< std::unique_ptr< amrex::MultiFab > > terrain_blanking
Definition: ERF.H:846
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_nd_new
Definition: ERF.H:837
amrex::Vector< std::unique_ptr< amrex::MultiFab > > thin_zforce
Definition: ERF.H:899
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > sst_lev
Definition: ERF.H:810
amrex::Vector< std::unique_ptr< amrex::MultiFab > > thin_xforce
Definition: ERF.H:897
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > th_bc_data
Definition: ERF.H:686
amrex::Vector< std::string > plot_var_names_1
Definition: ERF.H:975
amrex::Vector< amrex::Real > t_old
Definition: ERF.H:720
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_t_rk
Definition: ERF.H:843
amrex::Vector< std::string > plot_var_names_2
Definition: ERF.H:976
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Lwave_onegrid
Definition: ERF.H:866
amrex::Vector< std::unique_ptr< ForestDrag > > m_forest_drag
Definition: ERF.H:1174
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > xvel_bc_data
Definition: ERF.H:683
amrex::Vector< std::unique_ptr< amrex::MultiFab > > detJ_cc_src
Definition: ERF.H:832
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ay_src
Definition: ERF.H:834
amrex::Vector< std::unique_ptr< amrex::iMultiFab > > yflux_imask
Definition: ERF.H:892
amrex::Vector< std::unique_ptr< amrex::MultiFab > > az_new
Definition: ERF.H:841
amrex::Vector< amrex::Vector< amrex::MultiFab * > > lsm_flux
Definition: ERF.H:780
void refinement_criteria_setup()
Definition: ERF_Tagging.cpp:150
amrex::Vector< std::unique_ptr< amrex::MultiFab > > sinPhi_m
Definition: ERF.H:674
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ax_src
Definition: ERF.H:833
amrex::Vector< amrex::Vector< amrex::Real > > zlevels_stag
Definition: ERF.H:820
amrex::Vector< amrex::Vector< amrex::MultiFab * > > lsm_data
Definition: ERF.H:779
amrex::Vector< amrex::Vector< amrex::Real > > stretched_dz_h
Definition: ERF.H:856
amrex::Vector< std::unique_ptr< amrex::MultiFab > > az_src
Definition: ERF.H:835
static amrex::Real dt_max_initial
Definition: ERF.H:933
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Lwave
Definition: ERF.H:864
amrex::Vector< std::unique_ptr< amrex::MultiFab > > cosPhi_m
Definition: ERF.H:674
amrex::Vector< std::unique_ptr< amrex::iMultiFab > > zflux_imask
Definition: ERF.H:893
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ax_new
Definition: ERF.H:839
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > zvel_bc_data
Definition: ERF.H:685
amrex::Vector< std::unique_ptr< amrex::MultiFab > > detJ_cc_new
Definition: ERF.H:838
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > yvel_bc_data
Definition: ERF.H:684
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Hwave
Definition: ERF.H:863
amrex::Vector< std::unique_ptr< amrex::iMultiFab > > xflux_imask
Definition: ERF.H:891
void initializeMicrophysics(const int &)
Definition: ERF.cpp:1288
void ReSize(const int &nlev)
Definition: ERF_LandSurface.H:24
Definition: ERF_EBIFTerrain.H:14
const char * buildInfoGetGitHash(int i)
amrex::Real dz0
Definition: ERF_DataStruct.H:716
amrex::Real grid_stretching_ratio
Definition: ERF_DataStruct.H:714
amrex::Real zsurf
Definition: ERF_DataStruct.H:715
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  //
21  // Make sure the ghost cells of the level we are tagging at are filled
22  // in case we take differences that require them
23  // NOTE: We are Fillpatching only the cell-centered variables here
24  //
25  MultiFab& S_new = vars_new[levc][Vars::cons];
26  MultiFab& U_new = vars_new[levc][Vars::xvel];
27  MultiFab& V_new = vars_new[levc][Vars::yvel];
28  MultiFab& W_new = vars_new[levc][Vars::zvel];
29  //
30  if (levc == 0) {
31  FillPatch(levc, time, {&S_new, &U_new, &V_new, &W_new});
32  } else {
33  FillPatch(levc, time, {&S_new, &U_new, &V_new, &W_new},
34  {&S_new, &rU_new[levc], &rV_new[levc], &rW_new[levc]},
35  base_state[levc], base_state[levc],
36  false, true);
37  }
38 
39  for (int j=0; j < ref_tags.size(); ++j)
40  {
41  //
42  // This mf must have ghost cells because we may take differences between adjacent values
43  //
44  std::unique_ptr<MultiFab> mf = std::make_unique<MultiFab>(grids[levc], dmap[levc], 1, 1);
45 
46  // This allows dynamic refinement based on the value of the density
47  if (ref_tags[j].Field() == "density")
48  {
49  MultiFab::Copy(*mf,vars_new[levc][Vars::cons],Rho_comp,0,1,1);
50 
51  // This allows dynamic refinement based on the value of qv
52  } else if ( ref_tags[j].Field() == "qv" ) {
53  MultiFab::Copy( *mf, vars_new[levc][Vars::cons], RhoQ1_comp, 0, 1, 1);
54  MultiFab::Divide(*mf, vars_new[levc][Vars::cons], Rho_comp, 0, 1, 1);
55 
56 
57  // This allows dynamic refinement based on the value of qc
58  } else if (ref_tags[j].Field() == "qc" ) {
59  MultiFab::Copy( *mf, vars_new[levc][Vars::cons], RhoQ2_comp, 0, 1, 1);
60  MultiFab::Divide(*mf, vars_new[levc][Vars::cons], Rho_comp, 0, 1, 1);
61 
62  // This allows dynamic refinement based on the value of the z-component of vorticity
63  } else if (ref_tags[j].Field() == "vorticity" ) {
64  Vector<MultiFab> mf_cc_vel(1);
65  mf_cc_vel[0].define(grids[levc], dmap[levc], AMREX_SPACEDIM, IntVect(1,1,1));
66  average_face_to_cellcenter(mf_cc_vel[0],0,Array<const MultiFab*,3>{&U_new, &V_new, &W_new});
67 
68  // Impose bc's at domain boundaries at all levels
69  FillBdyCCVels(mf_cc_vel,levc);
70 
71  mf->setVal(0.);
72 
73  for (MFIter mfi(*mf, TilingIfNotGPU()); mfi.isValid(); ++mfi)
74  {
75  const Box& bx = mfi.tilebox();
76  auto& dfab = (*mf)[mfi];
77  auto& sfab = mf_cc_vel[0][mfi];
78  derived::erf_dervortz(bx, dfab, 0, 1, sfab, Geom(levc), time, nullptr, levc);
79  }
80 
81  // This allows dynamic refinement based on the value of the scalar/theta
82  } else if ( (ref_tags[j].Field() == "scalar" ) ||
83  (ref_tags[j].Field() == "theta" ) )
84  {
85  for (MFIter mfi(*mf, TilingIfNotGPU()); mfi.isValid(); ++mfi)
86  {
87  const Box& bx = mfi.growntilebox();
88  auto& dfab = (*mf)[mfi];
89  auto& sfab = vars_new[levc][Vars::cons][mfi];
90  if (ref_tags[j].Field() == "scalar") {
91  derived::erf_derscalar(bx, dfab, 0, 1, sfab, Geom(levc), time, nullptr, levc);
92  } else if (ref_tags[j].Field() == "theta") {
93  derived::erf_dertheta(bx, dfab, 0, 1, sfab, Geom(levc), time, nullptr, levc);
94  }
95  } // mfi
96  // This allows dynamic refinement based on the value of the density
97  } else if ( (SolverChoice::terrain_type == TerrainType::ImmersedForcing) &&
98  (ref_tags[j].Field() == "terrain_blanking") )
99  {
100  MultiFab::Copy(*mf,*terrain_blanking[levc],0,0,1,1);
101 
102 #ifdef ERF_USE_PARTICLES
103  } else {
104  //
105  // This allows dynamic refinement based on the number of particles per cell
106  //
107  // Note that we must count all the particles in levels both at and above the current,
108  // since otherwise, e.g., if the particles are all at level 1, counting particles at
109  // level 0 will not trigger refinement when regridding so level 1 will disappear,
110  // then come back at the next regridding
111  //
112  const auto& particles_namelist( particleData.getNames() );
113  mf->setVal(0.0);
114  for (ParticlesNamesVector::size_type i = 0; i < particles_namelist.size(); i++)
115  {
116  std::string tmp_string(particles_namelist[i]+"_count");
117  IntVect rr = IntVect::TheUnitVector();
118  if (ref_tags[j].Field() == tmp_string) {
119  for (int lev = levc; lev <= finest_level; lev++)
120  {
121  MultiFab temp_dat(grids[lev], dmap[lev], 1, 0); temp_dat.setVal(0);
122  particleData[particles_namelist[i]]->IncrementWithTotal(temp_dat, lev);
123 
124  MultiFab temp_dat_crse(grids[levc], dmap[levc], 1, 0); temp_dat_crse.setVal(0);
125 
126  if (lev == levc) {
127  MultiFab::Copy(*mf, temp_dat, 0, 0, 1, 0);
128  } else {
129  for (int d = 0; d < AMREX_SPACEDIM; d++) {
130  rr[d] *= ref_ratio[levc][d];
131  }
132  average_down(temp_dat, temp_dat_crse, 0, 1, rr);
133  MultiFab::Add(*mf, temp_dat_crse, 0, 0, 1, 0);
134  }
135  }
136  }
137  }
138 #endif
139  }
140 
141  ref_tags[j](tags,mf.get(),clearval,tagval,time,levc,geom[levc]);
142  } // loop over j
143 }
void FillBdyCCVels(amrex::Vector< amrex::MultiFab > &mf_cc_vel, int levc=0)
Definition: ERF_FillBdyCCVels.cpp:11
static amrex::Vector< amrex::AMRErrorTag > ref_tags
Definition: ERF.H:1179
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_dervortz(const amrex::Box &bx, amrex::FArrayBox &derfab, int dcomp, int ncomp, const amrex::FArrayBox &datfab, const amrex::Geometry &geomdata, amrex::Real, const int *, const int)
Definition: ERF_Derive.cpp:256
void erf_dertheta(const Box &bx, FArrayBox &derfab, int, int, const FArrayBox &datfab, const Geometry &, Real, const int *, const int)
Definition: ERF_Derive.cpp:144
Here is the call graph for this function:

◆ estTimeStep()

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

Function that calls estTimeStep for each level

Parameters
[in]levellevel of refinement (coarsest level i 0)
[out]dt_fast_ratioratio of slow to fast time step
55 {
56  BL_PROFILE("ERF::estTimeStep()");
57 
58  Real estdt_comp = 1.e20;
59  Real estdt_lowM = 1.e20;
60 
61  // We intentionally use the level 0 domain to compute whether to use this direction in the dt calculation
62  const int nxc = geom[0].Domain().length(0);
63  const int nyc = geom[0].Domain().length(1);
64 
65  auto const dxinv = geom[level].InvCellSizeArray();
66  auto const dzinv = 1.0 / dz_min[level];
67 
68  MultiFab const& S_new = vars_new[level][Vars::cons];
69 
70  MultiFab ccvel(grids[level],dmap[level],3,0);
71 
72  average_face_to_cellcenter(ccvel,0,
73  Array<const MultiFab*,3>{&vars_new[level][Vars::xvel],
74  &vars_new[level][Vars::yvel],
75  &vars_new[level][Vars::zvel]});
76 
77  int l_implicit_substepping = (solverChoice.substepping_type[level] == SubsteppingType::Implicit);
78  int l_anelastic = solverChoice.anelastic[level];
79 
80  Real estdt_comp_inv;
81 
82  if (solverChoice.terrain_type == TerrainType::EB)
83  {
84  const eb_& eb_lev = get_eb(level);
85  const MultiFab& detJ = (eb_lev.get_const_factory())->getVolFrac();
86 
87  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  {
93  Real new_comp_dt = -1.e100;
94  amrex::Loop(b, [=,&new_comp_dt] (int i, int j, int k) noexcept
95  {
96  if (vf(i,j,k) > 0.)
97  {
98  const Real rho = s(i, j, k, Rho_comp);
99  const Real rhotheta = s(i, j, k, RhoTheta_comp);
100 
101  // NOTE: even when moisture is present,
102  // we only use the partial pressure of the dry air
103  // to compute the soundspeed
104  Real pressure = getPgivenRTh(rhotheta);
105  Real c = std::sqrt(Gamma * pressure / rho);
106 
107  // If we are doing implicit acoustic substepping, then the z-direction does not contribute
108  // to the computation of the time step
109  if (l_implicit_substepping) {
110  if ((nxc > 1) && (nyc==1)) {
111  // 2-D in x-z
112  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]), new_comp_dt);
113  } else if ((nyc > 1) && (nxc==1)) {
114  // 2-D in y-z
115  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,1))+c)*dxinv[1]), new_comp_dt);
116  } else {
117  // 3-D or SCM
118  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]),
119  ((amrex::Math::abs(u(i,j,k,1))+c)*dxinv[1]), new_comp_dt);
120  }
121 
122  // If we are not doing implicit acoustic substepping, then the z-direction contributes
123  // to the computation of the time step
124  } else {
125  if (nxc > 1 && nyc > 1) {
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]),
128  ((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
129  } else if (nxc > 1) {
130  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]),
131  ((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
132  } else if (nyc > 1) {
133  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,1))+c)*dxinv[1]),
134  ((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
135  } else {
136  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
137  }
138 
139  }
140  }
141  });
142  return new_comp_dt;
143  });
144 
145  } else {
146  estdt_comp_inv = ReduceMax(S_new, ccvel, 0,
147  [=] AMREX_GPU_HOST_DEVICE (Box const& b,
148  Array4<Real const> const& s,
149  Array4<Real const> const& u) -> Real
150  {
151  Real new_comp_dt = -1.e100;
152  amrex::Loop(b, [=,&new_comp_dt] (int i, int j, int k) noexcept
153  {
154  {
155  const Real rho = s(i, j, k, Rho_comp);
156  const Real rhotheta = s(i, j, k, RhoTheta_comp);
157 
158  // NOTE: even when moisture is present,
159  // we only use the partial pressure of the dry air
160  // to compute the soundspeed
161  Real pressure = getPgivenRTh(rhotheta);
162  Real c = std::sqrt(Gamma * pressure / rho);
163 
164  // If we are doing implicit acoustic substepping, then the z-direction does not contribute
165  // to the computation of the time step
166  if (l_implicit_substepping) {
167  if ((nxc > 1) && (nyc==1)) {
168  // 2-D in x-z
169  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]), new_comp_dt);
170  } else if ((nyc > 1) && (nxc==1)) {
171  // 2-D in y-z
172  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,1))+c)*dxinv[1]), new_comp_dt);
173  } else {
174  // 3-D or SCM
175  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]),
176  ((amrex::Math::abs(u(i,j,k,1))+c)*dxinv[1]), new_comp_dt);
177  }
178 
179  // If we are not doing implicit acoustic substepping, then the z-direction contributes
180  // to the computation of the time step
181  } else {
182  if (nxc > 1 && nyc > 1) {
183  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]),
184  ((amrex::Math::abs(u(i,j,k,1))+c)*dxinv[1]),
185  ((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
186  } else if (nxc > 1) {
187  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0))+c)*dxinv[0]),
188  ((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
189  } else if (nyc > 1) {
190  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,1))+c)*dxinv[1]),
191  ((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
192  } else {
193  new_comp_dt = amrex::max(((amrex::Math::abs(u(i,j,k,2))+c)*dzinv ), new_comp_dt);
194  }
195 
196  }
197  }
198  });
199  return new_comp_dt;
200  });
201  } // not EB
202 
203  ParallelDescriptor::ReduceRealMax(estdt_comp_inv);
204  estdt_comp = cfl / estdt_comp_inv;
205 
206  Real estdt_lowM_inv = ReduceMax(ccvel, 0,
207  [=] AMREX_GPU_HOST_DEVICE (Box const& b,
208  Array4<Real const> const& u) -> Real
209  {
210  Real new_lm_dt = -1.e100;
211  Loop(b, [=,&new_lm_dt] (int i, int j, int k) noexcept
212  {
213  new_lm_dt = amrex::max(((amrex::Math::abs(u(i,j,k,0)))*dxinv[0]),
214  ((amrex::Math::abs(u(i,j,k,1)))*dxinv[1]),
215  ((amrex::Math::abs(u(i,j,k,2)))*dxinv[2]), new_lm_dt);
216  });
217  return new_lm_dt;
218  });
219 
220  ParallelDescriptor::ReduceRealMax(estdt_lowM_inv);
221  if (estdt_lowM_inv > 0.0_rt)
222  estdt_lowM = cfl / estdt_lowM_inv;
223 
224  if (verbose) {
225  if (fixed_dt[level] <= 0.0) {
226  Print() << "Using cfl = " << cfl << " and dx/dy/dz_min = " <<
227  1.0/dxinv[0] << " " << 1.0/dxinv[1] << " " << dz_min[level] << std::endl;
228  Print() << "Compressible dt at level " << level << ": " << estdt_comp << std::endl;
229  if (estdt_lowM_inv > 0.0_rt) {
230  Print() << "Anelastic dt at level " << level << ": " << estdt_lowM << std::endl;
231  } else {
232  Print() << "Anelastic dt at level " << level << ": undefined " << std::endl;
233  }
234  }
235 
236  if (fixed_dt[level] > 0.0) {
237  Print() << "Based on cfl of 1.0 " << std::endl;
238  Print() << "Compressible dt at level " << level << " would be: " << estdt_comp/cfl << std::endl;
239  if (estdt_lowM_inv > 0.0_rt) {
240  Print() << "Anelastic dt at level " << level << " would be: " << estdt_lowM/cfl << std::endl;
241  } else {
242  Print() << "Anelastic dt at level " << level << " would be undefined " << std::endl;
243  }
244  Print() << "Fixed dt at level " << level << " is: " << fixed_dt[level] << std::endl;
245  if (fixed_fast_dt[level] > 0.0) {
246  Print() << "Fixed fast dt at level " << level << " is: " << fixed_fast_dt[level] << std::endl;
247  }
248  }
249  }
250 
251  if (solverChoice.substepping_type[level] != SubsteppingType::None) {
252  if (fixed_dt[level] > 0. && fixed_fast_dt[level] > 0.) {
253  dt_fast_ratio = static_cast<long>( fixed_dt[level] / fixed_fast_dt[level] );
254  } else if (fixed_dt[level] > 0.) {
255  // Max CFL_c = 1.0 for substeps by default, but we enforce a min of 4 substeps
256  auto dt_sub_max = (estdt_comp/cfl * sub_cfl);
257  dt_fast_ratio = static_cast<long>( std::max(fixed_dt[level]/dt_sub_max,4.) );
258  } else {
259  // auto dt_sub_max = (estdt_comp/cfl * sub_cfl);
260  // dt_fast_ratio = static_cast<long>( std::max(estdt_comp/dt_sub_max,4.) );
261  dt_fast_ratio = static_cast<long>( std::max(cfl / sub_cfl, 4.) );
262  }
263 
264  // Force time step ratio to be an even value
266  if ( dt_fast_ratio%2 != 0) dt_fast_ratio += 1;
267  } else {
268  if ( dt_fast_ratio%6 != 0) {
269  Print() << "mri_dt_ratio = " << dt_fast_ratio
270  << " not divisible by 6 for N/3 substeps in stage 1" << std::endl;
271  dt_fast_ratio = static_cast<int>(std::ceil(dt_fast_ratio/6.0) * 6);
272  }
273  }
274 
275  if (verbose) {
276  Print() << "smallest even ratio is: " << dt_fast_ratio << std::endl;
277  }
278  } // if substepping, either explicit or implicit
279 
280  if (fixed_dt[level] > 0.0) {
281  return fixed_dt[level];
282  } else {
283  // Anelastic (substepping is not allowed)
284  if (l_anelastic) {
285 
286  // Make sure that timestep is less than the dt_max
287  estdt_lowM = amrex::min(estdt_lowM, dt_max);
288 
289  // On the first timestep enforce dt_max_initial
290  if(istep[level] == 0){
291  return amrex::min(dt_max_initial, estdt_lowM);
292  }
293  else{
294  return estdt_lowM;
295  }
296 
297 
298  // Compressible with or without substepping
299  } else {
300  return estdt_comp;
301  }
302  }
303 }
constexpr amrex::Real Gamma
Definition: ERF_Constants.H:19
amrex::Vector< amrex::Real > dz_min
Definition: ERF.H:1187
eb_ const & get_eb(int lev) const noexcept
Definition: ERF.H:1436
amrex::Vector< amrex::Real > fixed_dt
Definition: ERF.H:937
static amrex::Real dt_max
Definition: ERF.H:934
amrex::Vector< amrex::Real > fixed_fast_dt
Definition: ERF.H:938
static amrex::Real cfl
Definition: ERF.H:929
static amrex::Real sub_cfl
Definition: ERF.H:930
Definition: ERF_EB.H:13
const std::unique_ptr< amrex::EBFArrayBoxFactory > & get_const_factory() const noexcept
Definition: ERF_EB.H:40
@ rho
Definition: ERF_Kessler.H:22
int force_stage1_single_substep
Definition: ERF_DataStruct.H:678
Here is the call graph for this function:

◆ Evolve()

void ERF::Evolve ( )
399 {
400  BL_PROFILE_VAR("ERF::Evolve()", evolve);
401 
402  Real cur_time = t_new[0];
403 
404  // Take one coarse timestep by calling timeStep -- which recursively calls timeStep
405  // for finer levels (with or without subcycling)
406  for (int step = istep[0]; step < max_step && cur_time < stop_time; ++step)
407  {
408  if (use_datetime) {
409  Print() << "\n" << getTimestamp(cur_time, datetime_format)
410  << " (" << cur_time-start_time << " s elapsed)"
411  << std::endl;
412  }
413  Print() << "\nCoarse STEP " << step+1 << " starts ..." << std::endl;
414 
415  ComputeDt(step);
416 
417  // Make sure we have read enough of the boundary plane data to make it through this timestep
418  if (input_bndry_planes)
419  {
420  m_r2d->read_input_files(cur_time,dt[0],m_bc_extdir_vals);
421  }
422 
423  int lev = 0;
424  int iteration = 1;
425  timeStep(lev, cur_time, iteration);
426 
427  cur_time += dt[0];
428 
429  Print() << "Coarse STEP " << step+1 << " ends." << " TIME = " << cur_time
430  << " DT = " << dt[0] << std::endl;
431 
432  post_timestep(step, cur_time, dt[0]);
433 
434  if (writeNow(cur_time, dt[0], step+1, m_plot_int_1, m_plot_per_1)) {
435  last_plot_file_step_1 = step+1;
437  }
438  if (writeNow(cur_time, dt[0], step+1, m_plot_int_2, m_plot_per_2)) {
439  last_plot_file_step_2 = step+1;
441  }
442  if (writeNow(cur_time, dt[0], step+1, m_subvol_int, m_subvol_per)) {
443  last_subvol = step+1;
444  WriteSubvolume();
445  }
446 
447  if (writeNow(cur_time, dt[0], step+1, m_check_int, m_check_per)) {
448  last_check_file_step = step+1;
449 #ifdef ERF_USE_NETCDF
450  if (check_type == "netcdf") {
451  WriteNCCheckpointFile();
452  }
453 #endif
454  if (check_type == "native") {
456  }
457  }
458 
459 #ifdef AMREX_MEM_PROFILING
460  {
461  std::ostringstream ss;
462  ss << "[STEP " << step+1 << "]";
463  MemProfiler::report(ss.str());
464  }
465 #endif
466 
467  if (cur_time >= stop_time - 1.e-6*dt[0]) break;
468  }
469 
470  // Write plotfiles at final time
471  if ( (m_plot_int_1 > 0 || m_plot_per_1 > 0.) && istep[0] > last_plot_file_step_1 ) {
473  }
474  if ( (m_plot_int_2 > 0 || m_plot_per_2 > 0.) && istep[0] > last_plot_file_step_2) {
476  }
477  if ( (m_subvol_int > 0 || m_subvol_per > 0.) && istep[0] > last_subvol) {
478  WriteSubvolume();
479  }
480 
481  if ( (m_check_int > 0 || m_check_per > 0.) && istep[0] > last_check_file_step) {
482 #ifdef ERF_USE_NETCDF
483  if (check_type == "netcdf") {
484  WriteNCCheckpointFile();
485  }
486 #endif
487  if (check_type == "native") {
489  }
490  }
491 
492  BL_PROFILE_VAR_STOP(evolve);
493 }
AMREX_FORCE_INLINE std::string getTimestamp(const amrex::Real epoch_real, const std::string &datetime_format)
Definition: ERF_EpochTime.H:35
int last_check_file_step
Definition: ERF.H:905
int max_step
Definition: ERF.H:918
int last_plot_file_step_2
Definition: ERF.H:902
static PlotFileType plotfile_type_1
Definition: ERF.H:1065
int m_subvol_int
Definition: ERF.H:956
amrex::Array< amrex::Array< amrex::Real, AMREX_SPACEDIM *2 >, AMREX_SPACEDIM+NBCVAR_max > m_bc_extdir_vals
Definition: ERF.H:882
amrex::Real m_plot_per_1
Definition: ERF.H:957
std::string check_type
Definition: ERF.H:970
void WriteSubvolume()
Definition: ERF_WriteSubvolume.cpp:9
int m_plot_int_1
Definition: ERF.H:954
void post_timestep(int nstep, amrex::Real time, amrex::Real dt_lev)
Definition: ERF.cpp:497
amrex::Real m_subvol_per
Definition: ERF.H:959
amrex::Real m_check_per
Definition: ERF.H:973
int m_check_int
Definition: ERF.H:972
int last_plot_file_step_1
Definition: ERF.H:901
static int input_bndry_planes
Definition: ERF.H:1115
int last_subvol
Definition: ERF.H:903
const std::string datetime_format
Definition: ERF.H:923
bool use_datetime
Definition: ERF.H:922
static PlotFileType plotfile_type_2
Definition: ERF.H:1066
void WritePlotFile(int which, PlotFileType plotfile_type, amrex::Vector< std::string > plot_var_names)
Definition: ERF_Plotfile.cpp:225
amrex::Real start_time
Definition: ERF.H:919
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:955
std::unique_ptr< ReadBndryPlanes > m_r2d
Definition: ERF.H:1172
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:2072
void timeStep(int lev, amrex::Real time, int iteration)
Definition: ERF_TimeStep.cpp:16
amrex::Real m_plot_per_2
Definition: ERF.H:958

Referenced by main().

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

◆ fill_from_bndryregs()

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

◆ fill_rhs()

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

◆ FillBdyCCVels()

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

eb_ const& ERF::get_eb ( int  lev) const
inlineprivatenoexcept
1436  {
1437  AMREX_ASSERT(lev >= 0 && lev < eb.size() && eb[lev] != nullptr);
1438  return *eb[lev];
1439  }

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

◆ getAdvFluxReg()

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

◆ getCPUTime()

static amrex::Real ERF::getCPUTime ( )
inlinestaticprivate
1332  {
1333  int numCores = amrex::ParallelDescriptor::NProcs();
1334 #ifdef _OPENMP
1335  numCores = numCores * omp_get_max_threads();
1336 #endif
1337 
1338  amrex::Real T =
1339  numCores * (amrex::ParallelDescriptor::second() - startCPUTime) +
1341 
1342  return T;
1343  }
static amrex::Real previousCPUTimeUsed
Definition: ERF.H:1328
static amrex::Real startCPUTime
Definition: ERF.H:1327
@ T
Definition: ERF_IndexDefines.H:110

◆ GotoNextLine()

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

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

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, InflowOutflow, Periodic, Dirichlet, ...) to the specific implementation needed for each variable.

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

21 {
22  bool rho_read = false;
23  bool read_prim_theta = true;
24  Vector<Real> cons_dir_init(NBCVAR_max,0.0);
25  cons_dir_init[BCVars::Rho_bc_comp] = 1.0;
26  cons_dir_init[BCVars::RhoTheta_bc_comp] = -1.0;
27  auto f = [this,&rho_read,&read_prim_theta] (std::string const& bcid, Orientation ori)
28  {
29  // These are simply defaults for Dirichlet faces -- they should be over-written below
31  m_bc_extdir_vals[BCVars::RhoTheta_bc_comp][ori] = -1.0; // It is important to set this negative
32  // because the sign is tested on below
41 
42  m_bc_extdir_vals[BCVars::xvel_bc][ori] = 0.0; // default
45 
46  // These are simply defaults for Neumann gradients -- they should be over-written below
49 
58 
62 
63  std::string pp_text = pp_prefix + "." + bcid;
64  ParmParse pp(pp_text);
65 
66  std::string bc_type_in;
67  if (pp.query("type", bc_type_in) <= 0)
68  {
69  pp_text = bcid;
70  pp = ParmParse(pp_text);
71  pp.query("type", bc_type_in);
72  }
73 
74  std::string bc_type = amrex::toLower(bc_type_in);
75 
76  if (bc_type == "symmetry")
77  {
78  // Print() << bcid << " set to symmetry.\n";
80  domain_bc_type[ori] = "Symmetry";
81  }
82  else if (bc_type == "outflow")
83  {
84  // Print() << bcid << " set to outflow.\n";
86  domain_bc_type[ori] = "Outflow";
87  }
88  else if (bc_type == "open")
89  {
90  // Print() << bcid << " set to open.\n";
91  AMREX_ASSERT_WITH_MESSAGE((ori.coordDir() != 2), "Open boundary not valid on zlo or zhi!");
93  domain_bc_type[ori] = "Open";
94  }
95  else if (bc_type == "ho_outflow")
96  {
98  domain_bc_type[ori] = "HO_Outflow";
99  }
100 
101  else if (bc_type == "inflow" || bc_type == "inflow_outflow")
102  {
103  if (bc_type == "inflow") {
104  // Print() << bcid << " set to inflow.\n";
106  domain_bc_type[ori] = "Inflow";
107  } else {
108  // Print() << bcid << " set to inflow_outflow.\n";
110  domain_bc_type[ori] = "InflowOutflow";
111  }
112 
113  std::vector<Real> v;
114  if (input_bndry_planes && m_r2d->ingested_velocity()) {
118  } else {
119  // Test for input data file if at xlo face
120  std::string dirichlet_file;
121  auto file_exists = pp.query("dirichlet_file", dirichlet_file);
122  if (file_exists) {
123  pp.query("read_prim_theta", read_prim_theta);
124  init_Dirichlet_bc_data(dirichlet_file);
125  } else {
126  pp.getarr("velocity", v, 0, AMREX_SPACEDIM);
127  m_bc_extdir_vals[BCVars::xvel_bc][ori] = v[0];
128  m_bc_extdir_vals[BCVars::yvel_bc][ori] = v[1];
129  m_bc_extdir_vals[BCVars::zvel_bc][ori] = v[2];
130  }
131  }
132 
133  Real rho_in = 0.;
134  if (input_bndry_planes && m_r2d->ingested_density()) {
136  } else {
137  if (!pp.query("density", rho_in)) {
138  amrex::Print() << "Using interior values to set conserved vars" << std::endl;
139  }
140  m_bc_extdir_vals[BCVars::Rho_bc_comp][ori] = rho_in;
141  }
142 
143  bool th_read = (th_bc_data[0].data()!=nullptr);
144  Real theta_in = 0.;
145  if (input_bndry_planes && m_r2d->ingested_theta()) {
147  } else if (!th_read) {
148  if (rho_in > 0) {
149  pp.get("theta", theta_in);
150  }
151  m_bc_extdir_vals[BCVars::RhoTheta_bc_comp][ori] = rho_in*theta_in;
152  }
153 
154  Real scalar_in = 0.;
155  if (input_bndry_planes && m_r2d->ingested_scalar()) {
157  } else {
158  if (pp.query("scalar", scalar_in))
159  m_bc_extdir_vals[BCVars::RhoScalar_bc_comp][ori] = rho_in*scalar_in;
160  }
161 
162  if (solverChoice.moisture_type != MoistureType::None) {
163  Real qv_in = 0.;
164  if (input_bndry_planes && m_r2d->ingested_q1()) {
166  } else {
167  if (pp.query("qv", qv_in))
168  m_bc_extdir_vals[BCVars::RhoQ1_bc_comp][ori] = rho_in*qv_in;
169  }
170  Real qc_in = 0.;
171  if (input_bndry_planes && m_r2d->ingested_q2()) {
173  } else {
174  if (pp.query("qc", qc_in))
175  m_bc_extdir_vals[BCVars::RhoQ2_bc_comp][ori] = rho_in*qc_in;
176  }
177  }
178 
179  Real KE_in = 0.;
180  if (input_bndry_planes && m_r2d->ingested_KE()) {
182  } else {
183  if (pp.query("KE", KE_in))
184  m_bc_extdir_vals[BCVars::RhoKE_bc_comp][ori] = rho_in*KE_in;
185  }
186  }
187  else if (bc_type == "noslipwall")
188  {
189  // Print() << bcid <<" set to no-slip wall.\n";
191  domain_bc_type[ori] = "NoSlipWall";
192 
193  std::vector<Real> v;
194 
195  // The values of m_bc_extdir_vals default to 0.
196  // But if we find "velocity" in the inputs file, use those values instead.
197  if (pp.queryarr("velocity", v, 0, AMREX_SPACEDIM))
198  {
199  v[ori.coordDir()] = 0.0;
200  m_bc_extdir_vals[BCVars::xvel_bc][ori] = v[0];
201  m_bc_extdir_vals[BCVars::yvel_bc][ori] = v[1];
202  m_bc_extdir_vals[BCVars::zvel_bc][ori] = v[2];
203  }
204 
205  Real rho_in;
206  rho_read = pp.query("density", rho_in);
207  if (rho_read)
208  {
209  m_bc_extdir_vals[BCVars::Rho_bc_comp][ori] = rho_in;
210  }
211 
212  Real theta_in;
213  if (pp.query("theta", theta_in))
214  {
216  }
217 
218  Real theta_grad_in;
219  if (pp.query("theta_grad", theta_grad_in))
220  {
221  m_bc_neumann_vals[BCVars::RhoTheta_bc_comp][ori] = theta_grad_in;
222  }
223 
224  Real qv_in;
225  if (pp.query("qv", qv_in))
226  {
228  }
229  }
230  else if (bc_type == "slipwall")
231  {
232  // Print() << bcid <<" set to slip wall.\n";
233 
235  domain_bc_type[ori] = "SlipWall";
236 
237  Real rho_in;
238  rho_read = pp.query("density", rho_in);
239  if (rho_read)
240  {
241  m_bc_extdir_vals[BCVars::Rho_bc_comp][ori] = rho_in;
242  }
243 
244  Real theta_in;
245  if (pp.query("theta", theta_in))
246  {
248  }
249 
250  Real rho_grad_in;
251  if (pp.query("density_grad", rho_grad_in))
252  {
253  m_bc_neumann_vals[BCVars::Rho_bc_comp][ori] = rho_grad_in;
254  }
255 
256  Real theta_grad_in;
257  if (pp.query("theta_grad", theta_grad_in))
258  {
259  m_bc_neumann_vals[BCVars::RhoTheta_bc_comp][ori] = theta_grad_in;
260  }
261  }
262  else if (bc_type == "most")
263  {
264  phys_bc_type[ori] = ERF_BC::MOST;
265  domain_bc_type[ori] = "MOST";
266  }
267  else
268  {
270  }
271 
272  if (geom[0].isPeriodic(ori.coordDir())) {
273  domain_bc_type[ori] = "Periodic";
274  if (phys_bc_type[ori] == ERF_BC::undefined)
275  {
277  } else {
278  Abort("Wrong BC type for periodic boundary");
279  }
280  }
281 
282  if (phys_bc_type[ori] == ERF_BC::undefined)
283  {
284  Print() << "BC Type specified for face " << bcid << " is " << bc_type_in << std::endl;
285  Abort("This BC type is unknown");
286  }
287  };
288 
289  f("xlo", Orientation(Direction::x,Orientation::low));
290  f("xhi", Orientation(Direction::x,Orientation::high));
291  f("ylo", Orientation(Direction::y,Orientation::low));
292  f("yhi", Orientation(Direction::y,Orientation::high));
293  f("zlo", Orientation(Direction::z,Orientation::low));
294  f("zhi", Orientation(Direction::z,Orientation::high));
295 
296  // *****************************************************************************
297  //
298  // Here we translate the physical boundary conditions -- one type per face --
299  // into logical boundary conditions for each velocity component
300  //
301  // *****************************************************************************
302  {
303  domain_bcs_type.resize(AMREX_SPACEDIM+NBCVAR_max);
304  domain_bcs_type_d.resize(AMREX_SPACEDIM+NBCVAR_max);
305 
306  for (OrientationIter oit; oit; ++oit) {
307  Orientation ori = oit();
308  int dir = ori.coordDir();
309  Orientation::Side side = ori.faceDir();
310  auto const bct = phys_bc_type[ori];
311  if ( bct == ERF_BC::symmetry )
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::outflow or bct == ERF_BC::ho_outflow )
326  {
327  if (side == Orientation::low) {
328  for (int i = 0; i < AMREX_SPACEDIM; i++) {
330  }
331  if (!solverChoice.anelastic[0]) {
333  }
334  } else {
335  for (int i = 0; i < AMREX_SPACEDIM; i++) {
337  }
338  if (!solverChoice.anelastic[0]) {
340  }
341  }
342  }
343  else if (bct == ERF_BC::open)
344  {
345  if (side == Orientation::low) {
346  for (int i = 0; i < AMREX_SPACEDIM; i++)
348  } else {
349  for (int i = 0; i < AMREX_SPACEDIM; i++)
351  }
352  }
353  else if (bct == ERF_BC::inflow)
354  {
355  if (side == Orientation::low) {
356  for (int i = 0; i < AMREX_SPACEDIM; i++) {
358  if (input_bndry_planes && dir < 2 && m_r2d->ingested_velocity()) {
360  }
361  }
362  } else {
363  for (int i = 0; i < AMREX_SPACEDIM; i++) {
365  if (input_bndry_planes && dir < 2 && m_r2d->ingested_velocity()) {
367  }
368  }
369  }
370  }
371  else if (bct == ERF_BC::inflow_outflow)
372  {
373  if (side == Orientation::low) {
374  for (int i = 0; i < AMREX_SPACEDIM; i++) {
376  }
377  } else {
378  for (int i = 0; i < AMREX_SPACEDIM; i++) {
380  }
381  }
382  }
383  else if (bct == ERF_BC::no_slip_wall)
384  {
385  if (side == Orientation::low) {
386  for (int i = 0; i < AMREX_SPACEDIM; i++) {
388  }
389  } else {
390  for (int i = 0; i < AMREX_SPACEDIM; i++) {
392  }
393  }
394  }
395  else if (bct == ERF_BC::slip_wall)
396  {
397  if (side == Orientation::low) {
398  for (int i = 0; i < AMREX_SPACEDIM; i++) {
400  }
401  // Only normal direction has ext_dir
403 
404  } else {
405  for (int i = 0; i < AMREX_SPACEDIM; i++) {
407  }
408  // Only normal direction has ext_dir
410  }
411  }
412  else if (bct == ERF_BC::periodic)
413  {
414  if (side == Orientation::low) {
415  for (int i = 0; i < AMREX_SPACEDIM; i++) {
417  }
418  } else {
419  for (int i = 0; i < AMREX_SPACEDIM; i++) {
421  }
422  }
423  }
424  else if ( bct == ERF_BC::MOST )
425  {
426  AMREX_ALWAYS_ASSERT(dir == 2 && side == Orientation::low);
430  }
431  }
432  }
433 
434  // *****************************************************************************
435  //
436  // Here we translate the physical boundary conditions -- one type per face --
437  // into logical boundary conditions for each cell-centered variable
438  // (including the base state variables)
439  // NOTE: all "scalars" share the same type of boundary condition
440  //
441  // *****************************************************************************
442  {
443  for (OrientationIter oit; oit; ++oit) {
444  Orientation ori = oit();
445  int dir = ori.coordDir();
446  Orientation::Side side = ori.faceDir();
447  auto const bct = phys_bc_type[ori];
448  if ( bct == ERF_BC::symmetry )
449  {
450  if (side == Orientation::low) {
451  for (int i = 0; i < NBCVAR_max; i++) {
453  }
454  } else {
455  for (int i = 0; i < NBCVAR_max; i++) {
457  }
458  }
459  }
460  else if ( bct == ERF_BC::outflow )
461  {
462  if (side == Orientation::low) {
463  for (int i = 0; i < NBCVAR_max; i++) {
465  }
466  } else {
467  for (int i = 0; i < NBCVAR_max; i++) {
469  }
470  }
471  }
472  else if ( bct == ERF_BC::ho_outflow )
473  {
474  if (side == Orientation::low) {
475  for (int i = 0; i < NBCVAR_max; i++) {
477  }
478  } else {
479  for (int i = 0; i < NBCVAR_max; i++) {
481  }
482  }
483  }
484  else if ( bct == ERF_BC::open )
485  {
486  if (side == Orientation::low) {
487  for (int i = 0; i < NBCVAR_max; i++)
489  } else {
490  for (int i = 0; i < NBCVAR_max; i++)
492  }
493  }
494  else if ( bct == ERF_BC::no_slip_wall )
495  {
496  if (side == Orientation::low) {
497  for (int i = 0; i < NBCVAR_max; i++) {
499  if (m_bc_extdir_vals[BCVars::cons_bc+i][ori] != cons_dir_init[BCVars::cons_bc+i]) {
500  if (rho_read) {
502  } else {
504  }
505  }
506  }
507  if (std::abs(m_bc_neumann_vals[BCVars::RhoTheta_bc_comp][ori]) > 0.) {
509  }
510  } else {
511  for (int i = 0; i < NBCVAR_max; i++) {
513  if (m_bc_extdir_vals[BCVars::cons_bc+i][ori] != cons_dir_init[BCVars::cons_bc+i]) {
514  if (rho_read) {
516  } else {
518  }
519  }
520  }
521  if (std::abs(m_bc_neumann_vals[BCVars::RhoTheta_bc_comp][ori]) > 0.) {
523  }
524  }
525  }
526  else if (bct == ERF_BC::slip_wall)
527  {
528  if (side == Orientation::low) {
529  for (int i = 0; i < NBCVAR_max; i++) {
531  if (m_bc_extdir_vals[BCVars::cons_bc+i][ori] != cons_dir_init[BCVars::cons_bc+i]) {
532  if (rho_read) {
534  } else {
536  }
537  }
538  }
539  if (std::abs(m_bc_neumann_vals[BCVars::RhoTheta_bc_comp][ori]) > 0.) {
541  }
542  if (std::abs(m_bc_neumann_vals[BCVars::Rho_bc_comp][ori]) > 0.) {
544  }
545  } else {
546  for (int i = 0; i < NBCVAR_max; i++) {
548  if (m_bc_extdir_vals[BCVars::cons_bc+i][ori] != cons_dir_init[BCVars::cons_bc+i]) {
549  if (rho_read) {
551  } else {
553  }
554  }
555  }
556  if (std::abs(m_bc_neumann_vals[BCVars::RhoTheta_bc_comp][ori]) > 0.) {
558  }
559  if (std::abs(m_bc_neumann_vals[BCVars::Rho_bc_comp][ori]) > 0.) {
561  }
562  }
563  }
564  else if (bct == ERF_BC::inflow)
565  {
566  if (side == Orientation::low) {
567  for (int i = 0; i < NBCVAR_max; i++) {
569  if ((BCVars::cons_bc+i == RhoTheta_comp) &&
570  (th_bc_data[0].data() != nullptr))
571  {
572  if (read_prim_theta) domain_bcs_type[BCVars::cons_bc+i].setLo(dir, ERFBCType::ext_dir_prim);
573  }
574  else if (input_bndry_planes && dir < 2 && (
575  ( (BCVars::cons_bc+i == BCVars::Rho_bc_comp) && m_r2d->ingested_density()) ||
576  ( (BCVars::cons_bc+i == BCVars::RhoTheta_bc_comp) && m_r2d->ingested_theta() ) ||
577  ( (BCVars::cons_bc+i == BCVars::RhoKE_bc_comp) && m_r2d->ingested_KE() ) ||
578  ( (BCVars::cons_bc+i == BCVars::RhoScalar_bc_comp) && m_r2d->ingested_scalar() ) ||
579  ( (BCVars::cons_bc+i == BCVars::RhoQ1_bc_comp) && m_r2d->ingested_q1() ) ||
580  ( (BCVars::cons_bc+i == BCVars::RhoQ2_bc_comp) && m_r2d->ingested_q2() )) )
581  {
583  }
584  else if (m_bc_extdir_vals[BCVars::Rho_bc_comp][ori] == 0) {
586  }
587  }
588  } else {
589  for (int i = 0; i < NBCVAR_max; i++) {
591  if ((BCVars::cons_bc+i == RhoTheta_comp) &&
592  (th_bc_data[0].data() != nullptr))
593  {
594  if (read_prim_theta) domain_bcs_type[BCVars::cons_bc+i].setHi(dir, ERFBCType::ext_dir_prim);
595  }
596  else if (input_bndry_planes && dir < 2 && (
597  ( (BCVars::cons_bc+i == BCVars::Rho_bc_comp) && m_r2d->ingested_density()) ||
598  ( (BCVars::cons_bc+i == BCVars::RhoTheta_bc_comp) && m_r2d->ingested_theta() ) ||
599  ( (BCVars::cons_bc+i == BCVars::RhoKE_bc_comp) && m_r2d->ingested_KE() ) ||
600  ( (BCVars::cons_bc+i == BCVars::RhoScalar_bc_comp) && m_r2d->ingested_scalar() ) ||
601  ( (BCVars::cons_bc+i == BCVars::RhoQ1_bc_comp) && m_r2d->ingested_q1() ) ||
602  ( (BCVars::cons_bc+i == BCVars::RhoQ2_bc_comp) && m_r2d->ingested_q2() )
603  ) )
604  {
606  }
607  else if (m_bc_extdir_vals[BCVars::Rho_bc_comp][ori] == 0) {
609  }
610  }
611  }
612  }
613  else if (bct == ERF_BC::inflow_outflow )
614  {
615  if (side == Orientation::low) {
616  for (int i = 0; i < NBCVAR_max; i++) {
618  if (m_bc_extdir_vals[BCVars::Rho_bc_comp][ori] == 0) {
620  }
621  }
622  } else {
623  for (int i = 0; i < NBCVAR_max; i++) {
625  if (m_bc_extdir_vals[BCVars::Rho_bc_comp][ori] == 0) {
627  }
628  }
629  }
630  }
631  else if (bct == ERF_BC::periodic)
632  {
633  if (side == Orientation::low) {
634  for (int i = 0; i < NBCVAR_max; i++) {
636  }
637  } else {
638  for (int i = 0; i < NBCVAR_max; i++) {
640  }
641  }
642  }
643  else if ( bct == ERF_BC::MOST )
644  {
645  AMREX_ALWAYS_ASSERT(dir == 2 && side == Orientation::low);
646  for (int i = 0; i < NBCVAR_max; i++) {
648  }
649  }
650  }
651  }
652 
653  // NOTE: Gpu:copy is a wrapper to htod_memcpy (GPU) or memcpy (CPU) and is a blocking comm
654  Gpu::copy(Gpu::hostToDevice, domain_bcs_type.begin(), domain_bcs_type.end(), domain_bcs_type_d.begin());
655 }
#define NBCVAR_max
Definition: ERF_IndexDefines.H:29
@ ho_outflow
@ inflow_outflow
void init_Dirichlet_bc_data(const std::string input_file)
Definition: ERF_InitBCs.cpp:657
amrex::Array< amrex::Array< amrex::Real, AMREX_SPACEDIM *2 >, AMREX_SPACEDIM+NBCVAR_max > m_bc_neumann_vals
Definition: ERF.H:885
@ 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:195
@ open
Definition: ERF_IndexDefines.H:197
@ reflect_odd
Definition: ERF_IndexDefines.H:187
@ foextrap
Definition: ERF_IndexDefines.H:190
@ ext_dir
Definition: ERF_IndexDefines.H:191
@ ext_dir_prim
Definition: ERF_IndexDefines.H:193
@ hoextrapcc
Definition: ERF_IndexDefines.H:198
@ ext_dir_upwind
Definition: ERF_IndexDefines.H:199
@ int_dir
Definition: ERF_IndexDefines.H:188
@ neumann_int
Definition: ERF_IndexDefines.H:196
@ reflect_even
Definition: ERF_IndexDefines.H:189
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 = (z_phys_nd[lev]) ? z_phys_nd[lev]->const_array(mfi) : Array4<Real const>{};
62  Array4<Real const> z_cc_arr = (z_phys_cc[lev]) ? 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 if not doing anelastic with fixed-in-time density
80  MultiFab::Add(lev_new[Vars::cons], cons_pert, Rho_comp, Rho_comp, 1, cons_pert.nGrow());
81  }
82  MultiFab::Add(lev_new[Vars::cons], cons_pert, RhoTheta_comp, RhoTheta_comp, 1, cons_pert.nGrow());
83  MultiFab::Add(lev_new[Vars::cons], cons_pert, RhoScalar_comp,RhoScalar_comp,NSCALARS, cons_pert.nGrow());
84 
85  // RhoKE is relevant if using Deardorff with LES, k-equation for RANS, or MYNN with PBL
86  if ((solverChoice.turbChoice[lev].les_type == LESType::Deardorff) ||
87  (solverChoice.turbChoice[lev].rans_type == RANSType::kEqn) ||
88  (solverChoice.turbChoice[lev].pbl_type == PBLType::MYNN25) ||
89  (solverChoice.turbChoice[lev].pbl_type == PBLType::MYNNEDMF) ) {
90  MultiFab::Add(lev_new[Vars::cons], cons_pert, RhoKE_comp, RhoKE_comp, 1, cons_pert.nGrow());
91  }
92 
93  if (solverChoice.moisture_type != MoistureType::None) {
94  int qstate_size = micro->Get_Qstate_Size();
95  MultiFab::Add(lev_new[Vars::cons], cons_pert, RhoQ1_comp, RhoQ1_comp, 1, cons_pert.nGrow());
96  MultiFab::Add(lev_new[Vars::cons], cons_pert, RhoQ2_comp, RhoQ2_comp, 1, cons_pert.nGrow());
97  for (int q_offset(2); q_offset<qstate_size; ++q_offset) {
98  int q_idx = RhoQ1_comp+q_offset;
99  MultiFab::Add(lev_new[Vars::cons], cons_pert, q_idx, q_idx, 1, cons_pert.nGrow());
100  }
101  }
102 
103  MultiFab::Add(lev_new[Vars::xvel], xvel_pert, 0, 0, 1, xvel_pert.nGrowVect());
104  MultiFab::Add(lev_new[Vars::yvel], yvel_pert, 0, 0, 1, yvel_pert.nGrowVect());
105  MultiFab::Add(lev_new[Vars::zvel], zvel_pert, 0, 0, 1, zvel_pert.nGrowVect());
106 }
bool fixed_density
Definition: ERF_DataStruct.H:683
Here is the call graph for this function:

◆ init_Dirichlet_bc_data()

void ERF::init_Dirichlet_bc_data ( const std::string  input_file)
private
658 {
659  const bool use_terrain = (solverChoice.terrain_type != TerrainType::None);
660 
661  // Read the dirichlet_input file
662  Print() << "dirichlet_input file location : " << input_file << std::endl;
663  std::ifstream input_reader(input_file);
664  if (!input_reader.is_open()) {
665  amrex::Abort("Error opening the dirichlet_input file.\n");
666  }
667 
668  Print() << "Successfully opened the dirichlet_input file. Now reading... " << std::endl;
669  std::string line;
670 
671  // Size of Ninp (number of z points in input file)
672  Vector<Real> z_inp_tmp, u_inp_tmp, v_inp_tmp, w_inp_tmp, th_inp_tmp;
673 
674  // Top and bot for domain
675  const int klo = geom[0].Domain().smallEnd()[2];
676  const int khi = geom[0].Domain().bigEnd()[2];
677  const Real zbot = (use_terrain) ? zlevels_stag[0][klo] : geom[0].ProbLo(2);
678  const Real ztop = (use_terrain) ? zlevels_stag[0][khi+1] : geom[0].ProbHi(2);
679 
680  // Flag if theta input
681  Real th_init = -300.0;
682  bool th_read{false};
683 
684  // Add surface
685  z_inp_tmp.push_back(zbot); // height above sea level [m]
686  u_inp_tmp.push_back(0.);
687  v_inp_tmp.push_back(0.);
688  w_inp_tmp.push_back(0.);
689  th_inp_tmp.push_back(th_init);
690 
691  // Read the vertical profile at each given height
692  Real z, u, v, w, th;
693  while(std::getline(input_reader, line)) {
694  std::istringstream iss_z(line);
695 
696  Vector<Real> rval_v;
697  Real rval;
698  while (iss_z >> rval) {
699  rval_v.push_back(rval);
700  }
701  z = rval_v[0];
702  u = rval_v[1];
703  v = rval_v[2];
704  w = rval_v[3];
705 
706  // Format without theta
707  if (rval_v.size() == 4) {
708  if (z == zbot) {
709  u_inp_tmp[0] = u;
710  v_inp_tmp[0] = v;
711  w_inp_tmp[0] = w;
712  } else {
713  AMREX_ALWAYS_ASSERT(z > z_inp_tmp[z_inp_tmp.size()-1]); // sounding is increasing in height
714  z_inp_tmp.push_back(z);
715  u_inp_tmp.push_back(u);
716  v_inp_tmp.push_back(v);
717  w_inp_tmp.push_back(w);
718  if (z >= ztop) break;
719  }
720  } else if (rval_v.size() == 5) {
721  th_read = true;
722  th = rval_v[4];
723  if (z == zbot) {
724  u_inp_tmp[0] = u;
725  v_inp_tmp[0] = v;
726  w_inp_tmp[0] = w;
727  th_inp_tmp[0] = th;
728  } else {
729  AMREX_ALWAYS_ASSERT(z > z_inp_tmp[z_inp_tmp.size()-1]); // sounding is increasing in height
730  z_inp_tmp.push_back(z);
731  u_inp_tmp.push_back(u);
732  v_inp_tmp.push_back(v);
733  w_inp_tmp.push_back(w);
734  th_inp_tmp.push_back(th);
735  if (z >= ztop) break;
736  }
737  } else {
738  Abort("Unknown inflow file format!");
739  }
740  }
741 
742  // Ensure we set a reasonable theta surface
743  if (th_read) {
744  if (th_inp_tmp[0] == th_init) {
745  Real slope = (th_inp_tmp[2] - th_inp_tmp[1]) / (z_inp_tmp[2] - z_inp_tmp[1]);
746  Real dz = z_inp_tmp[0] - z_inp_tmp[1];
747  th_inp_tmp[0] = slope * dz + th_inp_tmp[1];
748  }
749  }
750 
751  amrex::Print() << "Successfully read and interpolated the dirichlet_input file..." << std::endl;
752  input_reader.close();
753 
754  for (int lev = 0; lev <= max_level; lev++) {
755 
756  const int Nz = geom[lev].Domain().size()[2];
757  const Real dz = geom[lev].CellSize()[2];
758 
759  // Size of Nz (domain grid)
760  Vector<Real> zcc_inp(Nz );
761  Vector<Real> znd_inp(Nz+1);
762  Vector<Real> u_inp(Nz ); xvel_bc_data[lev].resize(Nz ,0.0);
763  Vector<Real> v_inp(Nz ); yvel_bc_data[lev].resize(Nz ,0.0);
764  Vector<Real> w_inp(Nz+1); zvel_bc_data[lev].resize(Nz+1,0.0);
765  Vector<Real> th_inp;
766  if (th_read) {
767  th_inp.resize(Nz);
768  th_bc_data[lev].resize(Nz, 0.0);
769  }
770 
771  // At this point, we have an input from zbot up to
772  // z_inp_tmp[N-1] >= ztop. Now, interpolate to grid level 0 heights
773  const int Ninp = z_inp_tmp.size();
774  for (int k(0); k<Nz; ++k) {
775  zcc_inp[k] = (use_terrain) ? 0.5 * (zlevels_stag[lev][k] + zlevels_stag[lev][k+1])
776  : zbot + (k + 0.5) * dz;
777  znd_inp[k] = (use_terrain) ? zlevels_stag[lev][k+1] : zbot + (k) * dz;
778  u_inp[k] = interpolate_1d(z_inp_tmp.dataPtr(), u_inp_tmp.dataPtr(), zcc_inp[k], Ninp);
779  v_inp[k] = interpolate_1d(z_inp_tmp.dataPtr(), v_inp_tmp.dataPtr(), zcc_inp[k], Ninp);
780  w_inp[k] = interpolate_1d(z_inp_tmp.dataPtr(), w_inp_tmp.dataPtr(), znd_inp[k], Ninp);
781  if (th_read) {
782  th_inp[k] = interpolate_1d(z_inp_tmp.dataPtr(), th_inp_tmp.dataPtr(), zcc_inp[k], Ninp);
783  }
784  }
785  znd_inp[Nz] = ztop;
786  w_inp[Nz] = interpolate_1d(z_inp_tmp.dataPtr(), w_inp_tmp.dataPtr(), ztop, Ninp);
787 
788  // Copy host data to the device
789  Gpu::copy(Gpu::hostToDevice, u_inp.begin(), u_inp.end(), xvel_bc_data[lev].begin());
790  Gpu::copy(Gpu::hostToDevice, v_inp.begin(), v_inp.end(), yvel_bc_data[lev].begin());
791  Gpu::copy(Gpu::hostToDevice, w_inp.begin(), w_inp.end(), zvel_bc_data[lev].begin());
792  if (th_read) {
793  Gpu::copy(Gpu::hostToDevice, th_inp.begin(), th_inp.end(), th_bc_data[lev].begin());
794  }
795 
796  // NOTE: These device vectors are passed to the PhysBC constructors when that
797  // class is instantiated in ERF_MakeNewArrays.cpp.
798  } // lev
799 }
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
52 {
53  // We only want to read the file once -- here we fill one FArrayBox (per variable) that spans the domain
54  if (lev == 0) {
56  Error("input_sounding file name must be provided via input");
57  }
58 
60 
61  // this will interpolate the input profiles to the nominal height levels
62  // (ranging from 0 to the domain top)
63  for (int n = 0; n < input_sounding_data.n_sounding_files; n++) {
65  }
66 
67  // this will calculate the hydrostatically balanced density and pressure
68  // profiles following WRF ideal.exe
70 
71  } else {
72  //
73  // We need to do this interp from coarse level in order to set the values of
74  // the base state inside the domain but outside of the fine region
75  //
76  base_state[lev-1].FillBoundary(geom[lev-1].periodicity());
77  //
78  // NOTE: this interpolater assumes that ALL ghost cells of the coarse MultiFab
79  // have been pre-filled - this includes ghost cells both inside and outside
80  // the domain
81  //
82  InterpFromCoarseLevel(base_state[lev], base_state[lev].nGrowVect(),
83  IntVect(0,0,0), // do not fill ghost cells outside the domain
84  base_state[lev-1], 0, 0, base_state[lev].nComp(),
85  geom[lev-1], geom[lev],
86  refRatio(lev-1), &cell_cons_interp,
88 
89  // We need to do this here because the interpolation above may leave corners unfilled
90  // when the corners need to be filled by, for example, reflection of the fine ghost
91  // cell outside the fine region but inide the domain.
92  (*physbcs_base[lev])(base_state[lev],0,base_state[lev].nComp(),base_state[lev].nGrowVect());
93  }
94 
95  auto& lev_new = vars_new[lev];
96 
97  // update if init_sounding_ideal == true
98  MultiFab r_hse (base_state[lev], make_alias, BaseState::r0_comp, 1);
99  MultiFab p_hse (base_state[lev], make_alias, BaseState::p0_comp, 1);
100  MultiFab pi_hse(base_state[lev], make_alias, BaseState::pi0_comp, 1);
101  MultiFab th_hse(base_state[lev], make_alias, BaseState::th0_comp, 1);
102  MultiFab qv_hse(base_state[lev], make_alias, BaseState::qv0_comp, 1);
103 
104  const Real l_gravity = solverChoice.gravity;
105  const Real l_rdOcp = solverChoice.rdOcp;
106  const bool l_moist = (solverChoice.moisture_type != MoistureType::None);
107 
108 #ifdef _OPENMP
109 #pragma omp parallel if (Gpu::notInLaunchRegion())
110 #endif
111  for (MFIter mfi(lev_new[Vars::cons], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
112  const Box &bx = mfi.tilebox();
113  const auto &cons_arr = lev_new[Vars::cons].array(mfi);
114  const auto &xvel_arr = lev_new[Vars::xvel].array(mfi);
115  const auto &yvel_arr = lev_new[Vars::yvel].array(mfi);
116  const auto &zvel_arr = lev_new[Vars::zvel].array(mfi);
117  Array4<Real> r_hse_arr = r_hse.array(mfi);
118  Array4<Real> p_hse_arr = p_hse.array(mfi);
119  Array4<Real> pi_hse_arr = pi_hse.array(mfi);
120  Array4<Real> th_hse_arr = th_hse.array(mfi);
121  Array4<Real> qv_hse_arr = qv_hse.array(mfi);
122 
123  Array4<Real const> z_cc_arr = (z_phys_cc[lev]) ? z_phys_cc[lev]->const_array(mfi) : Array4<Real const>{};
124  Array4<Real const> z_nd_arr = (z_phys_nd[lev]) ? z_phys_nd[lev]->const_array(mfi) : Array4<Real const>{};
125 
127  {
128  // HSE will be initialized here, interpolated from values previously
129  // calculated by calc_rho_p()
131  bx, cons_arr,
132  r_hse_arr, p_hse_arr, pi_hse_arr, th_hse_arr, qv_hse_arr,
133  geom[lev].data(), z_cc_arr,
134  l_gravity, l_rdOcp, l_moist, input_sounding_data);
135  }
136  else
137  {
138  // HSE will be calculated later with call to initHSE
140  bx, cons_arr,
141  geom[lev].data(), z_cc_arr,
142  l_moist, input_sounding_data);
143  }
144 
146  bx, xvel_arr, yvel_arr, zvel_arr,
147  geom[lev].data(), z_nd_arr,
149 
150  } //mfi
151 }
void init_bx_scalars_from_input_sounding_hse(const Box &bx, Array4< Real > const &state, Array4< Real > const &r_hse_arr, Array4< Real > const &p_hse_arr, Array4< Real > const &pi_hse_arr, Array4< Real > const &th_hse_arr, Array4< Real > const &qv_hse_arr, GeometryData const &geomdata, Array4< const Real > const &z_cc_arr, const Real &l_gravity, const Real &l_rdOcp, const bool &l_moist, InputSoundingData const &inputSoundingData)
Definition: ERF_InitFromInputSounding.cpp:225
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:163
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:330
static bool init_sounding_ideal
Definition: ERF.H:1083
InputSoundingData input_sounding_data
Definition: ERF.H:677
@ rho0_bc_comp
Definition: ERF_IndexDefines.H:98
@ qv0_comp
Definition: ERF_IndexDefines.H:67
void resize_arrays()
Definition: ERF_InputSoundingData.H:60
int n_sounding_files
Definition: ERF_InputSoundingData.H: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 
)
1369 {
1370  t_new[lev] = time;
1371  t_old[lev] = time - 1.e200;
1372 
1373  auto& lev_new = vars_new[lev];
1374  auto& lev_old = vars_old[lev];
1375 
1376 #ifndef ERF_USE_NETCDF
1377  AMREX_ALWAYS_ASSERT_WITH_MESSAGE((solverChoice.init_type != InitType::WRFInput && solverChoice.init_type != InitType::Metgrid),
1378  "init_type cannot be 'WRFInput' or 'MetGrid' if we don't build with netcdf!");
1379 #endif
1380 
1381  // Loop over grids at this level to initialize our grid data
1382  lev_new[Vars::cons].setVal(0.0); lev_old[Vars::cons].setVal(0.0);
1383  lev_new[Vars::xvel].setVal(0.0); lev_old[Vars::xvel].setVal(0.0);
1384  lev_new[Vars::yvel].setVal(0.0); lev_old[Vars::yvel].setVal(0.0);
1385  lev_new[Vars::zvel].setVal(0.0); lev_old[Vars::zvel].setVal(0.0);
1386 
1387  // Initialize background flow (optional)
1388  if (solverChoice.init_type == InitType::Input_Sounding) {
1389  // The base state is initialized by integrating vertically through the
1390  // input sounding, if the init_sounding_ideal flag is set; otherwise
1391  // it is set by initHSE()
1392 
1393  // The physbc's need the terrain but are needed for initHSE
1394  // We have already made the terrain in the call to init_zphys
1395  // in MakeNewLevelFromScratch
1396  make_physbcs(lev);
1397 
1398  // Now init the base state and the data itself
1400 
1401  if (init_sounding_ideal) {
1402  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(solverChoice.use_gravity,
1403  "Gravity should be on to be consistent with sounding initialization.");
1404  } else {
1405  initHSE();
1406  }
1407 
1408 #ifdef ERF_USE_NETCDF
1409  }
1410  else if (solverChoice.init_type == InitType::WRFInput)
1411  {
1412  // The base state is initialized from WRF wrfinput data, output by
1413  // ideal.exe or real.exe
1414  init_from_wrfinput(lev);
1415  if (lev==0) {
1416  if ((start_time > 0) && (start_time != t_new[lev])) {
1417  Print() << "Ignoring specified start_time="
1418  << std::setprecision(timeprecision) << start_time
1419  << std::endl;
1420  }
1421  start_time = t_new[lev];
1422  }
1423  use_datetime = true;
1424 
1425  // The physbc's need the terrain but are needed for initHSE
1426  if (!solverChoice.use_real_bcs) {
1427  make_physbcs(lev);
1428  }
1429  }
1430  else if (solverChoice.init_type == InitType::Metgrid)
1431  {
1432  // The base state is initialized from data output by WPS metgrid;
1433  // we will rebalance after interpolation
1434  init_from_metgrid(lev);
1435 #endif
1436  } else if (solverChoice.init_type == InitType::Uniform) {
1437  // Initialize a uniform background field and base state based on the
1438  // problem-specified reference density and temperature
1439 
1440  // The physbc's need the terrain but are needed for initHSE
1441  make_physbcs(lev);
1442 
1443  init_uniform(lev);
1444  initHSE(lev);
1445  } else {
1446  // No background flow initialization specified, initialize the
1447  // background field to be equal to the base state, calculated from the
1448  // problem-specific erf_init_dens_hse
1449 
1450  // The bc's need the terrain but are needed for initHSE
1451  make_physbcs(lev);
1452 
1453  // We will initialize the state from the background state so must set that first
1454  initHSE(lev);
1455  init_from_hse(lev);
1456  }
1457 
1458  // Add problem-specific flow features
1459  //
1460  // Notes:
1461  // - This calls init_custom_pert that is defined for each problem
1462  // - This may modify the base state
1463  // - The fields set by init_custom_pert are **perturbations** to the
1464  // background flow set based on init_type
1465  init_custom(lev);
1466 
1467  // Ensure that the face-based data are the same on both sides of a periodic domain.
1468  // The data associated with the lower grid ID is considered the correct value.
1469  lev_new[Vars::xvel].OverrideSync(geom[lev].periodicity());
1470  lev_new[Vars::yvel].OverrideSync(geom[lev].periodicity());
1471  lev_new[Vars::zvel].OverrideSync(geom[lev].periodicity());
1472 
1473  if(solverChoice.spongeChoice.sponge_type == "input_sponge"){
1474  input_sponge(lev);
1475  }
1476 
1477  // Initialize turbulent perturbation
1478  if (solverChoice.pert_type == PerturbationType::Source ||
1479  solverChoice.pert_type == PerturbationType::Direct) {
1480  turbPert_update(lev, 0.);
1481  turbPert_amplitude(lev);
1482  }
1483 }
const int timeprecision
Definition: ERF.H:911
void init_from_input_sounding(int lev)
Definition: ERF_InitFromInputSounding.cpp:51
void init_custom(int lev)
Definition: ERF_InitCustom.cpp:26
void init_from_hse(int lev)
Definition: ERF_InitFromHSE.cpp:32
void initHSE()
Initialize HSE.
Definition: ERF_Init1D.cpp:142
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:604
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:693
static InitType init_type
Definition: ERF_DataStruct.H:656

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

◆ init_thin_body()

void ERF::init_thin_body ( int  lev,
const amrex::BoxArray &  ba,
const amrex::DistributionMapping &  dm 
)
584 {
585  //********************************************************************************************
586  // Thin immersed body
587  // *******************************************************************************************
588 #if 0
589  if ((solverChoice.advChoice.zero_xflux.size() > 0) ||
590  (solverChoice.advChoice.zero_yflux.size() > 0) ||
591  (solverChoice.advChoice.zero_zflux.size() > 0))
592  {
593  overset_imask[lev] = std::make_unique<iMultiFab>(ba,dm,1,0);
594  overset_imask[lev]->setVal(1); // == value is unknown (to be solved)
595  }
596 #endif
597 
598  if (solverChoice.advChoice.zero_xflux.size() > 0) {
599  amrex::Print() << "Setting up thin immersed body for "
600  << solverChoice.advChoice.zero_xflux.size() << " xfaces" << std::endl;
601  BoxArray ba_xf(ba);
602  ba_xf.surroundingNodes(0);
603  thin_xforce[lev] = std::make_unique<MultiFab>(ba_xf,dm,1,0);
604  thin_xforce[lev]->setVal(0.0);
605  xflux_imask[lev] = std::make_unique<iMultiFab>(ba_xf,dm,1,0);
606  xflux_imask[lev]->setVal(1);
607  for ( MFIter mfi(*xflux_imask[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi )
608  {
609  Array4<int> const& imask_arr = xflux_imask[lev]->array(mfi);
610  //Array4<int> const& imask_cell_arr = overset_imask[lev]->array(mfi);
611  Box xbx = mfi.nodaltilebox(0);
612  for (int iv=0; iv < solverChoice.advChoice.zero_xflux.size(); ++iv) {
613  const auto& faceidx = solverChoice.advChoice.zero_xflux[iv];
614  if ((faceidx[0] >= xbx.smallEnd(0)) && (faceidx[0] <= xbx.bigEnd(0)) &&
615  (faceidx[1] >= xbx.smallEnd(1)) && (faceidx[1] <= xbx.bigEnd(1)) &&
616  (faceidx[2] >= xbx.smallEnd(2)) && (faceidx[2] <= xbx.bigEnd(2)))
617  {
618  imask_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
619  //imask_cell_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
620  //imask_cell_arr(faceidx[0]-1,faceidx[1],faceidx[2]) = 0;
621  amrex::AllPrint() << " mask xface at " << faceidx << std::endl;
622  }
623  }
624  }
625  } else {
626  thin_xforce[lev] = nullptr;
627  xflux_imask[lev] = nullptr;
628  }
629 
630  if (solverChoice.advChoice.zero_yflux.size() > 0) {
631  amrex::Print() << "Setting up thin immersed body for "
632  << solverChoice.advChoice.zero_yflux.size() << " yfaces" << std::endl;
633  BoxArray ba_yf(ba);
634  ba_yf.surroundingNodes(1);
635  thin_yforce[lev] = std::make_unique<MultiFab>(ba_yf,dm,1,0);
636  thin_yforce[lev]->setVal(0.0);
637  yflux_imask[lev] = std::make_unique<iMultiFab>(ba_yf,dm,1,0);
638  yflux_imask[lev]->setVal(1);
639  for ( MFIter mfi(*yflux_imask[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi )
640  {
641  Array4<int> const& imask_arr = yflux_imask[lev]->array(mfi);
642  //Array4<int> const& imask_cell_arr = overset_imask[lev]->array(mfi);
643  Box ybx = mfi.nodaltilebox(1);
644  for (int iv=0; iv < solverChoice.advChoice.zero_yflux.size(); ++iv) {
645  const auto& faceidx = solverChoice.advChoice.zero_yflux[iv];
646  if ((faceidx[0] >= ybx.smallEnd(0)) && (faceidx[0] <= ybx.bigEnd(0)) &&
647  (faceidx[1] >= ybx.smallEnd(1)) && (faceidx[1] <= ybx.bigEnd(1)) &&
648  (faceidx[2] >= ybx.smallEnd(2)) && (faceidx[2] <= ybx.bigEnd(2)))
649  {
650  imask_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
651  //imask_cell_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
652  //imask_cell_arr(faceidx[0],faceidx[1]-1,faceidx[2]) = 0;
653  amrex::AllPrint() << " mask yface at " << faceidx << std::endl;
654  }
655  }
656  }
657  } else {
658  thin_yforce[lev] = nullptr;
659  yflux_imask[lev] = nullptr;
660  }
661 
662  if (solverChoice.advChoice.zero_zflux.size() > 0) {
663  amrex::Print() << "Setting up thin immersed body for "
664  << solverChoice.advChoice.zero_zflux.size() << " zfaces" << std::endl;
665  BoxArray ba_zf(ba);
666  ba_zf.surroundingNodes(2);
667  thin_zforce[lev] = std::make_unique<MultiFab>(ba_zf,dm,1,0);
668  thin_zforce[lev]->setVal(0.0);
669  zflux_imask[lev] = std::make_unique<iMultiFab>(ba_zf,dm,1,0);
670  zflux_imask[lev]->setVal(1);
671  for ( MFIter mfi(*zflux_imask[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi )
672  {
673  Array4<int> const& imask_arr = zflux_imask[lev]->array(mfi);
674  //Array4<int> const& imask_cell_arr = overset_imask[lev]->array(mfi);
675  Box zbx = mfi.nodaltilebox(2);
676  for (int iv=0; iv < solverChoice.advChoice.zero_zflux.size(); ++iv) {
677  const auto& faceidx = solverChoice.advChoice.zero_zflux[iv];
678  if ((faceidx[0] >= zbx.smallEnd(0)) && (faceidx[0] <= zbx.bigEnd(0)) &&
679  (faceidx[1] >= zbx.smallEnd(1)) && (faceidx[1] <= zbx.bigEnd(1)) &&
680  (faceidx[2] >= zbx.smallEnd(2)) && (faceidx[2] <= zbx.bigEnd(2)))
681  {
682  imask_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
683  //imask_cell_arr(faceidx[0],faceidx[1],faceidx[2]) = 0;
684  //imask_cell_arr(faceidx[0],faceidx[1],faceidx[2]-1) = 0;
685  amrex::AllPrint() << " mask zface at " << faceidx << std::endl;
686  }
687  }
688  }
689  } else {
690  thin_zforce[lev] = nullptr;
691  zflux_imask[lev] = nullptr;
692  }
693 }
amrex::Vector< amrex::IntVect > zero_yflux
Definition: ERF_AdvStruct.H:358
amrex::Vector< amrex::IntVect > zero_xflux
Definition: ERF_AdvStruct.H:357
amrex::Vector< amrex::IntVect > zero_zflux
Definition: ERF_AdvStruct.H:359

◆ 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 
)
467 {
468  if (solverChoice.init_type != InitType::WRFInput && solverChoice.init_type != InitType::Metgrid)
469  {
470  if (lev > 0) {
471  //
472  // First interpolate from coarser level if there is one
473  // NOTE: this interpolater assumes that ALL ghost cells of the coarse MultiFab
474  // have been pre-filled - this includes ghost cells both inside and outside
475  // the domain
476  //
477  InterpFromCoarseLevel(*z_phys_nd[lev], z_phys_nd[lev]->nGrowVect(),
478  IntVect(0,0,0), // do not fill ghost cells outside the domain
479  *z_phys_nd[lev-1], 0, 0, 1,
480  geom[lev-1], geom[lev],
481  refRatio(lev-1), &node_bilinear_interp,
483  }
484 
486  Box bx(surroundingNodes(Geom(lev).Domain())); bx.grow(ngrow);
487  FArrayBox terrain_fab(makeSlab(bx,2,0),1);
488 
489  //
490  // If we are using fitted mesh then we use the surface as defined above
491  // If we are not using fitted mesh but are using z_levels, we still need z_phys (for now)
492  // but we need to use a flat terrain for the mesh itself (the EB data has already been made
493  // from the correct terrain)
494  //
495  if (solverChoice.terrain_type != TerrainType::StaticFittedMesh &&
496  solverChoice.terrain_type != TerrainType::MovingFittedMesh) {
497  terrain_fab.template setVal<RunOn::Device>(0.0);
498  } else {
499  //
500  // Fill the values of the terrain height at k=0 only
501  //
502  prob->init_terrain_surface(geom[lev],terrain_fab,time);
503  }
504 
505  for (MFIter mfi(*z_phys_nd[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
506  {
507  Box isect = terrain_fab.box() & (*z_phys_nd[lev])[mfi].box();
508  if (!isect.isEmpty()) {
509  (*z_phys_nd[lev])[mfi].template copy<RunOn::Device>(terrain_fab,isect,0,isect,0,1);
510  }
511  }
512 
514 
515  z_phys_nd[lev]->FillBoundary(geom[lev].periodicity());
516 
517  if (solverChoice.terrain_type == TerrainType::ImmersedForcing) {
518  terrain_blanking[lev]->setVal(1.0);
519  MultiFab::Subtract(*terrain_blanking[lev], EBFactory(lev).getVolFrac(), 0, 0, 1, ngrow);
520  terrain_blanking[lev]->FillBoundary(geom[lev].periodicity());
521  }
522 
523  if (lev == 0) {
524  Real zmax = z_phys_nd[0]->max(0,0,false);
525  Real rel_diff = (zmax - zlevels_stag[0][zlevels_stag[0].size()-1]) / zmax;
526  if (rel_diff < 1.e-8) {
527  amrex::Print() << "max of zphys_nd " << zmax << std::endl;
528  amrex::Print() << "max of zlevels " << zlevels_stag[0][zlevels_stag[0].size()-1] << std::endl;
529  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(rel_diff < 1.e-8, "Terrain is taller than domain top!");
530  }
531  } // lev == 0
532 
533  } // init_type
534 }
void make_terrain_fitted_coords(int lev, const Geometry &geom, MultiFab &z_phys_nd, Vector< Real > const &z_levels_h, GpuArray< ERF_BC, AMREX_SPACEDIM *2 > &phys_bc_type)
Definition: ERF_TerrainMetrics.cpp:46
amrex::EBFArrayBoxFactory const & EBFactory(int lev) const noexcept
Definition: ERF.H:1442
Here is the call graph for this function:

◆ InitData()

void ERF::InitData ( )
644 {
645  BL_PROFILE_VAR("ERF::InitData()", InitData);
646  InitData_pre();
647  InitData_post();
648  BL_PROFILE_VAR_STOP(InitData);
649 }
void InitData_pre()
Definition: ERF.cpp:652
void InitData_post()
Definition: ERF.cpp:699
void InitData()
Definition: ERF.cpp:643

Referenced by main().

Here is the caller graph for this function:

◆ InitData_post()

void ERF::InitData_post ( )
700 {
701  if (restart_chkfile.empty()) {
702  //
703  // Make sure that detJ and z_phys_cc are the average of the data on a finer level if there is one
704  //
705  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
706  for (int crse_lev = finest_level-1; crse_lev >= 0; crse_lev--) {
707  average_down( *detJ_cc[crse_lev+1], *detJ_cc[crse_lev], 0, 1, refRatio(crse_lev));
708  average_down(*z_phys_cc[crse_lev+1], *z_phys_cc[crse_lev], 0, 1, refRatio(crse_lev));
709  }
710  }
711 
712  if (solverChoice.coupling_type == CouplingType::TwoWay) {
713  AverageDown();
714  }
715 
717  {
718  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(finest_level == 0,
719  "Thin immersed body with refinement not currently supported.");
720  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
721  amrex::Print() << "NOTE: Thin immersed body with non-constant dz has not been tested." << std::endl;
722  }
723  }
724 
725 #ifdef ERF_USE_PARTICLES
726  if (Microphysics::modelType(solverChoice.moisture_type) == MoistureModelType::Lagrangian) {
727  for (int lev = 0; lev <= finest_level; lev++) {
728  dynamic_cast<LagrangianMicrophysics&>(*micro).initParticles(z_phys_nd[lev]);
729  }
730  }
731 #endif
732 
733  } else { // Restart from a checkpoint
734 
735  restart();
736 
737  // Create the physbc objects for {cons, u, v, w, base state}
738  // We fill the additional base state ghost cells just in case we have read the old format
739  for (int lev(0); lev <= finest_level; ++lev) {
740  make_physbcs(lev);
741  (*physbcs_base[lev])(base_state[lev],0,base_state[lev].nComp(),base_state[lev].nGrowVect());
742  }
743 
745  for (int lev(0); lev <= finest_level; ++lev) {
746  m_forest_drag[lev]->define_drag_field(grids[lev], dmap[lev], geom[lev],
747  z_phys_cc[lev].get(), z_phys_nd[lev].get());
748  }
749  }
750  }
751 
752 #ifdef ERF_USE_PARTICLES
753  /* If using a Lagrangian microphysics model, its particle container has now been
754  constructed and initialized (calls to micro->Init). So, add its pointer to
755  ERF::particleData and remove its name from list of unallocated particle containers. */
756  if (Microphysics::modelType(solverChoice.moisture_type) == MoistureModelType::Lagrangian) {
757  const auto& pc_name( dynamic_cast<LagrangianMicrophysics&>(*micro).getName() );
758  const auto& pc_ptr( dynamic_cast<LagrangianMicrophysics&>(*micro).getParticleContainer() );
759  particleData.pushBack(pc_name, pc_ptr);
760  particleData.getNamesUnalloc().remove(pc_name);
761  }
762 #endif
763 
764  if (input_bndry_planes) {
765  // Read the "time.dat" file to know what data is available
766  m_r2d->read_time_file();
767 
768  // We haven't populated dt yet, set to 0 to ensure assert doesn't crash
769  Real dt_dummy = 0.0;
770  m_r2d->read_input_files(t_new[0],dt_dummy,m_bc_extdir_vals);
771  }
772 
774  {
775  h_rhotheta_src.resize(max_level+1, Vector<Real>(0));
776  d_rhotheta_src.resize(max_level+1, Gpu::DeviceVector<Real>(0));
777  for (int lev = 0; lev <= finest_level; lev++) {
778  const int domlen = geom[lev].Domain().length(2);
779  h_rhotheta_src[lev].resize(domlen, 0.0_rt);
780  d_rhotheta_src[lev].resize(domlen, 0.0_rt);
781  prob->update_rhotheta_sources(t_new[0],
782  h_rhotheta_src[lev], d_rhotheta_src[lev],
783  geom[lev], z_phys_cc[lev]);
784  }
785  }
786 
788  {
789  h_u_geos.resize(max_level+1, Vector<Real>(0));
790  d_u_geos.resize(max_level+1, Gpu::DeviceVector<Real>(0));
791  h_v_geos.resize(max_level+1, Vector<Real>(0));
792  d_v_geos.resize(max_level+1, Gpu::DeviceVector<Real>(0));
793  for (int lev = 0; lev <= finest_level; lev++) {
794  const int domlen = geom[lev].Domain().length(2);
795  h_u_geos[lev].resize(domlen, 0.0_rt);
796  d_u_geos[lev].resize(domlen, 0.0_rt);
797  h_v_geos[lev].resize(domlen, 0.0_rt);
798  d_v_geos[lev].resize(domlen, 0.0_rt);
800  prob->update_geostrophic_profile(t_new[0],
801  h_u_geos[lev], d_u_geos[lev],
802  h_v_geos[lev], d_v_geos[lev],
803  geom[lev], z_phys_cc[lev]);
804  } else {
805  if (SolverChoice::mesh_type == MeshType::VariableDz) {
806  amrex::Print() << "Note: 1-D geostrophic wind profile input is not defined for real terrain" << std::endl;
807  }
809  h_u_geos[lev], d_u_geos[lev],
810  h_v_geos[lev], d_v_geos[lev],
811  geom[lev],
812  zlevels_stag[0]);
813  }
814  }
815  }
816 
818  {
819  h_rhoqt_src.resize(max_level+1, Vector<Real>(0));
820  d_rhoqt_src.resize(max_level+1, Gpu::DeviceVector<Real>(0));
821  for (int lev = 0; lev <= finest_level; lev++) {
822  const int domlen = geom[lev].Domain().length(2);
823  h_rhoqt_src[lev].resize(domlen, 0.0_rt);
824  d_rhoqt_src[lev].resize(domlen, 0.0_rt);
825  prob->update_rhoqt_sources(t_new[0],
826  h_rhoqt_src[lev], d_rhoqt_src[lev],
827  geom[lev], z_phys_cc[lev]);
828  }
829  }
830 
832  {
833  h_w_subsid.resize(max_level+1, Vector<Real>(0));
834  d_w_subsid.resize(max_level+1, Gpu::DeviceVector<Real>(0));
835  for (int lev = 0; lev <= finest_level; lev++) {
836  const int domlen = geom[lev].Domain().length(2) + 1; // lives on z-faces
837  h_w_subsid[lev].resize(domlen, 0.0_rt);
838  d_w_subsid[lev].resize(domlen, 0.0_rt);
839  prob->update_w_subsidence(t_new[0],
840  h_w_subsid[lev], d_w_subsid[lev],
841  geom[lev], z_phys_nd[lev]);
842  }
843  }
844 
847  {
848  initRayleigh();
849  if (solverChoice.init_type == InitType::Input_Sounding)
850  {
851  // Overwrite ubar, vbar, and thetabar with input profiles;
852  // wbar is assumed to be 0. Note: the tau coefficient set by
853  // prob->erf_init_rayleigh() is still used
854  bool restarting = (!restart_chkfile.empty());
855  setRayleighRefFromSounding(restarting);
856  }
857  }
858 
859  // Read in sponge data from input file
860  if(solverChoice.spongeChoice.sponge_type == "input_sponge")
861  {
862  initSponge();
863  bool restarting = (!restart_chkfile.empty());
864  setSpongeRefFromSounding(restarting);
865  }
866 
867  if (solverChoice.pert_type == PerturbationType::Source ||
868  solverChoice.pert_type == PerturbationType::Direct) {
869  if (is_it_time_for_action(istep[0], t_new[0], dt[0], pert_interval, -1.)) {
870  turbPert.debug(t_new[0]);
871  }
872  }
873 
874  // We only write the file at level 0 for now
876  {
877  // Create the WriteBndryPlanes object so we can handle writing of boundary plane data
878  m_w2d = std::make_unique<WriteBndryPlanes>(grids,geom);
879 
880  Real time = 0.;
881  if (time >= bndry_output_planes_start_time) {
882  bool is_moist = (micro->Get_Qstate_Size() > 0);
883  m_w2d->write_planes(0, time, vars_new, is_moist);
884  }
885  }
886 
887  //
888  // If we are starting from scratch, we have the option to project the initial velocity field
889  // regardless of how we initialized.
890  // pp_inc is used as scratch space here; we zero it out after the projection
891  //
892  if (restart_chkfile == "")
893  {
895  Real dummy_dt = 1.0;
896  if (verbose > 0) {
897  amrex::Print() << "Projecting initial velocity field" << std::endl;
898  }
899  for (int lev = 0; lev <= finest_level; ++lev)
900  {
901  project_velocities(lev, dummy_dt, vars_new[lev], pp_inc[lev]);
902  pp_inc[lev].setVal(0.);
903  }
904  }
905  }
906 
907  // Copy from new into old just in case
908  for (int lev = 0; lev <= finest_level; ++lev)
909  {
910  auto& lev_new = vars_new[lev];
911  auto& lev_old = vars_old[lev];
912 
913  // ***************************************************************************
914  // Physical bc's at domain boundary
915  // ***************************************************************************
916  IntVect ngvect_cons = vars_new[lev][Vars::cons].nGrowVect();
917  IntVect ngvect_vels = vars_new[lev][Vars::xvel].nGrowVect();
918 
919  int ncomp_cons = lev_new[Vars::cons].nComp();
920  bool do_fb = true;
921 
922 #ifdef ERF_USE_NETCDF
923  // We call this here because it is an ERF routine
924  if (solverChoice.use_real_bcs && (lev==0)) {
925  int icomp_cons = 0;
926  bool cons_only = false;
927  Vector<MultiFab*> mfs_vec = {&lev_new[Vars::cons],&lev_new[Vars::xvel],
928  &lev_new[Vars::yvel],&lev_new[Vars::zvel]};
929  fill_from_realbdy(mfs_vec,t_new[lev],cons_only,icomp_cons,
930  ncomp_cons,ngvect_cons,ngvect_vels);
931  do_fb = false;
932  }
933 #endif
934 
935  (*physbcs_cons[lev])(lev_new[Vars::cons],lev_new[Vars::xvel],lev_new[Vars::yvel],0,ncomp_cons,
936  ngvect_cons,t_new[lev],BCVars::cons_bc,do_fb);
937  ( *physbcs_u[lev])(lev_new[Vars::xvel],lev_new[Vars::xvel],lev_new[Vars::yvel],
938  ngvect_vels,t_new[lev],BCVars::xvel_bc,do_fb);
939  ( *physbcs_v[lev])(lev_new[Vars::yvel],lev_new[Vars::xvel],lev_new[Vars::yvel],
940  ngvect_vels,t_new[lev],BCVars::yvel_bc,do_fb);
941  ( *physbcs_w[lev])(lev_new[Vars::zvel],lev_new[Vars::xvel],lev_new[Vars::yvel],
942  ngvect_vels,t_new[lev],BCVars::zvel_bc,do_fb);
943 
944  MultiFab::Copy(lev_old[Vars::cons],lev_new[Vars::cons],0,0,ncomp_cons,lev_new[Vars::cons].nGrowVect());
945  MultiFab::Copy(lev_old[Vars::xvel],lev_new[Vars::xvel],0,0, 1,lev_new[Vars::xvel].nGrowVect());
946  MultiFab::Copy(lev_old[Vars::yvel],lev_new[Vars::yvel],0,0, 1,lev_new[Vars::yvel].nGrowVect());
947  MultiFab::Copy(lev_old[Vars::zvel],lev_new[Vars::zvel],0,0, 1,lev_new[Vars::zvel].nGrowVect());
948  }
949 
950  // Compute the minimum dz in the domain at each level (to be used for setting the timestep)
951  dz_min.resize(max_level+1);
952  for (int lev = 0; lev <= finest_level; ++lev)
953  {
954  dz_min[lev] = geom[lev].CellSize(2);
955  if ( SolverChoice::mesh_type != MeshType::ConstantDz ) {
956  dz_min[lev] *= (*detJ_cc[lev]).min(0);
957  }
958  }
959 
960  ComputeDt();
961 
962  // Fill ghost cells/faces
963  for (int lev = 0; lev <= finest_level; ++lev)
964  {
965  if (lev > 0 && cf_width >= 0) {
967  }
968 
969  auto& lev_new = vars_new[lev];
970 
971  //
972  // Fill boundary conditions -- not sure why we need this here
973  //
974  bool fillset = false;
975  if (lev == 0) {
976  FillPatch(lev, t_new[lev],
977  {&lev_new[Vars::cons],&lev_new[Vars::xvel],&lev_new[Vars::yvel],&lev_new[Vars::zvel]});
978  } else {
979  FillPatch(lev, t_new[lev],
980  {&lev_new[Vars::cons],&lev_new[Vars::xvel],&lev_new[Vars::yvel],&lev_new[Vars::zvel]},
981  {&lev_new[Vars::cons],&rU_new[lev],&rV_new[lev],&rW_new[lev]},
982  base_state[lev], base_state[lev],
983  fillset);
984  }
985 
986  //
987  // We do this here to make sure level (lev-1) boundary conditions are filled
988  // before we interpolate to level (lev) ghost cells
989  //
990  if (lev < finest_level) {
991  auto& lev_old = vars_old[lev];
992  MultiFab::Copy(lev_old[Vars::cons],lev_new[Vars::cons],0,0,lev_old[Vars::cons].nComp(),lev_old[Vars::cons].nGrowVect());
993  MultiFab::Copy(lev_old[Vars::xvel],lev_new[Vars::xvel],0,0,lev_old[Vars::xvel].nComp(),lev_old[Vars::xvel].nGrowVect());
994  MultiFab::Copy(lev_old[Vars::yvel],lev_new[Vars::yvel],0,0,lev_old[Vars::yvel].nComp(),lev_old[Vars::yvel].nGrowVect());
995  MultiFab::Copy(lev_old[Vars::zvel],lev_new[Vars::zvel],0,0,lev_old[Vars::zvel].nComp(),lev_old[Vars::zvel].nGrowVect());
996  }
997 
998  //
999  // We fill the ghost cell values of the base state in case it wasn't done in the initialization
1000  //
1001  base_state[lev].FillBoundary(geom[lev].periodicity());
1002 
1003  // For moving terrain only
1004  if (solverChoice.terrain_type == TerrainType::MovingFittedMesh) {
1005  MultiFab::Copy(base_state_new[lev],base_state[lev],0,0,BaseState::num_comps,base_state[lev].nGrowVect());
1006  base_state_new[lev].FillBoundary(geom[lev].periodicity());
1007  }
1008 
1009  }
1010 
1011  // Allow idealized cases over water, used to set lmask
1012  ParmParse pp("erf");
1013  int is_land;
1014  for (int lev = 0; lev <= finest_level; ++lev)
1015  {
1016  if (pp.query("is_land", is_land, lev)) {
1017  if (is_land == 1) {
1018  amrex::Print() << "Level " << lev << " is land" << std::endl;
1019  } else if (is_land == 0) {
1020  amrex::Print() << "Level " << lev << " is water" << std::endl;
1021  } else {
1022  Error("is_land should be 0 or 1");
1023  }
1024  lmask_lev[lev][0]->setVal(is_land);
1025  lmask_lev[lev][0]->FillBoundary(geom[lev].periodicity());
1026  }
1027  }
1028 
1029 #ifdef ERF_USE_WW3_COUPLING
1030  int lev = 0;
1031  amrex::Print() << " About to call send_to_ww3 from ERF.cpp" << std::endl;
1032  send_to_ww3(lev);
1033  amrex::Print() << " About to call read_waves from ERF.cpp" << std::endl;
1034  read_waves(lev);
1035  // send_to_ww3(lev);
1036 #endif
1037 
1038  // Configure ABLMost params if used MostWall boundary condition
1039  // NOTE: we must set up the MOST routine after calling FillPatch
1040  // in order to have lateral ghost cells filled (MOST + terrain interp).
1041  // FillPatch does not call MOST, FillIntermediatePatch does.
1042  if (phys_bc_type[Orientation(Direction::z,Orientation::low)] == ERF_BC::MOST)
1043  {
1044  bool use_exp_most = solverChoice.use_explicit_most;
1045  bool use_rot_most = solverChoice.use_rotate_most;
1046  if (use_exp_most) {
1047  Print() << "Using MOST with explicitly included surface stresses" << std::endl;
1048  if (use_rot_most) {
1049  Print() << "Using MOST with surface stress rotations" << std::endl;
1050  }
1051  }
1052 
1053  //
1054  // This constructor will make the ABLMost object but not allocate the arrays at each level.
1055  //
1056  m_most = std::make_unique<ABLMost>(geom, use_exp_most, use_rot_most, pp_prefix, Qv_prim,
1058 #ifdef ERF_USE_NETCDF
1059  ,start_bdy_time, bdy_time_interval
1060 #endif
1061  );
1062  // This call will allocate the arrays at each level. If we regrid later, either changing
1063  // the number of level sor just the grids at each existing level, we will call an update routine
1064  // to redefine the internal arrays in m_most.
1065  int nlevs = geom.size();
1066  for (int lev = 0; lev < nlevs; lev++)
1067  {
1068  Vector<MultiFab*> mfv_old = {&vars_old[lev][Vars::cons], &vars_old[lev][Vars::xvel],
1069  &vars_old[lev][Vars::yvel], &vars_old[lev][Vars::zvel]};
1070  m_most->make_MOST_at_level(lev,nlevs,
1071  mfv_old, Theta_prim[lev], Qv_prim[lev],
1072  Qr_prim[lev], z_phys_nd[lev],
1073  Hwave[lev].get(),Lwave[lev].get(),eddyDiffs_lev[lev].get(),
1074  lsm_data[lev], lsm_flux[lev], sst_lev[lev], lmask_lev[lev]);
1075  }
1076 
1077 
1078  if (restart_chkfile != "") {
1079  // Update surface fields if needed
1081  }
1082 
1083  // We now configure ABLMost params here so that we can print the averages at t=0
1084  // Note we don't fill ghost cells here because this is just for diagnostics
1085  for (int lev = 0; lev <= finest_level; ++lev)
1086  {
1087  Real time = t_new[lev];
1088  IntVect ng = Theta_prim[lev]->nGrowVect();
1089 
1090  MultiFab::Copy( *Theta_prim[lev], vars_new[lev][Vars::cons], RhoTheta_comp, 0, 1, ng);
1091  MultiFab::Divide(*Theta_prim[lev], vars_new[lev][Vars::cons], Rho_comp, 0, 1, ng);
1092 
1093  if (solverChoice.moisture_type != MoistureType::None) {
1094  ng = Qv_prim[lev]->nGrowVect();
1095 
1096  MultiFab::Copy( *Qv_prim[lev], vars_new[lev][Vars::cons], RhoQ1_comp, 0, 1, ng);
1097  MultiFab::Divide(*Qv_prim[lev], vars_new[lev][Vars::cons], Rho_comp, 0, 1, ng);
1098 
1099  int rhoqr_comp = solverChoice.RhoQr_comp;
1100  if (rhoqr_comp > -1) {
1101  MultiFab::Copy( *Qr_prim[lev], vars_new[lev][Vars::cons], rhoqr_comp, 0, 1, ng);
1102  MultiFab::Divide(*Qr_prim[lev], vars_new[lev][Vars::cons], Rho_comp, 0, 1, ng);
1103  } else {
1104  Qr_prim[lev]->setVal(0.0);
1105  }
1106  }
1107  m_most->update_mac_ptrs(lev, vars_new, Theta_prim, Qv_prim, Qr_prim);
1108 
1109  if (restart_chkfile == "") {
1110  // Only do this if starting from scratch; if restarting, then
1111  // we don't want to call update_fluxes multiple times because
1112  // it will change u* and theta* from their previous values
1113  m_most->update_pblh(lev, vars_new, z_phys_cc[lev].get(),
1117  m_most->update_fluxes(lev, time);
1118  }
1119  }
1120  }
1121 
1122  // Update micro vars before first plot file
1123  if (solverChoice.moisture_type != MoistureType::None) {
1124  for (int lev = 0; lev <= finest_level; ++lev) micro->Update_Micro_Vars_Lev(lev, vars_new[lev][Vars::cons]);
1125  }
1126 
1127  // Fill time averaged velocities before first plot file
1128  if (solverChoice.time_avg_vel) {
1129  for (int lev = 0; lev <= finest_level; ++lev) {
1130  Time_Avg_Vel_atCC(dt[lev], t_avg_cnt[lev], vel_t_avg[lev].get(),
1131  vars_new[lev][Vars::xvel],
1132  vars_new[lev][Vars::yvel],
1133  vars_new[lev][Vars::zvel]);
1134  }
1135  }
1136 
1137  // check for additional plotting variables that are available after particle containers
1138  // are setup.
1139  const std::string& pv1 = "plot_vars_1"; appendPlotVariables(pv1,plot_var_names_1);
1140  const std::string& pv2 = "plot_vars_2"; appendPlotVariables(pv2,plot_var_names_2);
1141 
1142  if ( restart_chkfile.empty() && (m_check_int > 0 || m_check_per > 0.) )
1143  {
1144 #ifdef ERF_USE_NETCDF
1145  if (check_type == "netcdf") {
1146  WriteNCCheckpointFile();
1147  }
1148 #endif
1149  if (check_type == "native") {
1151  }
1153  }
1154 
1155  if ( (restart_chkfile.empty()) ||
1156  (!restart_chkfile.empty() && plot_file_on_restart) )
1157  {
1158  if (m_plot_int_1 > 0 || m_plot_per_1 > 0.)
1159  {
1162  }
1163  if (m_plot_int_2 > 0 || m_plot_per_2 > 0.)
1164  {
1167  }
1168  if (m_subvol_int > 0 || m_subvol_per > 0.) {
1169  WriteSubvolume();
1170  last_subvol = istep[0];
1171  }
1172  }
1173 
1174  // Set these up here because we need to know which MPI rank "cell" is on...
1175  if (pp.contains("data_log"))
1176  {
1177  int num_datalogs = pp.countval("data_log");
1178  datalog.resize(num_datalogs);
1179  datalogname.resize(num_datalogs);
1180  pp.queryarr("data_log",datalogname,0,num_datalogs);
1181  for (int i = 0; i < num_datalogs; i++)
1183  }
1184 
1185  if (pp.contains("der_data_log"))
1186  {
1187  int num_der_datalogs = pp.countval("der_data_log");
1188  der_datalog.resize(num_der_datalogs);
1189  der_datalogname.resize(num_der_datalogs);
1190  pp.queryarr("der_data_log",der_datalogname,0,num_der_datalogs);
1191  for (int i = 0; i < num_der_datalogs; i++)
1193  }
1194 
1195 
1196  if (restart_chkfile.empty() && profile_int > 0) {
1197  if (destag_profiles) {
1198  // all variables cell-centered
1200  } else {
1201  // some variables staggered
1203  }
1204  }
1205 
1206  if (pp.contains("sample_point_log") && pp.contains("sample_point"))
1207  {
1208  int lev = 0;
1209 
1210  int num_samplepts = pp.countval("sample_point") / AMREX_SPACEDIM;
1211  if (num_samplepts > 0) {
1212  Vector<int> index; index.resize(num_samplepts*AMREX_SPACEDIM);
1213  samplepoint.resize(num_samplepts);
1214 
1215  pp.queryarr("sample_point",index,0,num_samplepts*AMREX_SPACEDIM);
1216  for (int i = 0; i < num_samplepts; i++) {
1217  IntVect iv(index[AMREX_SPACEDIM*i+0],index[AMREX_SPACEDIM*i+1],index[AMREX_SPACEDIM*i+2]);
1218  samplepoint[i] = iv;
1219  }
1220  }
1221 
1222  int num_sampleptlogs = pp.countval("sample_point_log");
1223  AMREX_ALWAYS_ASSERT(num_sampleptlogs == num_samplepts);
1224  if (num_sampleptlogs > 0) {
1225  sampleptlog.resize(num_sampleptlogs);
1226  sampleptlogname.resize(num_sampleptlogs);
1227  pp.queryarr("sample_point_log",sampleptlogname,0,num_sampleptlogs);
1228 
1229  for (int i = 0; i < num_sampleptlogs; i++) {
1231  }
1232  }
1233 
1234  }
1235 
1236  if (pp.contains("sample_line_log") && pp.contains("sample_line"))
1237  {
1238  int lev = 0;
1239 
1240  int num_samplelines = pp.countval("sample_line") / AMREX_SPACEDIM;
1241  if (num_samplelines > 0) {
1242  Vector<int> index; index.resize(num_samplelines*AMREX_SPACEDIM);
1243  sampleline.resize(num_samplelines);
1244 
1245  pp.queryarr("sample_line",index,0,num_samplelines*AMREX_SPACEDIM);
1246  for (int i = 0; i < num_samplelines; i++) {
1247  IntVect iv(index[AMREX_SPACEDIM*i+0],index[AMREX_SPACEDIM*i+1],index[AMREX_SPACEDIM*i+2]);
1248  sampleline[i] = iv;
1249  }
1250  }
1251 
1252  int num_samplelinelogs = pp.countval("sample_line_log");
1253  AMREX_ALWAYS_ASSERT(num_samplelinelogs == num_samplelines);
1254  if (num_samplelinelogs > 0) {
1255  samplelinelog.resize(num_samplelinelogs);
1256  samplelinelogname.resize(num_samplelinelogs);
1257  pp.queryarr("sample_line_log",samplelinelogname,0,num_samplelinelogs);
1258 
1259  for (int i = 0; i < num_samplelinelogs; i++) {
1261  }
1262  }
1263 
1264  }
1265 
1269  }
1270 
1271  // Create object to do line and plane sampling if needed
1272  bool do_line = false; bool do_plane = false;
1273  pp.query("do_line_sampling",do_line); pp.query("do_plane_sampling",do_plane);
1274  if (do_line || do_plane) { data_sampler = std::make_unique<SampleData>(do_line, do_plane); }
1275 
1276  if ( solverChoice.terrain_type == TerrainType::EB ||
1277  solverChoice.terrain_type == TerrainType::ImmersedForcing)
1278  {
1279  bool write_eb_surface = false;
1280  pp.query("write_eb_surface", write_eb_surface);
1281  if (write_eb_surface) WriteMyEBSurface();
1282  }
1283 
1284 }
void initRayleigh()
Initialize Rayleigh damping profiles.
Definition: ERF_InitRayleigh.cpp:14
amrex::Vector< std::string > samplelinelogname
Definition: ERF.H:1420
void setRayleighRefFromSounding(bool restarting)
Set Rayleigh mean profiles from input sounding.
Definition: ERF_InitRayleigh.cpp:55
amrex::Vector< amrex::IntVect > sampleline
Definition: ERF.H:1421
static amrex::Real sum_per
Definition: ERF.H:1062
void setRecordDataInfo(int i, const std::string &filename)
Definition: ERF.H:1345
void WriteMyEBSurface()
Definition: ERF_EBWriteSurface.cpp:5
void write_1D_profiles_stag(amrex::Real time)
Definition: ERF_Write1DProfiles_stag.cpp:25
amrex::Vector< std::unique_ptr< std::fstream > > samplelinelog
Definition: ERF.H:1419
static int sum_interval
Definition: ERF.H:1060
static int pert_interval
Definition: ERF.H:1061
void restart()
Definition: ERF.cpp:1323
void ReadCheckpointFileMOST()
Definition: ERF_Checkpoint.cpp:734
void write_1D_profiles(amrex::Real time)
Definition: ERF_Write1DProfiles.cpp:15
int profile_int
Definition: ERF.H:965
bool destag_profiles
Definition: ERF.H:966
void appendPlotVariables(const std::string &pp_plot_var_names, amrex::Vector< std::string > &plot_var_names)
Definition: ERF_Plotfile.cpp:167
static int output_bndry_planes
Definition: ERF.H:1109
void AverageDown()
Definition: ERF_AverageDown.cpp:16
std::unique_ptr< SampleData > data_sampler
Definition: ERF.H:1408
static amrex::Real bndry_output_planes_start_time
Definition: ERF.H:1112
std::string restart_chkfile
Definition: ERF.H:926
amrex::Vector< std::string > sampleptlogname
Definition: ERF.H:1416
void sum_derived_quantities(amrex::Real time)
Definition: ERF_WriteScalarProfiles.cpp:169
void sum_integrated_quantities(amrex::Real time)
Definition: ERF_WriteScalarProfiles.cpp:15
void setRecordDerDataInfo(int i, const std::string &filename)
Definition: ERF.H:1358
amrex::Vector< std::unique_ptr< std::fstream > > sampleptlog
Definition: ERF.H:1415
std::unique_ptr< WriteBndryPlanes > m_w2d
Definition: ERF.H:1171
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:538
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:906
void Construct_ERFFillPatchers(int lev)
Definition: ERF.cpp:1995
void setRecordSampleLineInfo(int i, int lev, amrex::IntVect &cell, const std::string &filename)
Definition: ERF.H:1388
void setSpongeRefFromSounding(bool restarting)
Set sponge mean profiles from input sounding.
Definition: ERF_InitSponge.cpp:65
amrex::Vector< amrex::IntVect > samplepoint
Definition: ERF.H:1417
void setRecordSamplePointInfo(int i, int lev, amrex::IntVect &cell, const std::string &filename)
Definition: ERF.H:1371
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:360
bool have_geo_wind_profile
Definition: ERF_DataStruct.H:768
bool project_initial_velocity
Definition: ERF_DataStruct.H:718
std::string abl_geo_wind_table
Definition: ERF_DataStruct.H:767
bool do_forest_drag
Definition: ERF_DataStruct.H:793
bool use_rotate_most
Definition: ERF_DataStruct.H:740
void debug(amrex::Real)
Definition: ERF_TurbPertStruct.H:528
Here is the call graph for this function:

◆ InitData_pre()

void ERF::InitData_pre ( )
653 {
654  // Initialize the start time for our CPU-time tracker
655  startCPUTime = ParallelDescriptor::second();
656 
657  // Create the ReadBndryPlanes object so we can read boundary plane data
658  // m_r2d is used by init_bcs so we must instantiate this class before
659  if (input_bndry_planes) {
660  Print() << "Defining r2d for the first time " << std::endl;
661  m_r2d = std::make_unique<ReadBndryPlanes>(geom[0], solverChoice.rdOcp);
662  }
663 
667 
668  if (restart_chkfile.empty()) {
669  // start simulation from the beginning
670 
671  const Real time = start_time;
672  InitFromScratch(time);
673  } else {
674  // For initialization this is done in init_only; it is done here for restart
675  init_bcs();
676  }
677 
678  // Verify BCs are compatible with solver choice
679  for (int lev(0); lev <= max_level; ++lev) {
680  if ( ( (solverChoice.turbChoice[lev].pbl_type == PBLType::MYNN25) ||
681  (solverChoice.turbChoice[lev].pbl_type == PBLType::MYNNEDMF) ||
682  (solverChoice.turbChoice[lev].pbl_type == PBLType::YSU) ) &&
683  phys_bc_type[Orientation(Direction::z,Orientation::low)] != ERF_BC::MOST ) {
684  Abort("MYNN2.5/MYNNEDMF/YSU PBL Model requires MOST at lower boundary");
685  }
686 
687  if ( (solverChoice.turbChoice[lev].les_type == LESType::Deardorff) &&
688  (solverChoice.turbChoice[lev].Ce_wall > 0) &&
689  (phys_bc_type[Orientation(Direction::z,Orientation::low)] != ERF_BC::MOST) &&
690  (phys_bc_type[Orientation(Direction::z,Orientation::low)] != ERF_BC::slip_wall) &&
691  (phys_bc_type[Orientation(Direction::z,Orientation::low)] != ERF_BC::no_slip_wall) ) {
692  Warning("Deardorff LES assumes wall at zlo when applying Ce_wall");
693  }
694 
695  }
696 }
void init_bcs()
Definition: ERF_InitBCs.cpp:20

◆ initHSE() [1/2]

void ERF::initHSE ( )
private

Initialize HSE.

143 {
144  AMREX_ALWAYS_ASSERT(!init_sounding_ideal);
145  for (int lev = 0; lev <= finest_level; lev++)
146  {
147  initHSE(lev);
148  }
149 }

◆ initHSE() [2/2]

void ERF::initHSE ( int  lev)
private

Initialize density and pressure base state in hydrostatic equilibrium.

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

◆ 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
1289 {
1290  if (Microphysics::modelType(solverChoice.moisture_type) == MoistureModelType::Eulerian) {
1291 
1292  micro = std::make_unique<EulerianMicrophysics>(a_nlevsmax, solverChoice.moisture_type);
1293 
1294  } else if (Microphysics::modelType(solverChoice.moisture_type) == MoistureModelType::Lagrangian) {
1295 #ifdef ERF_USE_PARTICLES
1296 
1297  micro = std::make_unique<LagrangianMicrophysics>(a_nlevsmax, solverChoice.moisture_type);
1298  /* Lagrangian microphysics models will have a particle container; it needs to be added
1299  to ERF::particleData */
1300  const auto& pc_name( dynamic_cast<LagrangianMicrophysics&>(*micro).getName() );
1301  /* The particle container has not yet been constructed and initialized, so just add
1302  its name here for now (so that functions to set plotting variables can see it). */
1303  particleData.addName( pc_name );
1304 
1305 #else
1306  Abort("Lagrangian microphysics can be used when compiled with ERF_USE_PARTICLES");
1307 #endif
1308  }
1309 
1310  qmoist.resize(a_nlevsmax);
1311  return;
1312 }
amrex::Vector< amrex::Vector< amrex::MultiFab * > > qmoist
Definition: ERF.H:763
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:1146
amrex::Real rayleigh_zdamp
Definition: ERF_DataStruct.H:702
amrex::Real rayleigh_ztop
Definition: ERF_DataStruct.H:703

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

◆ 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:680
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
539 {
540  bool int_test = (action_interval > 0 && nstep % action_interval == 0);
541 
542  bool per_test = false;
543  if (action_per > 0.0) {
544  const int num_per_old = static_cast<int>(amrex::Math::floor((time - dtlev) / action_per));
545  const int num_per_new = static_cast<int>(amrex::Math::floor((time) / action_per));
546 
547  if (num_per_old != num_per_new) {
548  per_test = true;
549  }
550  }
551 
552  return int_test || per_test;
553 }

◆ make_eb_box()

void ERF::make_eb_box ( )

◆ make_eb_regular()

void ERF::make_eb_regular ( )

◆ make_physbcs()

void ERF::make_physbcs ( int  lev)
private
605 {
606  if (SolverChoice::mesh_type == MeshType::VariableDz) {
607  AMREX_ALWAYS_ASSERT(z_phys_nd[lev] != nullptr);
608  }
609 
610  physbcs_cons[lev] = std::make_unique<ERFPhysBCFunct_cons> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
612  z_phys_nd[lev], solverChoice.use_real_bcs, th_bc_data[lev].data());
613  physbcs_u[lev] = std::make_unique<ERFPhysBCFunct_u> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
615  z_phys_nd[lev], solverChoice.use_real_bcs, xvel_bc_data[lev].data());
616  physbcs_v[lev] = std::make_unique<ERFPhysBCFunct_v> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
618  z_phys_nd[lev], solverChoice.use_real_bcs, yvel_bc_data[lev].data());
619  physbcs_w[lev] = std::make_unique<ERFPhysBCFunct_w> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
622  solverChoice.use_real_bcs, zvel_bc_data[lev].data());
623  physbcs_base[lev] = std::make_unique<ERFPhysBCFunct_base> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
624  (solverChoice.terrain_type == TerrainType::MovingFittedMesh));
625 }

◆ MakeDiagnosticAverage()

void ERF::MakeDiagnosticAverage ( amrex::Vector< amrex::Real > &  h_havg,
amrex::MultiFab &  S,
int  n 
)
1950 {
1951  // Get the number of cells in z at level 0
1952  int dir_z = AMREX_SPACEDIM-1;
1953  auto domain = geom[0].Domain();
1954  int size_z = domain.length(dir_z);
1955  int start_z = domain.smallEnd()[dir_z];
1956  Real area_z = static_cast<Real>(domain.length(0)*domain.length(1));
1957 
1958  // resize the level 0 horizontal average vectors
1959  h_havg.resize(size_z, 0.0_rt);
1960 
1961  // Get the cell centered data and construct sums
1962 #ifdef _OPENMP
1963 #pragma omp parallel if (Gpu::notInLaunchRegion())
1964 #endif
1965  for (MFIter mfi(S); mfi.isValid(); ++mfi) {
1966  const Box& box = mfi.validbox();
1967  const IntVect& se = box.smallEnd();
1968  const IntVect& be = box.bigEnd();
1969 
1970  auto fab_arr = S[mfi].array();
1971 
1972  FArrayBox fab_reduce(box, 1, The_Async_Arena());
1973  auto arr_reduce = fab_reduce.array();
1974 
1975  ParallelFor(box, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
1976  arr_reduce(i, j, k, 0) = fab_arr(i,j,k,n);
1977  });
1978 
1979  for (int k=se[dir_z]; k <= be[dir_z]; ++k) {
1980  Box kbox(box); kbox.setSmall(dir_z,k); kbox.setBig(dir_z,k);
1981  h_havg[k-start_z] += fab_reduce.sum<RunOn::Device>(kbox,0);
1982  }
1983  }
1984 
1985  // combine sums from different MPI ranks
1986  ParallelDescriptor::ReduceRealSum(h_havg.dataPtr(), h_havg.size());
1987 
1988  // divide by the total number of cells we are averaging over
1989  for (int k = 0; k < size_z; ++k) {
1990  h_havg[k] /= area_z;
1991  }
1992 }

◆ MakeEBGeometry()

void ERF::MakeEBGeometry ( )

◆ MakeHorizontalAverages()

void ERF::MakeHorizontalAverages ( )
1844 {
1845  int lev = 0;
1846 
1847  // First, average down all levels (if doing two-way coupling)
1848  if (solverChoice.coupling_type == CouplingType::TwoWay) {
1849  AverageDown();
1850  }
1851 
1852  MultiFab mf(grids[lev], dmap[lev], 5, 0);
1853 
1854  int zdir = 2;
1855  auto domain = geom[0].Domain();
1856 
1857  bool use_moisture = (solverChoice.moisture_type != MoistureType::None);
1858  bool is_anelastic = (solverChoice.anelastic[lev] == 1);
1859 
1860  for (MFIter mfi(mf); mfi.isValid(); ++mfi) {
1861  const Box& bx = mfi.validbox();
1862  auto fab_arr = mf.array(mfi);
1863  auto const hse_arr = base_state[lev].const_array(mfi);
1864  auto const cons_arr = vars_new[lev][Vars::cons].const_array(mfi);
1865  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
1866  Real dens = cons_arr(i, j, k, Rho_comp);
1867  fab_arr(i, j, k, 0) = dens;
1868  fab_arr(i, j, k, 1) = cons_arr(i, j, k, RhoTheta_comp) / dens;
1869  if (!use_moisture) {
1870  if (is_anelastic) {
1871  fab_arr(i,j,k,2) = hse_arr(i,j,k,BaseState::p0_comp);
1872  } else {
1873  fab_arr(i,j,k,2) = getPgivenRTh(cons_arr(i,j,k,RhoTheta_comp));
1874  }
1875  }
1876  });
1877  }
1878 
1879  if (use_moisture)
1880  {
1881  for (MFIter mfi(mf); mfi.isValid(); ++mfi) {
1882  const Box& bx = mfi.validbox();
1883  auto fab_arr = mf.array(mfi);
1884  auto const hse_arr = base_state[lev].const_array(mfi);
1885  auto const cons_arr = vars_new[lev][Vars::cons].const_array(mfi);
1886  int ncomp = vars_new[lev][Vars::cons].nComp();
1887 
1888  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
1889  Real dens = cons_arr(i, j, k, Rho_comp);
1890  if (is_anelastic) {
1891  fab_arr(i,j,k,2) = hse_arr(i,j,k,BaseState::p0_comp);
1892  } else {
1893  Real qv = cons_arr(i, j, k, RhoQ1_comp) / dens;
1894  fab_arr(i, j, k, 2) = getPgivenRTh(cons_arr(i, j, k, RhoTheta_comp), qv);
1895  }
1896  fab_arr(i, j, k, 3) = (ncomp > RhoQ1_comp ? cons_arr(i, j, k, RhoQ1_comp) / dens : 0.0);
1897  fab_arr(i, j, k, 4) = (ncomp > RhoQ2_comp ? cons_arr(i, j, k, RhoQ2_comp) / dens : 0.0);
1898  });
1899  }
1900 
1901  Gpu::HostVector<Real> h_avg_qv = sumToLine(mf,3,1,domain,zdir);
1902  Gpu::HostVector<Real> h_avg_qc = sumToLine(mf,4,1,domain,zdir);
1903  }
1904 
1905  // Sum in the horizontal plane
1906  Gpu::HostVector<Real> h_avg_density = sumToLine(mf,0,1,domain,zdir);
1907  Gpu::HostVector<Real> h_avg_temperature = sumToLine(mf,1,1,domain,zdir);
1908  Gpu::HostVector<Real> h_avg_pressure = sumToLine(mf,2,1,domain,zdir);
1909 
1910  // Divide by the total number of cells we are averaging over
1911  int size_z = domain.length(zdir);
1912  Real area_z = static_cast<Real>(domain.length(0)*domain.length(1));
1913  int klen = static_cast<int>(h_avg_density.size());
1914 
1915  for (int k = 0; k < klen; ++k) {
1916  h_havg_density[k] /= area_z;
1917  h_havg_temperature[k] /= area_z;
1918  h_havg_pressure[k] /= area_z;
1919  if (solverChoice.moisture_type != MoistureType::None)
1920  {
1921  h_havg_qc[k] /= area_z;
1922  h_havg_qv[k] /= area_z;
1923  }
1924  } // k
1925 
1926  // resize device vectors
1927  d_havg_density.resize(size_z, 0.0_rt);
1928  d_havg_temperature.resize(size_z, 0.0_rt);
1929  d_havg_pressure.resize(size_z, 0.0_rt);
1930 
1931  // copy host vectors to device vectors
1932  Gpu::copy(Gpu::hostToDevice, h_havg_density.begin(), h_havg_density.end(), d_havg_density.begin());
1933  Gpu::copy(Gpu::hostToDevice, h_havg_temperature.begin(), h_havg_temperature.end(), d_havg_temperature.begin());
1934  Gpu::copy(Gpu::hostToDevice, h_havg_pressure.begin(), h_havg_pressure.end(), d_havg_pressure.begin());
1935 
1936  if (solverChoice.moisture_type != MoistureType::None)
1937  {
1938  d_havg_qv.resize(size_z, 0.0_rt);
1939  d_havg_qc.resize(size_z, 0.0_rt);
1940  Gpu::copy(Gpu::hostToDevice, h_havg_qv.begin(), h_havg_qv.end(), d_havg_qv.begin());
1941  Gpu::copy(Gpu::hostToDevice, h_havg_qc.begin(), h_havg_qc.end(), d_havg_qc.begin());
1942  }
1943 }
amrex::Gpu::DeviceVector< amrex::Real > d_havg_temperature
Definition: ERF.H:1164
amrex::Gpu::DeviceVector< amrex::Real > d_havg_qv
Definition: ERF.H:1166
amrex::Vector< amrex::Real > h_havg_pressure
Definition: ERF.H:1159
amrex::Vector< amrex::Real > h_havg_qc
Definition: ERF.H:1161
amrex::Vector< amrex::Real > h_havg_density
Definition: ERF.H:1157
amrex::Gpu::DeviceVector< amrex::Real > d_havg_qc
Definition: ERF.H:1167
amrex::Gpu::DeviceVector< amrex::Real > d_havg_density
Definition: ERF.H:1163
amrex::Vector< amrex::Real > h_havg_temperature
Definition: ERF.H:1158
amrex::Gpu::DeviceVector< amrex::Real > d_havg_pressure
Definition: ERF.H:1165
amrex::Vector< amrex::Real > h_havg_qv
Definition: ERF.H:1160
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
233 {
234  AMREX_ALWAYS_ASSERT(lev > 0);
235 
236  if (verbose) {
237  amrex::Print() <<" NEW BA FROM COARSE AT LEVEL " << lev << " " << ba << std::endl;
238  }
239 
240  //********************************************************************************************
241  // This allocates all kinds of things, including but not limited to: solution arrays,
242  // terrain arrays, metric terms and base state.
243  // *******************************************************************************************
244  init_stuff(lev, ba, dm, vars_new[lev], vars_old[lev], base_state[lev], z_phys_nd[lev]);
245 
246  t_new[lev] = time;
247  t_old[lev] = time - 1.e200;
248 
249  // ********************************************************************************************
250  // Build the data structures for metric quantities used with terrain-fitted coordinates
251  // ********************************************************************************************
252  init_zphys(lev, time);
254 
255  //
256  // Make sure that detJ and z_phys_cc are the average of the data on a finer level if there is one
257  //
258  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
259  for (int crse_lev = lev-1; crse_lev >= 0; crse_lev--) {
260  average_down( *detJ_cc[crse_lev+1], *detJ_cc[crse_lev], 0, 1, refRatio(crse_lev));
261  average_down(*z_phys_cc[crse_lev+1], *z_phys_cc[crse_lev], 0, 1, refRatio(crse_lev));
262  }
263  }
264 
265  // ********************************************************************************************
266  // Build the data structures for canopy model (depends upon z_phys)
267  // ********************************************************************************************
269  m_forest_drag[lev]->define_drag_field(ba, dm, geom[lev], z_phys_cc[lev].get(), z_phys_nd[lev].get());
270  }
271 
272  //********************************************************************************************
273  // Microphysics
274  // *******************************************************************************************
275  int q_size = micro->Get_Qmoist_Size(lev);
276  qmoist[lev].resize(q_size);
277  micro->Define(lev, solverChoice);
278  if (solverChoice.moisture_type != MoistureType::None)
279  {
280  micro->Init(lev, vars_new[lev][Vars::cons],
281  grids[lev], Geom(lev), 0.0,
282  z_phys_nd[lev], detJ_cc[lev]); // dummy dt value
283  }
284  for (int mvar(0); mvar<qmoist[lev].size(); ++mvar) {
285  qmoist[lev][mvar] = micro->Get_Qmoist_Ptr(lev,mvar);
286  }
287 
288  // *****************************************************************************************************
289  // Initialize the boundary conditions (after initializing the terrain but before calling
290  // initHSE or FillCoarsePatch)
291  // *****************************************************************************************************
292  make_physbcs(lev);
293 
294  // ********************************************************************************************
295  // Update the base state at this level by interpolation from coarser level (inside initHSE)
296  // ********************************************************************************************
297  initHSE(lev);
298 
299  // ********************************************************************************************
300  // Build the data structures for calculating diffusive/turbulent terms
301  // ********************************************************************************************
302  update_diffusive_arrays(lev, ba, dm);
303 
304  // ********************************************************************************************
305  // Fill data at the new level by interpolation from the coarser level
306  // Note that internal to FillCoarsePatch we will convert velocity to momentum,
307  // then interpolate momentum, then convert momentum back to velocity
308  // Also note that FillCoarsePatch is hard-wired to act only on lev_new at coarse and fine
309  // ********************************************************************************************
310  FillCoarsePatch(lev, time);
311 
312  // ********************************************************************************************
313  // Initialize the integrator class
314  // ********************************************************************************************
315  dt_mri_ratio[lev] = dt_mri_ratio[lev-1];
317 
318  // ********************************************************************************************
319  // If we are making a new level then the FillPatcher for this level hasn't been allocated yet
320  // ********************************************************************************************
321  if (lev > 0 && cf_width >= 0) {
324  }
325 
326  // ********************************************************************************************
327  // Create the MOST arrays at this (new) level
328  // ********************************************************************************************
329  if (phys_bc_type[Orientation(Direction::z,Orientation::low)] == ERF_BC::MOST) {
330  int nlevs = finest_level+1;
331  Vector<MultiFab*> mfv_old = {&vars_old[lev][Vars::cons], &vars_old[lev][Vars::xvel],
332  &vars_old[lev][Vars::yvel], &vars_old[lev][Vars::zvel]};
333  m_most->make_MOST_at_level(lev,nlevs,
334  mfv_old, Theta_prim[lev], Qv_prim[lev],
335  Qr_prim[lev], z_phys_nd[lev],
336  Hwave[lev].get(),Lwave[lev].get(),eddyDiffs_lev[lev].get(),
337  lsm_data[lev], lsm_flux[lev], sst_lev[lev], lmask_lev[lev]);
338  }
339 
340 #ifdef ERF_USE_PARTICLES
341  // particleData.Redistribute();
342 #endif
343 }
void update_diffusive_arrays(int lev, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm)
Definition: ERF_MakeNewArrays.cpp:375
void initialize_integrator(int lev, amrex::MultiFab &cons_mf, amrex::MultiFab &vel_mf)
Definition: ERF_MakeNewArrays.cpp:582
void update_terrain_arrays(int lev)
Definition: ERF_MakeNewArrays.cpp:571
void init_zphys(int lev, amrex::Real time)
Definition: ERF_MakeNewArrays.cpp:466
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:2021

◆ 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  if ( solverChoice.terrain_type == TerrainType::EB ||
57  solverChoice.terrain_type == TerrainType::ImmersedForcing)
58  {
59  const amrex::EB2::IndexSpace& ebis = amrex::EB2::IndexSpace::top();
60  const EB2::Level& eb_level = ebis.getLevel(geom[lev]);
61  eb[lev]->make_factory(lev, geom[lev], grids[lev], dmap[lev], eb_level);
62  } else {
63  // m_factory[lev] = std::make_unique<FabFactory<FArrayBox>>();
64  }
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::WRFInput) 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::WRFInput) 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 ( (solverChoice.init_type == InitType::WRFInput) || (solverChoice.init_type == InitType::Metgrid) )
121  {
122  AMREX_ALWAYS_ASSERT(solverChoice.terrain_type == TerrainType::StaticFittedMesh);
123  init_only(lev, start_time);
124  init_zphys(lev, time);
126  make_physbcs(lev);
127  } else {
128  init_zphys(lev, time);
130  // Note that for init_type != InitType::WRFInput and != InitType::Metgrid,
131  // make_physbcs is called inside init_only
132  init_only(lev, start_time);
133  }
134  } else {
135  // if restarting and nudging from input sounding, load the input sounding files
136  if (lev == 0 && solverChoice.init_type == InitType::Input_Sounding && solverChoice.nudging_from_input_sounding)
137  {
139  Error("input_sounding file name must be provided via input");
140  }
141 
143 
144  // this will interpolate the input profiles to the nominal height levels
145  // (ranging from 0 to the domain top)
146  for (int n = 0; n < input_sounding_data.n_sounding_files; n++) {
147  input_sounding_data.read_from_file(geom[lev], zlevels_stag[lev], n);
148  }
149 
150  // this will calculate the hydrostatically balanced density and pressure
151  // profiles following WRF ideal.exe
153  }
154  }
155 
156  // Read in tables needed for windfarm simulations
157  // fill in Nturb multifab - number of turbines in each mesh cell
158  // write out the vtk files for wind turbine location and/or
159  // actuator disks
160  #ifdef ERF_USE_WINDFARM
161  init_windfarm(lev);
162  #endif
163 
164  // ********************************************************************************************
165  // Build the data structures for canopy model (depends upon z_phys)
166  // ********************************************************************************************
167  if (restart_chkfile.empty()) {
169  m_forest_drag[lev]->define_drag_field(ba, dm, geom[lev], z_phys_cc[lev].get(), z_phys_nd[lev].get());
170  }
171  }
172 
173  //********************************************************************************************
174  // Create wall distance field for RANS model (depends upon z_phys)
175  // *******************************************************************************************
176  if (solverChoice.turbChoice[lev].rans_type != RANSType::None) {
177  // Handle bottom boundary
178  poisson_wall_dist(lev);
179 
180  // Correct the wall distance for immersed bodies
186  geom[lev],
187  z_phys_cc[lev]);
188  }
189  }
190 
191  //********************************************************************************************
192  // Microphysics
193  // *******************************************************************************************
194  int q_size = micro->Get_Qmoist_Size(lev);
195  qmoist[lev].resize(q_size);
196  micro->Define(lev, solverChoice);
197  if (solverChoice.moisture_type != MoistureType::None)
198  {
199  micro->Init(lev, vars_new[lev][Vars::cons],
200  grids[lev], Geom(lev), 0.0,
201  z_phys_nd[lev], detJ_cc[lev]); // dummy dt value
202  }
203  for (int mvar(0); mvar<qmoist[lev].size(); ++mvar) {
204  qmoist[lev][mvar] = micro->Get_Qmoist_Ptr(lev,mvar);
205  }
206 
207  // ********************************************************************************************
208  // If we are making a new level then the FillPatcher for this level hasn't been allocated yet
209  // ********************************************************************************************
210  if (lev > 0 && cf_width >= 0) {
213  }
214 
215 #ifdef ERF_USE_PARTICLES
216  if (restart_chkfile.empty()) {
217  if (lev == 0) {
218  initializeTracers((ParGDBBase*)GetParGDB(),z_phys_nd);
219  } else {
220  particleData.Redistribute();
221  }
222  }
223 #endif
224 }
BoxArray ERFPostProcessBaseGrids(const Box &domain, bool decompose_in_z)
Definition: ERF_ChopGrids.cpp:6
void thinbody_wall_dist(std::unique_ptr< MultiFab > &wdist, Vector< IntVect > &xfaces, Vector< IntVect > &yfaces, Vector< IntVect > &zfaces, const Geometry &geomdata, std::unique_ptr< MultiFab > &z_phys_cc)
Definition: ERF_ThinBodyWallDist.cpp:12
void init_only(int lev, amrex::Real time)
Definition: ERF.cpp:1368
void poisson_wall_dist(int lev)
Definition: ERF_PoissonWallDist.cpp:20
void init_thin_body(int lev, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm)
Definition: ERF_MakeNewLevel.cpp:583
int Get_Data_Size()
Definition: ERF_LandSurface.H:92
amrex::MultiFab * Get_Flux_Ptr(const int &lev, const int &varIdx)
Definition: ERF_LandSurface.H:86
void Init(const int &lev, const amrex::MultiFab &cons_in, const amrex::Geometry &geom, const amrex::Real &dt_advance)
Definition: ERF_LandSurface.H:43
void Define(const int &lev, SolverChoice &sc)
Definition: ERF_LandSurface.H:36
amrex::MultiFab * Get_Data_Ptr(const int &lev, const int &varIdx)
Definition: ERF_LandSurface.H:83
bool nudging_from_input_sounding
Definition: ERF_DataStruct.H:734
Here is the call graph for this function:

◆ nghost_eb_basic()

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

◆ nghost_eb_full()

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

◆ nghost_eb_volume()

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

◆ NumDataLogs()

AMREX_FORCE_INLINE int ERF::NumDataLogs ( )
inlineprivatenoexcept
1261  {
1262  return datalog.size();
1263  }

◆ NumDerDataLogs()

AMREX_FORCE_INLINE int ERF::NumDerDataLogs ( )
inlineprivatenoexcept
1268  {
1269  return der_datalog.size();
1270  }

◆ NumSampleLineLogs()

AMREX_FORCE_INLINE int ERF::NumSampleLineLogs ( )
inlineprivatenoexcept
1297  {
1298  return samplelinelog.size();
1299  }

◆ NumSampleLines()

AMREX_FORCE_INLINE int ERF::NumSampleLines ( )
inlineprivatenoexcept
1323  {
1324  return sampleline.size();
1325  }

◆ NumSamplePointLogs()

AMREX_FORCE_INLINE int ERF::NumSamplePointLogs ( )
inlineprivatenoexcept
1283  {
1284  return sampleptlog.size();
1285  }

◆ NumSamplePoints()

AMREX_FORCE_INLINE int ERF::NumSamplePoints ( )
inlineprivatenoexcept
1310  {
1311  return samplepoint.size();
1312  }

◆ operator=() [1/2]

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

◆ operator=() [2/2]

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

◆ ParameterSanityChecks()

void ERF::ParameterSanityChecks ( )
private
1778 {
1779  AMREX_ALWAYS_ASSERT(cfl > 0. || fixed_dt[0] > 0.);
1780 
1781  // We don't allow use_real_bcs to be true if init_type is not either InitType::WRFInput or InitType::Metgrid
1782  AMREX_ALWAYS_ASSERT(!solverChoice.use_real_bcs || ((solverChoice.init_type == InitType::WRFInput) || (solverChoice.init_type == InitType::Metgrid)) );
1783 
1784  AMREX_ALWAYS_ASSERT(real_width >= 0);
1785  AMREX_ALWAYS_ASSERT(real_set_width >= 0);
1786  AMREX_ALWAYS_ASSERT(real_width >= real_set_width);
1787 
1788  if (cf_width < 0 || cf_set_width < 0 || cf_width < cf_set_width) {
1789  Abort("You must set cf_width >= cf_set_width >= 0");
1790  }
1791  if (max_level > 0 && cf_set_width > 0) {
1792  for (int lev = 1; lev <= max_level; lev++) {
1793  if (cf_set_width%ref_ratio[lev-1][0] != 0 ||
1794  cf_set_width%ref_ratio[lev-1][1] != 0 ||
1795  cf_set_width%ref_ratio[lev-1][2] != 0 ) {
1796  Abort("You must set cf_width to be a multiple of ref_ratio");
1797  }
1798  }
1799  }
1800 
1801  // If fixed_mri_dt_ratio is set, it must be even
1802  if (fixed_mri_dt_ratio > 0 && (fixed_mri_dt_ratio%2 != 0) )
1803  {
1804  Abort("If you specify fixed_mri_dt_ratio, it must be even");
1805  }
1806 
1807  for (int lev = 0; lev <= max_level; lev++)
1808  {
1809  // We ignore fixed_fast_dt if not substepping
1810  if (solverChoice.substepping_type[lev] == SubsteppingType::None) {
1811  fixed_fast_dt[lev] = -1.0;
1812  }
1813 
1814  // If both fixed_dt and fast_dt are specified, their ratio must be an even integer
1815  if (fixed_dt[lev] > 0. && fixed_fast_dt[lev] > 0. && fixed_mri_dt_ratio <= 0)
1816  {
1817  Real eps = 1.e-12;
1818  int ratio = static_cast<int>( ( (1.0+eps) * fixed_dt[lev] ) / fixed_fast_dt[lev] );
1819  if (fixed_dt[lev] / fixed_fast_dt[lev] != ratio)
1820  {
1821  Abort("Ratio of fixed_dt to fixed_fast_dt must be an even integer");
1822  }
1823  }
1824 
1825  // If all three are specified, they must be consistent
1826  if (fixed_dt[lev] > 0. && fixed_fast_dt[lev] > 0. && fixed_mri_dt_ratio > 0)
1827  {
1828  if (fixed_dt[lev] / fixed_fast_dt[lev] != fixed_mri_dt_ratio)
1829  {
1830  Abort("Dt is over-specfied");
1831  }
1832  }
1833  } // lev
1834 
1835  if (solverChoice.coupling_type == CouplingType::TwoWay && cf_width > 0) {
1836  Abort("For two-way coupling you must set cf_width = 0");
1837  }
1838 }
int real_width
Definition: ERF.H:1078
int real_set_width
Definition: ERF.H:1079

◆ PlotFileName()

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

◆ PlotFileVarNames()

Vector< std::string > ERF::PlotFileVarNames ( amrex::Vector< std::string >  plot_var_names)
staticprivate
214 {
215  Vector<std::string> names;
216 
217  names.insert(names.end(), plot_var_names.begin(), plot_var_names.end());
218 
219  return names;
220 
221 }

◆ poisson_wall_dist()

void ERF::poisson_wall_dist ( int  lev)

Calculate wall distances using the Poisson equation

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

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

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

◆ post_timestep()

void ERF::post_timestep ( int  nstep,
amrex::Real  time,
amrex::Real  dt_lev 
)
498 {
499  BL_PROFILE("ERF::post_timestep()");
500 
501 #ifdef ERF_USE_PARTICLES
502  particleData.Redistribute();
503 #endif
504 
505  if (solverChoice.coupling_type == CouplingType::TwoWay)
506  {
507  int ncomp = vars_new[0][Vars::cons].nComp();
508  for (int lev = finest_level-1; lev >= 0; lev--)
509  {
510  // The quantity that is conserved is not (rho S), but rather (rho S / m^2) where
511  // m is the map scale factor at cell centers
512  // Here we pre-divide (rho S) by m^2 before refluxing
513  for (MFIter mfi(vars_new[lev][Vars::cons], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
514  const Box& bx = mfi.tilebox();
515  const Array4< Real> cons_arr = vars_new[lev][Vars::cons].array(mfi);
516  const Array4<const Real> mapfac_arr = mapfac_m[lev]->const_array(mfi);
517  if (SolverChoice::mesh_type == MeshType::ConstantDz) {
518  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
519  {
520  cons_arr(i,j,k,n) /= (mapfac_arr(i,j,0)*mapfac_arr(i,j,0));
521  });
522  } else {
523  const Array4<const Real> detJ_arr = detJ_cc[lev]->const_array(mfi);
524  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
525  {
526  cons_arr(i,j,k,n) *= detJ_arr(i,j,k) / (mapfac_arr(i,j,0)*mapfac_arr(i,j,0));
527  });
528  }
529  } // mfi
530 
531  // This call refluxes all "slow" cell-centered variables
532  // (i.e. not density or (rho theta) or velocities) from the lev/lev+1 interface onto lev
533  getAdvFluxReg(lev+1)->Reflux(vars_new[lev][Vars::cons], 2, 2, ncomp-2);
534 
535  // Here we multiply (rho S) by m^2 after refluxing
536  for (MFIter mfi(vars_new[lev][Vars::cons], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
537  const Box& bx = mfi.tilebox();
538  const Array4< Real> cons_arr = vars_new[lev][Vars::cons].array(mfi);
539  const Array4<const Real> mapfac_arr = mapfac_m[lev]->const_array(mfi);
540  if (SolverChoice::mesh_type == MeshType::ConstantDz) {
541  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
542  {
543  cons_arr(i,j,k,n) *= (mapfac_arr(i,j,0)*mapfac_arr(i,j,0));
544  });
545  } else {
546  const Array4<const Real> detJ_arr = detJ_cc[lev]->const_array(mfi);
547  ParallelFor(bx, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
548  {
549  cons_arr(i,j,k,n) *= (mapfac_arr(i,j,0)*mapfac_arr(i,j,0)) / detJ_arr(i,j,k);
550  });
551  }
552  } // mfi
553 
554  // We need to do this before anything else because refluxing changes the
555  // values of coarse cells underneath fine grids with the assumption they'll
556  // be over-written by averaging down
557  int src_comp;
558  if (solverChoice.anelastic[lev]) {
559  src_comp = 1;
560  } else {
561  src_comp = 0;
562  }
563  int num_comp = ncomp - src_comp;
564  AverageDownTo(lev,src_comp,num_comp);
565  }
566  }
567 
568  if (is_it_time_for_action(nstep, time, dt_lev0, sum_interval, sum_per)) {
571  }
572 
573  if (solverChoice.pert_type == PerturbationType::Source ||
574  solverChoice.pert_type == PerturbationType::Direct) {
575  if (is_it_time_for_action(nstep, time, dt_lev0, pert_interval, -1.)) {
576  turbPert.debug(time);
577  }
578  }
579 
580  if (profile_int > 0 && (nstep+1) % profile_int == 0) {
581  if (destag_profiles) {
582  // all variables cell-centered
583  write_1D_profiles(time);
584  } else {
585  // some variables staggered
587  }
588  }
589 
590  if (output_1d_column) {
591 #ifdef ERF_USE_NETCDF
592  if (is_it_time_for_action(nstep, time, dt_lev0, column_interval, column_per))
593  {
594  int lev_column = 0;
595  for (int lev = finest_level; lev >= 0; lev--)
596  {
597  Real dx_lev = geom[lev].CellSize(0);
598  Real dy_lev = geom[lev].CellSize(1);
599  int i_lev = static_cast<int>(std::floor(column_loc_x / dx_lev));
600  int j_lev = static_cast<int>(std::floor(column_loc_y / dy_lev));
601  if (grids[lev].contains(IntVect(i_lev,j_lev,0))) lev_column = lev;
602  }
603  writeToNCColumnFile(lev_column, column_file_name, column_loc_x, column_loc_y, time);
604  }
605 #else
606  Abort("To output 1D column files ERF must be compiled with NetCDF");
607 #endif
608  }
609 
611  {
614  {
615  bool is_moist = (micro->Get_Qstate_Size() > 0);
616  m_w2d->write_planes(istep[0], time, vars_new, is_moist);
617  }
618  }
619 
620  // Write plane/line sampler data
621  if (is_it_time_for_action(nstep+1, time, dt_lev0, sampler_interval, sampler_per) && (data_sampler) ) {
622  data_sampler->get_sample_data(geom, vars_new);
623  data_sampler->write_sample_data(t_new, istep, ref_ratio, geom);
624  }
625 
626  // Moving terrain
627  if ( solverChoice.terrain_type == TerrainType::MovingFittedMesh )
628  {
629  for (int lev = finest_level; lev >= 0; lev--)
630  {
631  // Copy z_phs_nd and detJ_cc at end of timestep
632  MultiFab::Copy(*z_phys_nd[lev], *z_phys_nd_new[lev], 0, 0, 1, z_phys_nd[lev]->nGrowVect());
633  MultiFab::Copy( *detJ_cc[lev], *detJ_cc_new[lev], 0, 0, 1, detJ_cc[lev]->nGrowVect());
634  MultiFab::Copy(base_state[lev],base_state_new[lev],0,0,BaseState::num_comps,base_state[lev].nGrowVect());
635 
636  make_zcc(geom[lev],*z_phys_nd[lev],*z_phys_cc[lev]);
637  }
638  }
639 } // post_timestep
void make_zcc(const Geometry &geom, MultiFab &z_phys_nd, MultiFab &z_phys_cc)
Definition: ERF_TerrainMetrics.cpp:623
static amrex::Real column_loc_y
Definition: ERF.H:1105
static std::string column_file_name
Definition: ERF.H:1106
AMREX_FORCE_INLINE amrex::YAFluxRegister * getAdvFluxReg(int lev)
Definition: ERF.H:1239
static amrex::Real bndry_output_planes_per
Definition: ERF.H:1111
static amrex::Real column_per
Definition: ERF.H:1103
amrex::Real sampler_per
Definition: ERF.H:1407
static amrex::Real column_loc_x
Definition: ERF.H:1104
static int bndry_output_planes_interval
Definition: ERF.H:1110
int sampler_interval
Definition: ERF.H:1406
static int output_1d_column
Definition: ERF.H:1101
static int column_interval
Definition: ERF.H:1102
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:86
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  auto const dom_lo = lbound(geom[lev].Domain());
15  auto const dom_hi = ubound(geom[lev].Domain());
16 
17  // Make sure the solver only sees the levels over which we are solving
18  Vector<BoxArray> ba_tmp; ba_tmp.push_back(mom_mf[Vars::cons].boxArray());
19  Vector<DistributionMapping> dm_tmp; dm_tmp.push_back(mom_mf[Vars::cons].DistributionMap());
20  Vector<Geometry> geom_tmp; geom_tmp.push_back(geom[lev]);
21 
22  MultiFab r_hse(base_state[lev], make_alias, BaseState::r0_comp, 1);
23 
24  Vector<MultiFab> rhs;
25  Vector<MultiFab> phi;
26 
27  if (solverChoice.terrain_type == TerrainType::EB)
28  {
29  rhs.resize(1); rhs[0].define(ba_tmp[0], dm_tmp[0], 1, 0, MFInfo(), EBFactory(lev));
30  phi.resize(1); phi[0].define(ba_tmp[0], dm_tmp[0], 1, 1, MFInfo(), EBFactory(lev));
31  } else {
32  rhs.resize(1); rhs[0].define(ba_tmp[0], dm_tmp[0], 1, 0);
33  phi.resize(1); phi[0].define(ba_tmp[0], dm_tmp[0], 1, 1);
34  }
35 
36  auto dxInv = geom[lev].InvCellSizeArray();
37 
38  // If !fixed_density, we must convert (rho u) which came in
39  // to (rho0 u) which is what we will project
41  ConvertForProjection(mom_mf[Vars::cons], r_hse,
42  mom_mf[IntVars::xmom],
43  mom_mf[IntVars::ymom],
44  mom_mf[IntVars::zmom],
45  Geom(lev).Domain(),
47  }
48 
49  //
50  // ****************************************************************************
51  // Now convert the rho0w MultiFab to hold Omega rather than rhow
52  // ****************************************************************************
53  //
54  if (solverChoice.mesh_type == MeshType::VariableDz)
55  {
56  for ( MFIter mfi(rhs[0],TilingIfNotGPU()); mfi.isValid(); ++mfi)
57  {
58  const Array4<Real const>& rho0u_arr = mom_mf[IntVars::xmom].const_array(mfi);
59  const Array4<Real const>& rho0v_arr = mom_mf[IntVars::ymom].const_array(mfi);
60  const Array4<Real >& rho0w_arr = mom_mf[IntVars::zmom].array(mfi);
61 
62  const Array4<Real const>& z_nd = z_phys_nd[lev]->const_array(mfi);
63  //
64  // Define Omega from (rho0 W) but store it in the same array
65  //
66  Box tbz = mfi.nodaltilebox(2);
67  ParallelFor(tbz, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept {
68  if (k > dom_lo.z && k <= dom_hi.z) {
69  Real rho0w = rho0w_arr(i,j,k);
70  rho0w_arr(i,j,k) = OmegaFromW(i,j,k,rho0w,rho0u_arr,rho0v_arr,z_nd,dxInv);
71  } else {
72  rho0w_arr(i,j,k) = Real(0.0);
73  }
74  });
75  } // mfi
76  }
77 
78  // ****************************************************************************
79  // Compute divergence which will form RHS
80  // Note that we replace "rho0w" with the contravariant momentum, Omega
81  // ****************************************************************************
82  Array<MultiFab const*, AMREX_SPACEDIM> rho0_u_const;
83  rho0_u_const[0] = &mom_mf[IntVars::xmom];
84  rho0_u_const[1] = &mom_mf[IntVars::ymom];
85  rho0_u_const[2] = &mom_mf[IntVars::zmom];
86 
87  compute_divergence(lev, rhs[0], rho0_u_const, geom_tmp[0]);
88 
89  Real rhsnorm = rhs[0].norm0();
90 
91  if (mg_verbose > 0) {
92  Print() << "Max/L2 norm of divergence before solve at level " << lev << " : " << rhsnorm << " " << rhs[0].norm2() << std::endl;
93  }
94 
95  // ****************************************************************************
96  //
97  // No need to build the solver if RHS == 0
98  //
99  if (rhsnorm <= solverChoice.poisson_abstol) return;
100  // ****************************************************************************
101 
102  // ****************************************************************************
103  // Initialize phi to 0
104  // (It is essential that we do this in order to fill the corners; these are never
105  // used but the Saxpy requires the values to be initialized.)
106  // ****************************************************************************
107  phi[0].setVal(0.0);
108 
109  Real start_step = static_cast<Real>(ParallelDescriptor::second());
110 
111  // ****************************************************************************
112  // Allocate fluxes
113  // ****************************************************************************
114  Vector<Array<MultiFab,AMREX_SPACEDIM> > fluxes;
115  fluxes.resize(1);
116  for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
117  if (solverChoice.terrain_type == TerrainType::EB) {
118  fluxes[0][idim].define(convert(ba_tmp[0], IntVect::TheDimensionVector(idim)), dm_tmp[0], 1, 0, MFInfo(), EBFactory(lev));
119  } else {
120  fluxes[0][idim].define(convert(ba_tmp[0], IntVect::TheDimensionVector(idim)), dm_tmp[0], 1, 0);
121  }
122  }
123 
124  // ****************************************************************************
125  // Choose the solver and solve
126  // ****************************************************************************
127 
128  // ****************************************************************************
129  // EB
130  // ****************************************************************************
131  if (solverChoice.terrain_type == TerrainType::EB) {
132  solve_with_EB_mlmg(lev, rhs, phi, fluxes);
133  } else {
134 
135 #ifdef ERF_USE_FFT
136  Box my_region(ba_tmp[0].minimalBox());
137  bool boxes_make_rectangle = (my_region.numPts() == ba_tmp[0].numPts());
138 #endif
139 
140  // ****************************************************************************
141  // No terrain or grid stretching
142  // ****************************************************************************
143  if (solverChoice.mesh_type == MeshType::ConstantDz) {
144 #ifdef ERF_USE_FFT
145  if (use_fft) {
146  if (boxes_make_rectangle) {
147  solve_with_fft(lev, rhs[0], phi[0], fluxes[0]);
148  } else {
149  amrex::Warning("FFT won't work unless the union of boxes is rectangular: defaulting to MLMG");
150  solve_with_mlmg(lev, rhs, phi, fluxes);
151  }
152  } else {
153  solve_with_mlmg(lev, rhs, phi, fluxes);
154  }
155 #else
156  if (use_fft) {
157  amrex::Warning("You set use_fft=true but didn't build with USE_FFT = TRUE; defaulting to MLMG");
158  }
159  solve_with_mlmg(lev, rhs, phi, fluxes);
160 #endif
161  } // No terrain or grid stretching
162 
163  // ****************************************************************************
164  // Grid stretching (flat terrain)
165  // ****************************************************************************
166  else if (solverChoice.mesh_type == MeshType::StretchedDz) {
167 #ifndef ERF_USE_FFT
168  amrex::Abort("Rebuild with USE_FFT = TRUE so you can use the FFT solver");
169 #else
170  if (!boxes_make_rectangle) {
171  amrex::Abort("FFT won't work unless the union of boxes is rectangular");
172  } else {
173  if (!use_fft) {
174  amrex::Warning("Using FFT even though you didn't set use_fft to true; it's the best choice");
175  }
176  solve_with_fft(lev, rhs[0], phi[0], fluxes[0]);
177  }
178 #endif
179  } // grid stretching
180 
181  // ****************************************************************************
182  // General terrain
183  // ****************************************************************************
184  else if (solverChoice.mesh_type == MeshType::VariableDz) {
185 #ifdef ERF_USE_FFT
186  if (use_fft)
187  {
188  amrex::Warning("FFT solver does not work for general terrain: switching to FFT-preconditioned GMRES");
189  }
190  if (!boxes_make_rectangle) {
191  amrex::Abort("FFT preconditioner for GMRES won't work unless the union of boxes is rectangular");
192  } else {
193  solve_with_gmres(lev, rhs, phi, fluxes);
194  }
195 #else
196  amrex::Abort("Rebuild with USE_FFT = TRUE so you can use the FFT preconditioner for GMRES");
197 #endif
198  } // general terrain
199 
200  } // not EB
201 
202  // ****************************************************************************
203  // Print time in solve
204  // ****************************************************************************
205  Real end_step = static_cast<Real>(ParallelDescriptor::second());
206  if (mg_verbose > 0) {
207  amrex::Print() << "Time in solve " << end_step - start_step << std::endl;
208  }
209 
210  // ****************************************************************************
211  // Subtract dt grad(phi) from the momenta (rho0u, rho0v, Omega)
212  // ****************************************************************************
213  MultiFab::Add(mom_mf[IntVars::xmom],fluxes[0][0],0,0,1,0);
214  MultiFab::Add(mom_mf[IntVars::ymom],fluxes[0][1],0,0,1,0);
215  MultiFab::Add(mom_mf[IntVars::zmom],fluxes[0][2],0,0,1,0);
216 
217  //
218  // This call is only to verify the divergence after the solve
219  // It is important we do this before computing the rho0w_arr from Omega back to rho0w
220  //
221  // ****************************************************************************
222  // THIS IS SIMPLY VERIFYING THE DIVERGENCE AFTER THE SOLVE
223  // ****************************************************************************
224  //
225  if (mg_verbose > 0)
226  {
227  compute_divergence(lev, rhs[0], rho0_u_const, geom_tmp[0]);
228 
229  Print() << "Max/L2 norm of divergence after solve at level " << lev << " : " << rhs[0].norm0() << " " << rhs[0].norm2() << std::endl;
230 
231 #if 0
232  // FOR DEBUGGING ONLY
233  for ( MFIter mfi(rhs[0],TilingIfNotGPU()); mfi.isValid(); ++mfi)
234  {
235  const Array4<Real const>& rhs_arr = rhs[0].const_array(mfi);
236  Box bx = mfi.validbox();
237  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept {
238  if (std::abs(rhs_arr(i,j,k)) > 1.e-10) {
239  amrex::AllPrint() << "RHS AFTER SOLVE AT " <<
240  IntVect(i,j,k) << " " << rhs_arr(i,j,k) << std::endl;
241  }
242  });
243  } // mfi
244 #endif
245 
246  } // mg_verbose
247 
248  //
249  // ****************************************************************************
250  // Now convert the rho0w MultiFab back to holding (rho0w) rather than Omega
251  // ****************************************************************************
252  //
253  if (solverChoice.mesh_type == MeshType::VariableDz)
254  {
255  for (MFIter mfi(mom_mf[Vars::cons],TilingIfNotGPU()); mfi.isValid(); ++mfi)
256  {
257  Box tbz = mfi.nodaltilebox(2);
258  const Array4<Real >& rho0u_arr = mom_mf[IntVars::xmom].array(mfi);
259  const Array4<Real >& rho0v_arr = mom_mf[IntVars::ymom].array(mfi);
260  const Array4<Real >& rho0w_arr = mom_mf[IntVars::zmom].array(mfi);
261  const Array4<Real const>& z_nd = z_phys_nd[lev]->const_array(mfi);
262  ParallelFor(tbz, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept {
263  Real omega = rho0w_arr(i,j,k);
264  rho0w_arr(i,j,k) = WFromOmega(i,j,k,omega,rho0u_arr,rho0v_arr,z_nd,dxInv);
265  });
266  } // mfi
267  }
268 
269  // If !fixed_density, we must convert (rho0 u) back
270  // to (rho0 u) which is what we will pass back out
272  ConvertForProjection(r_hse, mom_mf[Vars::cons],
273  mom_mf[IntVars::xmom],
274  mom_mf[IntVars::ymom],
275  mom_mf[IntVars::zmom],
276  Geom(lev).Domain(),
278  }
279 
280  // ****************************************************************************
281  // Update pressure variable with phi -- note that phi is dt * change in pressure
282  // ****************************************************************************
283  MultiFab::Saxpy(pmf, 1.0/l_dt, phi[0],0,0,1,1);
284  pmf.FillBoundary(geom[lev].periodicity());
285 }
void ConvertForProjection(const MultiFab &den_div, const MultiFab &den_mlt, MultiFab &xmom, MultiFab &ymom, MultiFab &zmom, const Box &domain, const Vector< BCRec > &domain_bcs_type_h)
Definition: ERF_ConvertForProjection.cpp:25
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:414
static bool use_fft
Definition: ERF.H:1057
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
void solve_with_EB_mlmg(int lev, amrex::Vector< amrex::MultiFab > &rhs, amrex::Vector< amrex::MultiFab > &p, amrex::Vector< amrex::Array< amrex::MultiFab, AMREX_SPACEDIM >> &fluxes)
Definition: ERF_SolveWithEBMLMG.cpp:19
@ omega
Definition: ERF_Morrison.H:45
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:409
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:450
int ncorr
Definition: ERF_DataStruct.H:684
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.

309 {
310  Print() << "Restart from native checkpoint " << restart_chkfile << "\n";
311 
312  // Header
313  std::string File(restart_chkfile + "/Header");
314 
315  VisMF::IO_Buffer io_buffer(VisMF::GetIOBufferSize());
316 
317  Vector<char> fileCharPtr;
318  ParallelDescriptor::ReadAndBcastFile(File, fileCharPtr);
319  std::string fileCharPtrString(fileCharPtr.dataPtr());
320  std::istringstream is(fileCharPtrString, std::istringstream::in);
321 
322  std::string line, word;
323 
324  int chk_ncomp_cons, chk_ncomp;
325 
326  // read in title line
327  std::getline(is, line);
328 
329  // read in finest_level
330  is >> finest_level;
331  GotoNextLine(is);
332 
333  // read the number of components
334  // for each variable we store
335 
336  // conservative, cell-centered vars
337  is >> chk_ncomp_cons;
338  GotoNextLine(is);
339 
340  // x-velocity on faces
341  is >> chk_ncomp;
342  GotoNextLine(is);
343  AMREX_ASSERT(chk_ncomp == 1);
344 
345  // y-velocity on faces
346  is >> chk_ncomp;
347  GotoNextLine(is);
348  AMREX_ASSERT(chk_ncomp == 1);
349 
350  // z-velocity on faces
351  is >> chk_ncomp;
352  GotoNextLine(is);
353  AMREX_ASSERT(chk_ncomp == 1);
354 
355  // read in array of istep
356  std::getline(is, line);
357  {
358  std::istringstream lis(line);
359  int i = 0;
360  while (lis >> word) {
361  istep[i++] = std::stoi(word);
362  }
363  }
364 
365  // read in array of dt
366  std::getline(is, line);
367  {
368  std::istringstream lis(line);
369  int i = 0;
370  while (lis >> word) {
371  dt[i++] = std::stod(word);
372  }
373  }
374 
375  // read in array of t_new
376  std::getline(is, line);
377  {
378  std::istringstream lis(line);
379  int i = 0;
380  while (lis >> word) {
381  t_new[i++] = std::stod(word);
382  }
383  }
384 
385  for (int lev = 0; lev <= finest_level; ++lev) {
386  // read in level 'lev' BoxArray from Header
387  BoxArray ba;
388  ba.readFrom(is);
389  GotoNextLine(is);
390 
391  // create a distribution mapping
392  DistributionMapping dm { ba, ParallelDescriptor::NProcs() };
393 
394  MakeNewLevelFromScratch (lev, t_new[lev], ba, dm);
395  }
396 
397  // ncomp is only valid after we MakeNewLevelFromScratch (asks micro how many vars)
398  // NOTE: Data is written over ncomp, so check that we match the header file
399  int ncomp_cons = vars_new[0][Vars::cons].nComp();
400 
401  // NOTE: QKE was removed so this is for backward compatibility
402  AMREX_ASSERT((chk_ncomp_cons==ncomp_cons) || ((chk_ncomp_cons-1)==ncomp_cons));
403  //
404  // See if we have a written separate file that tells how many components and how many ghost cells
405  // we have of the base state
406  //
407  // If we can't find the file, then set the number of components to the original number = 3
408  //
409  int ncomp_base_to_read = 3;
410  IntVect ng_base = IntVect{1};
411  {
412  std::string BaseStateFile(restart_chkfile + "/num_base_state_comps");
413 
414  if (amrex::FileExists(BaseStateFile))
415  {
416  Vector<char> BaseStatefileCharPtr;
417  ParallelDescriptor::ReadAndBcastFile(BaseStateFile, BaseStatefileCharPtr);
418  std::string BaseStatefileCharPtrString(BaseStatefileCharPtr.dataPtr());
419 
420  // We set this to the default value of 3 but allow it be larger if th0 and qv0 were written
421  std::istringstream isb(BaseStatefileCharPtrString, std::istringstream::in);
422  isb >> ncomp_base_to_read;
423  isb >> ng_base;
424  }
425  }
426 
427  // read in the MultiFab data
428  for (int lev = 0; lev <= finest_level; ++lev)
429  {
430  // NOTE: For backward compatibility (chk file has QKE)
431  if ((chk_ncomp_cons-1)==ncomp_cons) {
432  MultiFab cons(grids[lev],dmap[lev],chk_ncomp_cons,0);
433  VisMF::Read(cons, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Cell"));
434 
435  // Copy up to RhoKE_comp
436  MultiFab::Copy(vars_new[lev][Vars::cons],cons,0,0,(RhoKE_comp+1),0);
437 
438  // Only if we have a PBL model do we need to copy QKE is src to KE in dst
439  if ( (solverChoice.turbChoice[lev].pbl_type == PBLType::MYNN25) ||
440  (solverChoice.turbChoice[lev].pbl_type == PBLType::MYNNEDMF) ) {
441  MultiFab::Copy(vars_new[lev][Vars::cons],cons,(RhoKE_comp+1),RhoKE_comp,1,0);
442  vars_new[lev][Vars::cons].mult(0.5,RhoKE_comp,1,0);
443  }
444 
445  // Copy other components
446  int ncomp_remainder = ncomp_cons - (RhoKE_comp + 1);
447  MultiFab::Copy(vars_new[lev][Vars::cons],cons,(RhoKE_comp+2),(RhoKE_comp+1),ncomp_remainder,0);
448 
449  vars_new[lev][Vars::cons].setBndry(1.0e34);
450  } else {
451  MultiFab cons(grids[lev],dmap[lev],ncomp_cons,0);
452  VisMF::Read(cons, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Cell"));
453  MultiFab::Copy(vars_new[lev][Vars::cons],cons,0,0,ncomp_cons,0);
454  vars_new[lev][Vars::cons].setBndry(1.0e34);
455  }
456 
457  MultiFab xvel(convert(grids[lev],IntVect(1,0,0)),dmap[lev],1,0);
458  VisMF::Read(xvel, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "XFace"));
459  MultiFab::Copy(vars_new[lev][Vars::xvel],xvel,0,0,1,0);
460  vars_new[lev][Vars::xvel].setBndry(1.0e34);
461 
462  MultiFab yvel(convert(grids[lev],IntVect(0,1,0)),dmap[lev],1,0);
463  VisMF::Read(yvel, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "YFace"));
464  MultiFab::Copy(vars_new[lev][Vars::yvel],yvel,0,0,1,0);
465  vars_new[lev][Vars::yvel].setBndry(1.0e34);
466 
467  MultiFab zvel(convert(grids[lev],IntVect(0,0,1)),dmap[lev],1,0);
468  VisMF::Read(zvel, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "ZFace"));
469  MultiFab::Copy(vars_new[lev][Vars::zvel],zvel,0,0,1,0);
470  vars_new[lev][Vars::zvel].setBndry(1.0e34);
471 
472  // Note that we read the ghost cells of the base state (unlike above)
473 
474  // The original base state only had 3 components and 1 ghost cell -- we read this
475  // here to be consistent with the old style
476  MultiFab base(grids[lev],dmap[lev],ncomp_base_to_read,ng_base);
477  VisMF::Read(base, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "BaseState"));
478 
479  MultiFab::Copy(base_state[lev],base,0,0,ncomp_base_to_read,ng_base);
480 
481  // Create theta0 from p0, rh0
482  if (ncomp_base_to_read < 4) {
483  for (MFIter mfi(base_state[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
484  {
485  // We only compute theta_0 on valid cells since we will impose domain BC's after restart
486  const Box& bx = mfi.tilebox();
487  Array4<Real> const& fab = base_state[lev].array(mfi);
488  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
489  {
491  / fab(i,j,k,BaseState::r0_comp);
492  });
493  }
494  }
495  // Default theta0 to 0
496  if (ncomp_base_to_read < 5) {
497  for (MFIter mfi(base_state[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
498  {
499  // We only compute theta_0 on valid cells since we will impose domain BC's after restart
500  const Box& bx = mfi.tilebox();
501  Array4<Real> const& fab = base_state[lev].array(mfi);
502  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
503  {
504  fab(i,j,k,BaseState::qv0_comp) = 0.0;
505  });
506  }
507  }
508  base_state[lev].FillBoundary(geom[lev].periodicity());
509 
510  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
511  // Note that we also read the ghost cells of z_phys_nd
512  IntVect ng = z_phys_nd[lev]->nGrowVect();
513  MultiFab z_height(convert(grids[lev],IntVect(1,1,1)),dmap[lev],1,ng);
514  VisMF::Read(z_height, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Z_Phys_nd"));
515  MultiFab::Copy(*z_phys_nd[lev],z_height,0,0,1,ng);
517  }
518 
519  // Read in the moisture model restart variables
520  std::vector<int> qmoist_indices;
521  std::vector<std::string> qmoist_names;
522  micro->Get_Qmoist_Restart_Vars(lev, solverChoice, qmoist_indices, qmoist_names);
523  int qmoist_nvar = qmoist_indices.size();
524  for (int var = 0; var < qmoist_nvar; var++) {
525  const int ncomp = 1;
526  IntVect ng_moist = qmoist[lev][qmoist_indices[var]]->nGrowVect();
527  MultiFab moist_vars(grids[lev],dmap[lev],ncomp,ng_moist);
528  VisMF::Read(moist_vars, amrex::MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", qmoist_names[var]));
529  MultiFab::Copy(*(qmoist[lev][qmoist_indices[var]]),moist_vars,0,0,ncomp,ng_moist);
530  }
531 
532 #if defined(ERF_USE_WINDFARM)
533  if(solverChoice.windfarm_type == WindFarmType::Fitch or
534  solverChoice.windfarm_type == WindFarmType::EWP or
535  solverChoice.windfarm_type == WindFarmType::SimpleAD){
536  IntVect ng = Nturb[lev].nGrowVect();
537  MultiFab mf_Nturb(grids[lev],dmap[lev],1,ng);
538  VisMF::Read(mf_Nturb, amrex::MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "NumTurb"));
539  MultiFab::Copy(Nturb[lev],mf_Nturb,0,0,1,ng);
540  }
541 #endif
542 
543  if (solverChoice.lsm_type != LandSurfaceType::None) {
544  for (int mvar(0); mvar<lsm_data[lev].size(); ++mvar) {
545  BoxArray ba = lsm_data[lev][mvar]->boxArray();
546  DistributionMapping dm = lsm_data[lev][mvar]->DistributionMap();
547  IntVect ng = lsm_data[lev][mvar]->nGrowVect();
548  int nvar = lsm_data[lev][mvar]->nComp();
549  MultiFab lsm_vars(ba,dm,nvar,ng);
550  VisMF::Read(lsm_vars, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "LsmVars"));
551  MultiFab::Copy(*(lsm_data[lev][mvar]),lsm_vars,0,0,nvar,ng);
552  }
553  }
554 
555  // Note that we read the ghost cells of the mapfactors
556  BoxList bl2d = grids[lev].boxList();
557  for (auto& b : bl2d) {
558  b.setRange(2,0);
559  }
560  BoxArray ba2d(std::move(bl2d));
561 
562  IntVect ng = mapfac_m[lev]->nGrowVect();
563  MultiFab mf_m(ba2d,dmap[lev],1,ng);
564  VisMF::Read(mf_m, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "MapFactor_m"));
565  MultiFab::Copy(*mapfac_m[lev],mf_m,0,0,1,ng);
566 
567  ng = mapfac_u[lev]->nGrowVect();
568  MultiFab mf_u(convert(ba2d,IntVect(1,0,0)),dmap[lev],1,ng);
569  VisMF::Read(mf_u, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "MapFactor_u"));
570  MultiFab::Copy(*mapfac_u[lev],mf_u,0,0,1,ng);
571 
572  ng = mapfac_v[lev]->nGrowVect();
573  MultiFab mf_v(convert(ba2d,IntVect(0,1,0)),dmap[lev],1,ng);
574  VisMF::Read(mf_v, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "MapFactor_v"));
575  MultiFab::Copy(*mapfac_v[lev],mf_v,0,0,1,ng);
576 
577  if (m_most && m_most->have_variable_sea_roughness()) {
578  amrex::Print() << "Reading variable surface roughness" << std::endl;
579  ng = vars_new[lev][Vars::cons].nGrowVect(); ng[2]=0;
580  MultiFab z0(ba2d,dmap[lev],1,ng);
581  VisMF::Read(z0, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Z0"));
582  for (amrex::MFIter mfi(z0); mfi.isValid(); ++mfi) {
583  const Box& bx = mfi.growntilebox();
584  FArrayBox* most_z0 = (m_most->get_z0(lev));
585  most_z0->copy<RunOn::Host>(z0[mfi], bx);
586  }
587  }
588 
589 #ifdef ERF_USE_NETCDF
590  // Read lat/lon if it exists
592  amrex::Print() << "Reading Lat/Lon variables" << std::endl;
593  IntVect ngv = ng; ngv[2] = 0;
594  MultiFab lat(ba2d,dmap[lev],1,ngv);
595  MultiFab lon(ba2d,dmap[lev],1,ngv);
596  VisMF::Read(lat, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "LAT"));
597  VisMF::Read(lon, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "LON"));
598  lat_m[lev] = std::make_unique<MultiFab>(ba2d,dmap[lev],1,ngv);
599  lon_m[lev] = std::make_unique<MultiFab>(ba2d,dmap[lev],1,ngv);
600  MultiFab::Copy(*lat_m[lev],lat,0,0,1,ngv);
601  MultiFab::Copy(*lon_m[lev],lon,0,0,1,ngv);
602  }
603 
604  // Read sinPhi and cosPhi if it exists
606  amrex::Print() << "Reading Coriolis factors" << std::endl;
607  IntVect ngv = ng; ngv[2] = 0;
608  MultiFab sphi(ba2d,dmap[lev],1,ngv);
609  MultiFab cphi(ba2d,dmap[lev],1,ngv);
610  VisMF::Read(sphi, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "SinPhi"));
611  VisMF::Read(cphi, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "CosPhi"));
612  sinPhi_m[lev] = std::make_unique<MultiFab>(ba2d,dmap[lev],1,ngv);
613  cosPhi_m[lev] = std::make_unique<MultiFab>(ba2d,dmap[lev],1,ngv);
614  MultiFab::Copy(*sinPhi_m[lev],sphi,0,0,1,ngv);
615  MultiFab::Copy(*cosPhi_m[lev],cphi,0,0,1,ngv);
616  }
617 #endif
618 
619  } // for lev
620 
621 #ifdef ERF_USE_PARTICLES
622  restartTracers((ParGDBBase*)GetParGDB(),restart_chkfile);
623  if (Microphysics::modelType(solverChoice.moisture_type) == MoistureModelType::Lagrangian) {
624  dynamic_cast<LagrangianMicrophysics&>(*micro).restartParticles((ParGDBBase*)GetParGDB(),restart_chkfile);
625  }
626 #endif
627 
628 #ifdef ERF_USE_NETCDF
629  // Read bdy_data files
630  if ( (solverChoice.init_type==InitType::WRFInput) || (solverChoice.init_type==InitType::Metgrid) &&
632  {
633  int ioproc = ParallelDescriptor::IOProcessorNumber(); // I/O rank
634  int num_time;
635  int num_var;
636  Vector<Box> bx_v;
637  if (ParallelDescriptor::IOProcessor()) {
638  // Open header file and read from it
639  std::ifstream bdy_h_file(MultiFabFileFullPrefix(0, restart_chkfile, "Level_", "bdy_H"));
640  bdy_h_file >> num_time;
641  bdy_h_file >> num_var;
642  bdy_h_file >> start_bdy_time;
643  bdy_h_file >> bdy_time_interval;
644  bdy_h_file >> real_width;
645  bx_v.resize(4*num_var);
646  for (int ivar(0); ivar<num_var; ++ivar) {
647  bdy_h_file >> bx_v[4*ivar ];
648  bdy_h_file >> bx_v[4*ivar+1];
649  bdy_h_file >> bx_v[4*ivar+2];
650  bdy_h_file >> bx_v[4*ivar+3];
651  }
652 
653  // IO size the FABs
654  bdy_data_xlo.resize(num_time);
655  bdy_data_xhi.resize(num_time);
656  bdy_data_ylo.resize(num_time);
657  bdy_data_yhi.resize(num_time);
658  for (int itime(0); itime<num_time; ++itime) {
659  bdy_data_xlo[itime].resize(num_var);
660  bdy_data_xhi[itime].resize(num_var);
661  bdy_data_ylo[itime].resize(num_var);
662  bdy_data_yhi[itime].resize(num_var);
663  for (int ivar(0); ivar<num_var; ++ivar) {
664  bdy_data_xlo[itime][ivar].resize(bx_v[4*ivar ]);
665  bdy_data_xhi[itime][ivar].resize(bx_v[4*ivar+1]);
666  bdy_data_ylo[itime][ivar].resize(bx_v[4*ivar+2]);
667  bdy_data_yhi[itime][ivar].resize(bx_v[4*ivar+3]);
668  }
669  }
670 
671  // Open data file and read from it
672  std::ifstream bdy_d_file(MultiFabFileFullPrefix(0, restart_chkfile, "Level_", "bdy_D"));
673  for (int itime(0); itime<num_time; ++itime) {
674  for (int ivar(0); ivar<num_var; ++ivar) {
675  bdy_data_xlo[itime][ivar].readFrom(bdy_d_file);
676  bdy_data_xhi[itime][ivar].readFrom(bdy_d_file);
677  bdy_data_ylo[itime][ivar].readFrom(bdy_d_file);
678  bdy_data_yhi[itime][ivar].readFrom(bdy_d_file);
679  }
680  }
681  } // IO
682 
683  // Broadcast the data
684  ParallelDescriptor::Barrier();
685  ParallelDescriptor::Bcast(&start_bdy_time,1,ioproc);
686  ParallelDescriptor::Bcast(&bdy_time_interval,1,ioproc);
687  ParallelDescriptor::Bcast(&real_width,1,ioproc);
688  ParallelDescriptor::Bcast(&num_time,1,ioproc);
689  ParallelDescriptor::Bcast(&num_var,1,ioproc);
690 
691  // Everyone size their boxes
692  bx_v.resize(4*num_var);
693 
694  ParallelDescriptor::Bcast(bx_v.dataPtr(),bx_v.size(),ioproc);
695 
696  // Everyone but IO size their FABs
697  if (!ParallelDescriptor::IOProcessor()) {
698  bdy_data_xlo.resize(num_time);
699  bdy_data_xhi.resize(num_time);
700  bdy_data_ylo.resize(num_time);
701  bdy_data_yhi.resize(num_time);
702  for (int itime(0); itime<num_time; ++itime) {
703  bdy_data_xlo[itime].resize(num_var);
704  bdy_data_xhi[itime].resize(num_var);
705  bdy_data_ylo[itime].resize(num_var);
706  bdy_data_yhi[itime].resize(num_var);
707  for (int ivar(0); ivar<num_var; ++ivar) {
708  bdy_data_xlo[itime][ivar].resize(bx_v[4*ivar ]);
709  bdy_data_xhi[itime][ivar].resize(bx_v[4*ivar+1]);
710  bdy_data_ylo[itime][ivar].resize(bx_v[4*ivar+2]);
711  bdy_data_yhi[itime][ivar].resize(bx_v[4*ivar+3]);
712  }
713  }
714  }
715 
716  for (int itime(0); itime<num_time; ++itime) {
717  for (int ivar(0); ivar<num_var; ++ivar) {
718  ParallelDescriptor::Bcast(bdy_data_xlo[itime][ivar].dataPtr(),bdy_data_xlo[itime][ivar].box().numPts(),ioproc);
719  ParallelDescriptor::Bcast(bdy_data_xhi[itime][ivar].dataPtr(),bdy_data_xhi[itime][ivar].box().numPts(),ioproc);
720  ParallelDescriptor::Bcast(bdy_data_ylo[itime][ivar].dataPtr(),bdy_data_ylo[itime][ivar].box().numPts(),ioproc);
721  ParallelDescriptor::Bcast(bdy_data_yhi[itime][ivar].dataPtr(),bdy_data_yhi[itime][ivar].box().numPts(),ioproc);
722  }
723  }
724  } // init_type == WRFInput or Metgrid
725 #endif
726 }
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
bool variable_coriolis
Definition: ERF_DataStruct.H:771
bool has_lat_lon
Definition: ERF_DataStruct.H:770
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.

735 {
736  for (int lev = 0; lev <= finest_level; ++lev)
737  {
738  // Note that we read the ghost cells
739  BoxList bl2d = grids[lev].boxList();
740  for (auto& b : bl2d) {
741  b.setRange(2,0);
742  }
743  BoxArray ba2d(std::move(bl2d));
744 
745  if (m_most->have_variable_sea_roughness()) {
746  amrex::Print() << "Reading variable surface roughness" << std::endl;
747  IntVect ng = vars_new[lev][Vars::cons].nGrowVect(); ng[2]=0;
748  MultiFab z0_in(ba2d,dmap[lev],1,ng);
749  VisMF::Read(z0_in, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Z0"));
750  auto z0 = const_cast<FArrayBox*>(m_most->get_z0(lev));
751  for (amrex::MFIter mfi(z0_in); mfi.isValid(); ++mfi) {
752  const Box& bx = mfi.growntilebox();
753  z0->copy<RunOn::Host>(z0_in[mfi], bx);
754  }
755  }
756  }
757 }

◆ ReadParameters()

void ERF::ReadParameters ( )
private
1488 {
1489  {
1490  ParmParse pp; // Traditionally, max_step and stop_time do not have prefix.
1491  pp.query("max_step", max_step);
1492 
1493  std::string start_datetime, stop_datetime;
1494  if (pp.query("start_datetime", start_datetime)) {
1495  start_time = getEpochTime(start_datetime, datetime_format);
1496  if (pp.query("stop_datetime", stop_datetime)) {
1497  stop_time = getEpochTime(stop_datetime, datetime_format);
1498  }
1499  use_datetime = true;
1500  } else {
1501  pp.query("stop_time", stop_time);
1502  pp.query("start_time", start_time); // This is optional, it defaults to 0
1503  }
1504  }
1505 
1506  ParmParse pp(pp_prefix);
1507  ParmParse pp_amr("amr");
1508  {
1509  // The type of the file we restart from
1510  pp.query("restart_type", restart_type);
1511 
1512  pp.query("regrid_level_0_on_restart", regrid_level_0_on_restart);
1513  pp.query("regrid_int", regrid_int);
1514  pp.query("check_file", check_file);
1515  pp.query("check_type", check_type);
1516 
1517  // The regression tests use "amr.restart" and "amr.m_check_int" so we allow
1518  // for those or "erf.restart" / "erf.m_check_int" with the former taking
1519  // precedence if both are specified
1520  pp.query("check_int", m_check_int);
1521  pp.query("check_per", m_check_per);
1522  pp_amr.query("check_int", m_check_int);
1523  pp_amr.query("check_per", m_check_per);
1524 
1525  pp.query("restart", restart_chkfile);
1526  pp_amr.query("restart", restart_chkfile);
1527 
1528  // Verbosity
1529  pp.query("v", verbose);
1530  pp.query("mg_v", mg_verbose);
1531  pp.query("use_fft", use_fft);
1532 #ifndef ERF_USE_FFT
1533  if (use_fft) {
1534  amrex::Abort("You must build with USE_FFT in order to set use_fft = true in your inputs file");
1535  }
1536 #endif
1537 
1538  // Frequency of diagnostic output
1539  pp.query("sum_interval", sum_interval);
1540  pp.query("sum_period" , sum_per);
1541 
1542  pp.query("pert_interval", pert_interval);
1543 
1544  // Time step controls
1545  pp.query("cfl", cfl);
1546  pp.query("substepping_cfl", sub_cfl);
1547  pp.query("init_shrink", init_shrink);
1548  pp.query("change_max", change_max);
1549  pp.query("dt_max_initial", dt_max_initial);
1550  pp.query("dt_max", dt_max);
1551 
1552  fixed_dt.resize(max_level+1,-1.);
1553  fixed_fast_dt.resize(max_level+1,-1.);
1554 
1555  pp.query("fixed_dt", fixed_dt[0]);
1556  pp.query("fixed_fast_dt", fixed_fast_dt[0]);
1557 
1558  for (int lev = 1; lev <= max_level; lev++)
1559  {
1560  fixed_dt[lev] = fixed_dt[lev-1] / static_cast<Real>(MaxRefRatio(lev-1));
1561  fixed_fast_dt[lev] = fixed_fast_dt[lev-1] / static_cast<Real>(MaxRefRatio(lev-1));
1562  }
1563 
1564  pp.query("fixed_mri_dt_ratio", fixed_mri_dt_ratio);
1565 
1566  // We use this to keep track of how many boxes we read in from WRF initialization
1567  num_files_at_level.resize(max_level+1,0);
1568 
1569  // We use this to keep track of how many boxes are specified thru the refinement indicators
1570  num_boxes_at_level.resize(max_level+1,0);
1571  boxes_at_level.resize(max_level+1);
1572 
1573  // We always have exactly one file at level 0
1574  num_boxes_at_level[0] = 1;
1575  boxes_at_level[0].resize(1);
1576  boxes_at_level[0][0] = geom[0].Domain();
1577 
1578 #ifdef ERF_USE_NETCDF
1579  nc_init_file.resize(max_level+1);
1580 
1581  // NetCDF wrfinput initialization files -- possibly multiple files at each of multiple levels
1582  // but we always have exactly one file at level 0
1583  for (int lev = 0; lev <= max_level; lev++) {
1584  const std::string nc_file_names = Concatenate("nc_init_file_",lev,1);
1585  if (pp.contains(nc_file_names.c_str())) {
1586  int num_files = pp.countval(nc_file_names.c_str());
1587  num_files_at_level[lev] = num_files;
1588  nc_init_file[lev].resize(num_files);
1589  pp.queryarr(nc_file_names.c_str(), nc_init_file[lev],0,num_files);
1590  for (int j = 0; j < num_files; j++) {
1591  Print() << "Reading NC init file names at level " << lev << " and index " << j << " : " << nc_init_file[lev][j] << std::endl;
1592  } // j
1593  } // if pp.contains
1594  } // lev
1595 
1596  // NetCDF wrfbdy lateral boundary file
1597  pp.query("nc_bdy_file", nc_bdy_file);
1598  Print() << "Reading NC bdy file name " << nc_bdy_file << std::endl;
1599 #endif
1600 
1601  // Flag to trigger initialization from input_sounding like WRF's ideal.exe
1602  pp.query("init_sounding_ideal", init_sounding_ideal);
1603 
1604  // Options for vertical interpolation of met_em*.nc data.
1605  pp.query("metgrid_debug_quiescent", metgrid_debug_quiescent);
1606  pp.query("metgrid_debug_isothermal", metgrid_debug_isothermal);
1607  pp.query("metgrid_debug_dry", metgrid_debug_dry);
1608  pp.query("metgrid_debug_psfc", metgrid_debug_psfc);
1609  pp.query("metgrid_debug_msf", metgrid_debug_msf);
1610  pp.query("metgrid_interp_theta", metgrid_interp_theta);
1611  pp.query("metgrid_basic_linear", metgrid_basic_linear);
1612  pp.query("metgrid_use_below_sfc", metgrid_use_below_sfc);
1613  pp.query("metgrid_use_sfc", metgrid_use_sfc);
1614  pp.query("metgrid_retain_sfc", metgrid_retain_sfc);
1615  pp.query("metgrid_proximity", metgrid_proximity);
1616  pp.query("metgrid_order", metgrid_order);
1617  pp.query("metgrid_force_sfc_k", metgrid_force_sfc_k);
1618 
1619  // Set default to FullState for now ... later we will try Perturbation
1620  interpolation_type = StateInterpType::FullState;
1621  pp.query_enum_case_insensitive("interpolation_type" ,interpolation_type);
1622 
1623  PlotFileType plotfile_type_temp = PlotFileType::None;
1624  pp.query_enum_case_insensitive("plotfile_type" ,plotfile_type_temp);
1625  pp.query_enum_case_insensitive("plotfile_type_1",plotfile_type_1);
1626  pp.query_enum_case_insensitive("plotfile_type_2",plotfile_type_2);
1627  //
1628  // This option is for backward consistency -- if only plotfile_type is set,
1629  // then it will be used for both 1 and 2 if and only if they are not set
1630  //
1631  // Default is native amrex if no type is specified
1632  //
1633  if (plotfile_type_temp == PlotFileType::None) {
1634  if (plotfile_type_1 == PlotFileType::None) {
1635  plotfile_type_1 = PlotFileType::Amrex;
1636  }
1637  if (plotfile_type_2 == PlotFileType::None) {
1638  plotfile_type_2 = PlotFileType::Amrex;
1639  }
1640  } else {
1641  if (plotfile_type_1 == PlotFileType::None) {
1642  plotfile_type_1 = plotfile_type_temp;
1643  } else {
1644  amrex::Abort("You must set either plotfile_type or plotfile_type_1, not both");
1645  }
1646  if (plotfile_type_2 == PlotFileType::None) {
1647  plotfile_type_2 = plotfile_type_temp;
1648  } else {
1649  amrex::Abort("You must set either plotfile_type or plotfile_type_2, not both");
1650  }
1651  }
1652 #ifndef ERF_USE_NETCDF
1653  if (plotfile_type_1 == PlotFileType::Netcdf ||
1654  plotfile_type_2 == PlotFileType::Netcdf) {
1655  amrex::Abort("Plotfile type = Netcdf is not allowed without USE_NETCDF = TRUE");
1656  }
1657 #endif
1658 
1659  pp.query("plot_file_1", plot_file_1);
1660  pp.query("plot_file_2", plot_file_2);
1661  pp.query("plot_int_1" , m_plot_int_1);
1662  pp.query("plot_int_2" , m_plot_int_2);
1663  pp.query("plot_per_1", m_plot_per_1);
1664  pp.query("plot_per_2", m_plot_per_2);
1665 
1666  pp.query("subvol_file", subvol_file);
1667  pp.query("subvol_int" , m_subvol_int);
1668  pp.query("subvol_per" , m_subvol_per);
1669 
1670  pp.query("expand_plotvars_to_unif_rr",m_expand_plotvars_to_unif_rr);
1671 
1672  pp.query("plot_face_vels",m_plot_face_vels);
1673 
1674  if ( (m_plot_int_1 > 0 && m_plot_per_1 > 0) ||
1675  (m_plot_int_2 > 0 && m_plot_per_2 > 0.) ) {
1676  Abort("Must choose only one of plot_int or plot_per");
1677  }
1678 
1679  pp.query("profile_int", profile_int);
1680  pp.query("destag_profiles", destag_profiles);
1681 
1682  pp.query("plot_lsm", plot_lsm);
1683 #ifdef ERF_USE_RRTMGP
1684  pp.query("plot_rad", plot_rad);
1685 #endif
1686 
1687  pp.query("output_1d_column", output_1d_column);
1688  pp.query("column_per", column_per);
1689  pp.query("column_interval", column_interval);
1690  pp.query("column_loc_x", column_loc_x);
1691  pp.query("column_loc_y", column_loc_y);
1692  pp.query("column_file_name", column_file_name);
1693 
1694  // Sampler output frequency
1695  pp.query("sampler_per", sampler_per);
1696  pp.query("sampler_interval", sampler_interval);
1697 
1698  // Specify information about outputting planes of data
1699  pp.query("output_bndry_planes", output_bndry_planes);
1700  pp.query("bndry_output_planes_interval", bndry_output_planes_interval);
1701  pp.query("bndry_output_planes_per", bndry_output_planes_per);
1702  pp.query("bndry_output_start_time", bndry_output_planes_start_time);
1703 
1704  // Specify whether ingest boundary planes of data
1705  pp.query("input_bndry_planes", input_bndry_planes);
1706 
1707  // Query the set and total widths for wrfbdy interior ghost cells
1708  pp.query("real_width", real_width);
1709  pp.query("real_set_width", real_set_width);
1710 
1711  // Query the set and total widths for crse-fine interior ghost cells
1712  pp.query("cf_width", cf_width);
1713  pp.query("cf_set_width", cf_set_width);
1714 
1715  // AmrMesh iterate on grids?
1716  bool iterate(true);
1717  pp_amr.query("iterate_grids",iterate);
1718  if (!iterate) SetIterateToFalse();
1719  }
1720 
1721 #ifdef ERF_USE_PARTICLES
1722  readTracersParams();
1723 #endif
1724 
1725  solverChoice.init_params(max_level,pp_prefix);
1726 
1727  // Query the canopy model file name
1728  std::string forestfile;
1729  solverChoice.do_forest_drag = pp.query("forest_file", forestfile);
1731  for (int lev = 0; lev <= max_level; ++lev) {
1732  m_forest_drag[lev] = std::make_unique<ForestDrag>(forestfile);
1733  }
1734  }
1735 
1736  // If init from WRFInput or Metgrid make sure a valid file name is present
1737  if ((solverChoice.init_type == InitType::WRFInput) ||
1738  (solverChoice.init_type == InitType::Metgrid) ) {
1739  for (int lev = 0; lev <= max_level; lev++) {
1740  int num_files = nc_init_file[lev].size();
1741  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(num_files>0, "A file name must be present for init type WRFInput or Metgrid.");
1742  for (int j = 0; j < num_files; j++) {
1743  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(!nc_init_file[lev][j].empty(), "Valid file name must be present for init type WRFInput or Metgrid.");
1744  } //j
1745  } // lev
1746  } // InitType
1747 
1748  // What type of land surface model to use
1749  // NOTE: Must be checked after init_params
1750  if (solverChoice.lsm_type == LandSurfaceType::SLM) {
1751  lsm.SetModel<SLM>();
1752  Print() << "SLM land surface model!\n";
1753  } else if (solverChoice.lsm_type == LandSurfaceType::MM5) {
1754  lsm.SetModel<MM5>();
1755  Print() << "MM5 land surface model!\n";
1756 #ifdef ERF_USE_NOAH
1757  } else if (solverChoice.lsm_type == LandSurfaceType::NOAH) {
1758  lsm.SetModel<NOAH>();
1759  Print() << "NOAH land surface model!\n";
1760 #endif
1761  } else if (solverChoice.lsm_type == LandSurfaceType::None) {
1762  lsm.SetModel<NullSurf>();
1763  Print() << "Null land surface model!\n";
1764  } else {
1765  Abort("Dont know this LandSurfaceType!") ;
1766  }
1767 
1768  if (verbose > 0) {
1769  solverChoice.display(max_level,pp_prefix);
1770  }
1771 
1773 }
AMREX_FORCE_INLINE std::time_t getEpochTime(const std::string &dateTime, const std::string &dateTimeFormat)
Definition: ERF_EpochTime.H:14
bool metgrid_basic_linear
Definition: ERF.H:1092
amrex::Vector< amrex::Vector< amrex::Box > > boxes_at_level
Definition: ERF.H:713
bool metgrid_debug_msf
Definition: ERF.H:1090
std::string plot_file_2
Definition: ERF.H:951
std::string restart_type
Definition: ERF.H:971
bool m_plot_face_vels
Definition: ERF.H:960
int regrid_int
Definition: ERF.H:943
bool metgrid_retain_sfc
Definition: ERF.H:1095
bool metgrid_use_sfc
Definition: ERF.H:1094
amrex::Vector< int > num_files_at_level
Definition: ERF.H:712
bool metgrid_debug_quiescent
Definition: ERF.H:1086
static std::string nc_bdy_file
Definition: ERF.H:1077
bool metgrid_interp_theta
Definition: ERF.H:1091
static amrex::Vector< amrex::Vector< std::string > > nc_init_file
Definition: ERF.H:1074
bool regrid_level_0_on_restart
Definition: ERF.H:947
int metgrid_force_sfc_k
Definition: ERF.H:1098
bool metgrid_use_below_sfc
Definition: ERF.H:1093
std::string subvol_file
Definition: ERF.H:952
amrex::Real metgrid_proximity
Definition: ERF.H:1096
std::string plot_file_1
Definition: ERF.H:950
bool metgrid_debug_dry
Definition: ERF.H:1088
bool metgrid_debug_isothermal
Definition: ERF.H:1087
bool metgrid_debug_psfc
Definition: ERF.H:1089
void ParameterSanityChecks()
Definition: ERF.cpp:1777
bool m_expand_plotvars_to_unif_rr
Definition: ERF.H:953
amrex::Vector< int > num_boxes_at_level
Definition: ERF.H:711
std::string check_file
Definition: ERF.H:969
int metgrid_order
Definition: ERF.H:1097
bool plot_lsm
Definition: ERF.H:962
void SetModel()
Definition: ERF_LandSurface.H:28
Definition: ERF_MM5.H:26
Definition: ERF_NOAH.H:30
Definition: ERF_NullSurf.H:8
Definition: ERF_SLM.H:26
void display(int max_level, std::string pp_prefix)
Definition: ERF_DataStruct.H:507
void init_params(int max_level, std::string pp_prefix)
Definition: ERF_DataStruct.H:88
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

151 {
152  if (max_level > 0)
153  {
154  ParmParse pp(pp_prefix);
155  Vector<std::string> refinement_indicators;
156  pp.queryarr("refinement_indicators",refinement_indicators,0,pp.countval("refinement_indicators"));
157 
158  for (int i=0; i<refinement_indicators.size(); ++i)
159  {
160  std::string ref_prefix = pp_prefix + "." + refinement_indicators[i];
161 
162  ParmParse ppr(ref_prefix);
163  RealBox realbox;
164  int lev_for_box;
165 
166  int num_real_lo = ppr.countval("in_box_lo");
167  int num_indx_lo = ppr.countval("in_box_lo_indices");
168  int num_real_hi = ppr.countval("in_box_hi");
169  int num_indx_hi = ppr.countval("in_box_hi_indices");
170 
171  AMREX_ALWAYS_ASSERT(num_real_lo == num_real_hi);
172  AMREX_ALWAYS_ASSERT(num_indx_lo == num_indx_hi);
173 
174  if ( !((num_real_lo >= AMREX_SPACEDIM-1 && num_indx_lo == 0) ||
175  (num_indx_lo >= AMREX_SPACEDIM-1 && num_real_lo == 0) ||
176  (num_indx_lo == 0 && num_real_lo == 0)) )
177  {
178  amrex::Abort("Must only specify box for refinement using real OR index space");
179  }
180 
181  if (num_real_lo > 0) {
182  std::vector<Real> rbox_lo(3), rbox_hi(3);
183  ppr.get("max_level",lev_for_box);
184  if (lev_for_box <= max_level)
185  {
186  if (n_error_buf[0] != IntVect::TheZeroVector()) {
187  amrex::Abort("Don't use n_error_buf > 0 when setting the box explicitly");
188  }
189 
190  const Real* plo = geom[lev_for_box].ProbLo();
191  const Real* phi = geom[lev_for_box].ProbHi();
192 
193  ppr.getarr("in_box_lo",rbox_lo,0,num_real_lo);
194  ppr.getarr("in_box_hi",rbox_hi,0,num_real_hi);
195 
196  if (rbox_lo[0] < plo[0]) rbox_lo[0] = plo[0];
197  if (rbox_lo[1] < plo[1]) rbox_lo[1] = plo[1];
198  if (rbox_hi[0] > phi[0]) rbox_hi[0] = phi[0];
199  if (rbox_hi[1] > phi[1]) rbox_hi[1] = phi[1];
200  if (num_real_lo < AMREX_SPACEDIM) {
201  rbox_lo[2] = plo[2];
202  rbox_hi[2] = phi[2];
203  }
204 
205  realbox = RealBox(&(rbox_lo[0]),&(rbox_hi[0]));
206 
207  Print() << "Realbox read in and intersected laterally with domain is " << realbox << std::endl;
208 
209  num_boxes_at_level[lev_for_box] += 1;
210 
211  int ilo, jlo, klo;
212  int ihi, jhi, khi;
213  const auto* dx = geom[lev_for_box].CellSize();
214  ilo = static_cast<int>((rbox_lo[0] - plo[0])/dx[0]);
215  jlo = static_cast<int>((rbox_lo[1] - plo[1])/dx[1]);
216  ihi = static_cast<int>((rbox_hi[0] - plo[0])/dx[0]-1);
217  jhi = static_cast<int>((rbox_hi[1] - plo[1])/dx[1]-1);
218  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
219  // Search for k indices corresponding to nominal grid
220  // AGL heights
221  const Box& domain = geom[lev_for_box].Domain();
222  klo = domain.smallEnd(2) - 1;
223  khi = domain.smallEnd(2) - 1;
224 
225  if (rbox_lo[2] <= zlevels_stag[lev_for_box][domain.smallEnd(2)])
226  {
227  klo = domain.smallEnd(2);
228  }
229  else
230  {
231  for (int k=domain.smallEnd(2); k<=domain.bigEnd(2)+1; ++k) {
232  if (zlevels_stag[lev_for_box][k] > rbox_lo[2]) {
233  klo = k-1;
234  break;
235  }
236  }
237  }
238  AMREX_ASSERT(klo >= domain.smallEnd(2));
239 
240  if (rbox_hi[2] >= zlevels_stag[lev_for_box][domain.bigEnd(2)+1])
241  {
242  khi = domain.bigEnd(2);
243  }
244  else
245  {
246  for (int k=klo+1; k<=domain.bigEnd(2)+1; ++k) {
247  if (zlevels_stag[lev_for_box][k] > rbox_hi[2]) {
248  khi = k-1;
249  break;
250  }
251  }
252  }
253  AMREX_ASSERT((khi <= domain.bigEnd(2)) && (khi > klo));
254 
255  // Need to update realbox because tagging is based on
256  // the initial _un_deformed grid
257  realbox = RealBox(plo[0]+ ilo *dx[0], plo[1]+ jlo *dx[1], plo[2]+ klo *dx[2],
258  plo[0]+(ihi+1)*dx[0], plo[1]+(jhi+1)*dx[1], plo[2]+(khi+1)*dx[2]);
259  } else {
260  klo = static_cast<int>((rbox_lo[2] - plo[2])/dx[2]);
261  khi = static_cast<int>((rbox_hi[2] - plo[2])/dx[2]-1);
262  }
263 
264  Box bx(IntVect(ilo,jlo,klo),IntVect(ihi,jhi,khi));
265  if ( (ilo%ref_ratio[lev_for_box-1][0] != 0) || ((ihi+1)%ref_ratio[lev_for_box-1][0] != 0) ||
266  (jlo%ref_ratio[lev_for_box-1][1] != 0) || ((jhi+1)%ref_ratio[lev_for_box-1][1] != 0) ||
267  (klo%ref_ratio[lev_for_box-1][2] != 0) || ((khi+1)%ref_ratio[lev_for_box-1][2] != 0) )
268  {
269  amrex::Print() << "Box : " << bx << std::endl;
270  amrex::Print() << "RealBox : " << realbox << std::endl;
271  amrex::Print() << "ilo, ihi+1, jlo, jhi+1, klo, khi+1 by ref_ratio : "
272  << ilo%ref_ratio[lev_for_box-1][0] << " " << (ihi+1)%ref_ratio[lev_for_box-1][0] << " "
273  << jlo%ref_ratio[lev_for_box-1][1] << " " << (jhi+1)%ref_ratio[lev_for_box-1][1] << " "
274  << klo%ref_ratio[lev_for_box-1][2] << " " << (khi+1)%ref_ratio[lev_for_box-1][2] << std::endl;
275  amrex::Error("Fine box is not legit with this ref_ratio");
276  }
277  boxes_at_level[lev_for_box].push_back(bx);
278  Print() << "Saving in 'boxes at level' as " << bx << std::endl;
279  } // lev
280  if (solverChoice.init_type == InitType::WRFInput) {
281  if (num_boxes_at_level[lev_for_box] != num_files_at_level[lev_for_box]) {
282  amrex::Error("Number of boxes doesn't match number of input files");
283 
284  }
285  }
286 
287  } else if (num_indx_lo > 0) {
288 
289  std::vector<int> box_lo(3), box_hi(3);
290  ppr.get("max_level",lev_for_box);
291  if (lev_for_box <= max_level)
292  {
293  if (n_error_buf[0] != IntVect::TheZeroVector()) {
294  amrex::Abort("Don't use n_error_buf > 0 when setting the box explicitly");
295  }
296 
297  ppr.getarr("in_box_lo_indices",box_lo,0,AMREX_SPACEDIM);
298  ppr.getarr("in_box_hi_indices",box_hi,0,AMREX_SPACEDIM);
299 
300  Box bx(IntVect(box_lo[0],box_lo[1],box_lo[2]),IntVect(box_hi[0],box_hi[1],box_hi[2]));
301  amrex::Print() << "BOX " << bx << std::endl;
302 
303  const auto* dx = geom[lev_for_box].CellSize();
304  const Real* plo = geom[lev_for_box].ProbLo();
305  realbox = RealBox(plo[0]+ box_lo[0] *dx[0], plo[1]+ box_lo[1] *dx[1], plo[2]+ box_lo[2] *dx[2],
306  plo[0]+(box_hi[0]+1)*dx[0], plo[1]+(box_hi[1]+1)*dx[1], plo[2]+(box_hi[2]+1)*dx[2]);
307 
308  Print() << "Reading " << bx << " at level " << lev_for_box << std::endl;
309  num_boxes_at_level[lev_for_box] += 1;
310 
311  if ( (box_lo[0]%ref_ratio[lev_for_box-1][0] != 0) || ((box_hi[0]+1)%ref_ratio[lev_for_box-1][0] != 0) ||
312  (box_lo[1]%ref_ratio[lev_for_box-1][1] != 0) || ((box_hi[1]+1)%ref_ratio[lev_for_box-1][1] != 0) ||
313  (box_lo[2]%ref_ratio[lev_for_box-1][2] != 0) || ((box_hi[2]+1)%ref_ratio[lev_for_box-1][2] != 0) )
314  amrex::Error("Fine box is not legit with this ref_ratio");
315  boxes_at_level[lev_for_box].push_back(bx);
316  Print() << "Saving in 'boxes at level' as " << bx << std::endl;
317  } // lev
318  if (solverChoice.init_type == InitType::WRFInput) {
319  if (num_boxes_at_level[lev_for_box] != num_files_at_level[lev_for_box]) {
320  amrex::Error("Number of boxes doesn't match number of input files");
321 
322  }
323  }
324  }
325 
326  AMRErrorTagInfo info;
327 
328  if (realbox.ok()) {
329  info.SetRealBox(realbox);
330  }
331  if (ppr.countval("start_time") > 0) {
332  Real ref_min_time; ppr.get("start_time",ref_min_time);
333  info.SetMinTime(ref_min_time);
334  }
335  if (ppr.countval("end_time") > 0) {
336  Real ref_max_time; ppr.get("end_time",ref_max_time);
337  info.SetMaxTime(ref_max_time);
338  }
339  if (ppr.countval("max_level") > 0) {
340  int ref_max_level; ppr.get("max_level",ref_max_level);
341  info.SetMaxLevel(ref_max_level);
342  }
343 
344  if (ppr.countval("value_greater")) {
345  int num_val = ppr.countval("value_greater");
346  Vector<Real> value(num_val);
347  ppr.getarr("value_greater",value,0,num_val);
348  std::string field; ppr.get("field_name",field);
349  ref_tags.push_back(AMRErrorTag(value,AMRErrorTag::GREATER,field,info));
350  }
351  else if (ppr.countval("value_less")) {
352  int num_val = ppr.countval("value_less");
353  Vector<Real> value(num_val);
354  ppr.getarr("value_less",value,0,num_val);
355  std::string field; ppr.get("field_name",field);
356  ref_tags.push_back(AMRErrorTag(value,AMRErrorTag::LESS,field,info));
357  }
358  else if (ppr.countval("adjacent_difference_greater")) {
359  int num_val = ppr.countval("adjacent_difference_greater");
360  Vector<Real> value(num_val);
361  ppr.getarr("adjacent_difference_greater",value,0,num_val);
362  std::string field; ppr.get("field_name",field);
363  ref_tags.push_back(AMRErrorTag(value,AMRErrorTag::GRAD,field,info));
364  }
365  else if (realbox.ok())
366  {
367  ref_tags.push_back(AMRErrorTag(info));
368  } else {
369  Abort(std::string("Unrecognized refinement indicator for " + refinement_indicators[i]).c_str());
370  }
371  } // loop over criteria
372  } // if max_level > 0
373 }
Here is the call graph for this function:

◆ remake_zphys()

void ERF::remake_zphys ( int  lev,
amrex::Real  time,
std::unique_ptr< amrex::MultiFab > &  temp_zphys_nd 
)
538 {
539  if (lev > 0)
540  {
541  //
542  // First interpolate from coarser level
543  // NOTE: this interpolater assumes that ALL ghost cells of the coarse MultiFab
544  // have been pre-filled - this includes ghost cells both inside and outside
545  // the domain
546  //
547  InterpFromCoarseLevel(*temp_zphys_nd, z_phys_nd[lev]->nGrowVect(),
548  IntVect(0,0,0), // do not fill ghost cells outside the domain
549  *z_phys_nd[lev-1], 0, 0, 1,
550  geom[lev-1], geom[lev],
551  refRatio(lev-1), &node_bilinear_interp,
553 
554  // This recomputes the fine values using the bottom terrain at the fine resolution,
555  // and also fills values of z_phys_nd outside the domain
556  make_terrain_fitted_coords(lev,geom[lev],*temp_zphys_nd,zlevels_stag[lev],phys_bc_type);
557 
558  std::swap(temp_zphys_nd, z_phys_nd[lev]);
559 
560  } // lev > 0
561 
562  if (solverChoice.terrain_type == TerrainType::ImmersedForcing) {
563  //
564  // This assumes we have already remade the EBGeometry
565  //
566  terrain_blanking[lev]->setVal(1.0);
567  MultiFab::Subtract(*terrain_blanking[lev], EBFactory(lev).getVolFrac(), 0, 0, 1, z_phys_nd[lev]->nGrowVect());
568  }
569 }
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
351 {
352  if (verbose) {
353  amrex::Print() <<" REMAKING WITH NEW BA AT LEVEL " << lev << " " << ba << std::endl;
354  }
355 
356  AMREX_ALWAYS_ASSERT(solverChoice.terrain_type != TerrainType::MovingFittedMesh);
357 
358  BoxArray ba_old(vars_new[lev][Vars::cons].boxArray());
359  DistributionMapping dm_old(vars_new[lev][Vars::cons].DistributionMap());
360 
361  if (verbose) {
362  amrex::Print() <<" OLD BA AT LEVEL " << lev << " " << ba_old << std::endl;
363  }
364 
365  int ncomp_cons = vars_new[lev][Vars::cons].nComp();
366  IntVect ngrow_state = vars_new[lev][Vars::cons].nGrowVect();
367 
369 
370  Vector<MultiFab> temp_lev_new(Vars::NumTypes);
371  Vector<MultiFab> temp_lev_old(Vars::NumTypes);
372  MultiFab temp_base_state;
373 
374  std::unique_ptr<MultiFab> temp_zphys_nd;
375 
376  //********************************************************************************************
377  // This allocates all kinds of things, including but not limited to: solution arrays,
378  // terrain arrays and metrics, and base state.
379  // *******************************************************************************************
380  init_stuff(lev, ba, dm, temp_lev_new, temp_lev_old, temp_base_state, temp_zphys_nd);
381 
382  // ********************************************************************************************
383  // Build the data structures for terrain-related quantities
384  // ********************************************************************************************
385  remake_zphys(lev, time, temp_zphys_nd);
387 
388  //
389  // Make sure that detJ and z_phys_cc are the average of the data on a finer level if there is one
390  //
391  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
392  for (int crse_lev = lev-1; crse_lev >= 0; crse_lev--) {
393  average_down( *detJ_cc[crse_lev+1], *detJ_cc[crse_lev], 0, 1, refRatio(crse_lev));
394  average_down(*z_phys_cc[crse_lev+1], *z_phys_cc[crse_lev], 0, 1, refRatio(crse_lev));
395  }
396  }
397 
398  // ********************************************************************************************
399  // Build the data structures for canopy model (depends upon z_phys)
400  // ********************************************************************************************
402  m_forest_drag[lev]->define_drag_field(ba, dm, geom[lev], z_phys_cc[lev].get(), z_phys_nd[lev].get());
403  }
404 
405  // *****************************************************************************************************
406  // Create the physbcs objects (after initializing the terrain but before calling FillCoarsePatch
407  // *****************************************************************************************************
408  make_physbcs(lev);
409 
410  // ********************************************************************************************
411  // Update the base state at this level by interpolation from coarser level AND copy
412  // from previous (pre-regrid) base_state array
413  // ********************************************************************************************
414  if (lev > 0) {
415  Interpolater* mapper = &cell_cons_interp;
416 
417  Vector<MultiFab*> fmf = {&base_state[lev ], &base_state[lev ]};
418  Vector<MultiFab*> cmf = {&base_state[lev-1], &base_state[lev-1]};
419  Vector<Real> ftime = {time, time};
420  Vector<Real> ctime = {time, time};
421 
422  // Call FillPatch which ASSUMES that all ghost cells at lev-1 have already been filled
423  FillPatchTwoLevels(temp_base_state, temp_base_state.nGrowVect(), IntVect(0,0,0),
424  time, cmf, ctime, fmf, ftime,
425  0, 0, temp_base_state.nComp(), geom[lev-1], geom[lev],
426  refRatio(lev-1), mapper, domain_bcs_type,
428 
429  // Impose bc's outside the domain
430  (*physbcs_base[lev])(temp_base_state,0,temp_base_state.nComp(),base_state[lev].nGrowVect());
431 
432  // *************************************************************************************************
433  // This will fill the temporary MultiFabs with data from vars_new
434  // NOTE: the momenta here are only used as scratch space, the momenta themselves are not fillpatched
435  // NOTE: we must create the new base state before calling FillPatch because we will
436  // interpolate perturbational quantities
437  // *************************************************************************************************
438  FillPatch(lev, time, {&temp_lev_new[Vars::cons],&temp_lev_new[Vars::xvel],
439  &temp_lev_new[Vars::yvel],&temp_lev_new[Vars::zvel]},
440  {&temp_lev_new[Vars::cons],&rU_new[lev],&rV_new[lev],&rW_new[lev]},
441  base_state[lev], temp_base_state, false);
442  } else {
443  temp_base_state.ParallelCopy(base_state[lev],0,0,base_state[lev].nComp(),
444  base_state[lev].nGrowVect(),base_state[lev].nGrowVect());
445  temp_lev_new[Vars::cons].ParallelCopy(vars_new[lev][Vars::cons],0,0,ncomp_cons,ngrow_state,ngrow_state);
446  temp_lev_new[Vars::xvel].ParallelCopy(vars_new[lev][Vars::xvel],0,0, 1,ngrow_vels,ngrow_vels);
447  temp_lev_new[Vars::yvel].ParallelCopy(vars_new[lev][Vars::yvel],0,0, 1,ngrow_vels,ngrow_vels);
448 
449  temp_lev_new[Vars::zvel].setVal(0.);
450  temp_lev_new[Vars::zvel].ParallelCopy(vars_new[lev][Vars::zvel],0,0, 1,
451  IntVect(ngrow_vels,ngrow_vels,0),IntVect(ngrow_vels,ngrow_vels,0));
452  }
453 
454  // Now swap the pointers since we needed both old and new in the FillPatch
455  std::swap(temp_base_state, base_state[lev]);
456 
457  // ********************************************************************************************
458  // Copy from new into old just in case
459  // ********************************************************************************************
460  MultiFab::Copy(temp_lev_old[Vars::cons],temp_lev_new[Vars::cons],0,0,ncomp_cons,ngrow_state);
461  MultiFab::Copy(temp_lev_old[Vars::xvel],temp_lev_new[Vars::xvel],0,0, 1,ngrow_vels);
462  MultiFab::Copy(temp_lev_old[Vars::yvel],temp_lev_new[Vars::yvel],0,0, 1,ngrow_vels);
463  MultiFab::Copy(temp_lev_old[Vars::zvel],temp_lev_new[Vars::zvel],0,0, 1,IntVect(ngrow_vels,ngrow_vels,0));
464 
465  // ********************************************************************************************
466  // Now swap the pointers
467  // ********************************************************************************************
468  for (int var_idx = 0; var_idx < Vars::NumTypes; ++var_idx) {
469  std::swap(temp_lev_new[var_idx], vars_new[lev][var_idx]);
470  std::swap(temp_lev_old[var_idx], vars_old[lev][var_idx]);
471  }
472 
473  t_new[lev] = time;
474  t_old[lev] = time - 1.e200;
475 
476  // ********************************************************************************************
477  // Build the data structures for calculating diffusive/turbulent terms
478  // ********************************************************************************************
479  update_diffusive_arrays(lev, ba, dm);
480 
481  //********************************************************************************************
482  // Microphysics
483  // *******************************************************************************************
484  int q_size = micro->Get_Qmoist_Size(lev);
485  qmoist[lev].resize(q_size);
486  micro->Define(lev, solverChoice);
487  if (solverChoice.moisture_type != MoistureType::None)
488  {
489  micro->Init(lev, vars_new[lev][Vars::cons],
490  grids[lev], Geom(lev), 0.0,
491  z_phys_nd[lev], detJ_cc[lev]); // dummy dt value
492  }
493  for (int mvar(0); mvar<qmoist[lev].size(); ++mvar) {
494  qmoist[lev][mvar] = micro->Get_Qmoist_Ptr(lev,mvar);
495  }
496 
497  // ********************************************************************************************
498  // Initialize the integrator class
499  // ********************************************************************************************
501 
502  // We need to re-define the FillPatcher if the grids have changed
503  if (lev > 0 && cf_width >= 0) {
504  bool ba_changed = (ba != ba_old);
505  bool dm_changed = (dm != dm_old);
506  if (ba_changed || dm_changed) {
508  }
509  }
510 
511  // ********************************************************************************************
512  // Update the MOST arrays at this level
513  // ********************************************************************************************
514  if (phys_bc_type[Orientation(Direction::z,Orientation::low)] == ERF_BC::MOST) {
515  int nlevs = finest_level+1;
516  Vector<MultiFab*> mfv_old = {&vars_old[lev][Vars::cons], &vars_old[lev][Vars::xvel],
517  &vars_old[lev][Vars::yvel], &vars_old[lev][Vars::zvel]};
518  m_most->make_MOST_at_level(lev,nlevs,
519  mfv_old, Theta_prim[lev], Qv_prim[lev],
520  Qr_prim[lev], z_phys_nd[lev],
521  Hwave[lev].get(),Lwave[lev].get(),eddyDiffs_lev[lev].get(),
522  lsm_data[lev], lsm_flux[lev], sst_lev[lev], lmask_lev[lev]);
523  }
524 
525  // These calls are done in AmrCore::regrid if this is a regrid at lev > 0
526  // For a level 0 regrid we must explicitly do them here
527  if (lev == 0) {
528  // Define grids[lev] to be ba
529  SetBoxArray(lev, ba);
530 
531  // Define dmap[lev] to be dm
532  SetDistributionMap(lev, dm);
533  }
534 
535 #ifdef ERF_USE_PARTICLES
536  particleData.Redistribute();
537 #endif
538 }
void remake_zphys(int lev, amrex::Real time, std::unique_ptr< amrex::MultiFab > &temp_zphys_nd)
Definition: ERF_MakeNewArrays.cpp:537

◆ restart()

void ERF::restart ( )
1324 {
1325 #ifdef ERF_USE_NETCDF
1326  if (restart_type == "netcdf") {
1327  ReadNCCheckpointFile();
1328  }
1329 #endif
1330  if (restart_type == "native") {
1332  }
1333 
1334  // We set this here so that we don't over-write the checkpoint file we just started from
1336 
1338  //
1339  // Coarsening before we split the grids ensures that each resulting
1340  // grid will have an even number of cells in each direction.
1341  //
1342  BoxArray new_ba(amrex::coarsen(Geom(0).Domain(),2));
1343  //
1344  // Now split up into list of grids within max_grid_size[0] limit.
1345  //
1346  new_ba.maxSize(max_grid_size[0]/2);
1347  //
1348  // Now refine these boxes back to level 0.
1349  //
1350  new_ba.refine(2);
1351 
1352  if (refine_grid_layout) {
1353  ChopGrids(0, new_ba, ParallelDescriptor::NProcs());
1354  }
1355 
1356  if (new_ba != grids[0]) {
1357  DistributionMapping new_dm(new_ba);
1358  RemakeLevel(0,t_new[0],new_ba,new_dm);
1359  }
1360  }
1361 }
void RemakeLevel(int lev, amrex::Real time, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm) override
Definition: ERF_MakeNewLevel.cpp:350
void ReadCheckpointFile()
Definition: ERF_Checkpoint.cpp:308

◆ 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
363 {
364  int ifile = 0;
365 
366  const int ncomp = mf.nComp(); // cell-centered state vars
367 
368  MultiFab mf_vels(grids[lev], dmap[lev], AMREX_SPACEDIM, 0);
369  average_face_to_cellcenter(mf_vels, 0,
370  Array<const MultiFab*,3>{&vars_new[lev][Vars::xvel],&vars_new[lev][Vars::yvel],&vars_new[lev][Vars::zvel]});
371 
372  //
373  // Sample the data at a line (in direction "dir") in space
374  // In this case we sample in the vertical direction so dir = 2
375  // The "k" value of "cell" is ignored
376  //
377  int dir = 2;
378  MultiFab my_line = get_line_data(mf, dir, cell);
379  MultiFab my_line_vels = get_line_data(mf_vels, dir, cell);
380  MultiFab my_line_tau11 = get_line_data(*Tau11_lev[lev], dir, cell);
381  MultiFab my_line_tau12 = get_line_data(*Tau12_lev[lev], dir, cell);
382  MultiFab my_line_tau13 = get_line_data(*Tau13_lev[lev], dir, cell);
383  MultiFab my_line_tau22 = get_line_data(*Tau22_lev[lev], dir, cell);
384  MultiFab my_line_tau23 = get_line_data(*Tau23_lev[lev], dir, cell);
385  MultiFab my_line_tau33 = get_line_data(*Tau33_lev[lev], dir, cell);
386 
387  for (MFIter mfi(my_line, false); mfi.isValid(); ++mfi)
388  {
389  // HERE DO WHATEVER YOU WANT TO THE DATA BEFORE WRITING
390 
391  std::ostream& sample_log = SampleLineLog(ifile);
392  if (sample_log.good()) {
393  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << time;
394  const auto& my_line_arr = my_line[0].const_array();
395  const auto& my_line_vels_arr = my_line_vels[0].const_array();
396  const auto& my_line_tau11_arr = my_line_tau11[0].const_array();
397  const auto& my_line_tau12_arr = my_line_tau12[0].const_array();
398  const auto& my_line_tau13_arr = my_line_tau13[0].const_array();
399  const auto& my_line_tau22_arr = my_line_tau22[0].const_array();
400  const auto& my_line_tau23_arr = my_line_tau23[0].const_array();
401  const auto& my_line_tau33_arr = my_line_tau33[0].const_array();
402  const Box& my_box = my_line[0].box();
403  const int klo = my_box.smallEnd(2);
404  const int khi = my_box.bigEnd(2);
405  int i = cell[0];
406  int j = cell[1];
407  for (int n = 0; n < ncomp; n++) {
408  for (int k = klo; k <= khi; k++) {
409  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << my_line_arr(i,j,k,n);
410  }
411  }
412  for (int n = 0; n < AMREX_SPACEDIM; n++) {
413  for (int k = klo; k <= khi; k++) {
414  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << my_line_vels_arr(i,j,k,n);
415  }
416  }
417  for (int k = klo; k <= khi; k++) {
418  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << my_line_tau11_arr(i,j,k);
419  }
420  for (int k = klo; k <= khi; k++) {
421  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << my_line_tau12_arr(i,j,k);
422  }
423  for (int k = klo; k <= khi; k++) {
424  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << my_line_tau13_arr(i,j,k);
425  }
426  for (int k = klo; k <= khi; k++) {
427  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << my_line_tau22_arr(i,j,k);
428  }
429  for (int k = klo; k <= khi; k++) {
430  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << my_line_tau23_arr(i,j,k);
431  }
432  for (int k = klo; k <= khi; k++) {
433  sample_log << std::setw(datwidth) << std::setprecision(datprecision) << my_line_tau33_arr(i,j,k);
434  }
435  sample_log << std::endl;
436  } // if good
437  } // mfi
438 }
const int datwidth
Definition: ERF.H:909
AMREX_FORCE_INLINE std::ostream & SampleLineLog(int i)
Definition: ERF.H:1289
const int datprecision
Definition: ERF.H:910

◆ 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
327 {
328  int ifile = 0;
329 
330  //
331  // Sample the data at a single point in space
332  //
333  int ncomp = mf.nComp();
334  Vector<Real> my_point = get_cell_data(mf, cell);
335 
336  if (!my_point.empty()) {
337 
338  // HERE DO WHATEVER YOU WANT TO THE DATA BEFORE WRITING
339 
340  std::ostream& sample_log = SamplePointLog(ifile);
341  if (sample_log.good()) {
342  sample_log << std::setw(datwidth) << time;
343  for (int i = 0; i < ncomp; ++i)
344  {
345  sample_log << std::setw(datwidth) << my_point[i];
346  }
347  sample_log << std::endl;
348  } // if good
349  } // only write from processor that holds the cell
350 }
AMREX_FORCE_INLINE std::ostream & SamplePointLog(int i)
Definition: ERF.H:1275

◆ SampleLine()

amrex::IntVect& ERF::SampleLine ( int  i)
inlineprivate
1316  {
1317  return sampleline[i];
1318  }

◆ SampleLineLog()

AMREX_FORCE_INLINE std::ostream& ERF::SampleLineLog ( int  i)
inlineprivate
1290  {
1291  return *samplelinelog[i];
1292  }

◆ SampleLineLogName()

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

The filename of the ith samplelinelog file.

1431 { return samplelinelogname[i]; }

◆ SamplePoint()

amrex::IntVect& ERF::SamplePoint ( int  i)
inlineprivate
1303  {
1304  return samplepoint[i];
1305  }

◆ SamplePointLog()

AMREX_FORCE_INLINE std::ostream& ERF::SamplePointLog ( int  i)
inlineprivate
1276  {
1277  return *sampleptlog[i];
1278  }

◆ SamplePointLogName()

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

The filename of the ith sampleptlog file.

1428 { return sampleptlogname[i]; }

◆ setPlotVariables()

void ERF::setPlotVariables ( const std::string &  pp_plot_var_names,
amrex::Vector< std::string > &  plot_var_names 
)
private
14 {
15  ParmParse pp(pp_prefix);
16 
17  if (pp.contains(pp_plot_var_names.c_str()))
18  {
19  std::string nm;
20 
21  int nPltVars = pp.countval(pp_plot_var_names.c_str());
22 
23  for (int i = 0; i < nPltVars; i++)
24  {
25  pp.get(pp_plot_var_names.c_str(), nm, i);
26 
27  // Add the named variable to our list of plot variables
28  // if it is not already in the list
29  if (!containerHasElement(plot_var_names, nm)) {
30  plot_var_names.push_back(nm);
31  }
32  }
33  } else {
34  //
35  // The default is to add none of the variables to the list
36  //
37  plot_var_names.clear();
38  }
39 
40  // Get state variables in the same order as we define them,
41  // since they may be in any order in the input list
42  Vector<std::string> tmp_plot_names;
43 
44  for (int i = 0; i < cons_names.size(); ++i) {
45  if ( containerHasElement(plot_var_names, cons_names[i]) ) {
46  if (solverChoice.moisture_type == MoistureType::None) {
47  if (cons_names[i] != "rhoQ1" && cons_names[i] != "rhoQ2" && cons_names[i] != "rhoQ3" &&
48  cons_names[i] != "rhoQ4" && cons_names[i] != "rhoQ5" && cons_names[i] != "rhoQ6")
49  {
50  tmp_plot_names.push_back(cons_names[i]);
51  }
52  } else if (solverChoice.moisture_type == MoistureType::Kessler) { // allow rhoQ1, rhoQ2, rhoQ3
53  if (cons_names[i] != "rhoQ4" && cons_names[i] != "rhoQ5" && cons_names[i] != "rhoQ6")
54  {
55  tmp_plot_names.push_back(cons_names[i]);
56  }
57  } else if ( (solverChoice.moisture_type == MoistureType::SatAdj) ||
58  (solverChoice.moisture_type == MoistureType::SAM_NoPrecip_NoIce) ||
59  (solverChoice.moisture_type == MoistureType::Kessler_NoRain) ) { // allow rhoQ1, rhoQ2
60  if (cons_names[i] != "rhoQ3" && cons_names[i] != "rhoQ4" &&
61  cons_names[i] != "rhoQ5" && cons_names[i] != "rhoQ6")
62  {
63  tmp_plot_names.push_back(cons_names[i]);
64  }
65  } else if (solverChoice.moisture_type == MoistureType::SAM_NoIce) { // allow rhoQ1, rhoQ2, rhoQ4
66  if (cons_names[i] != "rhoQ3" && cons_names[i] != "rhoQ5" && cons_names[i] != "rhoQ6")
67  {
68  tmp_plot_names.push_back(cons_names[i]);
69  }
70  } else
71  {
72  // For moisture_type SAM and Morrison we have all six variables
73  tmp_plot_names.push_back(cons_names[i]);
74  }
75  }
76  }
77 
78  // check for velocity since it's not in cons_names
79  // if we are asked for any velocity component, we will need them all
80  if (containerHasElement(plot_var_names, "x_velocity") ||
81  containerHasElement(plot_var_names, "y_velocity") ||
82  containerHasElement(plot_var_names, "z_velocity")) {
83  tmp_plot_names.push_back("x_velocity");
84  tmp_plot_names.push_back("y_velocity");
85  tmp_plot_names.push_back("z_velocity");
86  }
87 
88  //
89  // If the model we are running doesn't have the variable listed in the inputs file,
90  // just ignore it rather than aborting
91  //
92  for (int i = 0; i < derived_names.size(); ++i) {
93  if ( containerHasElement(plot_var_names, derived_names[i]) ) {
94  if ( ( (SolverChoice::terrain_type == TerrainType::StaticFittedMesh) ||
95  (SolverChoice::terrain_type == TerrainType::MovingFittedMesh) ||
96  (derived_names[i] != "z_phys" && derived_names[i] != "detJ") )
97 #ifndef ERF_USE_WINDFARM
98  && (derived_names[i] != "SMark0" && derived_names[i] != "SMark1") )
99 #else
100  )
101 #endif
102  {
103  if (solverChoice.moisture_type == MoistureType::None) { // no moist quantities allowed
104  if (derived_names[i] != "qv" && derived_names[i] != "qc" && derived_names[i] != "qrain" &&
105  derived_names[i] != "qi" && derived_names[i] != "qsnow" && derived_names[i] != "qgraup" &&
106  derived_names[i] != "rain_accum" && derived_names[i] != "snow_accum" && derived_names[i] != "graup_accum")
107  {
108  tmp_plot_names.push_back(derived_names[i]);
109  }
110  } else if ( (solverChoice.moisture_type == MoistureType::Kessler) ||
111  (solverChoice.moisture_type == MoistureType::SAM_NoIce) ) { // allow qv, qc, qrain
112  if (derived_names[i] != "qi" && derived_names[i] != "qsnow" && derived_names[i] != "qgraup" &&
113  derived_names[i] != "snow_accum" && derived_names[i] != "graup_accum")
114  {
115  tmp_plot_names.push_back(derived_names[i]);
116  }
117  } else if ( (solverChoice.moisture_type == MoistureType::SatAdj) ||
118  (solverChoice.moisture_type == MoistureType::SAM_NoPrecip_NoIce) ||
119  (solverChoice.moisture_type == MoistureType::Kessler_NoRain) ) { // allow qv, qc
120  if (derived_names[i] != "qrain" &&
121  derived_names[i] != "qi" && derived_names[i] != "qsnow" && derived_names[i] != "qgraup" &&
122  derived_names[i] != "rain_accum" && derived_names[i] != "snow_accum" && derived_names[i] != "graup_accum")
123  {
124  tmp_plot_names.push_back(derived_names[i]);
125  }
126  } else
127  {
128  // For moisture_type SAM and Morrison we have all moist quantities
129  tmp_plot_names.push_back(derived_names[i]);
130  }
131  } // use_terrain?
132  } // hasElement
133  }
134 
135 #ifdef ERF_USE_WINDFARM
136  for (int i = 0; i < derived_names.size(); ++i) {
137  if ( containerHasElement(plot_var_names, derived_names[i]) ) {
138  if(solverChoice.windfarm_type == WindFarmType::Fitch or solverChoice.windfarm_type == WindFarmType::EWP) {
139  if(derived_names[i] == "num_turb" or derived_names[i] == "SMark0") {
140  tmp_plot_names.push_back(derived_names[i]);
141  }
142  }
143  if( solverChoice.windfarm_type == WindFarmType::SimpleAD or
144  solverChoice.windfarm_type == WindFarmType::GeneralAD ) {
145  if(derived_names[i] == "num_turb" or derived_names[i] == "SMark0" or derived_names[i] == "SMark1") {
146  tmp_plot_names.push_back(derived_names[i]);
147  }
148  }
149  }
150  }
151 #endif
152 
153 #ifdef ERF_USE_PARTICLES
154  const auto& particles_namelist( particleData.getNamesUnalloc() );
155  for (auto it = particles_namelist.cbegin(); it != particles_namelist.cend(); ++it) {
156  std::string tmp( (*it)+"_count" );
157  if (containerHasElement(plot_var_names, tmp) ) {
158  tmp_plot_names.push_back(tmp);
159  }
160  }
161 #endif
162 
163  plot_var_names = tmp_plot_names;
164 }
const amrex::Vector< std::string > derived_names
Definition: ERF.H:982
const amrex::Vector< std::string > cons_names
Definition: ERF.H:977
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
1346  {
1347  if (amrex::ParallelDescriptor::IOProcessor())
1348  {
1349  datalog[i] = std::make_unique<std::fstream>();
1350  datalog[i]->open(filename.c_str(),std::ios::out|std::ios::app);
1351  if (!datalog[i]->good()) {
1352  amrex::FileOpenFailed(filename);
1353  }
1354  }
1355  amrex::ParallelDescriptor::Barrier("ERF::setRecordDataInfo");
1356  }

◆ setRecordDerDataInfo()

void ERF::setRecordDerDataInfo ( int  i,
const std::string &  filename 
)
inlineprivate
1359  {
1360  if (amrex::ParallelDescriptor::IOProcessor())
1361  {
1362  der_datalog[i] = std::make_unique<std::fstream>();
1363  der_datalog[i]->open(filename.c_str(),std::ios::out|std::ios::app);
1364  if (!der_datalog[i]->good()) {
1365  amrex::FileOpenFailed(filename);
1366  }
1367  }
1368  amrex::ParallelDescriptor::Barrier("ERF::setRecordDerDataInfo");
1369  }

◆ setRecordSampleLineInfo()

void ERF::setRecordSampleLineInfo ( int  i,
int  lev,
amrex::IntVect &  cell,
const std::string &  filename 
)
inlineprivate
1389  {
1390  amrex::MultiFab dummy(grids[lev],dmap[lev],1,0);
1391  for (amrex::MFIter mfi(dummy); mfi.isValid(); ++mfi)
1392  {
1393  const amrex::Box& bx = mfi.validbox();
1394  if (bx.contains(cell)) {
1395  samplelinelog[i] = std::make_unique<std::fstream>();
1396  samplelinelog[i]->open(filename.c_str(),std::ios::out|std::ios::app);
1397  if (!samplelinelog[i]->good()) {
1398  amrex::FileOpenFailed(filename);
1399  }
1400  }
1401  }
1402  amrex::ParallelDescriptor::Barrier("ERF::setRecordSampleLineInfo");
1403  }

◆ setRecordSamplePointInfo()

void ERF::setRecordSamplePointInfo ( int  i,
int  lev,
amrex::IntVect &  cell,
const std::string &  filename 
)
inlineprivate
1372  {
1373  amrex::MultiFab dummy(grids[lev],dmap[lev],1,0);
1374  for (amrex::MFIter mfi(dummy); mfi.isValid(); ++mfi)
1375  {
1376  const amrex::Box& bx = mfi.validbox();
1377  if (bx.contains(cell)) {
1378  sampleptlog[i] = std::make_unique<std::fstream>();
1379  sampleptlog[i]->open(filename.c_str(),std::ios::out|std::ios::app);
1380  if (!sampleptlog[i]->good()) {
1381  amrex::FileOpenFailed(filename);
1382  }
1383  }
1384  }
1385  amrex::ParallelDescriptor::Barrier("ERF::setRecordSamplePointInfo");
1386  }

◆ 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_EB_mlmg()

void ERF::solve_with_EB_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 EB_enabled MLMG Note that the level may or may not be level 0.

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

◆ 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_derived_quantities()

void ERF::sum_derived_quantities ( amrex::Real  time)
170 {
171  if (verbose <= 0 || NumDerDataLogs() <= 0) return;
172 
173  int lev = 0;
174 
175  AMREX_ALWAYS_ASSERT(lev == 0);
176 
177  // ************************************************************************
178  // WARNING: we are not filling ghost cells other than periodic outside the domain
179  // ************************************************************************
180 
181  MultiFab mf_cc_vel(grids[lev], dmap[lev], AMREX_SPACEDIM, IntVect(1,1,1));
182  mf_cc_vel.setVal(0.); // We just do this to avoid uninitialized values
183 
184  // Average all three components of velocity (on faces) to the cell center
185  average_face_to_cellcenter(mf_cc_vel,0,
186  Array<const MultiFab*,3>{&vars_new[lev][Vars::xvel],
187  &vars_new[lev][Vars::yvel],
188  &vars_new[lev][Vars::zvel]});
189  mf_cc_vel.FillBoundary(geom[lev].periodicity());
190 
191  if (!geom[lev].isPeriodic(0) || !geom[lev].isPeriodic(1) || !geom[lev].isPeriodic(2)) {
192  amrex::Warning("Ghost cells outside non-periodic physical boundaries are not filled -- vel set to 0 there");
193  }
194 
195  MultiFab r_wted_magvelsq(grids[lev], dmap[lev], AMREX_SPACEDIM, IntVect(0,0,0));
196  MultiFab unwted_magvelsq(grids[lev], dmap[lev], AMREX_SPACEDIM, IntVect(0,0,0));
197  MultiFab enstrophysq(grids[lev], dmap[lev], AMREX_SPACEDIM, IntVect(1,1,1));
198 
199 #ifdef _OPENMP
200 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
201 #endif
202  for (MFIter mfi(unwted_magvelsq, TilingIfNotGPU()); mfi.isValid(); ++mfi)
203  {
204  const Box& bx = mfi.tilebox();
205  auto& src_fab = mf_cc_vel[mfi];
206 
207  auto& dest1_fab = unwted_magvelsq[mfi];
208  derived::erf_dermagvelsq(bx, dest1_fab, 0, 1, src_fab, Geom(lev), t_new[0], nullptr, lev);
209 
210  auto& dest2_fab = enstrophysq[mfi];
211  derived::erf_derenstrophysq(bx, dest2_fab, 0, 1, src_fab, Geom(lev), t_new[0], nullptr, lev);
212  }
213 
214  // Copy the MF holding 1/2(u^2 + v^2 + w^2) into the MF that will hold 1/2 rho (u^2 + v^2 + w^2)d
215  MultiFab::Copy(r_wted_magvelsq, unwted_magvelsq, 0, 0, 1, 0);
216 
217  // Multiply the MF holding 1/2(u^2 + v^2 + w^2) by rho to get 1/2 rho (u^2 + v^2 + w^2)
218  MultiFab::Multiply(r_wted_magvelsq, vars_new[lev][Vars::cons], 0, 0, 1, 0);
219 
220  Real unwted_avg = volWgtSumMF(lev, unwted_magvelsq, 0, *mapfac_m[lev],true,false);
221  Real r_wted_avg = volWgtSumMF(lev, r_wted_magvelsq, 0, *mapfac_m[lev],true,false);
222  Real enstrsq_avg = volWgtSumMF(lev, enstrophysq, 0, *mapfac_m[lev],true,false);
223 
224  Real vol = geom[lev].ProbDomain().volume(); // Volume of the domain;
225  unwted_avg /= vol;
226  r_wted_avg /= vol;
227  enstrsq_avg /= vol;
228 
229  if (ParallelDescriptor::IOProcessor()) {
230 
231  std::ostream& data_log_der = DerDataLog(0);
232 
233  if (time == 0.0) {
234  data_log_der << std::setw(datwidth) << " time";
235  data_log_der << std::setw(datwidth) << " ke_den";
236  data_log_der << std::setw(datwidth) << " velsq";
237  data_log_der << std::setw(datwidth) << " enstrophy";
238  data_log_der << std::endl;
239  }
240  data_log_der << std::setw(datwidth) << std::setprecision(timeprecision) << time;
241  data_log_der << std::setw(datwidth) << std::setprecision(datprecision) << unwted_avg;
242  data_log_der << std::setw(datwidth) << std::setprecision(datprecision) << r_wted_avg;
243  data_log_der << std::setw(datwidth) << std::setprecision(datprecision) << enstrsq_avg;
244  data_log_der << std::endl;
245 
246  } // if IOProcessor
247 }
AMREX_FORCE_INLINE std::ostream & DerDataLog(int i)
Definition: ERF.H:1253
AMREX_FORCE_INLINE int NumDerDataLogs() noexcept
Definition: ERF.H:1267
void erf_dermagvelsq(const amrex::Box &bx, amrex::FArrayBox &derfab, int dcomp, int ncomp, const amrex::FArrayBox &datfab, const amrex::Geometry &, amrex::Real, const int *, const int)
Definition: ERF_Derive.cpp:346
void erf_derenstrophysq(const amrex::Box &bx, amrex::FArrayBox &derfab, int dcomp, int ncomp, const amrex::FArrayBox &datfab, const amrex::Geometry &geomdata, amrex::Real, const int *, const int)
Definition: ERF_Derive.cpp:284
Here is the call graph for this function:

◆ sum_integrated_quantities()

void ERF::sum_integrated_quantities ( amrex::Real  time)

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

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

◆ 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() << std::setprecision(timeprecision)
83  << "ADVANCE from time = " << t_old[lev] << " to " << t_new[lev]
84  << " with dt = " << dt[lev] << std::endl;
85  }
86 
87 #ifdef ERF_USE_WW3_COUPLING
88  amrex::Print() << " About to call send_to_ww3 from ERF_Timestep" << std::endl;
89  send_to_ww3(lev);
90  amrex::Print() << " About to call read_waves from ERF_Timestep" << std::endl;
91  read_waves(lev);
92  //send_to_ww3(lev);
93  //read_waves(lev);
94  //send_to_ww3(lev);
95 #endif
96 
97  // Advance a single level for a single time step
98  Advance(lev, time, dt[lev], istep[lev], nsubsteps[lev]);
99 
100  ++istep[lev];
101 
102  if (Verbose()) {
103  amrex::Print() << "[Level " << lev << " step " << istep[lev] << "] ";
104  amrex::Print() << "Advanced " << CountCells(lev) << " cells" << std::endl;
105  }
106 
107  if (lev < finest_level)
108  {
109  // recursive call for next-finer level
110  for (int i = 1; i <= nsubsteps[lev+1]; ++i)
111  {
112  Real strt_time_for_fine = time + (i-1)*dt[lev+1];
113  timeStep(lev+1, strt_time_for_fine, i);
114  }
115  }
116 
117  if (verbose && lev == 0 && solverChoice.moisture_type != MoistureType::None) {
118  amrex::Print() << "Cloud fraction " << time << " " << cloud_fraction(time) << std::endl;
119  }
120 }
amrex::Real cloud_fraction(amrex::Real time)
Definition: ERF_WriteScalarProfiles.cpp:250
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[lev].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:546

◆ update_diffusive_arrays()

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

◆ update_terrain_arrays()

void ERF::update_terrain_arrays ( int  lev)
572 {
573  if (SolverChoice::mesh_type == MeshType::StretchedDz ||
574  SolverChoice::mesh_type == MeshType::VariableDz) {
575  make_J(geom[lev],*z_phys_nd[lev],*detJ_cc[lev]);
576  make_areas(geom[lev],*z_phys_nd[lev],*ax[lev],*ay[lev],*az[lev]);
577  make_zcc(geom[lev],*z_phys_nd[lev],*z_phys_cc[lev]);
578  }
579 }
void make_areas(const Geometry &geom, MultiFab &z_phys_nd, MultiFab &ax, MultiFab &ay, MultiFab &az)
Definition: ERF_TerrainMetrics.cpp:558
void make_J(const Geometry &geom, MultiFab &z_phys_nd, MultiFab &detJ_cc)
Definition: ERF_TerrainMetrics.cpp:520
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
453 {
454  BL_PROFILE("ERF::volWgtSumMF()");
455 
456  Real sum = 0.0;
457  MultiFab tmp(grids[lev], dmap[lev], 1, 0);
458  MultiFab::Copy(tmp, mf, comp, 0, 1, 0);
459 
460  // The quantity that is conserved is not (rho S), but rather (rho S / m^2) where
461  // m is the map scale factor at cell centers
462  for (MFIter mfi(tmp, TilingIfNotGPU()); mfi.isValid(); ++mfi) {
463  const Box& bx = mfi.tilebox();
464  const Array4< Real> tmp_arr = tmp.array(mfi);
465  const Array4<const Real> mapfac_arr = mapfac.const_array(mfi);
466  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
467  {
468  tmp_arr(i,j,k) /= (mapfac_arr(i,j,0)*mapfac_arr(i,j,0));
469  });
470  } // mfi
471 
472  if (lev < finest_level && finemask) {
473  const MultiFab& mask = build_fine_mask(lev+1);
474  MultiFab::Multiply(tmp, mask, 0, 0, 1, 0);
475  }
476 
477  MultiFab volume(grids[lev], dmap[lev], 1, 0);
478  auto const& dx = geom[lev].CellSizeArray();
479  Real cell_vol = dx[0]*dx[1]*dx[2];
480  volume.setVal(cell_vol);
481  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
482  MultiFab::Multiply(volume, *detJ_cc[lev], 0, 0, 1, 0);
483  }
484  sum = MultiFab::Dot(tmp, 0, volume, 0, 1, 0, local);
485 
486  if (!local) {
487  ParallelDescriptor::ReduceRealSum(sum);
488  }
489 
490  return sum;
491 }
amrex::MultiFab & build_fine_mask(int lev)
Definition: ERF_WriteScalarProfiles.cpp:501

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

◆ write_1D_profiles_stag()

void ERF::write_1D_profiles_stag ( amrex::Real  time)

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

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

The structure of file should follow ERF_Write1DProfiles.cpp

Parameters
timeCurrent time
26 {
27  BL_PROFILE("ERF::write_1D_profiles()");
28 
29  if (NumDataLogs() > 1)
30  {
31  // Define the 1d arrays we will need
32  Gpu::HostVector<Real> h_avg_u, h_avg_v, h_avg_w;
33  Gpu::HostVector<Real> h_avg_rho, h_avg_th, h_avg_ksgs, h_avg_Kmv, h_avg_Khv;
34  Gpu::HostVector<Real> h_avg_qv, h_avg_qc, h_avg_qr, h_avg_wqv, h_avg_wqc, h_avg_wqr, h_avg_qi, h_avg_qs, h_avg_qg;
35  Gpu::HostVector<Real> h_avg_wthv;
36  Gpu::HostVector<Real> h_avg_uth, h_avg_vth, h_avg_wth, h_avg_thth;
37  Gpu::HostVector<Real> h_avg_uu, h_avg_uv, h_avg_uw, h_avg_vv, h_avg_vw, h_avg_ww;
38  Gpu::HostVector<Real> h_avg_uiuiu, h_avg_uiuiv, h_avg_uiuiw;
39  Gpu::HostVector<Real> h_avg_p, h_avg_pu, h_avg_pv, h_avg_pw;
40  Gpu::HostVector<Real> h_avg_tau11, h_avg_tau12, h_avg_tau13, h_avg_tau22, h_avg_tau23, h_avg_tau33;
41  Gpu::HostVector<Real> h_avg_sgshfx, h_avg_sgsq1fx, h_avg_sgsq2fx, h_avg_sgsdiss; // only output tau_{theta,w} and epsilon for now
42 
43  if (NumDataLogs() > 1) {
45  h_avg_u, h_avg_v, h_avg_w,
46  h_avg_rho, h_avg_th, h_avg_ksgs,
47  h_avg_Kmv, h_avg_Khv,
48  h_avg_qv, h_avg_qc, h_avg_qr,
49  h_avg_wqv, h_avg_wqc, h_avg_wqr,
50  h_avg_qi, h_avg_qs, h_avg_qg,
51  h_avg_uu, h_avg_uv, h_avg_uw, h_avg_vv, h_avg_vw, h_avg_ww,
52  h_avg_uth, h_avg_vth, h_avg_wth, h_avg_thth,
53  h_avg_uiuiu, h_avg_uiuiv, h_avg_uiuiw,
54  h_avg_p, h_avg_pu, h_avg_pv, h_avg_pw,
55  h_avg_wthv);
56  }
57 
58  if (NumDataLogs() > 3 && time > 0.) {
59  derive_stress_profiles_stag(h_avg_tau11, h_avg_tau12, h_avg_tau13,
60  h_avg_tau22, h_avg_tau23, h_avg_tau33,
61  h_avg_sgshfx, h_avg_sgsq1fx, h_avg_sgsq2fx,
62  h_avg_sgsdiss);
63  }
64 
65  int unstag_size = h_avg_w.size() - 1; // _un_staggered heights
66 
67  auto const& dx = geom[0].CellSizeArray();
68  if (ParallelDescriptor::IOProcessor()) {
69  if (NumDataLogs() > 1) {
70  std::ostream& data_log1 = DataLog(1);
71  if (data_log1.good()) {
72  // Write the quantities at this time
73  for (int k = 0; k < unstag_size; k++) {
74  Real z = (zlevels_stag[0].size() > 1) ? zlevels_stag[0][k] : k * dx[2];
75  data_log1 << std::setw(datwidth) << std::setprecision(timeprecision) << time << " "
76  << std::setw(datwidth) << std::setprecision(datprecision) << z << " "
77  << h_avg_u[k] << " " << h_avg_v[k] << " " << h_avg_w[k] << " "
78  << h_avg_rho[k] << " " << h_avg_th[k] << " " << h_avg_ksgs[k] << " "
79  << h_avg_Kmv[k] << " " << h_avg_Khv[k] << " "
80  << h_avg_qv[k] << " " << h_avg_qc[k] << " " << h_avg_qr[k] << " "
81  << h_avg_qi[k] << " " << h_avg_qs[k] << " " << h_avg_qg[k]
82  << std::endl;
83  } // loop over z
84  // Write top face values
85  Real z = (zlevels_stag[0].size() > 1) ? zlevels_stag[0][unstag_size] : unstag_size * dx[2];
86  data_log1 << std::setw(datwidth) << std::setprecision(timeprecision) << time << " "
87  << std::setw(datwidth) << std::setprecision(datprecision) << z << " "
88  << 0 << " " << 0 << " " << h_avg_w[unstag_size] << " "
89  << 0 << " " << 0 << " " << 0 << " " // rho, theta, ksgs
90  << 0 << " " << 0 << " " // Kmv, Khv
91  << 0 << " " << 0 << " " << 0 << " " // qv, qc, qr
92  << 0 << " " << 0 << " " << 0 // qi, qs, qg
93  << std::endl;
94  } // if good
95  } // NumDataLogs
96 
97  if (NumDataLogs() > 2) {
98  std::ostream& data_log2 = DataLog(2);
99  if (data_log2.good()) {
100  // Write the perturbational quantities at this time
101  // For surface values (k=0), assume w = uw = vw = ww = 0
102  Real w_cc = h_avg_w[1] / 2; // w at first cell center
103  Real uw_cc = h_avg_uw[1] / 2; // u*w at first cell center
104  Real vw_cc = h_avg_vw[1] / 2; // v*w at first cell center
105  Real ww_cc = h_avg_ww[1] / 2; // w*w at first cell center
106  data_log2 << std::setw(datwidth) << std::setprecision(timeprecision) << time << " "
107  << std::setw(datwidth) << std::setprecision(datprecision) << 0 << " "
108  << h_avg_uu[0] - h_avg_u[0]*h_avg_u[0] << " " // u'u'
109  << h_avg_uv[0] - h_avg_u[0]*h_avg_v[0] << " " // u'v'
110  << 0 << " " // u'w'
111  << h_avg_vv[0] - h_avg_v[0]*h_avg_v[0] << " " // v'v'
112  << 0 << " " // v'w'
113  << 0 << " " // w'w'
114  << h_avg_uth[0] - h_avg_u[0]*h_avg_th[0] << " " // u'th'
115  << h_avg_vth[0] - h_avg_v[0]*h_avg_th[0] << " " // v'th'
116  << 0 << " " // w'th'
117  << h_avg_thth[0] - h_avg_th[0]*h_avg_th[0] << " " // th'th'
118  << h_avg_uiuiu[0]
119  - (h_avg_uu[0] + h_avg_vv[0] + ww_cc)*h_avg_u[0]
120  - 2*(h_avg_u[0]*h_avg_uu[0] + h_avg_v[0]*h_avg_uv[0] + w_cc*uw_cc)
121  + 2*(h_avg_u[0]*h_avg_u[0] + h_avg_v[0]*h_avg_v[0] + w_cc*w_cc)*h_avg_u[0]
122  << " " // (u'_i u'_i)u'
123  << h_avg_uiuiv[0]
124  - (h_avg_uu[0] + h_avg_vv[0] + ww_cc)*h_avg_v[0]
125  - 2*(h_avg_u[0]*h_avg_uv[0] + h_avg_v[0]*h_avg_vv[0] + w_cc*vw_cc)
126  + 2*(h_avg_u[0]*h_avg_u[0] + h_avg_v[0]*h_avg_v[0] + w_cc*w_cc)*h_avg_v[0]
127  << " " // (u'_i u'_i)v'
128  << 0 << " " // (u'_i u'_i)w'
129  << h_avg_pu[0] - h_avg_p[0]*h_avg_u[0] << " " // p'u'
130  << h_avg_pv[0] - h_avg_p[0]*h_avg_v[0] << " " // p'v'
131  << 0 << " " // p'w'
132  << 0 << " " // qv'w'
133  << 0 << " " // qc'w'
134  << 0 << " " // qr'w'
135  << 0 // thv'w'
136  << std::endl;
137 
138  // For internal values, interpolate scalar quantities to faces
139  for (int k = 1; k < unstag_size; k++) {
140  Real z = (zlevels_stag[0].size() > 1) ? zlevels_stag[0][k] : k * dx[2];
141  Real uface = 0.5*(h_avg_u[k] + h_avg_u[k-1]);
142  Real vface = 0.5*(h_avg_v[k] + h_avg_v[k-1]);
143  Real thface = 0.5*(h_avg_th[k] + h_avg_th[k-1]);
144  Real pface = 0.5*(h_avg_p[k] + h_avg_p[k-1]);
145  Real qvface = 0.5*(h_avg_qv[k] + h_avg_qv[k-1]);
146  Real qcface = 0.5*(h_avg_qc[k] + h_avg_qc[k-1]);
147  Real qrface = 0.5*(h_avg_qr[k] + h_avg_qr[k-1]);
148  Real uuface = 0.5*(h_avg_uu[k] + h_avg_uu[k-1]);
149  Real vvface = 0.5*(h_avg_vv[k] + h_avg_vv[k-1]);
150  Real thvface = thface * (1 + 0.61*qvface - qcface - qrface);
151  w_cc = 0.5*(h_avg_w[k-1] + h_avg_w[k]);
152  uw_cc = 0.5*(h_avg_uw[k-1] + h_avg_uw[k]);
153  vw_cc = 0.5*(h_avg_vw[k-1] + h_avg_vw[k]);
154  ww_cc = 0.5*(h_avg_ww[k-1] + h_avg_ww[k]);
155  data_log2 << std::setw(datwidth) << std::setprecision(timeprecision) << time << " "
156  << std::setw(datwidth) << std::setprecision(datprecision) << z << " "
157  << h_avg_uu[k] - h_avg_u[k]*h_avg_u[k] << " " // u'u'
158  << h_avg_uv[k] - h_avg_u[k]*h_avg_v[k] << " " // u'v'
159  << h_avg_uw[k] - uface*h_avg_w[k] << " " // u'w'
160  << h_avg_vv[k] - h_avg_v[k]*h_avg_v[k] << " " // v'v'
161  << h_avg_vw[k] - vface*h_avg_w[k] << " " // v'w'
162  << h_avg_ww[k] - h_avg_w[k]*h_avg_w[k] << " " // w'w'
163  << h_avg_uth[k] - h_avg_u[k]*h_avg_th[k] << " " // u'th'
164  << h_avg_vth[k] - h_avg_v[k]*h_avg_th[k] << " " // v'th'
165  << h_avg_wth[k] - h_avg_w[k]*thface << " " // w'th'
166  << h_avg_thth[k] - h_avg_th[k]*h_avg_th[k] << " " // th'th'
167  // Note: <u'_i u'_i u'_j> = <u_i u_i u_j>
168  // - <u_i u_i> * <u_j>
169  // - 2*<u_i> * <u_i u_j>
170  // + 2*<u_i>*<u_i> * <u_j>
171  << h_avg_uiuiu[k]
172  - (h_avg_uu[k] + h_avg_vv[k] + ww_cc)*h_avg_u[k]
173  - 2*(h_avg_u[k]*h_avg_uu[k] + h_avg_v[k]*h_avg_uv[k] + w_cc*uw_cc)
174  + 2*(h_avg_u[k]*h_avg_u[k] + h_avg_v[k]*h_avg_v[k] + w_cc*w_cc)*h_avg_u[k]
175  << " " // cell-centered (u'_i u'_i)u'
176  << h_avg_uiuiv[k]
177  - (h_avg_uu[k] + h_avg_vv[k] + ww_cc)*h_avg_v[k]
178  - 2*(h_avg_u[k]*h_avg_uv[k] + h_avg_v[k]*h_avg_vv[k] + w_cc*vw_cc)
179  + 2*(h_avg_u[k]*h_avg_u[k] + h_avg_v[k]*h_avg_v[k] + w_cc*w_cc)*h_avg_v[k]
180  << " " // cell-centered (u'_i u'_i)v'
181  << h_avg_uiuiw[k]
182  - (uuface + vvface + h_avg_ww[k])*h_avg_w[k]
183  - 2*(uface*h_avg_uw[k] + vface*h_avg_vw[k] + h_avg_w[k]*h_avg_ww[k])
184  + 2*(uface*uface + vface*vface + h_avg_w[k]*h_avg_w[k])*h_avg_w[k]
185  << " " // face-centered (u'_i u'_i)w'
186  << h_avg_pu[k] - h_avg_p[k]*h_avg_u[k] << " " // cell-centered p'u'
187  << h_avg_pv[k] - h_avg_p[k]*h_avg_v[k] << " " // cell-centered p'v'
188  << h_avg_pw[k] - pface*h_avg_w[k] << " " // face-centered p'w'
189  << h_avg_wqv[k] - qvface*h_avg_w[k] << " "
190  << h_avg_wqc[k] - qcface*h_avg_w[k] << " "
191  << h_avg_wqr[k] - qrface*h_avg_w[k] << " "
192  << h_avg_wthv[k] - thvface*h_avg_w[k]
193  << std::endl;
194  } // loop over z
195 
196  // Write top face values, extrapolating scalar quantities
197  const int k = unstag_size;
198  Real uface = 1.5*h_avg_u[k-1] - 0.5*h_avg_u[k-2];
199  Real vface = 1.5*h_avg_v[k-1] - 0.5*h_avg_v[k-2];
200  Real thface = 1.5*h_avg_th[k-1] - 0.5*h_avg_th[k-2];
201  Real pface = 1.5*h_avg_p[k-1] - 0.5*h_avg_p[k-2];
202  Real qvface = 1.5*h_avg_qv[k-1] - 0.5*h_avg_qv[k-2];
203  Real qcface = 1.5*h_avg_qc[k-1] - 0.5*h_avg_qc[k-2];
204  Real qrface = 1.5*h_avg_qr[k-1] - 0.5*h_avg_qr[k-2];
205  Real uuface = 1.5*h_avg_uu[k-1] - 0.5*h_avg_uu[k-2];
206  Real vvface = 1.5*h_avg_vv[k-1] - 0.5*h_avg_vv[k-2];
207  Real thvface = thface * (1 + 0.61*qvface - qcface - qrface);
208  Real z = (zlevels_stag[0].size() > 1) ? zlevels_stag[0][unstag_size] : unstag_size * dx[2];
209  data_log2 << std::setw(datwidth) << std::setprecision(timeprecision) << time << " "
210  << std::setw(datwidth) << std::setprecision(datprecision) << z << " "
211  << 0 << " " // u'u'
212  << 0 << " " // u'v'
213  << h_avg_uw[k] - uface*h_avg_w[k] << " " // u'w'
214  << 0 << " " // v'v'
215  << h_avg_vw[k] - vface*h_avg_w[k] << " " // v'w'
216  << h_avg_ww[k] - h_avg_w[k]*h_avg_w[k] << " " // w'w'
217  << 0 << " " // u'th'
218  << 0 << " " // v'th'
219  << h_avg_wth[k] - thface*h_avg_w[k] << " " // w'th'
220  << 0 << " " // th'th'
221  << 0 << " " // (u'_i u'_i)u'
222  << 0 << " " // (u'_i u'_i)v'
223  << h_avg_uiuiw[k]
224  - (uuface + vvface + h_avg_ww[k])*h_avg_w[k]
225  - 2*(uface*h_avg_uw[k] + vface*h_avg_vw[k] + h_avg_w[k]*h_avg_ww[k])
226  + 2*(uface*uface + vface*vface + h_avg_w[k]*h_avg_w[k])*h_avg_w[k]
227  << " " // (u'_i u'_i)w'
228  << 0 << " " // pu'
229  << 0 << " " // pv'
230  << h_avg_pw[k] - pface*h_avg_w[k] << " " // pw'
231  << h_avg_wqv[k] - qvface*h_avg_w[k] << " "
232  << h_avg_wqc[k] - qcface*h_avg_w[k] << " "
233  << h_avg_wqr[k] - qrface*h_avg_w[k] << " "
234  << h_avg_wthv[k] - thvface*h_avg_w[k]
235  << std::endl;
236  } // if good
237  } // NumDataLogs
238 
239  if (NumDataLogs() > 3 && time > 0.) {
240  std::ostream& data_log3 = DataLog(3);
241  if (data_log3.good()) {
242  // Write the average stresses
243  for (int k = 0; k < unstag_size; k++) {
244  Real z = (zlevels_stag[0].size() > 1) ? zlevels_stag[0][k] : k * dx[2];
245  data_log3 << std::setw(datwidth) << std::setprecision(timeprecision) << time << " "
246  << std::setw(datwidth) << std::setprecision(datprecision) << z << " "
247  << h_avg_tau11[k] << " " << h_avg_tau12[k] << " " << h_avg_tau13[k] << " "
248  << h_avg_tau22[k] << " " << h_avg_tau23[k] << " " << h_avg_tau33[k] << " "
249  << h_avg_sgshfx[k] << " "
250  << h_avg_sgsq1fx[k] << " " << h_avg_sgsq2fx[k] << " "
251  << h_avg_sgsdiss[k]
252  << std::endl;
253  } // loop over z
254  // Write top face values
255  Real NANval = 0.0;
256  Real z = (zlevels_stag[0].size() > 1) ? zlevels_stag[0][unstag_size] : unstag_size * dx[2];
257  data_log3 << std::setw(datwidth) << std::setprecision(timeprecision) << time << " "
258  << std::setw(datwidth) << std::setprecision(datprecision) << z << " "
259  << NANval << " " << NANval << " " << h_avg_tau13[unstag_size] << " "
260  << NANval << " " << h_avg_tau23[unstag_size] << " " << NANval << " "
261  << h_avg_sgshfx[unstag_size] << " "
262  << h_avg_sgsq1fx[unstag_size] << " " << h_avg_sgsq2fx[unstag_size] << " "
263  << NANval
264  << std::endl;
265  } // if good
266  } // if (NumDataLogs() > 3)
267  } // if IOProcessor
268  } // if (NumDataLogs() > 1)
269 }
void derive_diag_profiles_stag(amrex::Real time, amrex::Gpu::HostVector< amrex::Real > &h_avg_u, amrex::Gpu::HostVector< amrex::Real > &h_avg_v, amrex::Gpu::HostVector< amrex::Real > &h_avg_w, amrex::Gpu::HostVector< amrex::Real > &h_avg_rho, amrex::Gpu::HostVector< amrex::Real > &h_avg_th, amrex::Gpu::HostVector< amrex::Real > &h_avg_ksgs, amrex::Gpu::HostVector< amrex::Real > &h_avg_Kmv, amrex::Gpu::HostVector< amrex::Real > &h_avg_Khv, amrex::Gpu::HostVector< amrex::Real > &h_avg_qv, amrex::Gpu::HostVector< amrex::Real > &h_avg_qc, amrex::Gpu::HostVector< amrex::Real > &h_avg_qr, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqv, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqc, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqr, amrex::Gpu::HostVector< amrex::Real > &h_avg_qi, amrex::Gpu::HostVector< amrex::Real > &h_avg_qs, amrex::Gpu::HostVector< amrex::Real > &h_avg_qg, amrex::Gpu::HostVector< amrex::Real > &h_avg_uu, amrex::Gpu::HostVector< amrex::Real > &h_avg_uv, amrex::Gpu::HostVector< amrex::Real > &h_avg_uw, amrex::Gpu::HostVector< amrex::Real > &h_avg_vv, amrex::Gpu::HostVector< amrex::Real > &h_avg_vw, amrex::Gpu::HostVector< amrex::Real > &h_avg_ww, amrex::Gpu::HostVector< amrex::Real > &h_avg_uth, amrex::Gpu::HostVector< amrex::Real > &h_avg_vth, amrex::Gpu::HostVector< amrex::Real > &h_avg_wth, amrex::Gpu::HostVector< amrex::Real > &h_avg_thth, amrex::Gpu::HostVector< amrex::Real > &h_avg_ku, amrex::Gpu::HostVector< amrex::Real > &h_avg_kv, amrex::Gpu::HostVector< amrex::Real > &h_avg_kw, amrex::Gpu::HostVector< amrex::Real > &h_avg_p, amrex::Gpu::HostVector< amrex::Real > &h_avg_pu, amrex::Gpu::HostVector< amrex::Real > &h_avg_pv, amrex::Gpu::HostVector< amrex::Real > &h_avg_pw, amrex::Gpu::HostVector< amrex::Real > &h_avg_wthv)
Definition: ERF_Write1DProfiles_stag.cpp:296
void derive_stress_profiles_stag(amrex::Gpu::HostVector< amrex::Real > &h_avg_tau11, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau12, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau13, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau22, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau23, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau33, amrex::Gpu::HostVector< amrex::Real > &h_avg_hfx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_q1fx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_q2fx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_diss)
Definition: ERF_Write1DProfiles_stag.cpp: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  // Write separate file that tells how many components we have of the base state
113  std::string BaseStateFileName(checkpointname + "/num_base_state_comps");
114  std::ofstream BaseStateFile;
115  BaseStateFile.open(BaseStateFileName.c_str(), std::ofstream::out |
116  std::ofstream::trunc |
117  std::ofstream::binary);
118  if(! BaseStateFile.good()) {
119  FileOpenFailed(BaseStateFileName);
120  } else {
121  // write out number of components in base state
122  BaseStateFile << BaseState::num_comps << "\n";
123  BaseStateFile << base_state[0].nGrowVect() << "\n";
124  }
125  }
126 
127  // write the MultiFab data to, e.g., chk00010/Level_0/
128  // Here we make copies of the MultiFab with no ghost cells
129  for (int lev = 0; lev <= finest_level; ++lev)
130  {
131  MultiFab cons(grids[lev],dmap[lev],ncomp_cons,0);
132  MultiFab::Copy(cons,vars_new[lev][Vars::cons],0,0,ncomp_cons,0);
133  VisMF::Write(cons, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Cell"));
134 
135  MultiFab xvel(convert(grids[lev],IntVect(1,0,0)),dmap[lev],1,0);
136  MultiFab::Copy(xvel,vars_new[lev][Vars::xvel],0,0,1,0);
137  VisMF::Write(xvel, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "XFace"));
138 
139  MultiFab yvel(convert(grids[lev],IntVect(0,1,0)),dmap[lev],1,0);
140  MultiFab::Copy(yvel,vars_new[lev][Vars::yvel],0,0,1,0);
141  VisMF::Write(yvel, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "YFace"));
142 
143  MultiFab zvel(convert(grids[lev],IntVect(0,0,1)),dmap[lev],1,0);
144  MultiFab::Copy(zvel,vars_new[lev][Vars::zvel],0,0,1,0);
145  VisMF::Write(zvel, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "ZFace"));
146 
147  // Note that we write the ghost cells of the base state (unlike above)
148  IntVect ng_base = base_state[lev].nGrowVect();
149  int ncomp_base = base_state[lev].nComp();
150  MultiFab base(grids[lev],dmap[lev],ncomp_base,ng_base);
151  MultiFab::Copy(base,base_state[lev],0,0,ncomp_base,ng_base);
152  VisMF::Write(base, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "BaseState"));
153 
154  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
155  // Note that we also write the ghost cells of z_phys_nd
156  IntVect ng = z_phys_nd[lev]->nGrowVect();
157  MultiFab z_height(convert(grids[lev],IntVect(1,1,1)),dmap[lev],1,ng);
158  MultiFab::Copy(z_height,*z_phys_nd[lev],0,0,1,ng);
159  VisMF::Write(z_height, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Z_Phys_nd"));
160  }
161 
162  // We must read and write qmoist with ghost cells because we don't directly impose BCs on these vars
163  // Write the moisture model restart variables
164  std::vector<int> qmoist_indices;
165  std::vector<std::string> qmoist_names;
166  micro->Get_Qmoist_Restart_Vars(lev, solverChoice, qmoist_indices, qmoist_names);
167  int qmoist_nvar = qmoist_indices.size();
168  for (int var = 0; var < qmoist_nvar; var++) {
169  const int ncomp = 1;
170  IntVect ng_moist = qmoist[lev][qmoist_indices[var]]->nGrowVect();
171  MultiFab moist_vars(grids[lev],dmap[lev],ncomp,ng_moist);
172  MultiFab::Copy(moist_vars,*(qmoist[lev][qmoist_indices[var]]),0,0,ncomp,ng_moist);
173  VisMF::Write(moist_vars, amrex::MultiFabFileFullPrefix(lev, checkpointname, "Level_", qmoist_names[var]));
174  }
175 
176 #if defined(ERF_USE_WINDFARM)
177  if(solverChoice.windfarm_type == WindFarmType::Fitch or
178  solverChoice.windfarm_type == WindFarmType::EWP or
179  solverChoice.windfarm_type == WindFarmType::SimpleAD){
180  IntVect ng_turb = Nturb[lev].nGrowVect();
181  MultiFab mf_Nturb(grids[lev],dmap[lev],1,ng_turb);
182  MultiFab::Copy(mf_Nturb,Nturb[lev],0,0,1,ng_turb);
183  VisMF::Write(mf_Nturb, amrex::MultiFabFileFullPrefix(lev, checkpointname, "Level_", "NumTurb"));
184  }
185 #endif
186 
187  if (solverChoice.lsm_type != LandSurfaceType::None) {
188  for (int mvar(0); mvar<lsm_data[lev].size(); ++mvar) {
189  BoxArray ba = lsm_data[lev][mvar]->boxArray();
190  DistributionMapping dm = lsm_data[lev][mvar]->DistributionMap();
191  IntVect ng = lsm_data[lev][mvar]->nGrowVect();
192  int nvar = lsm_data[lev][mvar]->nComp();
193  MultiFab lsm_vars(ba,dm,nvar,ng);
194  MultiFab::Copy(lsm_vars,*(lsm_data[lev][mvar]),0,0,nvar,ng);
195  VisMF::Write(lsm_vars, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "LsmVars"));
196  }
197  }
198 
199  // Note that we also write the ghost cells of the mapfactors (2D)
200  BoxList bl2d = grids[lev].boxList();
201  for (auto& b : bl2d) {
202  b.setRange(2,0);
203  }
204  BoxArray ba2d(std::move(bl2d));
205 
206  IntVect ng = mapfac_m[lev]->nGrowVect();
207  MultiFab mf_m(ba2d,dmap[lev],1,ng);
208  MultiFab::Copy(mf_m,*mapfac_m[lev],0,0,1,ng);
209  VisMF::Write(mf_m, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "MapFactor_m"));
210 
211  ng = mapfac_u[lev]->nGrowVect();
212  MultiFab mf_u(convert(ba2d,IntVect(1,0,0)),dmap[lev],1,ng);
213  MultiFab::Copy(mf_u,*mapfac_u[lev],0,0,1,ng);
214  VisMF::Write(mf_u, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "MapFactor_u"));
215 
216  ng = mapfac_v[lev]->nGrowVect();
217  MultiFab mf_v(convert(ba2d,IntVect(0,1,0)),dmap[lev],1,ng);
218  MultiFab::Copy(mf_v,*mapfac_v[lev],0,0,1,ng);
219  VisMF::Write(mf_v, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "MapFactor_v"));
220 
221  if (m_most && m_most->have_variable_sea_roughness()) {
222  amrex::Print() << "Writing variable surface roughness" << std::endl;
223  ng = vars_new[lev][Vars::cons].nGrowVect(); ng[2]=0;
224  MultiFab z0(ba2d,dmap[lev],1,ng);
225  for (amrex::MFIter mfi(z0); mfi.isValid(); ++mfi) {
226  const Box& bx = mfi.growntilebox();
227  z0[mfi].copy<RunOn::Host>(*(m_most->get_z0(lev)), bx);
228  }
229  VisMF::Write(z0, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Z0"));
230  }
231 
232 #ifdef ERF_USE_NETCDF
233  // Write lat/lon if it exists
234  if (lat_m[lev] && lon_m[lev] && solverChoice.has_lat_lon) {
235  amrex::Print() << "Writing Lat/Lon variables" << std::endl;
236  IntVect ngv = ng; ngv[2] = 0;
237  MultiFab lat(ba2d,dmap[lev],1,ngv);
238  MultiFab lon(ba2d,dmap[lev],1,ngv);
239  MultiFab::Copy(lat,*lat_m[lev],0,0,1,ngv);
240  MultiFab::Copy(lon,*lon_m[lev],0,0,1,ngv);
241  VisMF::Write(lat, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "LAT"));
242  VisMF::Write(lon, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "LON"));
243  }
244 
245  // Write sinPhi and cosPhi if it exists
246  if (cosPhi_m[lev] && sinPhi_m[lev] && solverChoice.variable_coriolis) {
247  amrex::Print() << "Writing Coriolis factors" << std::endl;
248  IntVect ngv = ng; ngv[2] = 0;
249  MultiFab sphi(ba2d,dmap[lev],1,ngv);
250  MultiFab cphi(ba2d,dmap[lev],1,ngv);
251  MultiFab::Copy(sphi,*sinPhi_m[lev],0,0,1,ngv);
252  MultiFab::Copy(cphi,*cosPhi_m[lev],0,0,1,ngv);
253  VisMF::Write(sphi, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "SinPhi"));
254  VisMF::Write(cphi, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "CosPhi"));
255  }
256 #endif
257 
258  } // for lev
259 
260 #ifdef ERF_USE_PARTICLES
261  particleData.Checkpoint(checkpointname);
262 #endif
263 
264 #ifdef ERF_USE_NETCDF
265  // Write bdy_data files
266  if ( ParallelDescriptor::IOProcessor() &&
267  ((solverChoice.init_type==InitType::WRFInput) || (solverChoice.init_type==InitType::Metgrid)) &&
269  {
270  // Vector dimensions
271  int num_time = bdy_data_xlo.size();
272  int num_var = bdy_data_xlo[0].size();
273 
274  // Open header file and write to it
275  std::ofstream bdy_h_file(MultiFabFileFullPrefix(0, checkpointname, "Level_", "bdy_H"));
276  bdy_h_file << std::setprecision(1) << std::fixed;
277  bdy_h_file << num_time << "\n";
278  bdy_h_file << num_var << "\n";
279  bdy_h_file << start_bdy_time << "\n";
280  bdy_h_file << bdy_time_interval << "\n";
281  bdy_h_file << real_width << "\n";
282  for (int ivar(0); ivar<num_var; ++ivar) {
283  bdy_h_file << bdy_data_xlo[0][ivar].box() << "\n";
284  bdy_h_file << bdy_data_xhi[0][ivar].box() << "\n";
285  bdy_h_file << bdy_data_ylo[0][ivar].box() << "\n";
286  bdy_h_file << bdy_data_yhi[0][ivar].box() << "\n";
287  }
288 
289  // Open data file and write to it
290  std::ofstream bdy_d_file(MultiFabFileFullPrefix(0, checkpointname, "Level_", "bdy_D"));
291  for (int itime(0); itime<num_time; ++itime) {
292  for (int ivar(0); ivar<num_var; ++ivar) {
293  bdy_data_xlo[itime][ivar].writeOn(bdy_d_file,0,1);
294  bdy_data_xhi[itime][ivar].writeOn(bdy_d_file,0,1);
295  bdy_data_ylo[itime][ivar].writeOn(bdy_d_file,0,1);
296  bdy_data_yhi[itime][ivar].writeOn(bdy_d_file,0,1);
297  }
298  }
299  }
300 #endif
301 
302 }

◆ 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
1779 {
1780  AMREX_ALWAYS_ASSERT(nlevels <= bArray.size());
1781  AMREX_ALWAYS_ASSERT(nlevels <= my_ref_ratio.size()+1);
1782  AMREX_ALWAYS_ASSERT(nlevels <= level_steps.size());
1783 
1784  HeaderFile.precision(17);
1785 
1786  // ---- this is the generic plot file type name
1787  HeaderFile << versionName << '\n';
1788 
1789  HeaderFile << varnames.size() << '\n';
1790 
1791  for (int ivar = 0; ivar < varnames.size(); ++ivar) {
1792  HeaderFile << varnames[ivar] << "\n";
1793  }
1794  HeaderFile << AMREX_SPACEDIM << '\n';
1795  HeaderFile << my_time << '\n';
1796  HeaderFile << finest_level << '\n';
1797  for (int i = 0; i < AMREX_SPACEDIM; ++i) {
1798  HeaderFile << my_geom[0].ProbLo(i) << ' ';
1799  }
1800  HeaderFile << '\n';
1801  for (int i = 0; i < AMREX_SPACEDIM; ++i) {
1802  HeaderFile << my_geom[0].ProbHi(i) << ' ';
1803  }
1804  HeaderFile << '\n';
1805  for (int i = 0; i < finest_level; ++i) {
1806  HeaderFile << my_ref_ratio[i][0] << ' ';
1807  }
1808  HeaderFile << '\n';
1809  for (int i = 0; i <= finest_level; ++i) {
1810  HeaderFile << my_geom[i].Domain() << ' ';
1811  }
1812  HeaderFile << '\n';
1813  for (int i = 0; i <= finest_level; ++i) {
1814  HeaderFile << level_steps[i] << ' ';
1815  }
1816  HeaderFile << '\n';
1817  for (int i = 0; i <= finest_level; ++i) {
1818  for (int k = 0; k < AMREX_SPACEDIM; ++k) {
1819  HeaderFile << my_geom[i].CellSize()[k] << ' ';
1820  }
1821  HeaderFile << '\n';
1822  }
1823  HeaderFile << (int) my_geom[0].Coord() << '\n';
1824  HeaderFile << "0\n";
1825 
1826  for (int level = 0; level <= finest_level; ++level) {
1827  HeaderFile << level << ' ' << bArray[level].size() << ' ' << my_time << '\n';
1828  HeaderFile << level_steps[level] << '\n';
1829 
1830  const IntVect& domain_lo = my_geom[level].Domain().smallEnd();
1831  for (int i = 0; i < bArray[level].size(); ++i)
1832  {
1833  // Need to shift because the RealBox ctor we call takes the
1834  // physical location of index (0,0,0). This does not affect
1835  // the usual cases where the domain index starts with 0.
1836  const Box& b = shift(bArray[level][i], -domain_lo);
1837  RealBox loc = RealBox(b, my_geom[level].CellSize(), my_geom[level].ProbLo());
1838  for (int n = 0; n < AMREX_SPACEDIM; ++n) {
1839  HeaderFile << loc.lo(n) << ' ' << loc.hi(n) << '\n';
1840  }
1841  }
1842 
1843  HeaderFile << MultiFabHeaderPath(level, levelPrefix, mfPrefix) << '\n';
1844  }
1845  HeaderFile << "1" << "\n";
1846  HeaderFile << "3" << "\n";
1847  HeaderFile << "amrexvec_nu_x" << "\n";
1848  HeaderFile << "amrexvec_nu_y" << "\n";
1849  HeaderFile << "amrexvec_nu_z" << "\n";
1850  std::string mf_nodal_prefix = "Nu_nd";
1851  for (int level = 0; level <= finest_level; ++level) {
1852  HeaderFile << MultiFabHeaderPath(level, levelPrefix, mf_nodal_prefix) << '\n';
1853  }
1854 }
Coord
Definition: ERF_DataStruct.H:68

◆ 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:14
static amrex::Real getCPUTime()
Definition: ERF.H:1331
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
1693 {
1694  BL_PROFILE("WriteMultiLevelPlotfileWithTerrain()");
1695 
1696  AMREX_ALWAYS_ASSERT(nlevels <= mf.size());
1697  AMREX_ALWAYS_ASSERT(nlevels <= rr.size()+1);
1698  AMREX_ALWAYS_ASSERT(nlevels <= level_steps.size());
1699  AMREX_ALWAYS_ASSERT(mf[0]->nComp() == varnames.size());
1700 
1701  bool callBarrier(false);
1702  PreBuildDirectorHierarchy(plotfilename, levelPrefix, nlevels, callBarrier);
1703  if (!extra_dirs.empty()) {
1704  for (const auto& d : extra_dirs) {
1705  const std::string ed = plotfilename+"/"+d;
1706  PreBuildDirectorHierarchy(ed, levelPrefix, nlevels, callBarrier);
1707  }
1708  }
1709  ParallelDescriptor::Barrier();
1710 
1711  if (ParallelDescriptor::MyProc() == ParallelDescriptor::NProcs()-1) {
1712  Vector<BoxArray> boxArrays(nlevels);
1713  for(int level(0); level < boxArrays.size(); ++level) {
1714  boxArrays[level] = mf[level]->boxArray();
1715  }
1716 
1717  auto f = [=]() {
1718  VisMF::IO_Buffer io_buffer(VisMF::IO_Buffer_Size);
1719  std::string HeaderFileName(plotfilename + "/Header");
1720  std::ofstream HeaderFile;
1721  HeaderFile.rdbuf()->pubsetbuf(io_buffer.dataPtr(), io_buffer.size());
1722  HeaderFile.open(HeaderFileName.c_str(), std::ofstream::out |
1723  std::ofstream::trunc |
1724  std::ofstream::binary);
1725  if( ! HeaderFile.good()) FileOpenFailed(HeaderFileName);
1726  WriteGenericPlotfileHeaderWithTerrain(HeaderFile, nlevels, boxArrays, varnames,
1727  my_geom, time, level_steps, rr, versionName,
1728  levelPrefix, mfPrefix);
1729  };
1730 
1731  if (AsyncOut::UseAsyncOut()) {
1732  AsyncOut::Submit(std::move(f));
1733  } else {
1734  f();
1735  }
1736  }
1737 
1738  std::string mf_nodal_prefix = "Nu_nd";
1739  for (int level = 0; level <= finest_level; ++level)
1740  {
1741  if (AsyncOut::UseAsyncOut()) {
1742  VisMF::AsyncWrite(*mf[level],
1743  MultiFabFileFullPrefix(level, plotfilename, levelPrefix, mfPrefix),
1744  true);
1745  VisMF::AsyncWrite(*mf_nd[level],
1746  MultiFabFileFullPrefix(level, plotfilename, levelPrefix, mf_nodal_prefix),
1747  true);
1748  } else {
1749  const MultiFab* data;
1750  std::unique_ptr<MultiFab> mf_tmp;
1751  if (mf[level]->nGrowVect() != 0) {
1752  mf_tmp = std::make_unique<MultiFab>(mf[level]->boxArray(),
1753  mf[level]->DistributionMap(),
1754  mf[level]->nComp(), 0, MFInfo(),
1755  mf[level]->Factory());
1756  MultiFab::Copy(*mf_tmp, *mf[level], 0, 0, mf[level]->nComp(), 0);
1757  data = mf_tmp.get();
1758  } else {
1759  data = mf[level];
1760  }
1761  VisMF::Write(*data , MultiFabFileFullPrefix(level, plotfilename, levelPrefix, mfPrefix));
1762  VisMF::Write(*mf_nd[level], MultiFabFileFullPrefix(level, plotfilename, levelPrefix, mf_nodal_prefix));
1763  }
1764  }
1765 }
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:1768

◆ WriteMyEBSurface()

void ERF::WriteMyEBSurface ( )
6 {
7  using namespace amrex;
8 
9  amrex::Print() << "Writing the geometry to a vtp file.\n" << std::endl;
10 
11  // Only write at the finest level!
12  int lev = finest_level;
13 
14  BoxArray & ba = grids[lev];
15  DistributionMapping & dm = dmap[lev];
16 
17  const EBFArrayBoxFactory* ebfact = &EBFactory(lev);
18 
19  WriteEBSurface(ba,dm,Geom(lev),ebfact);
20 }
Definition: ERF_ConsoleIO.cpp:12
Here is the call graph for this function:

◆ 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 
)
2073 {
2074  bool write_now = false;
2075 
2076  if ( plot_int > 0 && (nstep % plot_int == 0) ) {
2077  write_now = true;
2078 
2079  } else if (plot_per > 0.0) {
2080 
2081  // Check to see if we've crossed a plot_per interval by comparing
2082  // the number of intervals that have elapsed for both the current
2083  // time and the time at the beginning of this timestep.
2084 
2085  const Real eps = std::numeric_limits<Real>::epsilon() * Real(10.0) * std::abs(cur_time);
2086 
2087  int num_per_old = static_cast<int>(std::floor((cur_time-eps-dt_lev) / plot_per));
2088  int num_per_new = static_cast<int>(std::floor((cur_time-eps ) / plot_per));
2089 
2090  // Before using these, however, we must test for the case where we're
2091  // within machine epsilon of the next interval. In that case, increment
2092  // the counter, because we have indeed reached the next plot_per interval
2093  // at this point.
2094 
2095  const Real next_plot_time = (num_per_old + 1) * plot_per;
2096 
2097  if ((num_per_new == num_per_old) && std::abs(cur_time - next_plot_time) <= eps)
2098  {
2099  num_per_new += 1;
2100  }
2101 
2102  // Similarly, we have to account for the case where the old time is within
2103  // machine epsilon of the beginning of this interval, so that we don't double
2104  // count that time threshold -- we already plotted at that time on the last timestep.
2105 
2106  if ((num_per_new != num_per_old) && std::abs((cur_time - dt_lev) - next_plot_time) <= eps)
2107  num_per_old += 1;
2108 
2109  if (num_per_old != num_per_new)
2110  write_now = true;
2111  }
2112  return write_now;
2113 }

◆ WritePlotFile()

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

◆ WriteSubvolume()

void ERF::WriteSubvolume ( )
10 {
11  ParmParse pp("erf.subvol");
12 
13  Vector<Real> origin;
14  Vector< int> ncell;
15  Vector<Real> delta;
16 
17  // **************************************************************
18  // Read in the origin, number of cells in each dir, and resolution
19  // **************************************************************
20  pp.getarr("origin",origin,0,AMREX_SPACEDIM);
21  pp.getarr("nxnynz", ncell,0,AMREX_SPACEDIM);
22  pp.getarr("dxdydz", delta,0,AMREX_SPACEDIM);
23 
24  int lev_for_sub = 0;
25 
26  bool found = false;
27  for (int i = 0; i <= finest_level; i++) {
28  if (!found) {
29  if (almostEqual(delta[0],geom[i].CellSize(0)) &&
30  almostEqual(delta[1],geom[i].CellSize(1)) &&
31  almostEqual(delta[2],geom[i].CellSize(2)) ) {
32 
33  // amrex::Print() << "XDIR " << delta[0] << " " << geom[i].CellSize(0) << std::endl;
34  // amrex::Print() << "YDIR " << delta[1] << " " << geom[i].CellSize(1) << std::endl;
35  // amrex::Print() << "ZDIR " << delta[2] << " " << geom[i].CellSize(2) << std::endl;
36  amrex::Print() << "Resolution specified matches that of level " << i << std::endl;
37  found = true;
38  lev_for_sub = i;
39  }
40  }
41  }
42 
43  if (!found) {
44  amrex::Abort("Resolution specified for subvol does not match the resolution of any of the levels.");
45  }
46 
47  // **************************************************************
48  // Now that we know which level we're at, we can figure out which (i,j,k) the origin corresponds to
49  // Note we use 1.0001 as a fudge factor since the division of two reals --> integer will do a floor
50  // **************************************************************
51  int i0 = static_cast<int>((origin[0] - geom[lev_for_sub].ProbLo(0)) * 1.0001 / delta[0]);
52  int j0 = static_cast<int>((origin[1] - geom[lev_for_sub].ProbLo(1)) * 1.0001 / delta[1]);
53  int k0 = static_cast<int>((origin[2] - geom[lev_for_sub].ProbLo(2)) * 1.0001 / delta[2]);
54 
55  found = false;
56  if (almostEqual(geom[lev_for_sub].ProbLo(0)+i0*delta[0],origin[0]) &&
57  almostEqual(geom[lev_for_sub].ProbLo(1)+j0*delta[1],origin[1]) &&
58  almostEqual(geom[lev_for_sub].ProbLo(2)+k0*delta[2],origin[2]) )
59  {
60  amrex::Print() << "Specified origin is the lower left corner of cell " << IntVect(i0,j0,k0) << std::endl;
61  found = true;
62  }
63 
64  if (!found) {
65  amrex::Abort("Origin specified does not correspond to a node at this level.");
66  }
67 
68  Box domain(geom[lev_for_sub].Domain());
69 
70  Box bx(IntVect(i0,j0,k0),IntVect(i0+ncell[0]-1,j0+ncell[1]-1,k0+ncell[2]-1));
71  amrex::Print() << "Box requested is " << bx << std::endl;
72 
73  if (!domain.contains(bx))
74  {
75  amrex::Abort("Box requested is larger than the existing domain");
76  }
77 
78  Vector<int> cs(3);
79  int count = pp.countval("chunk_size");
80  if (count > 0) {
81  pp.queryarr("chunk_size",cs,0,AMREX_SPACEDIM);
82  } else {
83  cs[0] = max_grid_size[0][0];
84  cs[1] = max_grid_size[0][1];
85  cs[2] = max_grid_size[0][2];
86  }
87  IntVect chunk_size(cs[0],cs[1],cs[2]);
88 
89  BoxArray ba(bx);
90  ba.maxSize(chunk_size);
91 
92  amrex::Print() << "BoxArray is " << ba << std::endl;
93 
94  int ncomp_mf = AMREX_SPACEDIM;
95 
96  DistributionMapping dm(ba);
97 
98  MultiFab mf(ba, dm, ncomp_mf, 0);
99 
100  MultiFab mf_cc_vel(grids[lev_for_sub], dmap[lev_for_sub], ncomp_mf, 0);
101  average_face_to_cellcenter(mf_cc_vel,0,
102  Array<const MultiFab*,3>{&vars_new[lev_for_sub][Vars::xvel],
103  &vars_new[lev_for_sub][Vars::yvel],
104  &vars_new[lev_for_sub][Vars::zvel]});
105 
106  mf.ParallelCopy(mf_cc_vel,0,0,AMREX_SPACEDIM,0,0);
107 
108  std::string subvol_filename = Concatenate(subvol_file, istep[0], 5);
109 
110  Vector<std::string> varnames;
111  varnames.push_back("x_velocity");
112  varnames.push_back("y_velocity");
113  varnames.push_back("z_velocity");
114 
115  Real time = t_new[lev_for_sub];
116 
117  amrex::Print() <<"Writing subvolume into " << subvol_filename << std::endl;
118  WriteSingleLevelPlotfile(subvol_filename,mf,varnames,geom[lev_for_sub],time,istep[0]);
119 }
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"}

◆ cosPhi_m

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

◆ d_havg_density

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

◆ d_havg_pressure

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

◆ d_havg_qc

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

◆ d_havg_qv

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

◆ d_havg_temperature

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

◆ d_rayleigh_ptrs

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

◆ d_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().

◆ datetime_format

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

◆ datprecision

const int ERF::datprecision = 6
private

◆ datwidth

const int ERF::datwidth = 14
private

◆ der_datalog

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

◆ der_datalogname

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

Referenced by DerDataLogName().

◆ derived_names

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

◆ destag_profiles

bool ERF::destag_profiles = true
private

◆ detJ_cc

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

◆ detJ_cc_new

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

◆ detJ_cc_src

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

◆ domain_bc_type

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

◆ domain_bcs_type

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

◆ domain_bcs_type_d

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

◆ dt

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

◆ dt_max

Real ERF::dt_max = 1e9
staticprivate

◆ dt_max_initial

Real ERF::dt_max_initial = 2.0e100
staticprivate

◆ dt_mri_ratio

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

◆ dz_min

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

◆ eb

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

Referenced by EBFactory(), and get_eb().

◆ eddyDiffs_lev

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

◆ 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

◆ 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

◆ last_subvol

int ERF::last_subvol
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_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_subvol_int

int ERF::m_subvol_int = -1
private

◆ m_subvol_per

amrex::Real ERF::m_subvol_per = -1.0
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 {6}
private

◆ metgrid_interp_theta

bool ERF::metgrid_interp_theta {false}
private

◆ metgrid_order

int ERF::metgrid_order {2}
private

◆ metgrid_proximity

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

◆ metgrid_retain_sfc

bool ERF::metgrid_retain_sfc {false}
private

◆ metgrid_use_below_sfc

bool ERF::metgrid_use_below_sfc {true}
private

◆ metgrid_use_sfc

bool ERF::metgrid_use_sfc {true}
private

◆ 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

◆ regrid_level_0_on_restart

bool ERF::regrid_level_0_on_restart = false
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

◆ sinPhi_m

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

◆ SmnSmn_lev

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

◆ 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

◆ subvol_file

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

◆ sum_interval

int ERF::sum_interval = -1
staticprivate

◆ sum_per

Real ERF::sum_per = -1.0
staticprivate

◆ 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

◆ terrain_blanking

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

◆ th_bc_data

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

◆ Theta_prim

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

◆ thin_xforce

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

◆ thin_yforce

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

◆ thin_zforce

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

◆ timeprecision

const int ERF::timeprecision = 13
private

◆ turbPert

TurbulentPerturbation ERF::turbPert
private

◆ use_datetime

bool ERF::use_datetime = false
private

◆ use_fft

bool ERF::use_fft = false
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: